From 4eba477e41332c6737b7125d3d16bc517d9ceaee Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 29 Oct 2024 20:20:35 -0500 Subject: [PATCH] Guard against read producing a too-long String Badly-behaved #read implementations may produce String output that exceeds the requested length, as theorized in jruby/jruby#8391. If this code blindly attempts to copy all bytes from such a String, it may cause an ArrayIndexOutOfBoundsError when it writes over the end of the passed-in buffer. This change guards against such #read implementations by raising a hard error; we do not maintain a buffer in this class, so we can't just hold onto the extra bytes, and we don't want to just silently discard them. A hard error will let a user of this class find bad #read implementations more quickly and fix the real problem. Fixes bug #1 from jruby/jruby#8391. --- core/src/main/java/org/jruby/util/IOInputStream.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/jruby/util/IOInputStream.java b/core/src/main/java/org/jruby/util/IOInputStream.java index 46884ad0550e..2a7703ad759a 100644 --- a/core/src/main/java/org/jruby/util/IOInputStream.java +++ b/core/src/main/java/org/jruby/util/IOInputStream.java @@ -141,8 +141,15 @@ public int read(byte[] b, int off, int len) throws IOException { if (readValue.isNil()) return -1; ByteList str = readValue.convertToString().getByteList(); - System.arraycopy(str.getUnsafeBytes(), str.getBegin(), b, off, str.getRealSize()); - return str.getRealSize(); + int readSize = str.realSize(); + + if (readSize > len) { + throw runtime.newIOError("read call of " + len + " bytes produced a String of length " + readSize); + } + + System.arraycopy(str.getUnsafeBytes(), str.getBegin(), b, off, readSize); + + return readSize; } }