From cf3f53127c13f9fe206c33de4666fabdcf14b2f2 Mon Sep 17 00:00:00 2001 From: JiangZhaoYu Date: Wed, 13 Nov 2024 17:58:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DCVE-2024-47535?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CVE-2024-47535.patch | 341 +++++++++++++++++++++++++++++++++++++++++++ netty.spec | 6 +- 2 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 CVE-2024-47535.patch diff --git a/CVE-2024-47535.patch b/CVE-2024-47535.patch new file mode 100644 index 0000000..b348828 --- /dev/null +++ b/CVE-2024-47535.patch @@ -0,0 +1,341 @@ +From 4ea290f9fc3350070ac17a439c5aea603c4c0fd8 Mon Sep 17 00:00:00 2001 +From: JiangZhaoYu +Date: Wed, 13 Nov 2024 17:55:33 +0800 +Subject: [PATCH] Motivation: + +We didnt verify the amount of data buffered while reading files / streams during startup which could allow an attacker to cause an OMME if the attacker was able to create a massive file. + +Modifications: + +Decorate InputStream with own that will throw an exception once we reach the limit of data read. + +Result: + +No more risk of OOME +--- + .../codec/http2/HashCollisionTest.java | 5 +- + .../src/main/java/io/netty/util/NetUtil.java | 7 +- + .../util/internal/BoundedInputStream.java | 83 +++++++++++++++++++ + .../util/internal/BoundedInputStreamTest.java | 44 ++++++++++ + ...esolverDnsServerAddressStreamProvider.java | 7 +- + .../io/netty/resolver/HostsFileParser.java | 5 +- + .../io/netty/osgitests/OsgiBundleTest.java | 5 +- + .../epoll/EpollSocketTestPermutation.java | 5 +- + 8 files changed, 147 insertions(+), 14 deletions(-) + create mode 100644 common/src/main/java/io/netty/util/internal/BoundedInputStream.java + create mode 100644 common/src/test/java/io/netty/util/internal/BoundedInputStreamTest.java + +diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/HashCollisionTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/HashCollisionTest.java +index 4fe437a..a3fc40d 100644 +--- a/codec-http2/src/test/java/io/netty/handler/codec/http2/HashCollisionTest.java ++++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/HashCollisionTest.java +@@ -18,11 +18,12 @@ import io.netty.handler.codec.http.HttpHeaderNames; + import io.netty.handler.codec.http.HttpHeaderValues; + import io.netty.util.AsciiString; + import io.netty.util.internal.PlatformDependent; ++import io.netty.util.CharsetUtil; + import org.junit.Ignore; + + import java.io.BufferedReader; + import java.io.File; +-import java.io.FileReader; ++import java.io.FileInputStream; + import java.io.IOException; + import java.io.PrintStream; + import java.lang.reflect.Field; +@@ -102,7 +103,7 @@ public final class HashCollisionTest { + + private static void addWordsFromFile(File file, List values) + throws IllegalAccessException, IOException { +- BufferedReader br = new BufferedReader(new FileReader(file)); ++ BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), CharsetUtil.UTF_8)); + try { + String line; + while ((line = br.readLine()) != null) { +diff --git a/common/src/main/java/io/netty/util/NetUtil.java b/common/src/main/java/io/netty/util/NetUtil.java +index 3bc8a0b..9f4a7c3 100644 +--- a/common/src/main/java/io/netty/util/NetUtil.java ++++ b/common/src/main/java/io/netty/util/NetUtil.java +@@ -24,7 +24,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory; + + import java.io.BufferedReader; + import java.io.File; +-import java.io.FileReader; ++import java.io.FileInputStream; + import java.io.IOException; + import java.io.InputStream; + import java.io.InputStreamReader; +@@ -263,7 +263,8 @@ public final class NetUtil { + // try / catch block. + // See https://github.com/netty/netty/issues/4936 + if (file.exists()) { +- in = new BufferedReader(new FileReader(file)); ++ in = new BufferedReader(new InputStreamReader( ++ new BoundedInputStream(new FileInputStream(file)))); + somaxconn = Integer.parseInt(in.readLine()); + if (logger.isDebugEnabled()) { + logger.debug("{}: {}", file, somaxconn); +@@ -314,7 +315,7 @@ public final class NetUtil { + Process process = new ProcessBuilder("sysctl", sysctlKey).start(); + try { + InputStream is = process.getInputStream(); +- InputStreamReader isr = new InputStreamReader(is); ++ InputStreamReader isr = new InputStreamReader(new BoundedInputStream(is)); + BufferedReader br = new BufferedReader(isr); + try { + String line = br.readLine(); +diff --git a/common/src/main/java/io/netty/util/internal/BoundedInputStream.java b/common/src/main/java/io/netty/util/internal/BoundedInputStream.java +new file mode 100644 +index 0000000..3062f46 +--- /dev/null ++++ b/common/src/main/java/io/netty/util/internal/BoundedInputStream.java +@@ -0,0 +1,83 @@ ++/* ++ * Copyright 2024 The Netty Project ++ * ++ * The Netty Project licenses this file to you under the Apache License, ++ * version 2.0 (the "License"); you may not use this file except in compliance ++ * with the License. You may obtain a copy of the License at: ++ * ++ * https://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT ++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ++ * License for the specific language governing permissions and limitations ++ * under the License. ++ */ ++package io.netty.util.internal; ++ ++import org.jetbrains.annotations.NotNull; ++ ++import java.io.FilterInputStream; ++import java.io.IOException; ++import java.io.InputStream; ++ ++public final class BoundedInputStream extends FilterInputStream { ++ ++ private final int maxBytesRead; ++ private int numRead; ++ ++ public BoundedInputStream(@NotNull InputStream in, int maxBytesRead) { ++ super(in); ++ this.maxBytesRead = ObjectUtil.checkPositive(maxBytesRead, "maxRead"); ++ } ++ ++ public BoundedInputStream(@NotNull InputStream in) { ++ this(in, 8 * 1024); ++ } ++ ++ @Override ++ public int read() throws IOException { ++ checkMaxBytesRead(1); ++ try { ++ int b = super.read(); ++ if (b <= 0) { ++ // We couldn't read anything. ++ numRead--; ++ } ++ return b; ++ } catch (IOException e) { ++ numRead--; ++ throw e; ++ } ++ } ++ ++ @Override ++ public int read(byte[] buf, int off, int len) throws IOException { ++ // Calculate the maximum number of bytes that we should try to read. ++ int num = Math.min(len, maxBytesRead - numRead + 1); ++ checkMaxBytesRead(num); ++ try { ++ int b = super.read(buf, off, num); ++ if (b == -1) { ++ // We couldn't read anything. ++ numRead -= num; ++ } else if (b != num) { ++ // Correct numRead based on the actual amount we were able to read. ++ numRead -= num - b; ++ } ++ return b; ++ } catch (IOException e) { ++ numRead -= num; ++ throw e; ++ } ++ } ++ ++ private void checkMaxBytesRead(int n) throws IOException { ++ int sum = numRead + n; ++ if (sum < 0 || sum > maxBytesRead) { ++ numRead = maxBytesRead + 1; ++ throw new IOException("Maximum number of bytes read: " + maxBytesRead); ++ } ++ numRead = sum; ++ } ++} +diff --git a/common/src/test/java/io/netty/util/internal/BoundedInputStreamTest.java b/common/src/test/java/io/netty/util/internal/BoundedInputStreamTest.java +new file mode 100644 +index 0000000..35e66e5 +--- /dev/null ++++ b/common/src/test/java/io/netty/util/internal/BoundedInputStreamTest.java +@@ -0,0 +1,44 @@ ++/* ++ * Copyright 2024 The Netty Project ++ * ++ * The Netty Project licenses this file to you under the Apache License, ++ * version 2.0 (the "License"); you may not use this file except in compliance ++ * with the License. You may obtain a copy of the License at: ++ * ++ * https://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT ++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ++ * License for the specific language governing permissions and limitations ++ * under the License. ++ */ ++package io.netty.util.internal; ++ ++import org.junit.jupiter.api.Test; ++import org.junit.jupiter.api.function.Executable; ++ ++import java.io.ByteArrayInputStream; ++import java.io.IOException; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++import static org.junit.jupiter.api.Assertions.assertThrows; ++ ++public class BoundedInputStreamTest { ++ ++ @Test ++ void testBoundEnforced() throws IOException { ++ final byte[] bytes = new byte[64]; ++ PlatformDependent.threadLocalRandom().nextBytes(bytes); ++ final BoundedInputStream reader = new BoundedInputStream(new ByteArrayInputStream(bytes), bytes.length - 1); ++ assertEquals(bytes[0], (byte) reader.read()); ++ ++ assertThrows(IOException.class, new Executable() { ++ @Override ++ public void execute() throws Throwable { ++ reader.read(new byte[64], 0, 64); ++ } ++ }); ++ reader.close(); ++ } ++} +diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/UnixResolverDnsServerAddressStreamProvider.java b/resolver-dns/src/main/java/io/netty/resolver/dns/UnixResolverDnsServerAddressStreamProvider.java +index d5571c9..668ed56 100644 +--- a/resolver-dns/src/main/java/io/netty/resolver/dns/UnixResolverDnsServerAddressStreamProvider.java ++++ b/resolver-dns/src/main/java/io/netty/resolver/dns/UnixResolverDnsServerAddressStreamProvider.java +@@ -20,10 +20,11 @@ import io.netty.util.internal.SocketUtils; + import io.netty.util.internal.UnstableApi; + import io.netty.util.internal.logging.InternalLogger; + import io.netty.util.internal.logging.InternalLoggerFactory; ++import io.netty.util.CharsetUtil; + + import java.io.BufferedReader; + import java.io.File; +-import java.io.FileReader; ++import java.io.FileInputStream; + import java.io.IOException; + import java.net.InetSocketAddress; + import java.util.ArrayList; +@@ -153,7 +154,7 @@ public final class UnixResolverDnsServerAddressStreamProvider implements DnsServ + if (!etcResolverFile.isFile()) { + continue; + } +- FileReader fr = new FileReader(etcResolverFile); ++ BufferedReader fr = new BufferedReader(new InputStreamReader(new FileInputStream(etcResolverFile), CharsetUtil.UTF_8)); + BufferedReader br = null; + try { + br = new BufferedReader(fr); +@@ -259,7 +260,7 @@ public final class UnixResolverDnsServerAddressStreamProvider implements DnsServ + * @throws IOException If a failure occurs parsing the file. + */ + static int parseEtcResolverFirstNdots(File etcResolvConf) throws IOException { +- FileReader fr = new FileReader(etcResolvConf); ++ BufferedReader fr = new BufferedReader(new InputStreamReader(new FileInputStream(etcResolvConf), CharsetUtil.UTF_8)); + BufferedReader br = null; + try { + br = new BufferedReader(fr); +diff --git a/resolver/src/main/java/io/netty/resolver/HostsFileParser.java b/resolver/src/main/java/io/netty/resolver/HostsFileParser.java +index 8ee1d19..617dbbe 100644 +--- a/resolver/src/main/java/io/netty/resolver/HostsFileParser.java ++++ b/resolver/src/main/java/io/netty/resolver/HostsFileParser.java +@@ -20,10 +20,11 @@ import io.netty.util.internal.PlatformDependent; + import io.netty.util.internal.UnstableApi; + import io.netty.util.internal.logging.InternalLogger; + import io.netty.util.internal.logging.InternalLoggerFactory; ++import io.netty.util.CharsetUtil; + + import java.io.BufferedReader; + import java.io.File; +-import java.io.FileReader; ++import java.io.FileInputStream; + import java.io.IOException; + import java.io.Reader; + import java.net.Inet4Address; +@@ -100,7 +101,7 @@ public final class HostsFileParser { + public static HostsFileEntries parse(File file) throws IOException { + checkNotNull(file, "file"); + if (file.exists() && file.isFile()) { +- return parse(new BufferedReader(new FileReader(file))); ++ return parse(new BufferedReader(new InputStreamReader(new FileInputStream(file), CharsetUtil.UTF_8))); + } else { + return HostsFileEntries.EMPTY; + } +diff --git a/testsuite-osgi/src/test/java/io/netty/osgitests/OsgiBundleTest.java b/testsuite-osgi/src/test/java/io/netty/osgitests/OsgiBundleTest.java +index f6c20f4..c052012 100644 +--- a/testsuite-osgi/src/test/java/io/netty/osgitests/OsgiBundleTest.java ++++ b/testsuite-osgi/src/test/java/io/netty/osgitests/OsgiBundleTest.java +@@ -21,10 +21,11 @@ import static org.ops4j.pax.exam.CoreOptions.junitBundles; + import static org.ops4j.pax.exam.CoreOptions.mavenBundle; + import static org.ops4j.pax.exam.CoreOptions.systemProperty; + import static org.ops4j.pax.exam.CoreOptions.wrappedBundle; ++import io.netty.util.CharsetUtil; + + import java.io.BufferedReader; + import java.io.File; +-import java.io.FileReader; ++import java.io.FileInputStream; + import java.io.IOException; + import java.util.Arrays; + import java.util.ArrayList; +@@ -50,7 +51,7 @@ public class OsgiBundleTest { + final Set artifacts = new HashSet(); + final File f = new File("target/classes/META-INF/maven/dependencies.properties"); + try { +- final BufferedReader r = new BufferedReader(new FileReader(f)); ++ final BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(f), CharsetUtil.UTF_8)); + try { + boolean haveDeps = false; + +diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketTestPermutation.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketTestPermutation.java +index 2da13e1..73a4db7 100644 +--- a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketTestPermutation.java ++++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollSocketTestPermutation.java +@@ -32,10 +32,11 @@ import io.netty.testsuite.transport.socket.SocketTestPermutation; + import io.netty.util.concurrent.DefaultThreadFactory; + import io.netty.util.internal.logging.InternalLogger; + import io.netty.util.internal.logging.InternalLoggerFactory; ++import io.netty.util.CharsetUtil; + + import java.io.BufferedReader; + import java.io.File; +-import java.io.FileReader; ++import java.io.FileInputStream; + import java.io.IOException; + import java.security.AccessController; + import java.security.PrivilegedAction; +@@ -188,7 +189,7 @@ class EpollSocketTestPermutation extends SocketTestPermutation { + if (file.exists()) { + BufferedReader in = null; + try { +- in = new BufferedReader(new FileReader(file)); ++ in = new BufferedReader(new InputStreamReader(new FileInputStream(file), CharsetUtil.UTF_8)); + fastopen = Integer.parseInt(in.readLine()); + if (logger.isDebugEnabled()) { + logger.debug("{}: {}", file, fastopen); +-- +2.45.2 + diff --git a/netty.spec b/netty.spec index 29167d5..a07ebbe 100644 --- a/netty.spec +++ b/netty.spec @@ -2,7 +2,7 @@ Name: netty Version: 4.1.13 -Release: 22 +Release: 23 Summary: Asynchronous event-driven network application Java framework License: ASL 2.0 URL: https://netty.io/ @@ -33,6 +33,7 @@ Patch0021: fix-strip.patch # https://github.com/netty/netty/commit/cd91cf3c99123bd1e53fd6a1de0e3d1922f05bb2 Patch0022: CVE-2022-41881.patch Patch0023: CVE-2024-29025.patch +Patch0024: CVE-2024-47535.patch BuildRequires: maven-local mvn(ant-contrib:ant-contrib) BuildRequires: mvn(com.jcraft:jzlib) mvn(commons-logging:commons-logging) @@ -157,6 +158,9 @@ export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS" %changelog +* Wed Nov 13 2024 ZhaoYu Jiang - 4.1.13-23 +- Fix CVE-2024-47535 + * Tue Nov 12 2024 yaoxin - 4.1.13-22 - Fix CVE-2024-29025 -- Gitee