Closed
fix(cve): 修复 CVE-2026-10532 在 logback 中的漏洞 #40
infra_teamAdd on Jun 2Closed at 26 days ago
fix(cve): 修复 CVE-2026-10532 在 logback 中的漏洞 #40
Closed
Total: 7 files changed+47-1214
| @@ -1,456 +0,0 @@ | |||
| 1 | -From bb095154be011267b64e37a1d401546e7cc2b7c3 Mon Sep 17 00:00:00 2001 | ||
| 2 | -From: Ceki Gulcu <ceki@qos.ch> | ||
| 3 | -Date: Fri, 1 Dec 2023 15:12:22 +0100 | ||
| 4 | -Subject: [PATCH] fix CVE-2023-6378 | ||
| 5 | - | ||
| 6 | -Signed-off-by: Ceki Gulcu <ceki@qos.ch> | ||
| 7 | ---- | ||
| 8 | - .../logback/classic/spi/LoggingEventVO.java | 7 ++ | ||
| 9 | - .../src/test/input/issue/logback-1754.xml | 30 +++++++ | ||
| 10 | - .../issue/logback_1754/LogbackTest.java | 78 +++++++++++++++++++ | ||
| 11 | - .../core/net/HardenedObjectInputStream.java | 55 ++++++++++++- | ||
| 12 | - .../ch/qos/logback/core/util/EnvUtil.java | 39 ++++++---- | ||
| 13 | - .../net/HardenedObjectInputStreamTest.java | 49 +++++++++++- | ||
| 14 | - .../rolling/ScaffoldingForRollingTests.java | 2 +- | ||
| 15 | - .../ch/qos/logback/core/util/EnvUtilTest.java | 34 ++++++++ | ||
| 16 | - 8 files changed, 275 insertions(+), 19 deletions(-) | ||
| 17 | - create mode 100644 logback-classic/src/test/input/issue/logback-1754.xml | ||
| 18 | - create mode 100644 logback-classic/src/test/java/ch/qos/logback/classic/issue/logback_1754/LogbackTest.java | ||
| 19 | - create mode 100644 logback-core/src/test/java/ch/qos/logback/core/util/EnvUtilTest.java | ||
| 20 | - | ||
| 21 | -diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEventVO.java b/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEventVO.java | ||
| 22 | -index e21350b2cc..ea2c6ac128 100644 | ||
| 23 | ---- a/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEventVO.java | ||
| 24 | -+++ b/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEventVO.java | ||
| 25 | -@@ -14,6 +14,7 @@ | ||
| 26 | - package ch.qos.logback.classic.spi; | ||
| 27 | - | ||
| 28 | - import java.io.IOException; | ||
| 29 | -+import java.io.InvalidObjectException; | ||
| 30 | - import java.io.ObjectInputStream; | ||
| 31 | - import java.io.ObjectOutputStream; | ||
| 32 | - import java.io.Serializable; | ||
| 33 | -@@ -38,6 +39,7 @@ public class LoggingEventVO implements ILoggingEvent, Serializable { | ||
| 34 | - | ||
| 35 | - private static final int NULL_ARGUMENT_ARRAY = -1; | ||
| 36 | - private static final String NULL_ARGUMENT_ARRAY_ELEMENT = "NULL_ARGUMENT_ARRAY_ELEMENT"; | ||
| 37 | -+ private static final int ARGUMENT_ARRAY_DESERIALIZATION_LIMIT = 128; | ||
| 38 | - | ||
| 39 | - private String threadName; | ||
| 40 | - private String loggerName; | ||
| 41 | -@@ -181,6 +183,11 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE | ||
| 42 | - level = Level.toLevel(levelInt); | ||
| 43 | - | ||
| 44 | - int argArrayLen = in.readInt(); | ||
| 45 | -+ // Prevent DOS attacks via large or negative arrays | ||
| 46 | -+ if (argArrayLen < NULL_ARGUMENT_ARRAY || argArrayLen > ARGUMENT_ARRAY_DESERIALIZATION_LIMIT) { | ||
| 47 | -+ throw new InvalidObjectException("Argument array length is invalid: " + argArrayLen); | ||
| 48 | -+ } | ||
| 49 | -+ | ||
| 50 | - if (argArrayLen != NULL_ARGUMENT_ARRAY) { | ||
| 51 | - argumentArray = new String[argArrayLen]; | ||
| 52 | - for (int i = 0; i < argArrayLen; i++) { | ||
| 53 | -diff --git a/logback-classic/src/test/input/issue/logback-1754.xml b/logback-classic/src/test/input/issue/logback-1754.xml | ||
| 54 | -new file mode 100644 | ||
| 55 | -index 0000000000..ab41185a34 | ||
| 56 | ---- /dev/null | ||
| 57 | -+++ b/logback-classic/src/test/input/issue/logback-1754.xml | ||
| 58 | -@@ -0,0 +1,30 @@ | ||
| 59 | -+<?xml version="1.0" encoding="UTF-8"?> | ||
| 60 | -+<!-- | ||
| 61 | -+ ~ Logback: the reliable, generic, fast and flexible logging framework. | ||
| 62 | -+ ~ Copyright (C) 1999-2023, QOS.ch. All rights reserved. | ||
| 63 | -+ ~ | ||
| 64 | -+ ~ This program and the accompanying materials are dual-licensed under | ||
| 65 | -+ ~ either the terms of the Eclipse Public License v1.0 as published by | ||
| 66 | -+ ~ the Eclipse Foundation | ||
| 67 | -+ ~ | ||
| 68 | -+ ~ or (per the licensee's choosing) | ||
| 69 | -+ ~ | ||
| 70 | -+ ~ under the terms of the GNU Lesser General Public License version 2.1 | ||
| 71 | -+ ~ as published by the Free Software Foundation. | ||
| 72 | -+ --> | ||
| 73 | -+ | ||
| 74 | -+<configuration debug="true"> | ||
| 75 | -+ <appender name="GENERAL" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
| 76 | -+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||
| 77 | -+ <fileNamePattern>${logback_1754_targetDirectory}/test-%d{yyyy-MM-dd}.log</fileNamePattern> | ||
| 78 | -+ <maxHistory>120</maxHistory> | ||
| 79 | -+ </rollingPolicy> | ||
| 80 | -+ <encoder> | ||
| 81 | -+ <pattern>%date{HH:mm:ss.SSS} [%level] %logger{0} [%thread] [%class{3}:%line] : %msg%n</pattern> | ||
| 82 | -+ </encoder> | ||
| 83 | -+ <prudent>true</prudent> | ||
| 84 | -+ </appender> | ||
| 85 | -+ <root level="debug"> | ||
| 86 | -+ <appender-ref ref="GENERAL" /> | ||
| 87 | -+ </root> | ||
| 88 | -+</configuration> | ||
| 89 | - | ||
| 90 | -diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/issue/logback_1754/LogbackTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/issue/logback_1754/LogbackTest.java | ||
| 91 | -new file mode 100644 | ||
| 92 | -index 0000000000..3001c00a66 | ||
| 93 | ---- /dev/null | ||
| 94 | -+++ b/logback-classic/src/test/java/ch/qos/logback/classic/issue/logback_1754/LogbackTest.java | ||
| 95 | -@@ -0,0 +1,78 @@ | ||
| 96 | -+/* | ||
| 97 | -+ * Logback: the reliable, generic, fast and flexible logging framework. | ||
| 98 | -+ * Copyright (C) 1999-2023, QOS.ch. All rights reserved. | ||
| 99 | -+ * | ||
| 100 | -+ * This program and the accompanying materials are dual-licensed under | ||
| 101 | -+ * either the terms of the Eclipse Public License v1.0 as published by | ||
| 102 | -+ * the Eclipse Foundation | ||
| 103 | -+ * | ||
| 104 | -+ * or (per the licensee's choosing) | ||
| 105 | -+ * | ||
| 106 | -+ * under the terms of the GNU Lesser General Public License version 2.1 | ||
| 107 | -+ * as published by the Free Software Foundation. | ||
| 108 | -+ */ | ||
| 109 | -+ | ||
| 110 | -+package ch.qos.logback.classic.issue.logback_1754; | ||
| 111 | -+ | ||
| 112 | -+import ch.qos.logback.classic.ClassicConstants; | ||
| 113 | -+import ch.qos.logback.classic.ClassicTestConstants; | ||
| 114 | -+import ch.qos.logback.core.testUtil.RandomUtil; | ||
| 115 | -+import org.slf4j.Logger; | ||
| 116 | -+import org.slf4j.LoggerFactory; | ||
| 117 | -+ | ||
| 118 | -+import java.util.ArrayList; | ||
| 119 | -+import java.util.List; | ||
| 120 | -+import java.util.concurrent.CountDownLatch; | ||
| 121 | -+ | ||
| 122 | -+import static ch.qos.logback.classic.util.ContextInitializer.CONFIG_FILE_PROPERTY; | ||
| 123 | -+ | ||
| 124 | -+public class LogbackTest { | ||
| 125 | -+ | ||
| 126 | -+ private static final int THREADS = 16; | ||
| 127 | -+ | ||
| 128 | -+ private void runTest() { | ||
| 129 | -+ | ||
| 130 | -+ int diff = RandomUtil.getPositiveInt(); | ||
| 131 | -+ //System.setProperty("logback.statusListenerClass", "sysout"); | ||
| 132 | -+ System.setProperty(CONFIG_FILE_PROPERTY, ClassicTestConstants.INPUT_PREFIX+"issue/logback-1754.xml"); | ||
| 133 | -+ System.setProperty("logback_1754_targetDirectory", ClassicTestConstants.OUTPUT_DIR_PREFIX+"safeWrite_"+diff); | ||
| 134 | -+ | ||
| 135 | -+ CountDownLatch latch = new CountDownLatch(THREADS); | ||
| 136 | -+ List<Thread> threads = new ArrayList<Thread>(THREADS); | ||
| 137 | -+ for (int i = 0; i < THREADS; i++) { | ||
| 138 | -+ LoggerThread thread = new LoggerThread(latch, "message from thread " + i); | ||
| 139 | -+ thread.start(); | ||
| 140 | -+ threads.add(thread); | ||
| 141 | -+ } | ||
| 142 | -+ for (Thread thread : threads) { | ||
| 143 | -+ try { | ||
| 144 | -+ thread.join(); | ||
| 145 | -+ } catch (InterruptedException e) { | ||
| 146 | -+ Thread.currentThread().interrupt(); | ||
| 147 | -+ throw new RuntimeException(e); | ||
| 148 | -+ } | ||
| 149 | -+ } | ||
| 150 | -+ } | ||
| 151 | -+ | ||
| 152 | -+ public static void main(String... args) { | ||
| 153 | -+ new LogbackTest().runTest(); | ||
| 154 | -+ } | ||
| 155 | -+ | ||
| 156 | -+ private static final class LoggerThread extends Thread { | ||
| 157 | -+ private static final Logger LOG = LoggerFactory.getLogger(LoggerThread.class); | ||
| 158 | -+ private final CountDownLatch latch; | ||
| 159 | -+ private final String message; | ||
| 160 | -+ | ||
| 161 | -+ LoggerThread(CountDownLatch latch, String message) { | ||
| 162 | -+ setDaemon(false); | ||
| 163 | -+ this.latch = latch; | ||
| 164 | -+ this.message = message; | ||
| 165 | -+ } | ||
| 166 | -+ | ||
| 167 | -+ @Override | ||
| 168 | -+ public void run() { | ||
| 169 | -+ latch.countDown(); | ||
| 170 | -+ LOG.info(message); | ||
| 171 | -+ } | ||
| 172 | -+ } | ||
| 173 | -+} | ||
| 174 | -diff --git a/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java b/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java | ||
| 175 | -index d1b7301ea4..0674aaf3ea 100755 | ||
| 176 | ---- a/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java | ||
| 177 | -+++ b/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java | ||
| 178 | -@@ -1,10 +1,27 @@ | ||
| 179 | -+/** | ||
| 180 | -+ * Logback: the reliable, generic, fast and flexible logging framework. | ||
| 181 | -+ * Copyright (C) 1999-2023, QOS.ch. All rights reserved. | ||
| 182 | -+ * | ||
| 183 | -+ * This program and the accompanying materials are dual-licensed under | ||
| 184 | -+ * either the terms of the Eclipse Public License v1.0 as published by | ||
| 185 | -+ * the Eclipse Foundation | ||
| 186 | -+ * | ||
| 187 | -+ * or (per the licensee's choosing) | ||
| 188 | -+ * | ||
| 189 | -+ * under the terms of the GNU Lesser General Public License version 2.1 | ||
| 190 | -+ * as published by the Free Software Foundation. | ||
| 191 | -+ */ | ||
| 192 | - package ch.qos.logback.core.net; | ||
| 193 | - | ||
| 194 | -+import ch.qos.logback.core.util.EnvUtil; | ||
| 195 | -+ | ||
| 196 | - import java.io.IOException; | ||
| 197 | - import java.io.InputStream; | ||
| 198 | - import java.io.InvalidClassException; | ||
| 199 | - import java.io.ObjectInputStream; | ||
| 200 | - import java.io.ObjectStreamClass; | ||
| 201 | -+import java.lang.reflect.InvocationTargetException; | ||
| 202 | -+import java.lang.reflect.Method; | ||
| 203 | - import java.util.ArrayList; | ||
| 204 | - import java.util.List; | ||
| 205 | - | ||
| 206 | -@@ -22,10 +39,12 @@ public class HardenedObjectInputStream extends ObjectInputStream { | ||
| 207 | - | ||
| 208 | - final List<String> whitelistedClassNames; | ||
| 209 | - final static String[] JAVA_PACKAGES = new String[] { "java.lang", "java.util" }; | ||
| 210 | -+ final private static int DEPTH_LIMIT = 16; | ||
| 211 | -+ final private static int ARRAY_LIMIT = 10000; | ||
| 212 | - | ||
| 213 | - public HardenedObjectInputStream(InputStream in, String[] whilelist) throws IOException { | ||
| 214 | - super(in); | ||
| 215 | -- | ||
| 216 | -+ initObjectFilter(); | ||
| 217 | - this.whitelistedClassNames = new ArrayList<String>(); | ||
| 218 | - if (whilelist != null) { | ||
| 219 | - for (int i = 0; i < whilelist.length; i++) { | ||
| 220 | -@@ -36,11 +55,43 @@ public HardenedObjectInputStream(InputStream in, String[] whilelist) throws IOEx | ||
| 221 | - | ||
| 222 | - public HardenedObjectInputStream(InputStream in, List<String> whitelist) throws IOException { | ||
| 223 | - super(in); | ||
| 224 | -- | ||
| 225 | -+ initObjectFilter(); | ||
| 226 | - this.whitelistedClassNames = new ArrayList<String>(); | ||
| 227 | - this.whitelistedClassNames.addAll(whitelist); | ||
| 228 | - } | ||
| 229 | - | ||
| 230 | -+ private void initObjectFilter() { | ||
| 231 | -+ | ||
| 232 | -+ // invoke the following code by reflection | ||
| 233 | -+ // this.setObjectInputFilter(ObjectInputFilter.Config.createFilter( | ||
| 234 | -+ // "maxarray=" + ARRAY_LIMIT + ";maxdepth=" + DEPTH_LIMIT + ";" | ||
| 235 | -+ // )); | ||
| 236 | -+ if(EnvUtil.isJDK9OrHigher()) { | ||
| 237 | -+ try { | ||
| 238 | -+ ClassLoader classLoader = this.getClass().getClassLoader(); | ||
| 239 | -+ | ||
| 240 | -+ Class oifClass = classLoader.loadClass("java.io.ObjectInputFilter"); | ||
| 241 | -+ Class oifConfigClass = classLoader.loadClass("java.io.ObjectInputFilter$Config"); | ||
| 242 | -+ Method setObjectInputFilterMethod = this.getClass().getMethod("setObjectInputFilter", oifClass); | ||
| 243 | -+ | ||
| 244 | -+ Method createFilterMethod = oifConfigClass.getMethod("createFilter", String.class); | ||
| 245 | -+ Object filter = createFilterMethod.invoke(null, "maxarray=" + ARRAY_LIMIT + ";maxdepth=" + DEPTH_LIMIT + ";"); | ||
| 246 | -+ setObjectInputFilterMethod.invoke(this, filter); | ||
| 247 | -+ } catch (ClassNotFoundException e) { | ||
| 248 | -+ // this code should be unreachable | ||
| 249 | -+ throw new RuntimeException("Failed to initialize object filter", e); | ||
| 250 | -+ } catch (InvocationTargetException e) { | ||
| 251 | -+ // this code should be unreachable | ||
| 252 | -+ throw new RuntimeException("Failed to initialize object filter", e); | ||
| 253 | -+ } catch (NoSuchMethodException e) { | ||
| 254 | -+ // this code should be unreachable | ||
| 255 | -+ throw new RuntimeException("Failed to initialize object filter", e); | ||
| 256 | -+ } catch (IllegalAccessException e) { | ||
| 257 | -+ // this code should be unreachable | ||
| 258 | -+ throw new RuntimeException("Failed to initialize object filter", e); | ||
| 259 | -+ } | ||
| 260 | -+ } | ||
| 261 | -+ } | ||
| 262 | - @Override | ||
| 263 | - protected Class<?> resolveClass(ObjectStreamClass anObjectStreamClass) throws IOException, ClassNotFoundException { | ||
| 264 | - | ||
| 265 | -diff --git a/logback-core/src/main/java/ch/qos/logback/core/util/EnvUtil.java b/logback-core/src/main/java/ch/qos/logback/core/util/EnvUtil.java | ||
| 266 | -index c200a1c984..f3dcd0cfe3 100644 | ||
| 267 | ---- a/logback-core/src/main/java/ch/qos/logback/core/util/EnvUtil.java | ||
| 268 | -+++ b/logback-core/src/main/java/ch/qos/logback/core/util/EnvUtil.java | ||
| 269 | -@@ -1,6 +1,6 @@ | ||
| 270 | - /** | ||
| 271 | - * Logback: the reliable, generic, fast and flexible logging framework. | ||
| 272 | -- * Copyright (C) 1999-2015, QOS.ch. All rights reserved. | ||
| 273 | -+ * Copyright (C) 1999-2023, QOS.ch. All rights reserved. | ||
| 274 | - * | ||
| 275 | - * This program and the accompanying materials are dual-licensed under | ||
| 276 | - * either the terms of the Eclipse Public License v1.0 as published by | ||
| 277 | -@@ -22,22 +22,27 @@ | ||
| 278 | - public class EnvUtil { | ||
| 279 | - | ||
| 280 | - static private boolean isJDK_N_OrHigher(int n) { | ||
| 281 | -- List<String> versionList = new ArrayList<String>(); | ||
| 282 | -- // this code should work at least until JDK 10 (assuming n parameter is | ||
| 283 | -- // always 6 or more) | ||
| 284 | -- for (int i = 0; i < 5; i++) { | ||
| 285 | -- versionList.add("1." + (n + i)); | ||
| 286 | -- } | ||
| 287 | -- | ||
| 288 | -- String javaVersion = System.getProperty("java.version"); | ||
| 289 | -- if (javaVersion == null) { | ||
| 290 | -+ String javaVersionStr = System.getProperty("java.version", ""); | ||
| 291 | -+ if (javaVersionStr.isEmpty()) | ||
| 292 | - return false; | ||
| 293 | -+ | ||
| 294 | -+ int version = getJDKVersion(javaVersionStr); | ||
| 295 | -+ return version > 0 && n <= version; | ||
| 296 | -+ } | ||
| 297 | -+ | ||
| 298 | -+ static public int getJDKVersion(String javaVersionStr) { | ||
| 299 | -+ int version = 0; | ||
| 300 | -+ | ||
| 301 | -+ for (char ch : javaVersionStr.toCharArray()) { | ||
| 302 | -+ if (Character.isDigit(ch)) { | ||
| 303 | -+ version = (version * 10) + (ch - 48); | ||
| 304 | -+ } else if (version == 1) { | ||
| 305 | -+ version = 0; | ||
| 306 | -+ } else { | ||
| 307 | -+ break; | ||
| 308 | -+ } | ||
| 309 | - } | ||
| 310 | -- for (String v : versionList) { | ||
| 311 | -- if (javaVersion.startsWith(v)) | ||
| 312 | -- return true; | ||
| 313 | -- } | ||
| 314 | -- return false; | ||
| 315 | -+ return version; | ||
| 316 | - } | ||
| 317 | - | ||
| 318 | - static public boolean isJDK5() { | ||
| 319 | -@@ -52,6 +57,10 @@ static public boolean isJDK7OrHigher() { | ||
| 320 | - return isJDK_N_OrHigher(7); | ||
| 321 | - } | ||
| 322 | - | ||
| 323 | -+ static public boolean isJDK9OrHigher() { | ||
| 324 | -+ return isJDK_N_OrHigher(9); | ||
| 325 | -+ } | ||
| 326 | -+ | ||
| 327 | - static public boolean isJaninoAvailable() { | ||
| 328 | - ClassLoader classLoader = EnvUtil.class.getClassLoader(); | ||
| 329 | - try { | ||
| 330 | -diff --git a/logback-core/src/test/java/ch/qos/logback/core/net/HardenedObjectInputStreamTest.java b/logback-core/src/test/java/ch/qos/logback/core/net/HardenedObjectInputStreamTest.java | ||
| 331 | -index ff4ddc599f..36f7f11b59 100755 | ||
| 332 | ---- a/logback-core/src/test/java/ch/qos/logback/core/net/HardenedObjectInputStreamTest.java | ||
| 333 | -+++ b/logback-core/src/test/java/ch/qos/logback/core/net/HardenedObjectInputStreamTest.java | ||
| 334 | -@@ -1,12 +1,17 @@ | ||
| 335 | - package ch.qos.logback.core.net; | ||
| 336 | - | ||
| 337 | - import static org.junit.Assert.assertEquals; | ||
| 338 | -+import static org.junit.Assert.fail; | ||
| 339 | - | ||
| 340 | - import java.io.ByteArrayInputStream; | ||
| 341 | - import java.io.ByteArrayOutputStream; | ||
| 342 | - import java.io.IOException; | ||
| 343 | -+import java.io.InvalidClassException; | ||
| 344 | - import java.io.ObjectOutputStream; | ||
| 345 | -+import java.util.HashSet; | ||
| 346 | -+import java.util.Set; | ||
| 347 | - | ||
| 348 | -+import ch.qos.logback.core.util.EnvUtil; | ||
| 349 | - import org.junit.After; | ||
| 350 | - import org.junit.Before; | ||
| 351 | - import org.junit.Test; | ||
| 352 | -@@ -54,5 +59,47 @@ private void writeObject(ObjectOutputStream oos, Object o) throws IOException { | ||
| 353 | - oos.flush(); | ||
| 354 | - oos.close(); | ||
| 355 | - } | ||
| 356 | -- | ||
| 357 | -+ | ||
| 358 | -+ @Test | ||
| 359 | -+ public void denialOfService() throws ClassNotFoundException, IOException { | ||
| 360 | -+ | ||
| 361 | -+ if(!EnvUtil.isJDK9OrHigher()) { | ||
| 362 | -+ return; | ||
| 363 | -+ } | ||
| 364 | -+ | ||
| 365 | -+ ByteArrayInputStream bis = new ByteArrayInputStream(payload()); | ||
| 366 | -+ inputStream = new HardenedObjectInputStream(bis, whitelist); | ||
| 367 | -+ try { | ||
| 368 | -+ inputStream.readObject(); | ||
| 369 | -+ fail("InvalidClassException expected"); | ||
| 370 | -+ } catch(InvalidClassException e) { | ||
| 371 | -+ } | ||
| 372 | -+ finally { | ||
| 373 | -+ inputStream.close(); | ||
| 374 | -+ } | ||
| 375 | -+ } | ||
| 376 | -+ | ||
| 377 | -+ private byte[] payload() throws IOException { | ||
| 378 | -+ Set root = buildEvilHashset(); | ||
| 379 | -+ writeObject(oos, root); | ||
| 380 | -+ return bos.toByteArray(); | ||
| 381 | -+ } | ||
| 382 | -+ | ||
| 383 | -+ private Set buildEvilHashset() { | ||
| 384 | -+ Set root = new HashSet(); | ||
| 385 | -+ Set s1 = root; | ||
| 386 | -+ Set s2 = new HashSet(); | ||
| 387 | -+ for (int i = 0; i < 100; i++) { | ||
| 388 | -+ Set t1 = new HashSet(); | ||
| 389 | -+ Set t2 = new HashSet(); | ||
| 390 | -+ t1.add("foo"); // make it not equal to t2 | ||
| 391 | -+ s1.add(t1); | ||
| 392 | -+ s1.add(t2); | ||
| 393 | -+ s2.add(t1); | ||
| 394 | -+ s2.add(t2); | ||
| 395 | -+ s1 = t1; | ||
| 396 | -+ s2 = t2; | ||
| 397 | -+ } | ||
| 398 | -+ return root; | ||
| 399 | -+ } | ||
| 400 | - } | ||
| 401 | -diff --git a/logback-core/src/test/java/ch/qos/logback/core/rolling/ScaffoldingForRollingTests.java b/logback-core/src/test/java/ch/qos/logback/core/rolling/ScaffoldingForRollingTests.java | ||
| 402 | -index 57389be3f7..504b52adc2 100755 | ||
| 403 | ---- a/logback-core/src/test/java/ch/qos/logback/core/rolling/ScaffoldingForRollingTests.java | ||
| 404 | -+++ b/logback-core/src/test/java/ch/qos/logback/core/rolling/ScaffoldingForRollingTests.java | ||
| 405 | -@@ -24,10 +24,10 @@ | ||
| 406 | - | ||
| 407 | - import java.io.File; | ||
| 408 | - import java.io.IOException; | ||
| 409 | --import java.sql.Date; | ||
| 410 | - import java.text.SimpleDateFormat; | ||
| 411 | - import java.util.ArrayList; | ||
| 412 | - import java.util.Calendar; | ||
| 413 | -+import java.util.Date; | ||
| 414 | - import java.util.Enumeration; | ||
| 415 | - import java.util.List; | ||
| 416 | - import java.util.concurrent.Future; | ||
| 417 | -diff --git a/logback-core/src/test/java/ch/qos/logback/core/util/EnvUtilTest.java b/logback-core/src/test/java/ch/qos/logback/core/util/EnvUtilTest.java | ||
| 418 | -new file mode 100644 | ||
| 419 | -index 0000000000..2ee4abd42e | ||
| 420 | ---- /dev/null | ||
| 421 | -+++ b/logback-core/src/test/java/ch/qos/logback/core/util/EnvUtilTest.java | ||
| 422 | -@@ -0,0 +1,34 @@ | ||
| 423 | -+/** | ||
| 424 | -+ * Logback: the reliable, generic, fast and flexible logging framework. | ||
| 425 | -+ * Copyright (C) 1999-2023, QOS.ch. All rights reserved. | ||
| 426 | -+ * | ||
| 427 | -+ * This program and the accompanying materials are dual-licensed under | ||
| 428 | -+ * either the terms of the Eclipse Public License v1.0 as published by | ||
| 429 | -+ * the Eclipse Foundation | ||
| 430 | -+ * | ||
| 431 | -+ * or (per the licensee's choosing) | ||
| 432 | -+ * | ||
| 433 | -+ * under the terms of the GNU Lesser General Public License version 2.1 | ||
| 434 | -+ * as published by the Free Software Foundation. | ||
| 435 | -+ */ | ||
| 436 | -+package ch.qos.logback.core.util; | ||
| 437 | -+ | ||
| 438 | -+import org.junit.Test; | ||
| 439 | -+ | ||
| 440 | -+import static org.junit.Assert.assertEquals; | ||
| 441 | -+ | ||
| 442 | -+public class EnvUtilTest { | ||
| 443 | -+ | ||
| 444 | -+ | ||
| 445 | -+ @Test | ||
| 446 | -+ public void jdkVersion() { | ||
| 447 | -+ assertEquals(4, EnvUtil.getJDKVersion("1.4.xx")); | ||
| 448 | -+ assertEquals(5, EnvUtil.getJDKVersion("1.5")); | ||
| 449 | -+ assertEquals(5, EnvUtil.getJDKVersion("1.5.xx")); | ||
| 450 | -+ assertEquals(5, EnvUtil.getJDKVersion("1.5AA")); | ||
| 451 | -+ assertEquals(9, EnvUtil.getJDKVersion("9EA")); | ||
| 452 | -+ assertEquals(9, EnvUtil.getJDKVersion("9.0.1")); | ||
| 453 | -+ assertEquals(18, EnvUtil.getJDKVersion("18.3+xx")); | ||
| 454 | -+ assertEquals(21, EnvUtil.getJDKVersion("21.0.1")); | ||
| 455 | -+ } | ||
| 456 | -+} | ||
| @@ -1,681 +0,0 @@ | |||
| 1 | -This security patch addresses the following vulnerabilities: | ||
| 2 | -CVE-2024-12801 (bsc#1234743) | ||
| 3 | - Server-Side Request Forgery (SSRF) in SaxEventRecorder | ||
| 4 | -CVE-2024-12798 (bsc#1234742) | ||
| 5 | - ACE vulnerability in JaninoEventEvaluator | ||
| 6 | - | ||
| 7 | -It is based on the following upstream patches: | ||
| 8 | -https://github.com/qos-ch/logback/commit/2cb6d520df7592ef1c3a198f1b5df3c10c93e183.patch | ||
| 9 | -https://github.com/qos-ch/logback/commit/5f05041cba4c4ac0a62748c5c527a2da48999f2d.patch | ||
| 10 | -https://github.com/qos-ch/logback/commit/6ddf91890a4c23e855132c89086ad7e069d81755.patch | ||
| 11 | - | ||
| 12 | -The change addresses the above issues by: | ||
| 13 | - - removing SaxEventRecorder and JaninoEventEvaluator | ||
| 14 | - - ignoring external DTD files in DOCTYPE to further reduce vulnerability to SSRF attacks | ||
| 15 | ---- a/logback-access/src/main/java/ch/qos/logback/access/boolex/JaninoEventEvaluator.java | ||
| 16 | -+++ /dev/null | ||
| 17 | -@@ -1,84 +0,0 @@ | ||
| 18 | --/** | ||
| 19 | -- * Logback: the reliable, generic, fast and flexible logging framework. | ||
| 20 | -- * Copyright (C) 1999-2015, QOS.ch. All rights reserved. | ||
| 21 | -- * | ||
| 22 | -- * This program and the accompanying materials are dual-licensed under | ||
| 23 | -- * either the terms of the Eclipse Public License v1.0 as published by | ||
| 24 | -- * the Eclipse Foundation | ||
| 25 | -- * | ||
| 26 | -- * or (per the licensee's choosing) | ||
| 27 | -- * | ||
| 28 | -- * under the terms of the GNU Lesser General Public License version 2.1 | ||
| 29 | -- * as published by the Free Software Foundation. | ||
| 30 | -- */ | ||
| 31 | --package ch.qos.logback.access.boolex; | ||
| 32 | -- | ||
| 33 | --import java.util.ArrayList; | ||
| 34 | --import java.util.List; | ||
| 35 | -- | ||
| 36 | --import ch.qos.logback.access.spi.IAccessEvent; | ||
| 37 | --import ch.qos.logback.core.CoreConstants; | ||
| 38 | --import ch.qos.logback.core.boolex.JaninoEventEvaluatorBase; | ||
| 39 | --import ch.qos.logback.core.boolex.Matcher; | ||
| 40 | -- | ||
| 41 | --public class JaninoEventEvaluator extends JaninoEventEvaluatorBase<IAccessEvent> { | ||
| 42 | -- | ||
| 43 | -- public final static List<String> DEFAULT_PARAM_NAME_LIST = new ArrayList<String>(); | ||
| 44 | -- public final static List<Class> DEFAULT_PARAM_TYPE_LIST = new ArrayList<Class>(); | ||
| 45 | -- | ||
| 46 | -- static { | ||
| 47 | -- DEFAULT_PARAM_NAME_LIST.add("event"); | ||
| 48 | -- DEFAULT_PARAM_TYPE_LIST.add(IAccessEvent.class); | ||
| 49 | -- } | ||
| 50 | -- | ||
| 51 | -- @Override | ||
| 52 | -- protected String getDecoratedExpression() { | ||
| 53 | -- String expression = getExpression(); | ||
| 54 | -- if (!expression.contains("return")) { | ||
| 55 | -- expression = "return " + expression + ";"; | ||
| 56 | -- addInfo("Adding [return] prefix and a semicolon suffix. Expression becomes [" + expression + "]"); | ||
| 57 | -- addInfo("See also " + CoreConstants.CODES_URL + "#block"); | ||
| 58 | -- } | ||
| 59 | -- return expression; | ||
| 60 | -- } | ||
| 61 | -- | ||
| 62 | -- @Override | ||
| 63 | -- protected String[] getParameterNames() { | ||
| 64 | -- List<String> fullNameList = new ArrayList<String>(); | ||
| 65 | -- fullNameList.addAll(DEFAULT_PARAM_NAME_LIST); | ||
| 66 | -- | ||
| 67 | -- for (int i = 0; i < matcherList.size(); i++) { | ||
| 68 | -- Matcher m = (Matcher) matcherList.get(i); | ||
| 69 | -- fullNameList.add(m.getName()); | ||
| 70 | -- } | ||
| 71 | -- | ||
| 72 | -- return (String[]) fullNameList.toArray(CoreConstants.EMPTY_STRING_ARRAY); | ||
| 73 | -- } | ||
| 74 | -- | ||
| 75 | -- @Override | ||
| 76 | -- protected Class[] getParameterTypes() { | ||
| 77 | -- List<Class> fullTypeList = new ArrayList<Class>(); | ||
| 78 | -- fullTypeList.addAll(DEFAULT_PARAM_TYPE_LIST); | ||
| 79 | -- for (int i = 0; i < matcherList.size(); i++) { | ||
| 80 | -- fullTypeList.add(Matcher.class); | ||
| 81 | -- } | ||
| 82 | -- return (Class[]) fullTypeList.toArray(CoreConstants.EMPTY_CLASS_ARRAY); | ||
| 83 | -- } | ||
| 84 | -- | ||
| 85 | -- @Override | ||
| 86 | -- protected Object[] getParameterValues(IAccessEvent accessEvent) { | ||
| 87 | -- final int matcherListSize = matcherList.size(); | ||
| 88 | -- | ||
| 89 | -- int i = 0; | ||
| 90 | -- Object[] values = new Object[DEFAULT_PARAM_NAME_LIST.size() + matcherListSize]; | ||
| 91 | -- | ||
| 92 | -- values[i++] = accessEvent; | ||
| 93 | -- | ||
| 94 | -- for (int j = 0; j < matcherListSize; j++) { | ||
| 95 | -- values[i++] = matcherList.get(j); | ||
| 96 | -- } | ||
| 97 | -- | ||
| 98 | -- return values; | ||
| 99 | -- } | ||
| 100 | -- | ||
| @@ -0,0 +1,42 @@ | |||
| 1 | +From: ceki <ceki@qos.ch> | ||
| 2 | +Date: Fri, 29 May 2026 21:50:57 +0200 | ||
| 3 | +Subject: [PATCH] fix: CVE-2026-10532 - prevent resolveProxyClass bypass | ||
| 4 | + | ||
| 5 | +Override resolveProxyClass() in HardenedObjectInputStream to throw | ||
| 6 | +InvalidClassException, preventing attackers from bypassing the class | ||
| 7 | +whitelist via dynamic proxy deserialization. | ||
| 8 | + | ||
| 9 | +Upstream-commit: https://github.com/qos-ch/logback/commit/f7a0654c2b7e8e1c461e3d9e483e82ef969b5818 | ||
| 10 | +Signed-off-by: infra_team <zhaiwenjie1@huawei.com> | ||
| 11 | +--- | ||
| 12 | +--- a/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java 2026-06-02 15:14:32.850745015 +0800 | ||
| 13 | ++++ b/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java 2026-06-02 15:19:26.051970533 +0800 | ||
| 14 | +@@ -6,6 +6,7 @@ | ||
| 15 | + import java.io.ObjectInputStream; | ||
| 16 | + import java.io.ObjectStreamClass; | ||
| 17 | + import java.util.ArrayList; | ||
| 18 | ++import java.util.Arrays; | ||
| 19 | + import java.util.List; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | +@@ -53,6 +54,20 @@ | ||
| 23 | + return super.resolveClass(anObjectStreamClass); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | ++ /** | ||
| 27 | ++ * There is no reason to have proxy classes in logback deserialization, so we just | ||
| 28 | ++ * throw an exception here to prevent any potential bypasses that could be achieved | ||
| 29 | ++ * through proxy classes. | ||
| 30 | ++ * | ||
| 31 | ++ * @param interfaces the list of interface names that were | ||
| 32 | ++ * deserialized in the proxy class descriptor | ||
| 33 | ++ * @since 1.2.8 | ||
| 34 | ++ */ | ||
| 35 | ++ @Override | ||
| 36 | ++ protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { | ||
| 37 | ++ throw new InvalidClassException("Unauthorized deserialization attempt ", Arrays.toString(interfaces)); | ||
| 38 | ++ } | ||
| 39 | ++ | ||
| 40 | + private boolean isWhitelisted(String incomingClassName) { | ||
| 41 | + for (int i = 0; i < JAVA_PACKAGES.length; i++) { | ||
| 42 | + if (incomingClassName.startsWith(JAVA_PACKAGES[i])) | ||
| @@ -1,71 +0,0 @@ | |||
| 1 | ---- logback-1.2.8/logback-access/pom.xml 2021-12-14 12:55:51.000000000 +0100 | ||
| 2 | -+++ logback-1.2.8/logback-access/pom.xml 2021-12-16 15:35:11.255651389 +0100 | ||
| 3 | -@@ -47,6 +47,12 @@ | ||
| 4 | - <optional>true</optional> | ||
| 5 | - </dependency> | ||
| 6 | - <dependency> | ||
| 7 | -+ <groupId>org.eclipse.jetty</groupId> | ||
| 8 | -+ <artifactId>jetty-util</artifactId> | ||
| 9 | -+ <scope>compile</scope> | ||
| 10 | -+ <optional>true</optional> | ||
| 11 | -+ </dependency> | ||
| 12 | -+ <dependency> | ||
| 13 | - <groupId>org.codehaus.janino</groupId> | ||
| 14 | - <artifactId>janino</artifactId> | ||
| 15 | - <scope>compile</scope> | ||
| 16 | ---- logback-1.2.8/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java 2021-12-14 12:55:51.000000000 +0100 | ||
| 17 | -+++ logback-1.2.8/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java 2021-12-16 15:35:11.255651389 +0100 | ||
| 18 | -@@ -209,11 +209,6 @@ | ||
| 19 | - started = false; | ||
| 20 | - } | ||
| 21 | - | ||
| 22 | -- @Override | ||
| 23 | -- public boolean isRunning() { | ||
| 24 | -- return started; | ||
| 25 | -- } | ||
| 26 | -- | ||
| 27 | - public void setFileName(String fileName) { | ||
| 28 | - this.fileName = fileName; | ||
| 29 | - } | ||
| 30 | -@@ -227,26 +222,6 @@ | ||
| 31 | - return started; | ||
| 32 | - } | ||
| 33 | - | ||
| 34 | -- @Override | ||
| 35 | -- public boolean isStarting() { | ||
| 36 | -- return false; | ||
| 37 | -- } | ||
| 38 | -- | ||
| 39 | -- @Override | ||
| 40 | -- public boolean isStopping() { | ||
| 41 | -- return false; | ||
| 42 | -- } | ||
| 43 | -- | ||
| 44 | -- @Override | ||
| 45 | -- public boolean isStopped() { | ||
| 46 | -- return !started; | ||
| 47 | -- } | ||
| 48 | -- | ||
| 49 | -- @Override | ||
| 50 | -- public boolean isFailed() { | ||
| 51 | -- return false; | ||
| 52 | -- } | ||
| 53 | -- | ||
| 54 | - public boolean isQuiet() { | ||
| 55 | - return quiet; | ||
| 56 | - } | ||
| 57 | -@@ -310,13 +285,7 @@ | ||
| 58 | - return fai.getFilterChainDecision(event); | ||
| 59 | - } | ||
| 60 | - | ||
| 61 | -- @Override | ||
| 62 | -- public void addLifeCycleListener(Listener listener) { | ||
| 63 | -- // we'll implement this when asked | ||
| 64 | -- } | ||
| 65 | -- | ||
| 66 | -- @Override | ||
| 67 | -- public void removeLifeCycleListener(Listener listener) { | ||
| 68 | -+ public void log(Request request, int status, long written) { | ||
| 69 | - // we'll implement this when asked | ||
| 70 | - } | ||
| 71 | - | ||
| @@ -1,15 +1,11 @@ | |||
| 1 | Name: logback | 1 | Name: logback |
| 2 | -Version: 1.2.8 | 2 | +Version: 1.5.34 |
| 3 | -Release: 4 | 3 | +Release: 1 |
| 4 | Summary: A Java logging library | 4 | Summary: A Java logging library |
| 5 | License: LGPLv2 or EPL-1.0 | 5 | License: LGPLv2 or EPL-1.0 |
| 6 | URL: http://logback.qos.ch/ | 6 | URL: http://logback.qos.ch/ |
| 7 | Source0: https://github.com/qos-ch/logback/archive/v_%{version}.tar.gz | 7 | Source0: https://github.com/qos-ch/logback/archive/v_%{version}.tar.gz |
| 8 | 8 | ||
| 9 | -Patch0001: logback-1.2.8-jetty.patch | ||
| 10 | -Patch0002: CVE-2023-6378-and-CVE-2023-6481.patch | ||
| 11 | -Patch0003: CVE-2024-12798-and-CVE-2024-12801.patch | ||
| 12 | - | ||
| 13 | BuildRequires: java-devel >= 1:1.6.0 maven-local mvn(javax.mail:mail) | 9 | BuildRequires: java-devel >= 1:1.6.0 maven-local mvn(javax.mail:mail) |
| 14 | BuildRequires: mvn(javax.servlet:javax.servlet-api) mvn(junit:junit) mvn(log4j:log4j:1.2.17) | 10 | BuildRequires: mvn(javax.servlet:javax.servlet-api) mvn(junit:junit) mvn(log4j:log4j:1.2.17) |
| 15 | BuildRequires: mvn(org.apache.ant:ant-junit) mvn(org.apache.felix:maven-bundle-plugin) | 11 | BuildRequires: mvn(org.apache.ant:ant-junit) mvn(org.apache.felix:maven-bundle-plugin) |
| @@ -124,6 +120,9 @@ cp -r %{name}-examples/pom.xml %{name}-examples/src %{buildroot}%{_datadir}/%{na | |||
| 124 | %files help -f .mfiles-javadoc | 120 | %files help -f .mfiles-javadoc |
| 125 | 121 | ||
| 126 | %changelog | 122 | %changelog |
| 123 | +* Tue Jun 02 2026 infra_team <zhaiwenjie1@huawei.com> - 1.5.34-1 | ||
| 124 | +- Upgrade to 1.5.34 to fix CVE-2026-10532 | ||
| 125 | + | ||
| 127 | * Mon Jan 20 2025 yaoxin <1024769339@qq.com> - 1.2.8-4 | 126 | * Mon Jan 20 2025 yaoxin <1024769339@qq.com> - 1.2.8-4 |
| 128 | - Fix CVE-2024-12798 and CVE-2024-12801 | 127 | - Fix CVE-2024-12798 and CVE-2024-12801 |
| 129 | 128 | ||
Binary files do not support preview