fix: require size when reading collection to prevent oom. Do not allow string longer than remaining bytes

This commit is contained in:
mworzala 2024-02-24 17:46:49 -05:00
parent d86b890cc6
commit fb7e4b10e0
No known key found for this signature in database
GPG Key ID: B148F922E64797C7
27 changed files with 120 additions and 52 deletions

View File

@ -8,12 +8,14 @@ import java.util.List;
import static net.minestom.server.network.NetworkBuffer.STRING;
public record ArgumentSignatures(@NotNull List<@NotNull Entry> entries) implements NetworkBuffer.Writer {
public static final int MAX_ENTRIES = 8;
public ArgumentSignatures {
entries = List.copyOf(entries);
}
public ArgumentSignatures(@NotNull NetworkBuffer reader) {
this(reader.readCollection(Entry::new));
this(reader.readCollection(Entry::new, MAX_ENTRIES));
}
@Override

View File

@ -9,12 +9,14 @@ import java.util.List;
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
public record LastSeenMessages(@NotNull List<@NotNull MessageSignature> entries) implements NetworkBuffer.Writer {
public static final int MAX_ENTRIES = 20;
public LastSeenMessages {
entries = List.copyOf(entries);
}
public LastSeenMessages(@NotNull NetworkBuffer reader) {
this(reader.readCollection(MessageSignature::new));
this(reader.readCollection(MessageSignature::new, MAX_ENTRIES));
}
@Override
@ -25,7 +27,7 @@ public record LastSeenMessages(@NotNull List<@NotNull MessageSignature> entries)
public static final Packed EMPTY = new Packed(List.of());
public Packed(@NotNull NetworkBuffer reader) {
this(reader.readCollection(MessageSignature.Packed::new));
this(reader.readCollection(MessageSignature.Packed::new, MAX_ENTRIES));
}
@Override

View File

@ -1,13 +1,5 @@
package net.minestom.server.network;
import java.util.BitSet;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import net.kyori.adventure.text.Component;
import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Entity;
@ -18,6 +10,7 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.data.DeathLocation;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.Either;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -27,6 +20,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
@ -176,8 +170,9 @@ public final class NetworkBuffer {
}
}
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Type<T> type) {
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Type<T> type, int maxSize) {
final int size = read(VAR_INT);
Check.argCondition(size > maxSize, "Collection size (" + size + ") is higher than the maximum allowed size (" + maxSize + ")");
final List<T> values = new java.util.ArrayList<>(size);
for (int i = 0; i < size; i++) {
values.add(read(type));
@ -185,8 +180,9 @@ public final class NetworkBuffer {
return values;
}
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Function<@NotNull NetworkBuffer, @NotNull T> function) {
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Function<@NotNull NetworkBuffer, @NotNull T> function, int maxSize) {
final int size = read(VAR_INT);
Check.argCondition(size > maxSize, "Collection size (" + size + ") is higher than the maximum allowed size (" + maxSize + ")");
final List<T> values = new java.util.ArrayList<>(size);
for (int i = 0; i < size; i++) {
values.add(function.apply(this));

View File

@ -13,6 +13,7 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.packet.server.play.data.DeathLocation;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.UnknownNullability;
import org.jglrxavpok.hephaistos.nbt.*;
@ -219,6 +220,8 @@ final class NetworkBufferTypes {
},
buffer -> {
final int length = buffer.read(VAR_INT);
final int remaining = buffer.nioBuffer.limit() - buffer.readIndex();
Check.argCondition(length > remaining, "String is too long (length: " + length + ", readable: " + remaining + ")");
byte[] bytes = new byte[length];
buffer.nioBuffer.get(buffer.readIndex(), bytes);
buffer.readIndex += length;

View File

@ -13,6 +13,8 @@ public record ClientClickWindowPacket(byte windowId, int stateId,
short slot, byte button, @NotNull ClickType clickType,
@NotNull List<ChangedSlot> changedSlots,
@NotNull ItemStack clickedItem) implements ClientPacket {
public static final int MAX_CHANGED_SLOTS = 128;
public ClientClickWindowPacket {
changedSlots = List.copyOf(changedSlots);
}
@ -20,7 +22,7 @@ public record ClientClickWindowPacket(byte windowId, int stateId,
public ClientClickWindowPacket(@NotNull NetworkBuffer reader) {
this(reader.read(BYTE), reader.read(VAR_INT),
reader.read(SHORT), reader.read(BYTE), reader.readEnum(ClickType.class),
reader.readCollection(ChangedSlot::new), reader.read(ITEM));
reader.readCollection(ChangedSlot::new, MAX_CHANGED_SLOTS), reader.read(ITEM));
}
@Override

View File

@ -12,6 +12,8 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT;
public record ClientEditBookPacket(int slot, @NotNull List<String> pages,
@Nullable String title) implements ClientPacket {
public static final int MAX_PAGES = 200;
public ClientEditBookPacket {
pages = List.copyOf(pages);
if (title != null && title.length() > 128) {
@ -20,7 +22,7 @@ public record ClientEditBookPacket(int slot, @NotNull List<String> pages,
}
public ClientEditBookPacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.readCollection(STRING),
this(reader.read(VAR_INT), reader.readCollection(STRING, MAX_PAGES),
reader.readOptional(STRING));
}

View File

@ -13,9 +13,10 @@ import java.util.Set;
import static net.minestom.server.network.NetworkBuffer.STRING;
public record UpdateEnabledFeaturesPacket(@NotNull Set<NamespaceID> features) implements ServerPacket {
public static final int MAX_FEATURES = 1024;
public UpdateEnabledFeaturesPacket(@NotNull NetworkBuffer buffer) {
this(Set.copyOf(buffer.readCollection((b) -> NamespaceID.from(b.read(STRING)))));
this(Set.copyOf(buffer.readCollection((b) -> NamespaceID.from(b.read(STRING)), MAX_FEATURES)));
}
@Override

View File

@ -24,6 +24,8 @@ import static net.minestom.server.network.NetworkBuffer.*;
public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping> advancementMappings,
@NotNull List<String> identifiersToRemove,
@NotNull List<ProgressMapping> progressMappings) implements ComponentHoldingServerPacket {
public static final int MAX_ADVANCEMENTS = Short.MAX_VALUE;
public AdvancementsPacket {
advancementMappings = List.copyOf(advancementMappings);
identifiersToRemove = List.copyOf(identifiersToRemove);
@ -31,9 +33,9 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
}
public AdvancementsPacket(@NotNull NetworkBuffer reader) {
this(reader.read(BOOLEAN), reader.readCollection(AdvancementMapping::new),
reader.readCollection(STRING),
reader.readCollection(ProgressMapping::new));
this(reader.read(BOOLEAN), reader.readCollection(AdvancementMapping::new, MAX_ADVANCEMENTS),
reader.readCollection(STRING, MAX_ADVANCEMENTS),
reader.readCollection(ProgressMapping::new, MAX_ADVANCEMENTS));
}
@Override
@ -112,7 +114,7 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
public Advancement(@NotNull NetworkBuffer reader) {
this(reader.readOptional(STRING), reader.readOptional(DisplayData::new),
reader.readCollection(Requirement::new), reader.read(BOOLEAN));
reader.readCollection(Requirement::new, MAX_ADVANCEMENTS), reader.read(BOOLEAN));
}
@Override
@ -140,7 +142,7 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
}
public Requirement(@NotNull NetworkBuffer reader) {
this(reader.readCollection(STRING));
this(reader.readCollection(STRING, MAX_ADVANCEMENTS));
}
@Override
@ -224,7 +226,7 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
}
public AdvancementProgress(@NotNull NetworkBuffer reader) {
this(reader.readCollection(Criteria::new));
this(reader.readCollection(Criteria::new, MAX_ADVANCEMENTS));
}
@Override

View File

@ -13,12 +13,14 @@ import static net.minestom.server.network.NetworkBuffer.STRING;
public record CustomChatCompletionPacket(@NotNull Action action,
@NotNull List<@NotNull String> entries) implements ServerPacket {
public static final int MAX_ENTRIES = Short.MAX_VALUE;
public CustomChatCompletionPacket {
entries = List.copyOf(entries);
}
public CustomChatCompletionPacket(@NotNull NetworkBuffer reader) {
this(reader.readEnum(Action.class), reader.readCollection(STRING));
this(reader.readEnum(Action.class), reader.readCollection(STRING, MAX_ENTRIES));
}
@Override

View File

@ -16,6 +16,8 @@ import static net.minestom.server.network.NetworkBuffer.*;
public record DeclareCommandsPacket(@NotNull List<Node> nodes,
int rootIndex) implements ServerPacket {
public static final int MAX_NODES = Short.MAX_VALUE;
public DeclareCommandsPacket {
nodes = List.copyOf(nodes);
}
@ -25,7 +27,7 @@ public record DeclareCommandsPacket(@NotNull List<Node> nodes,
Node node = new Node();
node.read(r);
return node;
}), reader.read(VAR_INT));
}, MAX_NODES), reader.read(VAR_INT));
}
@Override

View File

@ -16,6 +16,9 @@ import java.util.List;
import static net.minestom.server.network.NetworkBuffer.*;
public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implements ServerPacket {
public static final int MAX_RECIPES = Short.MAX_VALUE;
public static final int MAX_INGREDIENTS = 128;
public DeclareRecipesPacket {
recipes = List.copyOf(recipes);
}
@ -35,7 +38,7 @@ public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implem
case "smithing_transform" -> new DeclaredSmithingTransformRecipe(reader);
default -> throw new UnsupportedOperationException("Unrecognized type: " + type);
};
}));
}, MAX_RECIPES));
}
@Override
@ -72,7 +75,7 @@ public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implem
private DeclaredShapelessCraftingRecipe(@NotNull NetworkBuffer reader) {
this(reader.read(STRING), reader.read(STRING),
reader.readEnum(RecipeCategory.Crafting.class),
reader.readCollection(Ingredient::new), reader.read(ITEM));
reader.readCollection(Ingredient::new, MAX_INGREDIENTS), reader.read(ITEM));
}
@Override
@ -314,7 +317,7 @@ public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implem
}
public Ingredient(@NotNull NetworkBuffer reader) {
this(reader.readCollection(ITEM));
this(reader.readCollection(ITEM, MAX_INGREDIENTS));
}
public void write(@NotNull NetworkBuffer writer) {

View File

@ -12,6 +12,8 @@ import java.util.List;
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
public record DestroyEntitiesPacket(@NotNull List<Integer> entityIds) implements ServerPacket {
public static final int MAX_ENTRIES = Short.MAX_VALUE;
public DestroyEntitiesPacket {
entityIds = List.copyOf(entityIds);
}
@ -21,7 +23,7 @@ public record DestroyEntitiesPacket(@NotNull List<Integer> entityIds) implements
}
public DestroyEntitiesPacket(@NotNull NetworkBuffer reader) {
this(reader.readCollection(VAR_INT));
this(reader.readCollection(VAR_INT, MAX_ENTRIES));
}
@Override

View File

@ -17,6 +17,8 @@ import java.util.List;
import static net.minestom.server.network.NetworkBuffer.*;
public record EntityPropertiesPacket(int entityId, List<AttributeInstance> properties) implements ServerPacket {
public static final int MAX_ENTRIES = 1024;
public EntityPropertiesPacket {
properties = List.copyOf(properties);
}
@ -32,7 +34,7 @@ public record EntityPropertiesPacket(int entityId, List<AttributeInstance> prope
instance.addModifier(modifier);
}
return instance;
}));
}, MAX_ENTRIES));
}
@Override

