Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Backports:SLE-15-SP3
netty
netty-CVE-2020-11612.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File netty-CVE-2020-11612.patch of Package netty
--- netty-netty-4.1.13.Final/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java 2017-07-06 13:23:51.000000000 +0200 +++ netty-netty-4.1.13.Final/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java 2020-04-09 09:42:57.546195401 +0200 @@ -16,6 +16,7 @@ package io.netty.handler.codec.compression; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelHandlerContext; import java.util.List; @@ -63,7 +64,19 @@ * Creates a new instance with the default wrapper ({@link ZlibWrapper#ZLIB}). */ public JdkZlibDecoder() { - this(ZlibWrapper.ZLIB, null); + this(ZlibWrapper.ZLIB, null, false, 0); + } + + /** + * Creates a new instance with the default wrapper ({@link ZlibWrapper#ZLIB}) + * and the specified maximum buffer allocation. + * + * @param maxAllocation + * Maximum size of the decompression buffer. Must be >= 0. + * If zero, maximum size is decided by the {@link ByteBufAllocator}. + */ + public JdkZlibDecoder(int maxAllocation) { + this(ZlibWrapper.ZLIB, null, false, maxAllocation); } /** @@ -72,7 +85,20 @@ * supports the preset dictionary. */ public JdkZlibDecoder(byte[] dictionary) { - this(ZlibWrapper.ZLIB, dictionary); + this(ZlibWrapper.ZLIB, dictionary, false, 0); + } + + /** + * Creates a new instance with the specified preset dictionary and maximum buffer allocation. + * The wrapper is always {@link ZlibWrapper#ZLIB} because it is the only format that + * supports the preset dictionary. + * + * @param maxAllocation + * Maximum size of the decompression buffer. Must be >= 0. + * If zero, maximum size is decided by the {@link ByteBufAllocator}. + */ + public JdkZlibDecoder(byte[] dictionary, int maxAllocation) { + this(ZlibWrapper.ZLIB, dictionary, false, maxAllocation); } /** @@ -81,10 +107,41 @@ * supported atm. */ public JdkZlibDecoder(ZlibWrapper wrapper) { - this(wrapper, null); + this(wrapper, null, false, 0); + } + + /** + * Creates a new instance with the specified wrapper and maximum buffer allocation. + * Be aware that only {@link ZlibWrapper#GZIP}, {@link ZlibWrapper#ZLIB} and {@link ZlibWrapper#NONE} are + * supported atm. + * + * @param maxAllocation + * Maximum size of the decompression buffer. Must be >= 0. + * If zero, maximum size is decided by the {@link ByteBufAllocator}. + */ + public JdkZlibDecoder(ZlibWrapper wrapper, int maxAllocation) { + this(wrapper, null, false, maxAllocation); + } + + public JdkZlibDecoder(ZlibWrapper wrapper, boolean decompressConcatenated) { + this(wrapper, null, decompressConcatenated, 0); + } + + public JdkZlibDecoder(ZlibWrapper wrapper, boolean decompressConcatenated, int maxAllocation) { + this(wrapper, null, decompressConcatenated, maxAllocation); + } + + public JdkZlibDecoder(boolean decompressConcatenated) { + this(ZlibWrapper.GZIP, null, decompressConcatenated, 0); } - private JdkZlibDecoder(ZlibWrapper wrapper, byte[] dictionary) { + public JdkZlibDecoder(boolean decompressConcatenated, int maxAllocation) { + this(ZlibWrapper.GZIP, null, decompressConcatenated, maxAllocation); + } + + private JdkZlibDecoder(ZlibWrapper wrapper, byte[] dictionary, boolean decompressConcatenated, int maxAllocation) { + super(maxAllocation); + if (wrapper == null) { throw new NullPointerException("wrapper"); } @@ -167,7 +224,7 @@ inflater.setInput(array); } - ByteBuf decompressed = ctx.alloc().heapBuffer(inflater.getRemaining() << 1); + ByteBuf decompressed = prepareDecompressBuffer(ctx, null, inflater.getRemaining() << 1); try { boolean readFooter = false; while (!inflater.needsInput()) { @@ -198,7 +255,7 @@ } break; } else { - decompressed.ensureWritable(inflater.getRemaining() << 1); + decompressed = prepareDecompressBuffer(ctx, decompressed, inflater.getRemaining() << 1); } } @@ -223,6 +280,11 @@ } @Override + protected void decompressionBufferExhausted(ByteBuf buffer) { + finished = true; + } + + @Override protected void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { super.handlerRemoved0(ctx); if (inflater != null) { --- netty-netty-4.1.13.Final/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java 2017-07-06 13:23:51.000000000 +0200 +++ netty-netty-4.1.13.Final/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java 2020-04-09 09:34:03.351374501 +0200 @@ -18,6 +18,7 @@ import com.jcraft.jzlib.Inflater; import com.jcraft.jzlib.JZlib; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelHandlerContext; import java.util.List; @@ -34,7 +35,21 @@ * @throws DecompressionException if failed to initialize zlib */ public JZlibDecoder() { - this(ZlibWrapper.ZLIB); + this(ZlibWrapper.ZLIB, 0); + } + + /** + * Creates a new instance with the default wrapper ({@link ZlibWrapper#ZLIB}) + * and specified maximum buffer allocation. + * + * @param maxAllocation + * Maximum size of the decompression buffer. Must be >= 0. + * If zero, maximum size is decided by the {@link ByteBufAllocator}. + * + * @throws DecompressionException if failed to initialize zlib + */ + public JZlibDecoder(int maxAllocation) { + this(ZlibWrapper.ZLIB, maxAllocation); } /** @@ -43,6 +58,21 @@ * @throws DecompressionException if failed to initialize zlib */ public JZlibDecoder(ZlibWrapper wrapper) { + this(wrapper, 0); + } + + /** + * Creates a new instance with the specified wrapper and maximum buffer allocation. + * + * @param maxAllocation + * Maximum size of the decompression buffer. Must be >= 0. + * If zero, maximum size is decided by the {@link ByteBufAllocator}. + * + * @throws DecompressionException if failed to initialize zlib + */ + public JZlibDecoder(ZlibWrapper wrapper, int maxAllocation) { + super(maxAllocation); + if (wrapper == null) { throw new NullPointerException("wrapper"); } @@ -61,6 +91,22 @@ * @throws DecompressionException if failed to initialize zlib */ public JZlibDecoder(byte[] dictionary) { + this(dictionary, 0); + } + + /** + * Creates a new instance with the specified preset dictionary and maximum buffer allocation. + * The wrapper is always {@link ZlibWrapper#ZLIB} because it is the only format that + * supports the preset dictionary. + * + * @param maxAllocation + * Maximum size of the decompression buffer. Must be >= 0. + * If zero, maximum size is decided by the {@link ByteBufAllocator}. + * + * @throws DecompressionException if failed to initialize zlib + */ + public JZlibDecoder(byte[] dictionary, int maxAllocation) { + super(maxAllocation); if (dictionary == null) { throw new NullPointerException("dictionary"); } @@ -110,11 +156,11 @@ final int oldNextInIndex = z.next_in_index; // Configure output. - ByteBuf decompressed = ctx.alloc().heapBuffer(inputLength << 1); + ByteBuf decompressed = prepareDecompressBuffer(ctx, null, inputLength << 1); try { loop: for (;;) { - decompressed.ensureWritable(z.avail_in << 1); + decompressed = prepareDecompressBuffer(ctx, decompressed, z.avail_in << 1); z.avail_out = decompressed.writableBytes(); z.next_out = decompressed.array(); z.next_out_index = decompressed.arrayOffset() + decompressed.writerIndex(); @@ -170,4 +216,9 @@ z.next_out = null; } } + + @Override + protected void decompressionBufferExhausted(ByteBuf buffer) { + finished = true; + } } --- netty-netty-4.1.13.Final/codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java 2017-07-06 13:23:51.000000000 +0200 +++ netty-netty-4.1.13.Final/codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java 2020-04-09 09:29:03.593720874 +0200 @@ -16,6 +16,8 @@ package io.netty.handler.codec.compression; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; /** @@ -24,8 +26,71 @@ public abstract class ZlibDecoder extends ByteToMessageDecoder { /** + * Maximum allowed size of the decompression buffer. + */ + protected final int maxAllocation; + + /** + * Same as {@link #ZlibDecoder(int)} with maxAllocation = 0. + */ + public ZlibDecoder() { + this(0); + } + + /** + * Construct a new ZlibDecoder. + * @param maxAllocation + * Maximum size of the decompression buffer. Must be >= 0. + * If zero, maximum size is decided by the {@link ByteBufAllocator}. + */ + public ZlibDecoder(int maxAllocation) { + if (maxAllocation < 0) { + throw new IllegalArgumentException("maxAllocation must be >= 0"); + } + this.maxAllocation = maxAllocation; + } + + /** * Returns {@code true} if and only if the end of the compressed stream * has been reached. */ public abstract boolean isClosed(); + + /** + * Allocate or expand the decompression buffer, without exceeding the maximum allocation. + * Calls {@link #decompressionBufferExhausted(ByteBuf)} if the buffer is full and cannot be expanded further. + */ + protected ByteBuf prepareDecompressBuffer(ChannelHandlerContext ctx, ByteBuf buffer, int preferredSize) { + if (buffer == null) { + if (maxAllocation == 0) { + return ctx.alloc().heapBuffer(preferredSize); + } + + return ctx.alloc().heapBuffer(Math.min(preferredSize, maxAllocation), maxAllocation); + } + + // this always expands the buffer if possible, even if the expansion is less than preferredSize + // we throw the exception only if the buffer could not be expanded at all + // this means that one final attempt to deserialize will always be made with the buffer at maxAllocation + if (buffer.ensureWritable(preferredSize, true) == 1) { + // buffer must be consumed so subclasses don't add it to output + // we therefore duplicate it when calling decompressionBufferExhausted() to guarantee non-interference + // but wait until after to consume it so the subclass can tell how much output is really in the buffer + decompressionBufferExhausted(buffer.duplicate()); + buffer.skipBytes(buffer.readableBytes()); + throw new DecompressionException("Decompression buffer has reached maximum size: " + buffer.maxCapacity()); + } + + return buffer; + } + + /** + * Called when the decompression buffer cannot be expanded further. + * Default implementation is a no-op, but subclasses can override in case they want to + * do something before the {@link DecompressionException} is thrown, such as log the + * data that was decompressed so far. + */ + protected void decompressionBufferExhausted(ByteBuf buffer) { + } + } --- netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibTest.java 2017-07-06 13:23:51.000000000 +0200 +++ netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibTest.java 2020-04-09 09:29:03.593720874 +0200 @@ -26,8 +26,8 @@ } @Override - protected ZlibDecoder createDecoder(ZlibWrapper wrapper) { - return new JdkZlibDecoder(wrapper); + protected ZlibDecoder createDecoder(ZlibWrapper wrapper, int maxAllocation) { + return new JdkZlibDecoder(wrapper, maxAllocation); } @Test(expected = DecompressionException.class) --- netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/JZlibTest.java 2017-07-06 13:23:51.000000000 +0200 +++ netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/JZlibTest.java 2020-04-09 09:29:03.593720874 +0200 @@ -23,7 +23,7 @@ } @Override - protected ZlibDecoder createDecoder(ZlibWrapper wrapper) { - return new JZlibDecoder(wrapper); + protected ZlibDecoder createDecoder(ZlibWrapper wrapper, int maxAllocation) { + return new JZlibDecoder(wrapper, maxAllocation); } } --- netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/ZlibCrossTest1.java 2017-07-06 13:23:51.000000000 +0200 +++ netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/ZlibCrossTest1.java 2020-04-09 09:29:03.593720874 +0200 @@ -23,7 +23,7 @@ } @Override - protected ZlibDecoder createDecoder(ZlibWrapper wrapper) { - return new JZlibDecoder(wrapper); + protected ZlibDecoder createDecoder(ZlibWrapper wrapper, int maxAllocation) { + return new JZlibDecoder(wrapper, maxAllocation); } } --- netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/ZlibCrossTest2.java 2017-07-06 13:23:51.000000000 +0200 +++ netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/ZlibCrossTest2.java 2020-04-09 09:29:03.593720874 +0200 @@ -25,8 +25,8 @@ } @Override - protected ZlibDecoder createDecoder(ZlibWrapper wrapper) { - return new JdkZlibDecoder(wrapper); + protected ZlibDecoder createDecoder(ZlibWrapper wrapper, int maxAllocation) { + return new JdkZlibDecoder(wrapper, maxAllocation); } @Test(expected = DecompressionException.class) --- netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/ZlibTest.java 2017-07-06 13:23:51.000000000 +0200 +++ netty-netty-4.1.13.Final/codec/src/test/java/io/netty/handler/codec/compression/ZlibTest.java 2020-04-09 09:29:03.593720874 +0200 @@ -15,7 +15,9 @@ */ package io.netty.handler.codec.compression; +import io.netty.buffer.AbstractByteBufAllocator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.Unpooled; import io.netty.channel.embedded.EmbeddedChannel; @@ -88,8 +90,12 @@ rand.nextBytes(BYTES_LARGE); } + protected ZlibDecoder createDecoder(ZlibWrapper wrapper) { + return createDecoder(wrapper, 0); + } + protected abstract ZlibEncoder createEncoder(ZlibWrapper wrapper); - protected abstract ZlibDecoder createDecoder(ZlibWrapper wrapper); + protected abstract ZlibDecoder createDecoder(ZlibWrapper wrapper, int maxAllocation); @Test public void testGZIP2() throws Exception { @@ -345,6 +351,25 @@ testCompressLarge(ZlibWrapper.GZIP, ZlibWrapper.ZLIB_OR_NONE); } + @Test + public void testMaxAllocation() throws Exception { + int maxAllocation = 1024; + ZlibDecoder decoder = createDecoder(ZlibWrapper.ZLIB, maxAllocation); + EmbeddedChannel chDecoder = new EmbeddedChannel(decoder); + TestByteBufAllocator alloc = new TestByteBufAllocator(chDecoder.alloc()); + chDecoder.config().setAllocator(alloc); + + try { + chDecoder.writeInbound(Unpooled.wrappedBuffer(deflate(BYTES_LARGE))); + fail("decompressed size > maxAllocation, so should have thrown exception"); + } catch (DecompressionException e) { + assertTrue(e.getMessage().startsWith("Decompression buffer has reached maximum size")); + assertEquals(maxAllocation, alloc.getMaxAllocation()); + assertTrue(decoder.isClosed()); + assertFalse(chDecoder.finish()); + } + } + private static byte[] gzip(byte[] bytes) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); GZIPOutputStream stream = new GZIPOutputStream(out); @@ -360,4 +385,34 @@ stream.close(); return out.toByteArray(); } + + private static final class TestByteBufAllocator extends AbstractByteBufAllocator { + private ByteBufAllocator wrapped; + private int maxAllocation; + + TestByteBufAllocator(ByteBufAllocator wrapped) { + this.wrapped = wrapped; + } + + public int getMaxAllocation() { + return maxAllocation; + } + + @Override + public boolean isDirectBufferPooled() { + return wrapped.isDirectBufferPooled(); + } + + @Override + protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) { + maxAllocation = Math.max(maxAllocation, maxCapacity); + return wrapped.heapBuffer(initialCapacity, maxCapacity); + } + + @Override + protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) { + maxAllocation = Math.max(maxAllocation, maxCapacity); + return wrapped.directBuffer(initialCapacity, maxCapacity); + } + } }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor