From 4682f724f8185c818a9e44ccc626965a39c1bcff Mon Sep 17 00:00:00 2001
From: Norman Maurer <norman_maurer@apple.com>
Date: Tue, 12 Nov 2024 12:08:59 +0100
Subject: [PATCH] Merge commit from fork

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
---
 .../src/main/java/io/netty/util/NetUtil.java  |  9 ++-
 .../util/internal/BoundedInputStream.java     | 81 +++++++++++++++++++
 .../util/internal/PlatformDependent.java      |  5 +-
 3 files changed, 89 insertions(+), 6 deletions(-)
 create mode 100644 common/src/main/java/io/netty/util/internal/BoundedInputStream.java

diff --git a/common/src/main/java/io/netty/util/NetUtil.java b/common/src/main/java/io/netty/util/NetUtil.java
index ab6536d958..1ddd774b7a 100644
--- a/common/src/main/java/io/netty/util/NetUtil.java
+++ b/common/src/main/java/io/netty/util/NetUtil.java
@@ -15,6 +15,7 @@
  */
 package io.netty.util;
 
+import io.netty.util.internal.BoundedInputStream;
 import io.netty.util.internal.PlatformDependent;
 import io.netty.util.internal.SocketUtils;
 import io.netty.util.internal.StringUtil;
@@ -24,6 +25,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -259,13 +261,14 @@ public final class NetUtil {
                 // - Linux and Mac OS X: 128
                 int somaxconn = PlatformDependent.isWindows() ? 200 : 128;
                 File file = new File("/proc/sys/net/core/somaxconn");
-                BufferedReader in = null;
+                    BufferedReader in = null;
                 try {
                     // file.exists() may throw a SecurityException if a SecurityManager is used, so execute it in the
                     // 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);
@@ -316,7 +319,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 0000000000..239371ed29
--- /dev/null
+++ b/common/src/main/java/io/netty/util/internal/BoundedInputStream.java
@@ -0,0 +1,81 @@
+/*
+ * 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 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(InputStream in, int maxBytesRead) {
+        super(in);
+        this.maxBytesRead = ObjectUtil.checkPositive(maxBytesRead, "maxRead");
+    }
+
+    public BoundedInputStream(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/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java
index 2e00de454d..be8483a4eb 100644
--- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java
+++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java
@@ -226,9 +226,8 @@ public final class PlatformDependent {
             if (file.exists()) {
                 BufferedReader reader = null;
                 try {
-                    reader = new BufferedReader(
-                            new InputStreamReader(
-                                    new FileInputStream(file), CharsetUtil.UTF_8));
+                    reader = new BufferedReader(new InputStreamReader(
+                            new BoundedInputStream(new FileInputStream(file)), CharsetUtil.UTF_8));
 
                     String line;
                     while ((line = reader.readLine()) != null) {
-- 
2.43.0

