Skip to content

Commit 7fe72d6

Browse files
committed
LOG4J2-3201 - Limit the protocols JNDI can use by default. Limit the servers and classes that can be accessed via LDAP.
1 parent 5f81dd2 commit 7fe72d6

File tree

7 files changed

+103
-31
lines changed

7 files changed

+103
-31
lines changed

log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -209,43 +209,45 @@ protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
209209
public synchronized <T> T lookup(final String name) throws NamingException {
210210
try {
211211
URI uri = new URI(name);
212-
if (!allowedProtocols.contains(uri.getScheme().toLowerCase(Locale.ROOT))) {
213-
LOGGER.warn("Log4j JNDI does not allow protocol {}", uri.getScheme());
214-
return null;
215-
}
216-
if (LDAP.equalsIgnoreCase(uri.getScheme()) || LDAPS.equalsIgnoreCase(uri.getScheme())) {
217-
if (!allowedHosts.contains(uri.getHost())) {
218-
LOGGER.warn("Attempt to access ldap server not in allowed list");
212+
if (uri.getScheme() != null) {
213+
if (!allowedProtocols.contains(uri.getScheme().toLowerCase(Locale.ROOT))) {
214+
LOGGER.warn("Log4j JNDI does not allow protocol {}", uri.getScheme());
219215
return null;
220216
}
221-
Attributes attributes = this.context.getAttributes(name);
222-
if (attributes != null) {
223-
// In testing the "key" for attributes seems to be lowercase while the attribute id is
224-
// camelcase, but that may just be true for the test LDAP used here. This copies the Attributes
225-
// to a Map ignoring the "key" and using the Attribute's id as the key in the Map so it matches
226-
// the Java schema.
227-
Map<String, Attribute> attributeMap = new HashMap<>();
228-
NamingEnumeration<? extends Attribute> enumeration = attributes.getAll();
229-
while (enumeration.hasMore()) {
230-
Attribute attribute = enumeration.next();
231-
attributeMap.put(attribute.getID(), attribute);
217+
if (LDAP.equalsIgnoreCase(uri.getScheme()) || LDAPS.equalsIgnoreCase(uri.getScheme())) {
218+
if (!allowedHosts.contains(uri.getHost())) {
219+
LOGGER.warn("Attempt to access ldap server not in allowed list");
220+
return null;
232221
}
233-
Attribute classNameAttr = attributeMap.get(CLASS_NAME);
234-
if (attributeMap.get(SERIALIZED_DATA) != null) {
235-
if (classNameAttr != null) {
236-
String className = classNameAttr.get().toString();
237-
if (!allowedClasses.contains(className)) {
238-
LOGGER.warn("Deserialization of {} is not allowed", className);
222+
Attributes attributes = this.context.getAttributes(name);
223+
if (attributes != null) {
224+
// In testing the "key" for attributes seems to be lowercase while the attribute id is
225+
// camelcase, but that may just be true for the test LDAP used here. This copies the Attributes
226+
// to a Map ignoring the "key" and using the Attribute's id as the key in the Map so it matches
227+
// the Java schema.
228+
Map<String, Attribute> attributeMap = new HashMap<>();
229+
NamingEnumeration<? extends Attribute> enumeration = attributes.getAll();
230+
while (enumeration.hasMore()) {
231+
Attribute attribute = enumeration.next();
232+
attributeMap.put(attribute.getID(), attribute);
233+
}
234+
Attribute classNameAttr = attributeMap.get(CLASS_NAME);
235+
if (attributeMap.get(SERIALIZED_DATA) != null) {
236+
if (classNameAttr != null) {
237+
String className = classNameAttr.get().toString();
238+
if (!allowedClasses.contains(className)) {
239+
LOGGER.warn("Deserialization of {} is not allowed", className);
240+
return null;
241+
}
242+
} else {
243+
LOGGER.warn("No class name provided for {}", name);
239244
return null;
240245
}
241-
} else {
242-
LOGGER.warn("No class name provided for {}", name);
246+
} else if (attributeMap.get(REFERENCE_ADDRESS) != null
247+
|| attributeMap.get(OBJECT_FACTORY) != null) {
248+
LOGGER.warn("Referenceable class is not allowed for {}", name);
243249
return null;
244250
}
245-
} else if (attributeMap.get(REFERENCE_ADDRESS) != null
246-
|| attributeMap.get(OBJECT_FACTORY) != null) {
247-
LOGGER.warn("Referenceable class is not allowed for {}", name);
248-
return null;
249251
}
250252
}
251253
}

log4j-core/src/main/java/org/apache/logging/log4j/core/util/NetUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ public static String getLocalHostname() {
8484
}
8585
}
8686

87+
/**
88+
* Returns all the local host names and ip addresses.
89+
* @return The local host names and ip addresses.
90+
*/
8791
public static List<String> getLocalIps() {
8892
List<String> localIps = new ArrayList<>();
8993
localIps.add("localhost");

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@
110110
Improve PatternLayout performance by reducing unnecessary indirection and branching.
111111
</action>
112112
<!-- FIXES -->
113+
<action issue="LOG4J2-3201" dev="rgoers" type="fix">
114+
Limit the protocols JNDI can use by default. Limit the servers and classes that can be accessed via LDAP.
115+
</action>
113116
<action issue="LOG4J2-3114" dev="rgoers" type="fix" due-to="Barnabas Bodnar">
114117
Enable immediate flush on RollingFileAppender when buffered i/o is not enabled.
115118
</action>

src/site/xdoc/manual/appenders.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,33 @@ public class ConnectionFactory {
15551555
<th>Default</th>
15561556
<th>Description</th>
15571557
</tr>
1558+
<tr>
1559+
<td>allowdLdapClasses</td>
1560+
<td>String</td>
1561+
<td>null</td>
1562+
<td>
1563+
A comma separated list of fully qualified class names that may be accessed by LDAP. The classes
1564+
must implement Serializable. Only applies when the JMS Appender By default only Java primative classes are allowed.
1565+
</td>
1566+
</tr>
1567+
<tr>
1568+
<td>allowdLdapHosts</td>
1569+
<td>String</td>
1570+
<td>null</td>
1571+
<td>
1572+
A comma separated list of host names or ip addresses that may be accessed by LDAP. By default only
1573+
the local host names and ip addresses are allowed.
1574+
</td>
1575+
</tr>
1576+
<tr>
1577+
<td>allowdJndiProtocols</td>
1578+
<td>String</td>
1579+
<td>null</td>
1580+
<td>
1581+
A comma separated list of protocol names that JNDI will allow. By default only java, ldap, and ldaps
1582+
are the only allowed protocols.
1583+
</td>
1584+
</tr>
15581585
<tr>
15591586
<td>factoryBindingName</td>
15601587
<td>String</td>

src/site/xdoc/manual/configuration.xml.vm

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,6 +2146,32 @@ public class AwesomeTest {
21462146
before falling back to the default class loader.
21472147
</td>
21482148
</tr>
2149+
<tr>
2150+
<td><a name="allowedLdapClasses"/>log4j2.allowedLdapClasses</td>
2151+
<td>LOG4J_ALLOWED_LDAP_CLASSES</td>
2152+
<td>&nbsp;</td>
2153+
<td>
2154+
System property that specifies fully qualified class names that may be accessed by LDAP. The classes
2155+
must implement Serializable. By default only Java primative classes are allowed.
2156+
</td>
2157+
</tr>
2158+
<tr>
2159+
<td><a name="allowedLdapHosts"/>log4j2.allowedLdapHosts</td>
2160+
<td>LOG4J_ALLOWED_LDAP_HOSTS</td>
2161+
<td>&nbsp;</td>
2162+
<td>
2163+
System property that adds host names or ip addresses that may be access by LDAP. By default it only allows
2164+
the local host names and ip addresses.
2165+
</td>
2166+
</tr>
2167+
<tr>
2168+
<td><a name="allowedJndiProtocols"/>log4j2.allowedJndiProtocols</td>
2169+
<td>LOG4J_ALLOWED_JNDI_PROTOCOLS</td>
2170+
<td>&nbsp;</td>
2171+
<td>
2172+
System property that adds protocol names that JNDI will allow. By default it only allows java, ldap, and ldaps.
2173+
</td>
2174+
</tr>
21492175
<tr>
21502176
<td><a name="uuidSequence"/>log4j2.uuidSequence
21512177
<br />

src/site/xdoc/manual/extending.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@
9292
<dd>Associates LoggerContexts with the ClassLoader that created the caller of the getLogger call. This is
9393
the default ContextSelector.</dd>
9494
<dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/JndiContextSelector.html">JndiContextSelector</a></dt>
95-
<dd>Locates the LoggerContext by querying JNDI.</dd>
95+
<dd>Locates the LoggerContext by querying JNDI. Please see <a href="../manual/configuration.html#allowedJndiProtocols">log4j2.allowedJndiProtocols</a>,
96+
<a href="../manual/configuration.html#allowedLdapClasses">log4j2.allowedLdapClasses</a>, and
97+
<a href="../manual/configuration.html#allowedLdapHosts">log4j2.allowedLdapHosts</a> for restrictions on using JNDI
98+
with Log4j.</dd>
9699
<dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html">AsyncLoggerContextSelector</a></dt>
97100
<dd>Creates a LoggerContext that ensures that all loggers are AsyncLoggers.</dd>
98101
<dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/osgi/BundleContextSelector.html">BundleContextSelector</a></dt>

src/site/xdoc/manual/lookups.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,13 @@
270270
The JndiLookup allows variables to be retrieved via JNDI. By default the key will be prefixed with
271271
java:comp/env/, however if the key contains a ":" no prefix will be added.
272272
</p>
273+
<p>By default the JDNI Lookup only supports the java, ldap, and ldaps protocols or no protocol. Additional
274+
protocols may be supported by specifying them on the <code>log4j2.allowedJndiProtocols</code> property.
275+
When using LDAP Java classes that implement the Referenceable interface are not supported for security
276+
reasons. Only the Java primative classes are supported by default as well as any classes specified by the
277+
<code>log4j2.allowedLdapClasses</code> property. When using LDAP only references to the local host name
278+
or ip address are supported along with any hosts or ip addresses listed in the
279+
<code>log4j2.allowedLdapHosts</code> property.</p>
273280
<pre class="prettyprint linenums"><![CDATA[
274281
<File name="Application" fileName="application.log">
275282
<PatternLayout>

0 commit comments

Comments
 (0)