Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion log4j-1.2-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-1.2-api</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-api-java9/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-api-java9</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-api</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-appserver/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<artifactId>log4j</artifactId>
<groupId>org.apache.logging.log4j</groupId>
<version>2.14.1</version>
<version>2.16.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
4 changes: 2 additions & 2 deletions log4j-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<description>Apache Log4j Bill of Materials</description>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-bom</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
Expand Down Expand Up @@ -217,6 +217,6 @@
</build>

<scm>
<tag>log4j-2.14.1-rc1</tag>
<tag>log4j-2.16.0-rc1</tag>
</scm>
</project>
2 changes: 1 addition & 1 deletion log4j-cassandra/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion log4j-core-its/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-core-its</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-core-java9/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-core-java9</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,21 @@
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.net.JndiManager;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.PropertiesUtil;

/**
* Looks up keys from JNDI resources.
*
* <p>As of Log4j 2.16.0, JNDI lookups are disabled by default as a mitigation for
* CVE-2021-44228 (Log4Shell). To re-enable, set the system property
* {@code log4j2.enableJndiLookup=true}.</p>
*/
@Plugin(name = "jndi", category = StrLookup.CATEGORY)
public class JndiLookup extends AbstractLookup {

private static final Logger LOGGER = StatusLogger.getLogger();
private static final Marker LOOKUP = MarkerManager.getMarker("LOOKUP");
static final String JNDI_LOOKUP_ENABLED_PROPERTY = "log4j2.enableJndiLookup";

/** JNDI resource path prefix used in a J2EE container */
static final String CONTAINER_JNDI_RESOURCE_PATH_PREFIX = "java:comp/env/";
Expand All @@ -48,6 +54,11 @@ public class JndiLookup extends AbstractLookup {
*/
@Override
public String lookup(final LogEvent event, final String key) {
if (!isJndiLookupEnabled()) {
LOGGER.warn(LOOKUP, "JNDI lookup is not enabled. To enable, set system property '{}=true'. "
+ "See CVE-2021-44228 for details.", JNDI_LOOKUP_ENABLED_PROPERTY);
return null;
}
if (key == null) {
return null;
}
Expand All @@ -60,6 +71,10 @@ public String lookup(final LogEvent event, final String key) {
}
}

private static boolean isJndiLookupEnabled() {
return PropertiesUtil.getProperties().getBooleanProperty(JNDI_LOOKUP_ENABLED_PROPERTY, false);
}

/**
* Convert the given JNDI name to the actual JNDI name to use.
* Default implementation applies the "java:comp/env/" prefix
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

package org.apache.logging.log4j.core.net;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

Expand All @@ -27,15 +31,45 @@
import org.apache.logging.log4j.core.appender.AbstractManager;
import org.apache.logging.log4j.core.appender.ManagerFactory;
import org.apache.logging.log4j.core.util.JndiCloser;
import org.apache.logging.log4j.util.PropertiesUtil;

/**
* Manages a JNDI {@link javax.naming.Context}.
*
* <p>As of Log4j 2.16.0, JNDI features are disabled by default as a mitigation for
* CVE-2021-44228 (Log4Shell). To re-enable, set the system property
* {@code log4j2.enableJndi=true}. Allowed JNDI protocols can be configured via
* {@code log4j2.allowedJndiProtocols} (default: {@code java}) and allowed LDAP hosts
* via {@code log4j2.allowedLdapHosts} (default: {@code localhost}).</p>
*
* @since 2.1
*/
public class JndiManager extends AbstractManager {

private static final JndiManagerFactory FACTORY = new JndiManagerFactory();
static final String JNDI_MANAGER_ENABLED_PROPERTY = "log4j2.enableJndi";
private static final String ALLOWED_PROTOCOLS_PROPERTY = "log4j2.allowedJndiProtocols";
private static final String ALLOWED_HOSTS_PROPERTY = "log4j2.allowedLdapHosts";
private static final List<String> ALLOWED_PROTOCOLS;
private static final List<String> ALLOWED_HOSTS;

static {
final String protocols = PropertiesUtil.getProperties().getStringProperty(
ALLOWED_PROTOCOLS_PROPERTY, "java");
ALLOWED_PROTOCOLS = Arrays.asList(protocols.toLowerCase().split("\\s*,\\s*"));
final String hosts = PropertiesUtil.getProperties().getStringProperty(
ALLOWED_HOSTS_PROPERTY, "localhost,127.0.0.1,0:0:0:0:0:0:0:1,::1");
ALLOWED_HOSTS = Arrays.asList(hosts.toLowerCase().split("\\s*,\\s*"));
}

/**
* Returns whether JNDI is enabled via the {@code log4j2.enableJndi} system property.
*
* @return {@code true} if JNDI is enabled, {@code false} otherwise.
*/
public static boolean isJndiEnabled() {
return PropertiesUtil.getProperties().getBooleanProperty(JNDI_MANAGER_ENABLED_PROPERTY, false);
}

private final Context context;

Expand Down Expand Up @@ -162,13 +196,50 @@ protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
/**
* Looks up a named object through this JNDI context.
*
* <p>This method validates the URI scheme against the allowed protocols list
* ({@code log4j2.allowedJndiProtocols}). LDAP/LDAPS URIs are also validated
* against the allowed hosts list ({@code log4j2.allowedLdapHosts}).</p>
*
* @param name name of the object to look up.
* @param <T> the type of the object.
* @return the named object if it could be located.
* @throws NamingException if a naming exception is encountered
*/
@SuppressWarnings("unchecked")
public <T> T lookup(final String name) throws NamingException {
// Reject any name containing a colon before the first slash — this catches
// URI-like patterns such as "ldap:something" that may not parse as valid URIs
// but could still be interpreted by a JNDI provider as a remote lookup.
final int colonIndex = name.indexOf(':');
final int firstSlash = name.indexOf('/');
if (colonIndex >= 0 && (firstSlash < 0 || colonIndex < firstSlash)) {
final String potentialScheme = name.substring(0, colonIndex).toLowerCase();
if (!ALLOWED_PROTOCOLS.contains(potentialScheme)) {
LOGGER.warn("JNDI name '{}' uses a protocol that is not allowed. Allowed protocols: {}.",
name, ALLOWED_PROTOCOLS);
return null;
}
}
try {
final URI uri = new URI(name);
final String scheme = uri.getScheme();
if (scheme != null && !ALLOWED_PROTOCOLS.contains(scheme.toLowerCase())) {
LOGGER.warn("JNDI URI '{}' uses a protocol that is not allowed. Allowed protocols: {}.",
name, ALLOWED_PROTOCOLS);
return null;
}
if (scheme != null && (scheme.equalsIgnoreCase("ldap") || scheme.equalsIgnoreCase("ldaps"))) {
final String host = uri.getHost();
if (host != null && !ALLOWED_HOSTS.contains(host.toLowerCase())) {
LOGGER.warn("JNDI URI '{}' connects to a host that is not allowed. Allowed hosts: {}.",
name, ALLOWED_HOSTS);
return null;
}
}
} catch (final URISyntaxException e) {
LOGGER.warn("JNDI name '{}' is not a valid URI and could not be validated; lookup rejected.", name);
return null;
}
return (T) this.context.lookup(name);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,87 @@ private Map<String, Object> createBindings() {
return map;
}

/**
* Verifies that JNDI lookups return null when JNDI is disabled (the default).
* This is the expected secure-by-default behaviour introduced to mitigate CVE-2021-44228.
*/
@Test
public void testLookupDisabledByDefault() {
// Ensure the property is not set so the default (disabled) is used.
final String previous = System.getProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY);
try {
System.clearProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY);
final StrLookup lookup = new JndiLookup();
assertNull("JNDI lookup should return null when disabled by default (CVE-2021-44228)",
lookup.lookup(TEST_CONTEXT_RESOURCE_NAME));
} finally {
if (previous != null) {
System.setProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY, previous);
}
}
}

/**
* Verifies that JNDI lookups return null when the property is explicitly set to false.
*/
@Test
public void testLookupExplicitlyDisabled() {
final String previous = System.getProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY);
try {
System.setProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY, "false");
final StrLookup lookup = new JndiLookup();
assertNull("JNDI lookup should return null when explicitly disabled",
lookup.lookup(TEST_CONTEXT_RESOURCE_NAME));
} finally {
if (previous != null) {
System.setProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY, previous);
} else {
System.clearProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY);
}
}
}

@Test
public void testLookup() {
final StrLookup lookup = new JndiLookup();
final String previous = System.getProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY);
try {
System.setProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY, "true");
final StrLookup lookup = new JndiLookup();

String contextName = lookup.lookup(TEST_CONTEXT_RESOURCE_NAME);
assertEquals(TEST_CONTEXT_NAME, contextName);
String contextName = lookup.lookup(TEST_CONTEXT_RESOURCE_NAME);
assertEquals(TEST_CONTEXT_NAME, contextName);

contextName = lookup.lookup(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME);
assertEquals(TEST_CONTEXT_NAME, contextName);
contextName = lookup.lookup(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME);
assertEquals(TEST_CONTEXT_NAME, contextName);

final String nonExistingResource = lookup.lookup("logging/non-existing-resource");
assertNull(nonExistingResource);
final String nonExistingResource = lookup.lookup("logging/non-existing-resource");
assertNull(nonExistingResource);
} finally {
if (previous != null) {
System.setProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY, previous);
} else {
System.clearProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY);
}
}
}

@Test
public void testNonStringLookup() throws Exception {
// LOG4J2-1310
final StrLookup lookup = new JndiLookup();
final String integralValue = lookup.lookup(TEST_INTEGRAL_NAME);
assertEquals(String.valueOf(TEST_INTEGRAL_VALUE), integralValue);
final String collectionValue = lookup.lookup(TEST_STRINGS_NAME);
assertEquals(String.valueOf(TEST_STRINGS_COLLECTION), collectionValue);
final String previous = System.getProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY);
try {
System.setProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY, "true");
final StrLookup lookup = new JndiLookup();
final String integralValue = lookup.lookup(TEST_INTEGRAL_NAME);
assertEquals(String.valueOf(TEST_INTEGRAL_VALUE), integralValue);
final String collectionValue = lookup.lookup(TEST_STRINGS_NAME);
assertEquals(String.valueOf(TEST_STRINGS_COLLECTION), collectionValue);
} finally {
if (previous != null) {
System.setProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY, previous);
} else {
System.clearProperty(JndiLookup.JNDI_LOOKUP_ENABLED_PROPERTY);
}
}
}
}
2 changes: 1 addition & 1 deletion log4j-couchdb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion log4j-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-distribution</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-docker/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-docker</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-flume-ng/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-flume-ng</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-iostreams/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-iostreams</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion log4j-jcl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
<version>2.16.0</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-jcl</artifactId>
Expand Down
Loading