region: harden handling of ByteArrayTag

previously this would just explode if the wrong length of data was given.
This commit is contained in:
Dylan K. Taylor 2020-10-31 15:37:06 +00:00
parent 058bb3a91a
commit 0cbc5c9a4a
4 changed files with 24 additions and 5 deletions

View File

@ -36,7 +36,10 @@ class Anvil extends RegionWorldProvider{
} }
protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{ protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
return new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkYZX($subChunk->getByteArray("Blocks"), $subChunk->getByteArray("Data"))]); return new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkYZX(
self::readFixedSizeByteArray($subChunk, "Blocks", 4096),
self::readFixedSizeByteArray($subChunk, "Data", 2048)
)]);
//ignore legacy light information //ignore legacy light information
} }

View File

@ -36,7 +36,6 @@ use pocketmine\world\format\io\ChunkUtils;
use pocketmine\world\format\io\exception\CorruptedChunkException; use pocketmine\world\format\io\exception\CorruptedChunkException;
use pocketmine\world\format\io\SubChunkConverter; use pocketmine\world\format\io\SubChunkConverter;
use pocketmine\world\format\SubChunk; use pocketmine\world\format\SubChunk;
use function str_repeat;
use function zlib_decode; use function zlib_decode;
class McRegion extends RegionWorldProvider{ class McRegion extends RegionWorldProvider{
@ -68,8 +67,8 @@ class McRegion extends RegionWorldProvider{
} }
$subChunks = []; $subChunks = [];
$fullIds = ($fullIdsTag = $chunk->getTag("Blocks")) instanceof ByteArrayTag ? $fullIdsTag->getValue() : str_repeat("\x00", 32768); $fullIds = self::readFixedSizeByteArray($chunk, "Blocks", 32768);
$fullData = ($fullDataTag = $chunk->getTag("Data")) instanceof ByteArrayTag ? $fullDataTag->getValue() : str_repeat("\x00", 16384); $fullData = self::readFixedSizeByteArray($chunk, "Data", 16384);
for($y = 0; $y < 8; ++$y){ for($y = 0; $y < 8; ++$y){
$subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkFromLegacyColumn($fullIds, $fullData, $y)]); $subChunks[$y] = new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkFromLegacyColumn($fullIds, $fullData, $y)]);

View File

@ -36,7 +36,10 @@ class PMAnvil extends RegionWorldProvider{
use LegacyAnvilChunkTrait; use LegacyAnvilChunkTrait;
protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{ protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
return new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkXZY($subChunk->getByteArray("Blocks"), $subChunk->getByteArray("Data"))]); return new SubChunk(BlockLegacyIds::AIR << 4, [SubChunkConverter::convertSubChunkXZY(
self::readFixedSizeByteArray($subChunk, "Blocks", 4096),
self::readFixedSizeByteArray($subChunk, "Data", 2048)
)]);
} }
protected static function getRegionFileExtension() : string{ protected static function getRegionFileExtension() : string{

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\world\format\io\region; namespace pocketmine\world\format\io\region;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
@ -41,6 +42,7 @@ use function mkdir;
use function morton2d_encode; use function morton2d_encode;
use function rename; use function rename;
use function scandir; use function scandir;
use function strlen;
use function strrpos; use function strrpos;
use function substr; use function substr;
use function time; use function time;
@ -196,6 +198,18 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
return $result; return $result;
} }
protected static function readFixedSizeByteArray(CompoundTag $chunk, string $tagName, int $length) : string{
$tag = $chunk->getTag($tagName);
if(!($tag instanceof ByteArrayTag)){
throw new CorruptedChunkException("Expected TAG_ByteArray for '$tagName'");
}
$data = $tag->getValue();
if(strlen($data) !== $length){
throw new CorruptedChunkException("Expected '$tagName' payload to have exactly $length bytes, but have " . strlen($data));
}
return $data;
}
/** /**
* @throws CorruptedChunkException * @throws CorruptedChunkException
*/ */