View File

@ -9,7 +9,6 @@ import net.minestom.server.network.packet.server.play.data.DeathLocation;
import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.List;
@ -22,6 +21,8 @@ public record JoinGamePacket(
String dimensionType, String world, long hashedSeed, GameMode gameMode, GameMode previousGameMode,
boolean isDebug, boolean isFlat, DeathLocation deathLocation, int portalCooldown
) implements ServerPacket {
public static final int MAX_WORLDS = Short.MAX_VALUE;
public JoinGamePacket {
worlds = List.copyOf(worlds);
}
@ -30,7 +31,7 @@ public record JoinGamePacket(
this(
reader.read(INT),
reader.read(BOOLEAN),
reader.readCollection(STRING),
reader.readCollection(STRING, MAX_WORLDS),
reader.read(VAR_INT),
reader.read(VAR_INT),
reader.read(VAR_INT),

View File

@ -16,6 +16,8 @@ import static net.minestom.server.network.NetworkBuffer.*;
public record MapDataPacket(int mapId, byte scale, boolean locked,
boolean trackingPosition, @NotNull List<Icon> icons,
@Nullable MapDataPacket.ColorContent colorContent) implements ServerPacket {
public static final int MAX_ICONS = 1024;
public MapDataPacket {
icons = List.copyOf(icons);
}
@ -35,7 +37,7 @@ public record MapDataPacket(int mapId, byte scale, boolean locked,
var scale = reader.read(BYTE);
var locked = reader.read(BOOLEAN);
var trackingPosition = reader.read(BOOLEAN);
List<Icon> icons = trackingPosition ? reader.readCollection(Icon::new) : List.of();
List<Icon> icons = trackingPosition ? reader.readCollection(Icon::new, MAX_ICONS) : List.of();
var columns = reader.read(BYTE);
if (columns <= 0) return new MapDataPacket(mapId, scale, locked, trackingPosition, icons, null);

View File

@ -11,6 +11,8 @@ import java.util.List;
import java.util.UUID;
public record PlayerInfoRemovePacket(@NotNull List<@NotNull UUID> uuids) implements ServerPacket {
public static final int MAX_ENTRIES = 1024;
public PlayerInfoRemovePacket(@NotNull UUID uuid) {
this(List.of(uuid));
}
@ -20,7 +22,7 @@ public record PlayerInfoRemovePacket(@NotNull List<@NotNull UUID> uuids) impleme
}
public PlayerInfoRemovePacket(@NotNull NetworkBuffer reader) {
this(reader.readCollection(NetworkBuffer.UUID));
this(reader.readCollection(NetworkBuffer.UUID, MAX_ENTRIES));
}
@Override

View File

@ -7,6 +7,7 @@ import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.network.player.GameProfile;
import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -19,6 +20,8 @@ import java.util.UUID;
import static net.minestom.server.network.NetworkBuffer.*;
public final class PlayerInfoUpdatePacket implements ServerPacket {
public static final int MAX_ENTRIES = 1024;
private final @NotNull EnumSet<@NotNull Action> actions;
private final @NotNull List<@NotNull Entry> entries;
@ -47,7 +50,7 @@ public final class PlayerInfoUpdatePacket implements ServerPacket {
switch (action) {
case ADD_PLAYER -> {
username = reader.read(STRING);
properties = reader.readCollection(Property::new);
properties = reader.readCollection(Property::new, GameProfile.MAX_PROPERTIES);
}
case INITIALIZE_CHAT -> chatSession = new ChatSession(reader);
case UPDATE_GAME_MODE -> gameMode = reader.readEnum(GameMode.class);
@ -57,7 +60,7 @@ public final class PlayerInfoUpdatePacket implements ServerPacket {
}
}
return new Entry(uuid, username, properties, listed, latency, gameMode, displayName, chatSession);
});
}, MAX_ENTRIES);
}
@Override

View File

@ -13,12 +13,14 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT;
public record SetPassengersPacket(int vehicleEntityId,
@NotNull List<Integer> passengersId) implements ServerPacket {
public static final int MAX_PASSENGERS = 16384;
public SetPassengersPacket {
passengersId = List.copyOf(passengersId);
}
public SetPassengersPacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.readCollection(VAR_INT));
this(reader.read(VAR_INT), reader.readCollection(VAR_INT, MAX_PASSENGERS));
}
@Override

View File

@ -13,12 +13,14 @@ import java.util.List;
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
public record StatisticsPacket(@NotNull List<Statistic> statistics) implements ServerPacket {
public static final int MAX_ENTRIES = 16384;
public StatisticsPacket {
statistics = List.copyOf(statistics);
}
public StatisticsPacket(@NotNull NetworkBuffer reader) {
this(reader.readCollection(Statistic::new));
this(reader.readCollection(Statistic::new, MAX_ENTRIES));
}
@Override

View File

@ -20,12 +20,14 @@ import static net.minestom.server.network.NetworkBuffer.*;
public record TabCompletePacket(int transactionId, int start, int length,
@NotNull List<Match> matches) implements ComponentHoldingServerPacket {
public static final int MAX_ENTRIES = Short.MAX_VALUE;
public TabCompletePacket {
matches = List.copyOf(matches);
}
public TabCompletePacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.readCollection(Match::new));
this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.readCollection(Match::new, MAX_ENTRIES));
}
@Override

View File

@ -23,6 +23,8 @@ import static net.minestom.server.network.NetworkBuffer.*;
* The packet creates or updates teams
*/
public record TeamsPacket(String teamName, Action action) implements ComponentHoldingServerPacket {
public static final int MAX_MEMBERS = 16384;
public TeamsPacket(@NotNull NetworkBuffer reader) {
this(reader.read(STRING), switch (reader.read(BYTE)) {
case 0 -> new CreateTeamAction(reader);
@ -73,7 +75,7 @@ public record TeamsPacket(String teamName, Action action) implements ComponentHo
this(reader.read(COMPONENT), reader.read(BYTE),
NameTagVisibility.fromIdentifier(reader.read(STRING)), CollisionRule.fromIdentifier(reader.read(STRING)),
NamedTextColor.namedColor(reader.read(VAR_INT)), reader.read(COMPONENT), reader.read(COMPONENT),
reader.readCollection(STRING));
reader.readCollection(STRING, MAX_MEMBERS));
}
@Override
@ -178,7 +180,7 @@ public record TeamsPacket(String teamName, Action action) implements ComponentHo
}
public AddEntitiesToTeamAction(@NotNull NetworkBuffer reader) {
this(reader.readCollection(STRING));
this(reader.readCollection(STRING, MAX_MEMBERS));
}
@Override
@ -198,7 +200,7 @@ public record TeamsPacket(String teamName, Action action) implements ComponentHo
}
public RemoveEntitiesToTeamAction(@NotNull NetworkBuffer reader) {
this(reader.readCollection(STRING));
this(reader.readCollection(STRING, MAX_MEMBERS));
}
@Override

