已关闭
fix(cve): 修复 CVE-2026-104721 在 logback 中的漏洞 #51
infra_team创建于 27 天前关闭于 17 天前
fix(cve): 修复 CVE-2026-104721 在 logback 中的漏洞 #51
已关闭
infra_team创建于 27 天前关闭于 17 天前
共 2 个文件变更+169-1
@@ -0,0 +1,164 @@
1+From 5c10a5691f25841931d714a21c3baa828950ad9b Mon Sep 17 00:00:00 2001
2+From: infra_team <zhaiwenjie1@huawei.com>
3+Date: Fri, 2 Oct 2026 16:32:41 +0000
4+Subject: [PATCH] fix: CVE-2026-104721 - reject mischievous MDC values in
5+ MDCBasedDiscriminator
6+ 
7+Backport of the logback 1.6.5 fix for CVE-2026-104721 (incomplete
8+protection against mischievous MDC values in MDCBasedDiscriminator,
9+CWE-22). getDiscriminatingValue() previously returned the raw MDC value,
10+which flows into the nested FileAppender's file name via SiftingAppender,
11+allowing path traversal through MDC values.
12+ 
13+The value is now rejected (falling back to DefaultValue) when it is
14+empty, longer than 64 characters, contains any of the characters
15+/\${}[]()|?*+%@, or the sequence "..". Rejected-value warnings are rate
16+limited to one per 10 minutes via an inline timestamp guard, standing in
17+for the upstream BatchedFixedIntervalInvocationGate(4,
18+Duration.buildByMinutes(10)) which does not exist in 1.2.8.
19+ 
20+Upstream-commit: https://github.com/qos-ch/logback/commit/1c6f0bd528882cfb75e760116f3c5f5f0e277ae3
21+Signed-off-by: infra_team <zhaiwenjie1@huawei.com>
22+---
23+ .../classic/sift/MDCBasedDiscriminator.java | 105 +++++++++++++++++-
24+ 1 file changed, 104 insertions(+), 1 deletion(-)
25+ 
26+diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/sift/MDCBasedDiscriminator.java b/logback-classic/src/main/java/ch/qos/logback/classic/sift/MDCBasedDiscriminator.java
27+index d65f1b1..c1dada0 100644
28+--- a/logback-classic/src/main/java/ch/qos/logback/classic/sift/MDCBasedDiscriminator.java
29++++ b/logback-classic/src/main/java/ch/qos/logback/classic/sift/MDCBasedDiscriminator.java
30+@@ -24,11 +24,41 @@ import java.util.Map;
31+ * the said value is null, then a default value is returned.
32+ * <p/>
33+ * <p>Both Key and the DefaultValue are user specified properties.
34++ * </p>
35++ * <p>
36++ * MDC values containing any of the characters {@code /}, {@code \}, {@code $},
37++ * <code>{</code>, <code>}</code>, <code>[</code>, <code>]</code>, <code>(</code>,
38++ * <code>)</code> , <code>|</code>, <code>?</code>, <code>*</code>, <code>+</code>,
39++ * <code>%</code>, <code>,</code>, <code>@</code> or the sequence {@code ..} are rejected,
40++ * in which case the default value is returned. This prevents path separators, relative path components,
41++ * variable substitutions such as <code>${file.separator}</code>, regex
42++ * special characters as well as the anchor character '%' or the ',' and '@' characters from
43++ * leaking into file names or email addresses.
44++ * </p>
45++ *
46++ * <p>Moreover, the maximum length of an MDC value is limited to 64 characters.</p>
47+ *
48+ * @author Ceki G&uuml;lc&uuml;
49+ */
50+ public class MDCBasedDiscriminator extends AbstractDiscriminator<ILoggingEvent> {
51+
52++ static final String FORBIDDEN_CHARACTERS = "/\\${}[]()|?*+%@,";
53++ private static final int MAX_MDC_VALUE = 64;
54++
55++ private static final char DOT = '.';
56++
57++ static final String EMPTY_VALUE_WARNING = "MDC value [%s] is empty, using default value [%s] instead";
58++ static final String REJECTED_VALUE_WARNING = "MDC value [%s] contains forbidden characters, using default value [%s] instead";
59++ static final String REJECTED_VALUE_LENGTH_WARNING = "MDC value of length %s is longer than the maximum allowed length of " + MAX_MDC_VALUE + " characters, using default value [%s] instead";
60++
61++ /**
62++ * Limits how often rejected-value warnings are emitted on the hot path.
63++ * Inline stand-in for the upstream BatchedFixedIntervalInvocationGate(4,
64++ * Duration.buildByMinutes(10)) which does not exist in this version.
65++ */
66++ private static final long WARNING_INTERVAL_MILLIS = 10L * 60L * 1000L;
67++ private long lastWarningTimestamp = 0;
68++
69+ private String key;
70+ private String defaultValue;
71+
72+@@ -36,6 +66,15 @@ public class MDCBasedDiscriminator extends AbstractDiscriminator<ILoggingEvent>
73+ * Return the value associated with an MDC entry designated by the Key
74+ * property. If that value is null, then return the value assigned to the
75+ * DefaultValue property.
76++ * <p>
77++ * If the MDC value is empty, is longer than {@link #MAX_MDC_VALUE}
78++ * characters, or contains any of the characters {@code /}, {@code \},
79++ * {@code $}, <code>{</code>, <code>}</code>, <code>[</code>,
80++ * <code>]</code>, <code>(</code>, <code>)</code>, <code>|</code>,
81++ * <code>?</code>, <code>*</code>, <code>+</code>, <code>%</code>,
82++ * <code>,</code>, <code>@</code> or the sequence {@code ..}, then the value
83++ * assigned to the DefaultValue property is returned.
84++ * </p>
85+ */
86+ public String getDiscriminatingValue(ILoggingEvent event) {
87+ // http://jira.qos.ch/browse/LBCLASSIC-213
88+@@ -47,8 +86,72 @@ public class MDCBasedDiscriminator extends AbstractDiscriminator<ILoggingEvent>
89+ if (mdcValue == null) {
90+ return defaultValue;
91+ } else {
92+- return mdcValue;
93++ String sanitized = sanitizePathCharacters(mdcValue, event.getTimeStamp());
94++ return sanitized == null ? defaultValue : sanitized;
95++ }
96++ }
97++
98++ /**
99++ * Returns the value unchanged if it is safe as a file-name segment, and
100++ * {@code null} otherwise.
101++ * <p>
102++ * A value is rejected if it is empty, if it is longer than
103++ * {@link #MAX_MDC_VALUE} characters, if it contains any of the characters
104++ * {@code /}, {@code \}, {@code $}, <code>{</code> or <code>}</code>, or the
105++ * sequence {@code ..}. A (rate limited) warning is emitted for each
106++ * rejected value.
107++ * </p>
108++ * <p>
109++ * Performs a single scan and no allocation.
110++ * </p>
111++ */
112++ String sanitizePathCharacters(String value, long timestamp) {
113++ if (value == null) {
114++ return null;
115++ }
116++ final int len = value.length();
117++ if (len == 0) {
118++ if (!isTooSoon(timestamp)) {
119++ addWarn(String.format(EMPTY_VALUE_WARNING, value, defaultValue));
120++ }
121++ return null;
122++ }
123++
124++ if (len > MAX_MDC_VALUE) {
125++ if (!isTooSoon(timestamp)) {
126++ addWarn(String.format(REJECTED_VALUE_LENGTH_WARNING, len, defaultValue));
127++ }
128++ return null;
129++ }
130++
131++ char previous = 0;
132++ for (int i = 0; i < len; i++) {
133++ char c = value.charAt(i);
134++ if (isForbiddenCharacter(c) || (c == DOT && previous == DOT)) {
135++ if (!isTooSoon(timestamp)) {
136++ addWarn(String.format(REJECTED_VALUE_WARNING, value, defaultValue));
137++ }
138++ return null;
139++ }
140++ previous = c;
141++ }
142++ return value;
143++ }
144++
145++ private static boolean isForbiddenCharacter(char c) {
146++ return FORBIDDEN_CHARACTERS.indexOf(c) != -1;
147++ }
148++
149++ /**
150++ * Inline rate limiter standing in for the upstream invocation gate: allows
151++ * one warning per {@link #WARNING_INTERVAL_MILLIS}.
152++ */
153++ private boolean isTooSoon(long timestamp) {
154++ if (timestamp - lastWarningTimestamp < WARNING_INTERVAL_MILLIS) {
155++ return true;
156+ }
157++ lastWarningTimestamp = timestamp;
158++ return false;
159+ }
160+
161+ @Override
162+--
163+2.39.5
164+ 
@@ -1,6 +1,6 @@
1Name: logback1Name: logback
2Version: 1.2.82Version: 1.2.8
3-Release: 43+Release: 5
4Summary: A Java logging library4Summary: A Java logging library
5License: LGPLv2 or EPL-1.05License: LGPLv2 or EPL-1.0
6URL: http://logback.qos.ch/6URL: http://logback.qos.ch/
@@ -9,6 +9,7 @@ Source0: https://github.com/qos-ch/logback/archive/v_%{version}.tar.gz
9Patch0001: logback-1.2.8-jetty.patch9Patch0001: logback-1.2.8-jetty.patch
10Patch0002: CVE-2023-6378-and-CVE-2023-6481.patch10Patch0002: CVE-2023-6378-and-CVE-2023-6481.patch
11Patch0003: CVE-2024-12798-and-CVE-2024-12801.patch11Patch0003: CVE-2024-12798-and-CVE-2024-12801.patch
12+Patch0004: CVE-2026-104721.patch
12 13 
13BuildRequires: java-devel >= 1:1.6.0 maven-local mvn(javax.mail:mail)14BuildRequires: java-devel >= 1:1.6.0 maven-local mvn(javax.mail:mail)
14BuildRequires: mvn(javax.servlet:javax.servlet-api) mvn(junit:junit) mvn(log4j:log4j:1.2.17)15BuildRequires: mvn(javax.servlet:javax.servlet-api) mvn(junit:junit) mvn(log4j:log4j:1.2.17)
@@ -124,6 +125,9 @@ cp -r %{name}-examples/pom.xml %{name}-examples/src %{buildroot}%{_datadir}/%{na
124%files help -f .mfiles-javadoc125%files help -f .mfiles-javadoc
125 126 
126%changelog127%changelog
128+* Sat Oct 03 2026 infra_team <zhaiwenjie1@huawei.com> - 1.2.8-5
129+- Fix CVE-2026-104721
130+ 
127* Mon Jan 20 2025 yaoxin <1024769339@qq.com> - 1.2.8-4131* Mon Jan 20 2025 yaoxin <1024769339@qq.com> - 1.2.8-4
128- Fix CVE-2024-12798 and CVE-2024-12801132- Fix CVE-2024-12798 and CVE-2024-12801
129 133