authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-12 22:04:07+11:00
committergravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-20 09:09:06+11:00
loga53cf299a6a22422d734d54b6abed4ff8b6473c5
tree5b432d404112e31fe32aca2f830811498c6ef4a3
parent5a31fc2014ed6c1d806d08f1393e10b597ec427d

std.compress.zstandard: add error condition to ring buffer decoding

Previously `executeSequenceRingBuffer()` would not verify the offset against the number of bytes already decoded, so it would happily copy garbage bytes rather than return an error before the window was filled. To fix this a new `written_count` is added to the decode state that tracks the total number of bytes decoded.

1 files changed, 19 insertions(+), 1 deletions(-)

lib/std/compress/zstandard/decode/block.zig+19-1
......@@ -45,6 +45,7 @@ pub const DecodeState = struct {
4545 huffman_tree: ?LiteralsSection.HuffmanTree,
4646
4747 literal_written_count: usize,
48 written_count: usize = 0,
4849
4950 fn StateData(comptime max_accuracy_log: comptime_int) type {
5051 return struct {
......@@ -84,6 +85,8 @@ pub const DecodeState = struct {
8485 .literal_stream_reader = undefined,
8586 .literal_stream_index = undefined,
8687 .huffman_tree = null,
88
89 .written_count = 0,
8790 };
8891 }
8992
......@@ -296,6 +299,7 @@ pub const DecodeState = struct {
296299 // NOTE: we ignore the usage message for std.mem.copy and copy with dest.ptr >= src.ptr
297300 // to allow repeats
298301 std.mem.copy(u8, dest[write_pos + sequence.literal_length ..], dest[copy_start..copy_end]);
302 self.written_count += sequence.match_length;
299303 }
300304
301305 fn executeSequenceRingBuffer(
......@@ -303,7 +307,8 @@ pub const DecodeState = struct {
303307 dest: *RingBuffer,
304308 sequence: Sequence,
305309 ) (error{MalformedSequence} || DecodeLiteralsError)!void {
306 if (sequence.offset > dest.data.len) return error.MalformedSequence;
310 if (sequence.offset > @min(dest.data.len, self.written_count + sequence.literal_length))
311 return error.MalformedSequence;
307312
308313 try self.decodeLiteralsRingBuffer(dest, sequence.literal_length);
309314 const copy_start = dest.write_index + dest.data.len - sequence.offset;
......@@ -311,6 +316,7 @@ pub const DecodeState = struct {
311316 // TODO: would std.mem.copy and figuring out dest slice be better/faster?
312317 for (copy_slice.first) |b| dest.writeAssumeCapacity(b);
313318 for (copy_slice.second) |b| dest.writeAssumeCapacity(b);
319 self.written_count += sequence.match_length;
314320 }
315321
316322 const DecodeSequenceError = error{
......@@ -444,6 +450,7 @@ pub const DecodeState = struct {
444450 const literal_data = self.literal_streams.one[self.literal_written_count..literals_end];
445451 std.mem.copy(u8, dest, literal_data);
446452 self.literal_written_count += len;
453 self.written_count += len;
447454 },
448455 .rle => {
449456 var i: usize = 0;
......@@ -451,6 +458,7 @@ pub const DecodeState = struct {
451458 dest[i] = self.literal_streams.one[0];
452459 }
453460 self.literal_written_count += len;
461 self.written_count += len;
454462 },
455463 .compressed, .treeless => {
456464 // const written_bytes_per_stream = (literals.header.regenerated_size + 3) / 4;
......@@ -497,6 +505,7 @@ pub const DecodeState = struct {
497505 }
498506 }
499507 self.literal_written_count += len;
508 self.written_count += len;
500509 },
501510 }
502511 }
......@@ -516,6 +525,7 @@ pub const DecodeState = struct {
516525 const literal_data = self.literal_streams.one[self.literal_written_count..literals_end];
517526 dest.writeSliceAssumeCapacity(literal_data);
518527 self.literal_written_count += len;
528 self.written_count += len;
519529 },
520530 .rle => {
521531 var i: usize = 0;
......@@ -523,6 +533,7 @@ pub const DecodeState = struct {
523533 dest.writeAssumeCapacity(self.literal_streams.one[0]);
524534 }
525535 self.literal_written_count += len;
536 self.written_count += len;
526537 },
527538 .compressed, .treeless => {
528539 // const written_bytes_per_stream = (literals.header.regenerated_size + 3) / 4;
......@@ -565,6 +576,7 @@ pub const DecodeState = struct {
565576 }
566577 }
567578 self.literal_written_count += len;
579 self.written_count += len;
568580 },
569581 }
570582 }
......@@ -612,6 +624,7 @@ pub fn decodeBlock(
612624 const data = src[0..block_size];
613625 std.mem.copy(u8, dest[written_count..], data);
614626 consumed_count.* += block_size;
627 decode_state.written_count += block_size;
615628 return block_size;
616629 },
617630 .rle => {
......@@ -622,6 +635,7 @@ pub fn decodeBlock(
622635 dest[write_pos] = src[0];
623636 }
624637 consumed_count.* += 1;
638 decode_state.written_count += block_size;
625639 return block_size;
626640 },
627641 .compressed => {
......@@ -712,6 +726,7 @@ pub fn decodeBlockRingBuffer(
712726 const data = src[0..block_size];
713727 dest.writeSliceAssumeCapacity(data);
714728 consumed_count.* += block_size;
729 decode_state.written_count += block_size;
715730 return block_size;
716731 },
717732 .rle => {
......@@ -721,6 +736,7 @@ pub fn decodeBlockRingBuffer(
721736 dest.writeAssumeCapacity(src[0]);
722737 }
723738 consumed_count.* += 1;
739 decode_state.written_count += block_size;
724740 return block_size;
725741 },
726742 .compressed => {
......@@ -814,6 +830,7 @@ pub fn decodeBlockReader(
814830 try source.readNoEof(slice.first);
815831 try source.readNoEof(slice.second);
816832 dest.write_index = dest.mask2(dest.write_index + block_size);
833 decode_state.written_count += block_size;
817834 },
818835 .rle => {
819836 const byte = try source.readByte();
......@@ -821,6 +838,7 @@ pub fn decodeBlockReader(
821838 while (i < block_size) : (i += 1) {
822839 dest.writeAssumeCapacity(byte);
823840 }
841 decode_state.written_count += block_size;
824842 },
825843 .compressed => {
826844 const literals = try decodeLiteralsSection(block_reader, literals_buffer);