View File

@ -15,12 +15,14 @@ import static net.minestom.server.network.NetworkBuffer.*;
public record TradeListPacket(int windowId, @NotNull List<Trade> trades,
int villagerLevel, int experience,
boolean regularVillager, boolean canRestock) implements ServerPacket {
public static final int MAX_TRADES = Short.MAX_VALUE;
public TradeListPacket {
trades = List.copyOf(trades);
}
public TradeListPacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.readCollection(Trade::new),
this(reader.read(VAR_INT), reader.readCollection(Trade::new, MAX_TRADES),
reader.read(VAR_INT), reader.read(VAR_INT),
reader.read(BOOLEAN), reader.read(BOOLEAN));
}

View File

@ -49,8 +49,8 @@ public record UnlockRecipesPacket(int mode,
var blastFurnaceRecipeBookFilterActive = reader.read(BOOLEAN);
var smokerRecipeBookOpen = reader.read(BOOLEAN);
var smokerRecipeBookFilterActive = reader.read(BOOLEAN);
var recipeIds = reader.readCollection(STRING);
var initRecipeIds = mode == 0 ? reader.readCollection(STRING) : null;
var recipeIds = reader.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES);
var initRecipeIds = mode == 0 ? reader.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES) : null;
return new UnlockRecipesPacket(mode,
craftingRecipeBookOpen, craftingRecipeBookFilterActive,
smeltingRecipeBookOpen, smeltingRecipeBookFilterActive,

View File

@ -19,12 +19,14 @@ import static net.minestom.server.network.NetworkBuffer.*;
public record WindowItemsPacket(byte windowId, int stateId, @NotNull List<ItemStack> items,
@NotNull ItemStack carriedItem) implements ComponentHoldingServerPacket {
public static final int MAX_ENTRIES = 128;
public WindowItemsPacket {
items = List.copyOf(items);
}
public WindowItemsPacket(@NotNull NetworkBuffer reader) {
this(reader.read(BYTE), reader.read(VAR_INT), reader.readCollection(ITEM),
this(reader.read(BYTE), reader.read(VAR_INT), reader.readCollection(ITEM, MAX_ENTRIES),
reader.read(ITEM));
}

View File

@ -6,7 +6,8 @@ import org.jetbrains.annotations.NotNull;
import java.util.BitSet;
import java.util.List;
import static net.minestom.server.network.NetworkBuffer.*;
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
import static net.minestom.server.network.NetworkBuffer.LONG_ARRAY;
public record LightData(
@NotNull BitSet skyMask, @NotNull BitSet blockMask,
@ -14,11 +15,13 @@ public record LightData(
@NotNull List<byte[]> skyLight,
@NotNull List<byte[]> blockLight
) implements NetworkBuffer.Writer {
public static final int MAX_SECTIONS = 4096 / 16;
public LightData(@NotNull NetworkBuffer reader) {
this(
BitSet.valueOf(reader.read(LONG_ARRAY)), BitSet.valueOf(reader.read(LONG_ARRAY)),
BitSet.valueOf(reader.read(LONG_ARRAY)), BitSet.valueOf(reader.read(LONG_ARRAY)),
reader.readCollection(BYTE_ARRAY), reader.readCollection(BYTE_ARRAY)
reader.readCollection(BYTE_ARRAY, MAX_SECTIONS), reader.readCollection(BYTE_ARRAY, MAX_SECTIONS)
);
}

View File

@ -13,6 +13,8 @@ import static net.minestom.server.network.NetworkBuffer.STRING;
@ApiStatus.Experimental
public record GameProfile(@NotNull UUID uuid, @NotNull String name,
@NotNull List<@NotNull Property> properties) implements NetworkBuffer.Writer {
public static final int MAX_PROPERTIES = 1024;
public GameProfile {
if (name.isBlank())
throw new IllegalArgumentException("Name cannot be blank");
@ -22,7 +24,7 @@ public record GameProfile(@NotNull UUID uuid, @NotNull String name,
}
public GameProfile(@NotNull NetworkBuffer reader) {
this(reader.read(NetworkBuffer.UUID), reader.read(STRING), reader.readCollection(Property::new));
this(reader.read(NetworkBuffer.UUID), reader.read(STRING), reader.readCollection(Property::new, MAX_PROPERTIES));
}
@Override

View File

@ -8,12 +8,12 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
import org.junit.jupiter.api.Test;
import java.util.UUID;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static net.minestom.server.network.NetworkBuffer.*;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;
public class NetworkBufferTest {
@ -271,6 +271,28 @@ public class NetworkBufferTest {
assertBufferTypeCollection(BOOLEAN, List.of(true), new byte[]{0x01, 0x01});
}
@Test
public void collectionMaxSize() {
var buffer = new NetworkBuffer();
var list = new ArrayList<Boolean>();
for (int i = 0; i < 1000; i++)
list.add(true);
buffer.writeCollection(BOOLEAN, list);
assertThrows(IllegalArgumentException.class, () -> buffer.readCollection(BOOLEAN, 10));
buffer.readIndex(0); // reset
assertThrows(IllegalArgumentException.class, () -> buffer.readCollection(b -> b.read(BOOLEAN), 10));
}
@Test
public void oomStringRegression() {
var buffer = new NetworkBuffer(ByteBuffer.allocate(100));
buffer.write(VAR_INT, Integer.MAX_VALUE); // String length
buffer.write(RAW_BYTES, "Hello".getBytes(StandardCharsets.UTF_8)); // String data
assertThrows(IllegalArgumentException.class, () -> buffer.read(STRING)); // oom
}
static <T> void assertBufferType(NetworkBuffer.@NotNull Type<T> type, @UnknownNullability T value, byte[] expected, @NotNull Action<T> action) {
var buffer = new NetworkBuffer();
action.write(buffer, type, value);
@ -346,7 +368,7 @@ public class NetworkBufferTest {
assertEquals(0, buffer.readIndex());
if (expected != null) assertEquals(expected.length, buffer.writeIndex());
var actual = buffer.readCollection(type);
var actual = buffer.readCollection(type, Integer.MAX_VALUE);
assertEquals(values, actual);
if (expected != null) assertEquals(expected.length, buffer.readIndex());