Codebase list apache-log4j1.2 / 0316ea5
Fix CVE-2022-23302 and CVE-2022-23307 Markus Koschany 2 years ago
2 changed file(s) with 391 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 From: Markus Koschany <apo@debian.org>
1 Date: Mon, 31 Jan 2022 11:30:35 +0100
2 Subject: CVE-2022-23302
3
4 Origin: https://github.com/qos-ch/reload4j/commit/f221f2427c45134cf5768f46279ddf72fe1407c9
5 ---
6 src/main/java/org/apache/log4j/net/JMSSink.java | 14 ++------------
7 1 file changed, 2 insertions(+), 12 deletions(-)
8
9 diff --git a/src/main/java/org/apache/log4j/net/JMSSink.java b/src/main/java/org/apache/log4j/net/JMSSink.java
10 index 6a02831..c25b4a3 100644
11 --- a/src/main/java/org/apache/log4j/net/JMSSink.java
12 +++ b/src/main/java/org/apache/log4j/net/JMSSink.java
13 @@ -88,8 +88,7 @@ public class JMSSink implements javax.jms.MessageListener {
14 try {
15 Context ctx = new InitialContext();
16 TopicConnectionFactory topicConnectionFactory;
17 - topicConnectionFactory = (TopicConnectionFactory) lookup(ctx,
18 - tcfBindingName);
19 + topicConnectionFactory = (TopicConnectionFactory) JNDIUtil.lookupObject(ctx, tcfBindingName);
20
21 TopicConnection topicConnection =
22 topicConnectionFactory.createTopicConnection(username,
23 @@ -99,7 +98,7 @@ public class JMSSink implements javax.jms.MessageListener {
24 TopicSession topicSession = topicConnection.createTopicSession(false,
25 Session.AUTO_ACKNOWLEDGE);
26
27 - Topic topic = (Topic)ctx.lookup(topicBindingName);
28 + Topic topic = (Topic) JNDIUtil.lookupObject(ctx, topicBindingName);
29
30 TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
31
32 @@ -135,15 +134,6 @@ public class JMSSink implements javax.jms.MessageListener {
33 }
34
35
36 - protected static Object lookup(Context ctx, String name) throws NamingException {
37 - try {
38 - return ctx.lookup(name);
39 - } catch(NameNotFoundException e) {
40 - logger.error("Could not find name ["+name+"].");
41 - throw e;
42 - }
43 - }
44 -
45 static void usage(String msg) {
46 System.err.println(msg);
47 System.err.println("Usage: java " + JMSSink.class.getName()
0 From: Markus Koschany <apo@debian.org>
1 Date: Mon, 31 Jan 2022 11:37:03 +0100
2 Subject: CVE-2022-23307
3
4 Origin: https://github.com/qos-ch/reload4j/commit/64902fe18ce5a5dd40487051a2f6231d9fbbe9b0
5 ---
6 .../org/apache/log4j/chainsaw/LoggingReceiver.java | 8 +-
7 .../log4j/net/HardenedLoggingEventInputStream.java | 56 +++++++++++++
8 .../log4j/net/HardenedObjectInputStream.java | 93 +++++++++++++++++++++
9 src/test/input/xml/socketAppenderForChainsaw.xml | 24 ++++++
10 .../org/apache/log4j/net/SocketAppenderTest.java | 96 ++++++++++++++++++++++
11 5 files changed, 273 insertions(+), 4 deletions(-)
12 create mode 100644 src/main/java/org/apache/log4j/net/HardenedLoggingEventInputStream.java
13 create mode 100644 src/main/java/org/apache/log4j/net/HardenedObjectInputStream.java
14 create mode 100644 src/test/input/xml/socketAppenderForChainsaw.xml
15 create mode 100644 src/test/java/org/apache/log4j/net/SocketAppenderTest.java
16
17 diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java b/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java
18 index ca087ad..74ecc06 100644
19 --- a/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java
20 +++ b/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java
21 @@ -18,11 +18,11 @@ package org.apache.log4j.chainsaw;
22
23 import java.io.EOFException;
24 import java.io.IOException;
25 -import java.io.ObjectInputStream;
26 import java.net.ServerSocket;
27 import java.net.Socket;
28 import java.net.SocketException;
29 import org.apache.log4j.Logger;
30 +import org.apache.log4j.net.HardenedLoggingEventInputStream;
31 import org.apache.log4j.spi.LoggingEvent;
32
33 /**
34 @@ -58,10 +58,10 @@ class LoggingReceiver extends Thread {
35 public void run() {
36 LOG.debug("Starting to get data");
37 try {
38 - final ObjectInputStream ois =
39 - new ObjectInputStream(mClient.getInputStream());
40 + final HardenedLoggingEventInputStream hleis =
41 + new HardenedLoggingEventInputStream(mClient.getInputStream());
42 while (true) {
43 - final LoggingEvent event = (LoggingEvent) ois.readObject();
44 + final LoggingEvent event = (LoggingEvent) hleis.readObject();
45 mModel.addEvent(new EventDetails(event));
46 }
47 } catch (EOFException e) {
48 diff --git a/src/main/java/org/apache/log4j/net/HardenedLoggingEventInputStream.java b/src/main/java/org/apache/log4j/net/HardenedLoggingEventInputStream.java
49 new file mode 100644
50 index 0000000..f0f6a20
51 --- /dev/null
52 +++ b/src/main/java/org/apache/log4j/net/HardenedLoggingEventInputStream.java
53 @@ -0,0 +1,56 @@
54 +/*
55 + * Licensed to the Apache Software Foundation (ASF) under one or more
56 + * contributor license agreements. See the NOTICE file distributed with
57 + * this work for additional information regarding copyright ownership.
58 + * The ASF licenses this file to You under the Apache License, Version 2.0
59 + * (the "License"); you may not use this file except in compliance with
60 + * the License. You may obtain a copy of the License at
61 + *
62 + * http://www.apache.org/licenses/LICENSE-2.0
63 + *
64 + * Unless required by applicable law or agreed to in writing, software
65 + * distributed under the License is distributed on an "AS IS" BASIS,
66 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
67 + * See the License for the specific language governing permissions and
68 + * limitations under the License.
69 + */
70 +package org.apache.log4j.net;
71 +
72 +import java.io.IOException;
73 +import java.io.InputStream;
74 +import java.util.ArrayList;
75 +import java.util.List;
76 +
77 +import org.apache.log4j.Level;
78 +import org.apache.log4j.Priority;
79 +import org.apache.log4j.spi.LocationInfo;
80 +import org.apache.log4j.spi.LoggingEvent;
81 +import org.apache.log4j.spi.ThrowableInformation;
82 +
83 +// === Copied from the logback project with permission ==
84 +public class HardenedLoggingEventInputStream extends HardenedObjectInputStream {
85 +
86 + static final String ARRAY_PREFIX = "[L";
87 +
88 + static public List<String> getWhilelist() {
89 +
90 + List<String> whitelist = new ArrayList<String>();
91 + whitelist.add(LoggingEvent.class.getName());
92 + whitelist.add(Level.class.getName());
93 + whitelist.add(Priority.class.getName());
94 + whitelist.add(ThrowableInformation.class.getName());
95 + whitelist.add(LocationInfo.class.getName());
96 +
97 + return whitelist;
98 + }
99 +
100 + public HardenedLoggingEventInputStream(InputStream is) throws IOException {
101 + super(is, getWhilelist());
102 + }
103 +
104 + public HardenedLoggingEventInputStream(InputStream is, List<String> additionalAuthorizedClasses)
105 + throws IOException {
106 + this(is);
107 + super.addToWhitelist(additionalAuthorizedClasses);
108 + }
109 +}
110 diff --git a/src/main/java/org/apache/log4j/net/HardenedObjectInputStream.java b/src/main/java/org/apache/log4j/net/HardenedObjectInputStream.java
111 new file mode 100644
112 index 0000000..c911572
113 --- /dev/null
114 +++ b/src/main/java/org/apache/log4j/net/HardenedObjectInputStream.java
115 @@ -0,0 +1,93 @@
116 +/*
117 + * Licensed to the Apache Software Foundation (ASF) under one or more
118 + * contributor license agreements. See the NOTICE file distributed with
119 + * this work for additional information regarding copyright ownership.
120 + * The ASF licenses this file to You under the Apache License, Version 2.0
121 + * (the "License"); you may not use this file except in compliance with
122 + * the License. You may obtain a copy of the License at
123 + *
124 + * http://www.apache.org/licenses/LICENSE-2.0
125 + *
126 + * Unless required by applicable law or agreed to in writing, software
127 + * distributed under the License is distributed on an "AS IS" BASIS,
128 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
129 + * See the License for the specific language governing permissions and
130 + * limitations under the License.
131 + */
132 +package org.apache.log4j.net;
133 +
134 +import java.io.IOException;
135 +import java.io.InputStream;
136 +import java.io.InvalidClassException;
137 +import java.io.ObjectInputStream;
138 +import java.io.ObjectStreamClass;
139 +import java.util.ArrayList;
140 +import java.util.List;
141 +
142 +/**
143 + * HardenedObjectInputStream restricts the set of classes that can be
144 + * deserialized to a set of explicitly whitelisted classes. This prevents
145 + * certain type of attacks from being successful.
146 + *
147 + * <p>
148 + * It is assumed that classes in the "java.lang" and "java.util" packages are
149 + * always authorized.
150 + * </p>
151 + *
152 + * @author Ceki G&uuml;lc&uuml;
153 + * @since 1.2.18
154 + *
155 + * === Copied from the logback project with permission ==
156 + */
157 +public class HardenedObjectInputStream extends ObjectInputStream {
158 +
159 + static final String ARRAY_CLASS_PREFIX = "[L";
160 + final List<String> whitelistedClassNames;
161 + final static String[] JAVA_PACKAGES = new String[] { "java.lang", "java.util", ARRAY_CLASS_PREFIX + "java.lang" };
162 +
163 + public HardenedObjectInputStream(InputStream in, String[] whilelist) throws IOException {
164 + super(in);
165 +
166 + this.whitelistedClassNames = new ArrayList<String>();
167 + if (whilelist != null) {
168 + for (int i = 0; i < whilelist.length; i++) {
169 + this.whitelistedClassNames.add(whilelist[i]);
170 + }
171 + }
172 + }
173 +
174 + public HardenedObjectInputStream(InputStream in, List<String> whitelist) throws IOException {
175 + super(in);
176 +
177 + this.whitelistedClassNames = new ArrayList<String>();
178 + this.whitelistedClassNames.addAll(whitelist);
179 + }
180 +
181 + @Override
182 + protected Class<?> resolveClass(ObjectStreamClass anObjectStreamClass) throws IOException, ClassNotFoundException {
183 +
184 + String incomingClassName = anObjectStreamClass.getName();
185 +
186 + if (!isWhitelisted(incomingClassName)) {
187 + throw new InvalidClassException("Unauthorized deserialization attempt", incomingClassName);
188 + }
189 +
190 + return super.resolveClass(anObjectStreamClass);
191 + }
192 +
193 + private boolean isWhitelisted(String incomingClassName) {
194 + for (int i = 0; i < JAVA_PACKAGES.length; i++) {
195 + if (incomingClassName.startsWith(JAVA_PACKAGES[i]))
196 + return true;
197 + }
198 + for (String whiteListed : whitelistedClassNames) {
199 + if (incomingClassName.equals(whiteListed))
200 + return true;
201 + }
202 + return false;
203 + }
204 +
205 + protected void addToWhitelist(List<String> additionalAuthorizedClasses) {
206 + whitelistedClassNames.addAll(additionalAuthorizedClasses);
207 + }
208 +}
209 \ No newline at end of file
210 diff --git a/src/test/input/xml/socketAppenderForChainsaw.xml b/src/test/input/xml/socketAppenderForChainsaw.xml
211 new file mode 100644
212 index 0000000..b022ba5
213 --- /dev/null
214 +++ b/src/test/input/xml/socketAppenderForChainsaw.xml
215 @@ -0,0 +1,24 @@
216 +<?xml version="1.0" encoding="UTF-8" ?>
217 +<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
218 +
219 +<log4j:configuration debug="true"
220 +xmlns:log4j='http://jakarta.apache.org/log4j/'>
221 +
222 +
223 + <!-- primary appender -->
224 + <appender name="REMOTE" class="org.apache.log4j.net.SocketAppender">
225 +
226 + <param name="RemoteHost" value="localhost"/>
227 + <param name="Port" value="4445"/>
228 + <param name="ReconnectionDelay" value="10"/>
229 + </appender>
230 +
231 + <root>
232 + <priority value ="trace" />
233 + <appender-ref ref="REMOTE" />
234 + </root>
235 +
236 +
237 +</log4j:configuration>
238 +
239 +
240 diff --git a/src/test/java/org/apache/log4j/net/SocketAppenderTest.java b/src/test/java/org/apache/log4j/net/SocketAppenderTest.java
241 new file mode 100644
242 index 0000000..6c4a390
243 --- /dev/null
244 +++ b/src/test/java/org/apache/log4j/net/SocketAppenderTest.java
245 @@ -0,0 +1,96 @@
246 +/*
247 + * Licensed to the Apache Software Foundation (ASF) under one or more
248 + * contributor license agreements. See the NOTICE file distributed with
249 + * this work for additional information regarding copyright ownership.
250 + * The ASF licenses this file to You under the Apache License, Version 2.0
251 + * (the "License"); you may not use this file except in compliance with
252 + * the License. You may obtain a copy of the License at
253 + *
254 + * http://www.apache.org/licenses/LICENSE-2.0
255 + *
256 + * Unless required by applicable law or agreed to in writing, software
257 + * distributed under the License is distributed on an "AS IS" BASIS,
258 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
259 + * See the License for the specific language governing permissions and
260 + * limitations under the License.
261 + */
262 +package org.apache.log4j.net;
263 +
264 +import static org.apache.log4j.TestContants.TEST_INPUT_PREFIX;
265 +import static org.junit.Assert.assertEquals;
266 +
267 +import org.apache.log4j.AppenderSkeleton;
268 +import org.apache.log4j.Logger;
269 +import org.apache.log4j.spi.LoggingEvent;
270 +import org.apache.log4j.xml.DOMConfigurator;
271 +import org.junit.After;
272 +import org.junit.Before;
273 +import org.junit.Test;
274 +
275 +public class SocketAppenderTest {
276 +
277 + /* JUnit's setUp and tearDown */
278 +
279 + @Before
280 + public void setUp() {
281 + DOMConfigurator.configure(TEST_INPUT_PREFIX + "xml/SocketAppenderTestConfig.xml");
282 + // DOMConfigurator.configure(TEST_INPUT_PREFIX +
283 + // "xml/socketAppenderForChainsaw.xml");
284 +
285 + logger = Logger.getLogger(SocketAppenderTest.class);
286 + secondary = (LastOnlyAppender) Logger.getLogger("org.apache.log4j.net.SocketAppenderTestDummy")
287 + .getAppender("lastOnly");
288 + }
289 +
290 + @After
291 + public void tearDown() {
292 + }
293 +
294 + /* Tests */
295 +
296 + @Test
297 + public void testFallbackErrorHandlerWhenStarting() {
298 + String msg = "testFallbackErrorHandlerWhenStarting";
299 + logger.debug(msg);
300 +
301 + // above debug log will fail and shoul be redirected to secondary appender
302 + assertEquals("SocketAppender with FallbackErrorHandler", msg, secondary.getLastMessage());
303 + }
304 +
305 + /* Fields */
306 +
307 + private static Logger logger;
308 + private static LastOnlyAppender secondary;
309 +
310 + /* Inner classes */
311 +
312 + /**
313 + * Inner-class For debugging purposes only Saves last LoggerEvent
314 + */
315 + static public class LastOnlyAppender extends AppenderSkeleton {
316 + protected void append(LoggingEvent event) {
317 + this.lastEvent = event;
318 + }
319 +
320 + public boolean requiresLayout() {
321 + return false;
322 + }
323 +
324 + public void close() {
325 + this.closed = true;
326 + }
327 +
328 + /**
329 + * @return last appended LoggingEvent's message
330 + */
331 + public String getLastMessage() {
332 + if (this.lastEvent != null)
333 + return this.lastEvent.getMessage().toString();
334 + else
335 + return "";
336 + }
337 +
338 + private LoggingEvent lastEvent;
339 + };
340 +
341 +}
342 \ No newline at end of file