Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +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;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren