authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-06 13:20:23+11:00
committergravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-02-20 09:09:06+11:00
log2134769436f68547a5c1d93184a10fab03085b2a
treef88079ee4832454362cd4b4c43890f24119495ac
parent98bbd959b08db4d66a9ae68ce3fe4196594c6d9e

std.compress.zstandard: validate skippable frame size


1 files changed, 30 insertions(+), 14 deletions(-)

lib/std/compress/zstandard/decompress.zig+30-14
...@@ -107,19 +107,27 @@ pub fn decodeAlloc(...@@ -107,19 +107,27 @@ pub fn decodeAlloc(
107/// - `error.UnusedBitSet` if the unused bit of the frame header is set107/// - `error.UnusedBitSet` if the unused bit of the frame header is set
108/// - `error.EndOfStream` if `src` does not contain a complete frame108/// - `error.EndOfStream` if `src` does not contain a complete frame
109/// - an error in `block.Error` if there are errors decoding a block109/// - an error in `block.Error` if there are errors decoding a block
110/// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a
111/// size greater than `src.len`
110pub fn decodeFrame(112pub fn decodeFrame(
111 dest: []u8,113 dest: []u8,
112 src: []const u8,114 src: []const u8,
113 verify_checksum: bool,115 verify_checksum: bool,
114) !ReadWriteCount {116) !ReadWriteCount {
115 var fbs = std.io.fixedBufferStream(src);117 var fbs = std.io.fixedBufferStream(src);
116 return switch (try decodeFrameType(fbs.reader())) {118 switch (try decodeFrameType(fbs.reader())) {
117 .zstandard => decodeZstandardFrame(dest, src, verify_checksum),119 .zstandard => return decodeZstandardFrame(dest, src, verify_checksum),
118 .skippable => ReadWriteCount{120 .skippable => {
119 .read_count = try fbs.reader().readIntLittle(u32) + 8,121 const content_size = try fbs.reader().readIntLittle(u32);
120 .write_count = 0,122 if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge;
123 const read_count = @as(usize, content_size) + 8;
124 if (read_count > src.len) return error.SkippableSizeTooLarge;
125 return ReadWriteCount{
126 .read_count = read_count,
127 .write_count = 0,
128 };
121 },129 },
122 };130 }
123}131}
124132
125pub const DecodeResult = struct {133pub const DecodeResult = struct {
...@@ -150,6 +158,8 @@ pub const DecodedFrame = union(enum) {...@@ -150,6 +158,8 @@ pub const DecodedFrame = union(enum) {
150/// - `error.EndOfStream` if `src` does not contain a complete frame158/// - `error.EndOfStream` if `src` does not contain a complete frame
151/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory159/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
152/// - an error in `block.Error` if there are errors decoding a block160/// - an error in `block.Error` if there are errors decoding a block
161/// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a
162/// size greater than `src.len`
153pub fn decodeFrameAlloc(163pub fn decodeFrameAlloc(
154 allocator: Allocator,164 allocator: Allocator,
155 src: []const u8,165 src: []const u8,
...@@ -159,17 +169,23 @@ pub fn decodeFrameAlloc(...@@ -159,17 +169,23 @@ pub fn decodeFrameAlloc(
159 var fbs = std.io.fixedBufferStream(src);169 var fbs = std.io.fixedBufferStream(src);
160 const reader = fbs.reader();170 const reader = fbs.reader();
161 const magic = try reader.readIntLittle(u32);171 const magic = try reader.readIntLittle(u32);
162 return switch (try frameType(magic)) {172 switch (try frameType(magic)) {
163 .zstandard => .{173 .zstandard => return .{
164 .zstandard = try decodeZstandardFrameAlloc(allocator, src, verify_checksum, window_size_max),174 .zstandard = try decodeZstandardFrameAlloc(allocator, src, verify_checksum, window_size_max),
165 },175 },
166 .skippable => .{176 .skippable => {
167 .skippable = .{177 const content_size = try fbs.reader().readIntLittle(u32);
168 .magic_number = magic,178 if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge;
169 .frame_size = try reader.readIntLittle(u32),179 const read_count = @as(usize, content_size) + 8;
170 },180 if (read_count > src.len) return error.SkippableSizeTooLarge;
181 return .{
182 .skippable = .{
183 .magic_number = magic,
184 .frame_size = content_size,
185 },
186 };
171 },187 },
172 };188 }
173}189}
174190
175/// Returns the frame checksum corresponding to the data fed into `hasher`191/// Returns the frame checksum corresponding to the data fed into `hasher`