mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-30 16:19:03 +01:00
c0d376e242
Since the packet is broadcasted for players, it means that the packet will be sent to multiple players. In this case, modifying the data results in a possible race condition where a CME may occur as the packet will be serialized on many different netty IO threads.
86 lines
4.6 KiB
Diff
86 lines
4.6 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Nassim Jahnke <nassim@njahnke.dev>
|
|
Date: Wed, 1 Dec 2021 12:36:25 +0100
|
|
Subject: [PATCH] Prevent sending oversized item data in equipment and metadata
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java b/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
|
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
|
|
+++ b/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
|
|
@@ -0,0 +0,0 @@ public class EntityDataSerializers {
|
|
public static final EntityDataSerializer<ItemStack> ITEM_STACK = new EntityDataSerializer<ItemStack>() {
|
|
@Override
|
|
public void write(FriendlyByteBuf buf, ItemStack value) {
|
|
- buf.writeItem(value);
|
|
+ buf.writeItem(net.minecraft.world.entity.LivingEntity.sanitizeItemStack(value, true)); // Paper - prevent oversized data
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
@@ -0,0 +0,0 @@ public class ServerEntity {
|
|
ItemStack itemstack = ((LivingEntity) this.entity).getItemBySlot(enumitemslot);
|
|
|
|
if (!itemstack.isEmpty()) {
|
|
- list.add(Pair.of(enumitemslot, itemstack.copy()));
|
|
+ // Paper start - prevent oversized data
|
|
+ final ItemStack sanitized = LivingEntity.sanitizeItemStack(itemstack.copy(), false);
|
|
+ list.add(Pair.of(enumitemslot, sanitized));
|
|
+ // Paper end
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
equipmentChanges.forEach((enumitemslot, itemstack) -> {
|
|
ItemStack itemstack1 = itemstack.copy();
|
|
|
|
- list.add(Pair.of(enumitemslot, itemstack1));
|
|
+ // Paper start - prevent oversized data
|
|
+ ItemStack toSend = sanitizeItemStack(itemstack1, true);
|
|
+ list.add(Pair.of(enumitemslot, toSend));
|
|
+ // Paper end
|
|
switch (enumitemslot.getType()) {
|
|
case HAND:
|
|
this.setLastHandItem(enumitemslot, itemstack1);
|
|
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
((ServerLevel) this.level()).getChunkSource().broadcast(this, new ClientboundSetEquipmentPacket(this.getId(), list));
|
|
}
|
|
|
|
+ // Paper start - prevent oversized data
|
|
+ public static ItemStack sanitizeItemStack(final ItemStack itemStack, final boolean copyItemStack) {
|
|
+ if (itemStack.isEmpty() || !itemStack.hasTag()) {
|
|
+ return itemStack;
|
|
+ }
|
|
+
|
|
+ final ItemStack copy = copyItemStack ? itemStack.copy() : itemStack;
|
|
+ final CompoundTag tag = copy.getTag();
|
|
+ if (copy.is(Items.BUNDLE) && tag.get("Items") instanceof ListTag oldItems && !oldItems.isEmpty()) {
|
|
+ // Bundles change their texture based on their fullness.
|
|
+ org.bukkit.inventory.meta.BundleMeta bundleMeta = (org.bukkit.inventory.meta.BundleMeta) copy.asBukkitMirror().getItemMeta();
|
|
+ int sizeUsed = 0;
|
|
+ for (org.bukkit.inventory.ItemStack item : bundleMeta.getItems()) {
|
|
+ int scale = 64 / item.getMaxStackSize();
|
|
+ sizeUsed += scale * item.getAmount();
|
|
+ }
|
|
+ // Now we add a single fake item that uses the same amount of slots as all other items.
|
|
+ ListTag items = new ListTag();
|
|
+ items.add(new ItemStack(Items.PAPER, sizeUsed).save(new CompoundTag()));
|
|
+ tag.put("Items", items);
|
|
+ }
|
|
+ if (tag.get("BlockEntityTag") instanceof CompoundTag blockEntityTag) {
|
|
+ blockEntityTag.remove("Items");
|
|
+ }
|
|
+ return copy;
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
private ItemStack getLastArmorItem(EquipmentSlot slot) {
|
|
return (ItemStack) this.lastArmorItemStacks.get(slot.getIndex());
|
|
}
|