3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-09-29 06:30:16 +02:00

Strictly enforce packet size limits for incoming compressed packets

Dieser Commit ist enthalten in:
Andrew Steinborn 2019-06-09 04:23:21 -04:00
Ursprung f64b44ec21
Commit b19d36e939
6 geänderte Dateien mit 45 neuen und 15 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,28 @@
package com.velocitypowered.natives.compression;
import io.netty.buffer.ByteBuf;
import java.util.zip.DataFormatException;
class CompressorUtils {
/**
* The default preferred output buffer size for zlib.
*/
static final int ZLIB_BUFFER_SIZE = 8192;
/**
* Ensures that the buffer does not go over {@code max}.
* @param buf the buffer for check
* @param max the maximum size for the buffer
* @throws DataFormatException if the buffer becomes too bug
*/
static void ensureMaxSize(ByteBuf buf, int max) throws DataFormatException {
int len = buf.readableBytes();
if (len > max) {
throw new DataFormatException("Got too much data (" + len + " > " + max + ")");
}
}
private CompressorUtils() {
throw new AssertionError();
}
}

Datei anzeigen

@ -1,6 +1,7 @@
package com.velocitypowered.natives.compression; package com.velocitypowered.natives.compression;
import static com.velocitypowered.natives.util.NativeConstants.ZLIB_BUFFER_SIZE; import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFER_SIZE;
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
@ -24,7 +25,7 @@ public class JavaVelocityCompressor implements VelocityCompressor {
} }
@Override @Override
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException { public void inflate(ByteBuf source, ByteBuf destination, int max) throws DataFormatException {
ensureNotDisposed(); ensureNotDisposed();
if (source.hasArray()) { if (source.hasArray()) {
@ -37,6 +38,7 @@ public class JavaVelocityCompressor implements VelocityCompressor {
} }
while (!inflater.finished()) { while (!inflater.finished()) {
ensureMaxSize(destination, max);
int read = inflater.inflate(buf); int read = inflater.inflate(buf);
destination.writeBytes(buf, 0, read); destination.writeBytes(buf, 0, read);
} }

Datei anzeigen

@ -1,6 +1,7 @@
package com.velocitypowered.natives.compression; package com.velocitypowered.natives.compression;
import static com.velocitypowered.natives.util.NativeConstants.ZLIB_BUFFER_SIZE; import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFER_SIZE;
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
@ -22,18 +23,19 @@ public class NativeVelocityCompressor implements VelocityCompressor {
} }
@Override @Override
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException { public void inflate(ByteBuf source, ByteBuf destination, int max) throws DataFormatException {
ensureNotDisposed(); ensureNotDisposed();
source.memoryAddress(); source.memoryAddress();
destination.memoryAddress(); destination.memoryAddress();
while (!inflate.finished && source.isReadable()) { while (!inflate.finished && source.isReadable()) {
if (!destination.isWritable()) { if (!destination.isWritable()) {
ensureMaxSize(destination, max);
destination.ensureWritable(ZLIB_BUFFER_SIZE); destination.ensureWritable(ZLIB_BUFFER_SIZE);
} }
int produced = inflate.process(inflateCtx, source.memoryAddress() + source.readerIndex(), int produced = inflate.process(inflateCtx, source.memoryAddress() + source.readerIndex(),
source.readableBytes(), source.readableBytes(), destination.memoryAddress() + destination.writerIndex(),
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes()); destination.writableBytes());
source.readerIndex(source.readerIndex() + inflate.consumed); source.readerIndex(source.readerIndex() + inflate.consumed);
destination.writerIndex(destination.writerIndex() + produced); destination.writerIndex(destination.writerIndex() + produced);
} }

Datei anzeigen

@ -9,7 +9,7 @@ import java.util.zip.DataFormatException;
* Provides an interface to inflate and deflate {@link ByteBuf}s using zlib. * Provides an interface to inflate and deflate {@link ByteBuf}s using zlib.
*/ */
public interface VelocityCompressor extends Disposable, Native { public interface VelocityCompressor extends Disposable, Native {
void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException; void inflate(ByteBuf source, ByteBuf destination, int max) throws DataFormatException;
void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException; void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
} }

Datei anzeigen

@ -70,7 +70,7 @@ class VelocityCompressorTest {
try { try {
compressor.deflate(source, dest); compressor.deflate(source, dest);
compressor.inflate(dest, decompressed); compressor.inflate(dest, decompressed, Integer.MAX_VALUE);
source.readerIndex(0); source.readerIndex(0);
assertTrue(ByteBufUtil.equals(source, decompressed)); assertTrue(ByteBufUtil.equals(source, decompressed));
} finally { } finally {

Datei anzeigen

@ -13,7 +13,7 @@ import java.util.List;
public class MinecraftCompressDecoder extends MessageToMessageDecoder<ByteBuf> { public class MinecraftCompressDecoder extends MessageToMessageDecoder<ByteBuf> {
private static final int MAXIMUM_INITIAL_BUFFER_SIZE = 65536; // 64KiB private static final int MAXIMUM_UNCOMPRESSED_SIZE = 2 * 1024 * 1024; // 2MiB
private final int threshold; private final int threshold;
private final VelocityCompressor compressor; private final VelocityCompressor compressor;
@ -35,14 +35,12 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder<ByteBuf> {
checkFrame(expectedSize >= threshold, "Uncompressed size %s is greater than threshold %s", checkFrame(expectedSize >= threshold, "Uncompressed size %s is greater than threshold %s",
expectedSize, threshold); expectedSize, threshold);
checkFrame(expectedSize <= MAXIMUM_UNCOMPRESSED_SIZE, "Expected uncompressed size"
+ "%s is larger than protocol maximum of %s", expectedSize, MAXIMUM_UNCOMPRESSED_SIZE);
ByteBuf compatibleIn = ensureCompatible(ctx.alloc(), compressor, in); ByteBuf compatibleIn = ensureCompatible(ctx.alloc(), compressor, in);
int initialCapacity = Math.min(expectedSize, MAXIMUM_INITIAL_BUFFER_SIZE); ByteBuf uncompressed = preferredBuffer(ctx.alloc(), compressor, expectedSize);
ByteBuf uncompressed = preferredBuffer(ctx.alloc(), compressor, initialCapacity);
try { try {
compressor.inflate(compatibleIn, uncompressed); compressor.inflate(compatibleIn, uncompressed, expectedSize);
checkFrame(expectedSize == uncompressed.readableBytes(),
"Mismatched compression sizes (got %s, expected %s)",
uncompressed.readableBytes(), expectedSize);
out.add(uncompressed); out.add(uncompressed);
} catch (Exception e) { } catch (Exception e) {
uncompressed.release(); uncompressed.release();