Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package log4j for openSUSE:Factory checked in at 2026-04-14 17:49:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/log4j (Old) and /work/SRC/openSUSE:Factory/.log4j.new.21863 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "log4j" Tue Apr 14 17:49:58 2026 rev:46 rq:1346881 version:2.20.0 Changes: -------- --- /work/SRC/openSUSE:Factory/log4j/log4j.changes 2026-01-06 17:47:21.748483842 +0100 +++ /work/SRC/openSUSE:Factory/.log4j.new.21863/log4j.changes 2026-04-14 17:51:35.831668755 +0200 @@ -1,0 +2,23 @@ +Tue Apr 14 12:49:48 UTC 2026 - Fridrich Strba <[email protected]> + +- Added patches: + * log4j-CVE-2026-34479.patch + + backported upstream fix for bsc#1262091 (CVE-2026-34479): + log processing denial of service due to improper XML escaping + * log4j-CVE-2026-34480.patch + + backported upstream fix for bsc#1262092 (CVE-2026-34480): + invalid XML output causes denial of service in logging + * log4j-CVE-2026-34481.patch + + backported upstream fix for bsc#1262093 (CVE-2026-34481): + denial of service via invalid JSON output + +------------------------------------------------------------------- +Tue Apr 14 10:11:10 UTC 2026 - Fridrich Strba <[email protected]> + +- Added patch: + * log4j-CVE-2026-34477.patch + + backported upstream fix for bsc#1262050 (CVE-2026-34477): + man-in-the-middle attack due to incomplete hostname + verification + +------------------------------------------------------------------- New: ---- log4j-CVE-2026-34477.patch log4j-CVE-2026-34479.patch log4j-CVE-2026-34480.patch log4j-CVE-2026-34481.patch ----------(New B)---------- New:- Added patch: * log4j-CVE-2026-34477.patch + backported upstream fix for bsc#1262050 (CVE-2026-34477): New:- Added patches: * log4j-CVE-2026-34479.patch + backported upstream fix for bsc#1262091 (CVE-2026-34479): New: log processing denial of service due to improper XML escaping * log4j-CVE-2026-34480.patch + backported upstream fix for bsc#1262092 (CVE-2026-34480): New: invalid XML output causes denial of service in logging * log4j-CVE-2026-34481.patch + backported upstream fix for bsc#1262093 (CVE-2026-34481): ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ log4j.spec ++++++ --- /var/tmp/diff_new_pack.Yzie3g/_old 2026-04-14 17:51:39.259810465 +0200 +++ /var/tmp/diff_new_pack.Yzie3g/_new 2026-04-14 17:51:39.275811126 +0200 @@ -33,6 +33,10 @@ Patch1: 0002-Remove-usage-of-toolchains.patch Patch2: log4j-jackson-databind.patch Patch3: log4j-CVE-2025-68161.patch +Patch4: log4j-CVE-2026-34477.patch +Patch5: log4j-CVE-2026-34479.patch +Patch6: log4j-CVE-2026-34480.patch +Patch7: log4j-CVE-2026-34481.patch BuildRequires: fdupes BuildRequires: java-devel >= 9 BuildRequires: maven-local @@ -50,6 +54,7 @@ BuildRequires: mvn(org.apache.maven.plugins:maven-assembly-plugin) BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin) BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin) +BuildRequires: mvn(org.codehaus.woodstox:stax2-api) BuildRequires: mvn(org.fusesource.jansi:jansi) BuildRequires: mvn(org.jctools:jctools-core) BuildRequires: mvn(org.osgi:osgi.core) ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.Yzie3g/_old 2026-04-14 17:51:39.595824355 +0200 +++ /var/tmp/diff_new_pack.Yzie3g/_new 2026-04-14 17:51:39.619825347 +0200 @@ -1,6 +1,6 @@ -mtime: 1767687889 -commit: b95f4b757a7bba7c515825fc625f9f380a2d68ddceff9b2e7db277d251998d61 +mtime: 1776172016 +commit: 48a06f2217bc3d1a01f9115eec16b6d84822ea45c931b1fd0c36af4e2ca7b510 url: https://src.opensuse.org/java-packages/log4j.git -revision: b95f4b757a7bba7c515825fc625f9f380a2d68ddceff9b2e7db277d251998d61 +revision: 48a06f2217bc3d1a01f9115eec16b6d84822ea45c931b1fd0c36af4e2ca7b510 projectscmsync: https://src.opensuse.org/java-packages/_ObsPrj ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-04-14 15:08:26.000000000 +0200 @@ -0,0 +1 @@ +.osc ++++++ log4j-CVE-2026-34477.patch ++++++ --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java 2026-04-14 12:14:33.937832117 +0200 +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java 2026-04-14 12:16:02.690441235 +0200 @@ -165,13 +165,10 @@ * @param trustStoreConfig The TrustStoreConfiguration. * @return a new SslConfiguration */ - @PluginFactory public static SslConfiguration createSSLConfiguration( - // @formatter:off - @PluginAttribute("protocol") final String protocol, - @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig, - @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig) { - // @formatter:on + final String protocol, + final KeyStoreConfiguration keyStoreConfig, + final TrustStoreConfiguration trustStoreConfig) { return new SslConfiguration(protocol, false, keyStoreConfig, trustStoreConfig); } @@ -185,6 +182,7 @@ * @return a new SslConfiguration * @since 2.12 */ + @PluginFactory public static SslConfiguration createSSLConfiguration( // @formatter:off @PluginAttribute("protocol") final String protocol, ++++++ log4j-CVE-2026-34479.patch ++++++ --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Transform.java 2026-04-14 14:24:27.281838922 +0200 +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Transform.java 2026-04-14 14:58:31.391824083 +0200 @@ -30,60 +30,42 @@ private static final String CDATA_EMBEDED_END = CDATA_END + CDATA_PSEUDO_END + CDATA_START; private static final int CDATA_END_LEN = CDATA_END.length(); + private static final char REPLACEMENT_CHAR = '\uFFFD'; + private Transform() { } /** - * This method takes a string which may contain HTML tags (ie, - * <b>, <table>, etc) and replaces any - * '<', '>' , '&' or '"' - * characters with respective predefined entity references. + * Escapes characters in a string for safe inclusion in HTML or XML text. * - * @param input The text to be converted. - * @return The input string with the special characters replaced. + * <p>Replaces the characters {@code <}, {@code >}, {@code &}, {@code "} and {@code '} with their corresponding + * entity references ({@code <}, {@code >}, {@code &}, {@code "}, and {@code '}). Any code point + * that is invalid in XML 1.0 is replaced with the Unicode replacement character U+FFFD.</p> + * + * @param input The text to be escaped; may be {@code null} or empty. + * @return The escaped string, or the original {@code input} if no changes were required. */ public static String escapeHtmlTags(final String input) { - // Check if the string is null, zero length or devoid of special characters + // Check if the string is null or zero length // if so, return what was sent in. - - if (Strings.isEmpty(input) - || (input.indexOf('"') == -1 && - input.indexOf('&') == -1 && - input.indexOf('<') == -1 && - input.indexOf('>') == -1)) { + if (Strings.isEmpty(input)) { return input; } - //Use a StringBuilder in lieu of String concatenation -- it is - //much more efficient this way. - - final StringBuilder buf = new StringBuilder(input.length() + 6); - - final int len = input.length(); - for (int i = 0; i < len; i++) { - final char ch = input.charAt(i); - if (ch > '>') { - buf.append(ch); - } else - switch (ch) { - case '<': - buf.append("<"); - break; - case '>': - buf.append(">"); - break; - case '&': - buf.append("&"); - break; - case '"': - buf.append("""); - break; - default: - buf.append(ch); - break; - } + // Only create a new string if we find a special character or invalid code point. + // In the common case, this should avoid unnecessary allocations. + final int length = input.length(); + for (int i = 0; i < length; ) { + final int cp = input.codePointAt(i); + if (!isValidXml10(cp) || isHtmlTagCharacter(cp)) { + final StringBuilder out = new StringBuilder(length); + out.append(input, 0, i); + appendEscapingHtmlTags(input, i, length, out); + return out.toString(); + } + i += Character.charCount(cp); } - return buf.toString(); + return input; } /** @@ -99,11 +81,11 @@ if (str != null) { int end = str.indexOf(CDATA_END); if (end < 0) { - buf.append(str); + appendSanitizedXml10(str, 0, str.length(), buf); } else { int start = 0; while (end > -1) { - buf.append(str.substring(start, end)); + appendSanitizedXml10(str, start, end, buf); buf.append(CDATA_EMBEDED_END); start = end + CDATA_END_LEN; if (start < str.length()) { @@ -112,7 +94,7 @@ return; } } - buf.append(str.substring(start)); + appendSanitizedXml10(str, start, str.length(), buf); } } } @@ -187,4 +169,69 @@ } return buf.toString(); } + + private static void appendEscapingHtmlTags(final String input, int i, final int length, final StringBuilder buf) { + while (i < length) { + final int ch = input.codePointAt(i); + switch (ch) { + case '<': + buf.append("<"); + break; + case '>': + buf.append(">"); + break; + case '&': + buf.append("&"); + break; + case '"': + buf.append("""); + break; + case '\'': + buf.append("'"); + break; + default: + buf.appendCodePoint(isValidXml10(ch) ? ch : REPLACEMENT_CHAR); + break; + } + i += Character.charCount(ch); + } + } + + private static boolean isHtmlTagCharacter(final int cp) { + return cp == '<' || cp == '>' || cp == '&' || cp == '"' || cp == '\''; + } + + private static void appendSanitizedXml10( + final String input, final int start, final int end, final StringBuilder out) { + for (int i = start; i < end; ) { + final int cp = input.codePointAt(i); + out.appendCodePoint(isValidXml10(cp) ? cp : REPLACEMENT_CHAR); + i += Character.charCount(cp); + } + } + + /** + * Checks if a code point is valid in XML 1.0. + * + * @param codePoint a code point between {@code 0} and {@link Character#MAX_CODE_POINT} + * @return {@code true} if it is a valid XML 1.0 code point + */ + private static boolean isValidXml10(final int codePoint) { + assert codePoint >= 0 && codePoint <= Character.MAX_CODE_POINT; + // XML 1.0 valid characters (Fifth Edition): + // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + + // [#x20–#xD7FF] (placed early as a fast path for the most common case) + return (codePoint >= ' ' && codePoint < Character.MIN_SURROGATE) + // #x9 + || codePoint == '\t' + // #xA + || codePoint == '\n' + // #xD + || codePoint == '\r' + // [#xE000-#xFFFD] + || (codePoint > Character.MAX_SURROGATE && codePoint <= 0xFFFD) + // [#x10000-#x10FFFF] + || codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT; + } } ++++++ log4j-CVE-2026-34480.patch ++++++ --- a/log4j-core/pom.xml 2026-04-14 14:24:27.283057809 +0200 +++ b/log4j-core/pom.xml 2026-04-14 14:28:48.101299959 +0200 @@ -156,6 +156,11 @@ <scope>runtime</scope> <optional>true</optional> </dependency> + <dependency> + <groupId>org.codehaus.woodstox</groupId> + <artifactId>stax2-api</artifactId> + <optional>true</optional> + </dependency> </dependencies> <build> <plugins> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlObjectMapper.java 2026-04-14 14:24:27.248175588 +0200 +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlObjectMapper.java 2026-04-14 14:31:00.994779825 +0200 @@ -17,8 +17,22 @@ package org.apache.logging.log4j.core.jackson; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlFactory; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.dataformat.xml.XmlNameProcessor; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import org.codehaus.stax2.XMLStreamWriter2; +import org.codehaus.stax2.ri.Stax2WriterAdapter; +import org.codehaus.stax2.util.StreamWriter2Delegate; /** * A Jackson XML {@link ObjectMapper} initialized for Log4j. @@ -41,8 +55,167 @@ * Create a new instance using the {@link Log4jXmlModule}. */ public Log4jXmlObjectMapper(final boolean includeStacktrace, final boolean stacktraceAsString) { - super(new Log4jXmlModule(includeStacktrace, stacktraceAsString)); + super(new SanitizingXmlFactory(), new Log4jXmlModule(includeStacktrace, stacktraceAsString)); this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); } + + /** + * Writer that sanitizes text to be valid XML 1.0 by replacing disallowed code points with the replacement character (U+FFFD). + */ + private static final class SanitizingWriter extends StreamWriter2Delegate { + + private static final char REPLACEMENT_CHAR = '\uFFFD'; + + SanitizingWriter(final XMLStreamWriter2 delegate) { + super(delegate); + setParent(delegate); + } + + @Override + public void writeAttribute(final String localName, final String value) throws XMLStreamException { + super.writeAttribute(localName, sanitizeXml10(value)); + } + + @Override + public void writeAttribute(final String namespaceURI, final String localName, final String value) + throws XMLStreamException { + super.writeAttribute(namespaceURI, localName, sanitizeXml10(value)); + } + + @Override + public void writeAttribute( + final String prefix, final String namespaceURI, final String localName, final String value) + throws XMLStreamException { + super.writeAttribute(prefix, namespaceURI, localName, sanitizeXml10(value)); + } + + @Override + public void writeCData(String text) throws XMLStreamException { + super.writeCData(sanitizeXml10(text)); + } + + @Override + public void writeCData(char[] text, int start, int len) throws XMLStreamException { + super.writeCData(sanitizeXml10(text, start, len)); + } + + @Override + public void writeCharacters(final String text) throws XMLStreamException { + super.writeCharacters(sanitizeXml10(text)); + } + + @Override + public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException { + super.writeCharacters(sanitizeXml10(text, start, len)); + } + + @Override + public void writeComment(String text) throws XMLStreamException { + super.writeComment(sanitizeXml10(text)); + } + + private static String sanitizeXml10(final String input) { + if (input == null) { + return null; + } + final int length = input.length(); + // Only create a new string if we find an invalid code point. + // In the common case, this should avoid unnecessary allocations. + for (int i = 0; i < length; ) { + final int cp = input.codePointAt(i); + if (!isValidXml10(cp)) { + final StringBuilder out = new StringBuilder(length); + out.append(input, 0, i); + appendSanitized(input, i, length, out); + return out.toString(); + } + i += Character.charCount(cp); + } + return input; + } + + private static String sanitizeXml10(final char[] input, final int start, final int len) { + return sanitizeXml10(new String(input, start, len)); + } + + private static void appendSanitized(final String input, int i, final int length, final StringBuilder out) { + while (i < length) { + final int cp = input.codePointAt(i); + out.appendCodePoint(isValidXml10(cp) ? cp : REPLACEMENT_CHAR); + i += Character.charCount(cp); + } + } + + /** + * Checks if a code point is valid + * + * @param codePoint a code point between {@code 0} and {@link Character#MAX_CODE_POINT} + * @return {@code true} if it is a valid XML 1.0 code point + */ + private static boolean isValidXml10(final int codePoint) { + assert codePoint >= 0 && codePoint <= Character.MAX_CODE_POINT; + // XML 1.0 valid characters (Fifth Edition): + // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + + // [#x20–#xD7FF] (placed early as a fast path for the most common case) + return (codePoint >= ' ' && codePoint < Character.MIN_SURROGATE) + // #x9 + || codePoint == '\t' + // #xA + || codePoint == '\n' + // #xD + || codePoint == '\r' + // [#xE000-#xFFFD] + || (codePoint > Character.MAX_SURROGATE && codePoint <= 0xFFFD) + // [#x10000-#x10FFFF] + || codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT; + } + } + + /** + * Factory that creates {@link SanitizingWriter} instances to ensure that all text written to the XML output is valid XML 1.0. + */ + private static final class SanitizingXmlFactory extends XmlFactory { + + private static final long serialVersionUID = 1L; + + public SanitizingXmlFactory() { + super(); + } + + private SanitizingXmlFactory( + ObjectCodec oc, + int xpFeatures, + int xgFeatures, + XMLInputFactory xmlIn, + XMLOutputFactory xmlOut, + String nameForTextElem, + XmlNameProcessor nameProcessor) { + super(oc, xpFeatures, xgFeatures, xmlIn, xmlOut, nameForTextElem, nameProcessor); + } + + @Override + protected XMLStreamWriter _createXmlWriter(final IOContext ctxt, final Writer w) throws IOException { + return new SanitizingWriter(Stax2WriterAdapter.wrapIfNecessary(super._createXmlWriter(ctxt, w))); + } + + @Override + protected XMLStreamWriter _createXmlWriter(final IOContext ctxt, final OutputStream out) throws IOException { + return new SanitizingWriter(Stax2WriterAdapter.wrapIfNecessary(super._createXmlWriter(ctxt, out))); + } + + @Override + public XmlFactory copy() { + _checkInvalidCopy(SanitizingXmlFactory.class); + return new SanitizingXmlFactory( + _objectCodec, + _xmlParserFeatures, + _xmlGeneratorFeatures, + _xmlInputFactory, + _xmlOutputFactory, + _cfgNameForTextElement, + _nameProcessor); + } + } } ++++++ log4j-CVE-2026-34481.patch ++++++ --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/JsonWriter.java 2026-04-14 14:24:27.336457199 +0200 +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/JsonWriter.java 2026-04-14 14:24:45.379955387 +0200 @@ -757,11 +757,21 @@ } public void writeNumber(final float number) { - stringBuilder.append(number); + // Follows the same logic as Jackson's JsonWriteFeature#WRITE_NAN_AS_STRINGS feature. + if (!Float.isFinite(number)) { + writeString(Float.toString(number)); + } else { + stringBuilder.append(number); + } } public void writeNumber(final double number) { - stringBuilder.append(number); + // Follows the same logic as Jackson's JsonWriteFeature#WRITE_NAN_AS_STRINGS feature. + if (!Double.isFinite(number)) { + writeString(Double.toString(number)); + } else { + stringBuilder.append(number); + } } public void writeNumber(final short number) {
