Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-16 21:10:30 +01:00
Strictly enforce packet size limits for incoming compressed packets
Dieser Commit ist enthalten in:
Ursprung
f64b44ec21
Commit
b19d36e939
@ -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();
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
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 io.netty.buffer.ByteBuf;
|
||||
@ -24,7 +25,7 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
public void inflate(ByteBuf source, ByteBuf destination, int max) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
|
||||
if (source.hasArray()) {
|
||||
@ -37,6 +38,7 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
||||
}
|
||||
|
||||
while (!inflater.finished()) {
|
||||
ensureMaxSize(destination, max);
|
||||
int read = inflater.inflate(buf);
|
||||
destination.writeBytes(buf, 0, read);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
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 io.netty.buffer.ByteBuf;
|
||||
@ -22,18 +23,19 @@ public class NativeVelocityCompressor implements VelocityCompressor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
public void inflate(ByteBuf source, ByteBuf destination, int max) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
source.memoryAddress();
|
||||
destination.memoryAddress();
|
||||
|
||||
while (!inflate.finished && source.isReadable()) {
|
||||
if (!destination.isWritable()) {
|
||||
ensureMaxSize(destination, max);
|
||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
||||
}
|
||||
int produced = inflate.process(inflateCtx, source.memoryAddress() + source.readerIndex(),
|
||||
source.readableBytes(),
|
||||
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes());
|
||||
source.readableBytes(), destination.memoryAddress() + destination.writerIndex(),
|
||||
destination.writableBytes());
|
||||
source.readerIndex(source.readerIndex() + inflate.consumed);
|
||||
destination.writerIndex(destination.writerIndex() + produced);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import java.util.zip.DataFormatException;
|
||||
* Provides an interface to inflate and deflate {@link ByteBuf}s using zlib.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ class VelocityCompressorTest {
|
||||
|
||||
try {
|
||||
compressor.deflate(source, dest);
|
||||
compressor.inflate(dest, decompressed);
|
||||
compressor.inflate(dest, decompressed, Integer.MAX_VALUE);
|
||||
source.readerIndex(0);
|
||||
assertTrue(ByteBufUtil.equals(source, decompressed));
|
||||
} finally {
|
||||
|
@ -13,7 +13,7 @@ import java.util.List;
|
||||
|
||||
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 VelocityCompressor compressor;
|
||||
@ -35,14 +35,12 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
|
||||
checkFrame(expectedSize >= threshold, "Uncompressed size %s is greater than threshold %s",
|
||||
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);
|
||||
int initialCapacity = Math.min(expectedSize, MAXIMUM_INITIAL_BUFFER_SIZE);
|
||||
ByteBuf uncompressed = preferredBuffer(ctx.alloc(), compressor, initialCapacity);
|
||||
ByteBuf uncompressed = preferredBuffer(ctx.alloc(), compressor, expectedSize);
|
||||
try {
|
||||
compressor.inflate(compatibleIn, uncompressed);
|
||||
checkFrame(expectedSize == uncompressed.readableBytes(),
|
||||
"Mismatched compression sizes (got %s, expected %s)",
|
||||
uncompressed.readableBytes(), expectedSize);
|
||||
compressor.inflate(compatibleIn, uncompressed, expectedSize);
|
||||
out.add(uncompressed);
|
||||
} catch (Exception e) {
|
||||
uncompressed.release();
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren