Skip to content

Commit 5d4c06a

Browse files
committed
suite: apply more crash patches
1 parent ca7e94b commit 5d4c06a

8 files changed

Lines changed: 359 additions & 78 deletions

File tree

harness-suite/crashes/lzma-7z.bin

-441 Bytes
Binary file not shown.
-36 Bytes
Binary file not shown.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
diff --git a/sdk/C/Bra.c b/sdk/C/Bra.c
2+
index b57c9de..d2d5ecf 100644
3+
--- a/sdk/C/Bra.c
4+
+++ b/sdk/C/Bra.c
5+
@@ -66,6 +66,10 @@ SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
6+
Byte *p;
7+
const Byte *lim;
8+
size &= ~(size_t)1;
9+
+ if (size < 4) {
10+
+ return 0;
11+
+ }
12+
+
13+
p = data;
14+
lim = data + size - 4;
15+

harness-suite/projects-clike/lzma/prepare.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ DEBIAN_FRONTEND=noninteractive apt-get install -y autoconf automake libtool make
44
git clone-rev.sh https://github.com/fancycode/lzma-fuzz.git "$PROJECT/repo" d25e63d8f6b8186d04146cb19405bc5ad565412e
55
git -C "$PROJECT/repo" apply ../limit_allocs_more.patch
66
git -C "$PROJECT/repo" apply ../stub-crc-for-fuzzing.patch
7+
git -C "$PROJECT/repo" apply ../fix-armt-short-input-oob.patch

harness-suite/projects-clike/openssl/fuzzer-hashtable-sequence-of-ops.patch

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
diff --git a/fuzz/hashtable.c b/fuzz/hashtable.c
2-
index 9e9519b865..cfc0f80177 100644
2+
index 9e9519b865..51e0a35b24 100644
33
--- a/fuzz/hashtable.c
44
+++ b/fuzz/hashtable.c
5-
@@ -133,11 +133,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len)
5+
@@ -120,7 +120,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len)
6+
uint8_t op_flags;
7+
uint16_t keyval;
8+
int rc;
9+
- int rc_prediction = 1;
10+
+ int rc_prediction;
11+
size_t i;
12+
FUZZER_VALUE *valptr, *lval;
13+
FUZZER_KEY key;
14+
@@ -133,17 +133,16 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len)
615
* 1 byte to detect the operation to perform, 2 bytes
716
* for the lookup key, and 8 bytes of value
817
*/
@@ -15,7 +24,16 @@ index 9e9519b865..cfc0f80177 100644
1524
/*
1625
* parse out our operation flags and key
1726
*/
18-
@@ -323,15 +319,6 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len)
27+
op_flags = buf[0];
28+
memcpy(&keyval, &buf[1], sizeof(uint16_t));
29+
30+
+ /* Reset per-operation expectation state. */
31+
+ rc_prediction = 1;
32+
+
33+
/*
34+
* Initialize our key
35+
*/
36+
@@ -323,15 +322,6 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len)
1937
break;
2038

2139
case OP_FLUSH:
@@ -31,7 +49,7 @@ index 9e9519b865..cfc0f80177 100644
3149
/*
3250
* lock the table
3351
*/
34-
@@ -383,6 +370,10 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len)
52+
@@ -383,6 +373,10 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len)
3553
return -1;
3654
}
3755

harness-suite/projects-rust/jxl-rs/fix-decode-header-sample-limit.patch

Lines changed: 203 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,55 @@ index 0f56728..6f1b4c2 100644
1313
let initialized_decoder = JxlDecoder::<states::Initialized>::new(decoder_options);
1414
let _ = initialized_decoder.process(&mut data);
1515
});
16+
diff --git a/jxl/fuzz/fuzz_targets/decode.rs b/jxl/fuzz/fuzz_targets/decode.rs
17+
index e2966b4..442c79d 100644
18+
--- a/jxl/fuzz/fuzz_targets/decode.rs
19+
+++ b/jxl/fuzz/fuzz_targets/decode.rs
20+
@@ -38,12 +38,24 @@ fn fuzz_decode(mut data: &[u8]) -> Result<(), ()> {
21+
let decoder_with_frame_info = as_complete(decoder_with_image_info.process(&mut data))?;
22+
let frame_header = decoder_with_frame_info.frame_header();
23+
let frame_size = frame_header.size;
24+
+ let frame_pixels = frame_size.0.checked_mul(frame_size.1).ok_or(())?;
25+
+ const MAX_FRAME_PIXELS: usize = 1 << 22;
26+
+ if frame_pixels >= MAX_FRAME_PIXELS {
27+
+ return Err(());
28+
+ }
29+
+
30+
+ let row_samples = frame_size.0.checked_mul(samples_per_pixel).ok_or(())?;
31+
+ let output_samples = row_samples.checked_mul(frame_size.1).ok_or(())?;
32+
+ const MAX_OUTPUT_SAMPLES: usize = 1 << 22;
33+
+ if output_samples >= MAX_OUTPUT_SAMPLES {
34+
+ return Err(());
35+
+ }
36+
37+
let mut outputs =
38+
- vec![Image::<f32>::new((frame_size.0 * samples_per_pixel, frame_size.1)).unwrap()];
39+
+ vec![Image::<f32>::new((row_samples, frame_size.1)).map_err(|_| ())?];
40+
41+
for _ in 0..extra_channels {
42+
- outputs.push(Image::<f32>::new(frame_size).unwrap());
43+
+ outputs.push(Image::<f32>::new(frame_size).map_err(|_| ())?);
44+
}
45+
46+
let mut output_bufs: Vec<JxlOutputBuffer<'_>> = outputs
47+
diff --git a/jxl/src/api/inner/box_parser.rs b/jxl/src/api/inner/box_parser.rs
48+
index 6471b92..c1bab95 100644
49+
--- a/jxl/src/api/inner/box_parser.rs
50+
+++ b/jxl/src/api/inner/box_parser.rs
51+
@@ -360,7 +360,10 @@ impl BoxParser {
52+
if self.ooo_jxlp.buffered.contains_key(&idx) {
53+
return Err(Error::InvalidBox);
54+
}
55+
- if content_len == u64::MAX {
56+
+ const MAX_BUFFERED_OOO_JXLP: u64 = 16 * 1024 * 1024;
57+
+ if content_len == u64::MAX
58+
+ || content_len > MAX_BUFFERED_OOO_JXLP
59+
+ {
60+
return Err(Error::InvalidBox);
61+
}
62+
self.state = ParseState::BufferingOooJxlp {
1663
diff --git a/jxl/src/api/inner/codestream_parser/non_section.rs b/jxl/src/api/inner/codestream_parser/non_section.rs
17-
index cc35fae..732394a 100644
64+
index cc35fae..3e10767 100644
1865
--- a/jxl/src/api/inner/codestream_parser/non_section.rs
1966
+++ b/jxl/src/api/inner/codestream_parser/non_section.rs
2067
@@ -231,12 +231,25 @@ impl CodestreamParser {
@@ -24,13 +71,13 @@ index cc35fae..732394a 100644
2471
+ let (gw, gh) = frame_header.size_groups();
2572
+ let ng = gw.checked_mul(gh).ok_or(Error::SizeOverflow)?;
2673
+ const MAX_GRID_CELLS: usize = 1 << 22;
27-
+ if ng > MAX_GRID_CELLS {
74+
+ if ng >= MAX_GRID_CELLS {
2875
+ return Err(Error::ImageDimensionTooLarge(ng as u64));
2976
+ }
3077
+ if let Some(limit) = decode_options.sample_limit {
31-
+ let (pw, ph) = frame_header.size_padded();
78+
+ let (pw, ph) = frame_header.size_padded_upsampled();
3279
+ check_size_limit(Some(limit), (pw, ph), frame_header.num_extra_channels as usize)?;
33-
+ if ng > limit {
80+
+ if ng >= limit {
3481
+ return Err(Error::ImageDimensionTooLarge(ng as u64));
3582
+ }
3683
+ }
@@ -44,7 +91,58 @@ index cc35fae..732394a 100644
4491
.map(|_| (0..frame_header.passes.num_passes).map(|_| None).collect())
4592
.collect();
4693
self.candidate_hf_sections.clear();
47-
@@ -325,32 +338,36 @@ impl CodestreamParser {
94+
@@ -251,8 +264,28 @@ impl CodestreamParser {
95+
let mut br = BitReader::new(&self.non_section_buf);
96+
br.skip_bits(self.non_section_bit_offset as usize)?;
97+
if self.toc_parser.is_none() {
98+
- let num_toc_entries = self.frame_header.as_ref().unwrap().num_toc_entries();
99+
- self.toc_parser = Some(IncrementalTocReader::new(num_toc_entries as u32, &mut br)?);
100+
+ let fh = self.frame_header.as_ref().unwrap();
101+
+ let (gw, gh) = fh.size_groups();
102+
+ let ng = gw.checked_mul(gh).ok_or(Error::SizeOverflow)?;
103+
+ let (lw, lh) = fh.size_lf_groups();
104+
+ let nl = lw.checked_mul(lh).ok_or(Error::SizeOverflow)?;
105+
+ let np = fh.passes.num_passes as usize;
106+
+ let num_toc_entries = if ng == 1 && np == 1 {
107+
+ 1usize
108+
+ } else {
109+
+ ng.checked_mul(np)
110+
+ .and_then(|x| nl.checked_add(x))
111+
+ .and_then(|x| 2usize.checked_add(x))
112+
+ .ok_or(Error::SizeOverflow)?
113+
+ };
114+
+ const MAX_TOC_ENTRIES_USIZE: usize = 1 << 22;
115+
+ if num_toc_entries > MAX_TOC_ENTRIES_USIZE {
116+
+ return Err(Error::ImageDimensionTooLarge(num_toc_entries as u64));
117+
+ }
118+
+ self.toc_parser = Some(IncrementalTocReader::new(
119+
+ num_toc_entries as u32,
120+
+ &mut br,
121+
+ )?);
122+
}
123+
124+
let toc_parser = self.toc_parser.as_mut().unwrap();
125+
@@ -292,6 +325,19 @@ impl CodestreamParser {
126+
self.toc_parser.take().unwrap().finalize()
127+
};
128+
129+
+ const MAX_TOTAL_SECTION_BYTES: usize = 64 * 1024 * 1024;
130+
+ let max_section_bytes = decode_options
131+
+ .sample_limit
132+
+ .map(|limit| limit.saturating_mul(8))
133+
+ .unwrap_or(MAX_TOTAL_SECTION_BYTES)
134+
+ .min(MAX_TOTAL_SECTION_BYTES);
135+
+ let total_section_bytes = toc.entries.iter().try_fold(0usize, |acc, &entry| {
136+
+ acc.checked_add(entry as usize).ok_or(Error::SizeOverflow)
137+
+ })?;
138+
+ if total_section_bytes > max_section_bytes {
139+
+ return Err(Error::ImageDimensionTooLarge(total_section_bytes as u64));
140+
+ }
141+
+
142+
let mut frame = Frame::from_header_and_toc(
143+
self.frame_header.take().unwrap(),
144+
toc,
145+
@@ -325,32 +358,36 @@ impl CodestreamParser {
48146
self.ready_section_data = 0;
49147

50148
// Move data from the pre-section buffer into the sections.
@@ -118,7 +216,7 @@ index 2870225..cb09e44 100644
118216

119217
pub(super) fn can_read_more(&self) -> bool {
120218
diff --git a/jxl/src/frame/decode.rs b/jxl/src/frame/decode.rs
121-
index 82d091e..51ea9d2 100644
219+
index 82d091e..93dbe79 100644
122220
--- a/jxl/src/frame/decode.rs
123221
+++ b/jxl/src/frame/decode.rs
124222
@@ -156,6 +156,8 @@ impl Frame {
@@ -130,6 +228,24 @@ index 82d091e..51ea9d2 100644
130228
if frame_header.is_visible() {
131229
decoder_state.visible_frame_index += 1;
132230
decoder_state.nonvisible_frame_index = 0;
231+
@@ -211,7 +213,7 @@ impl Frame {
232+
let image_size = &decoder_state.file_header.size;
233+
let image_size = (image_size.xsize() as usize, image_size.ysize() as usize);
234+
let sz = if frame_header.save_before_ct {
235+
- frame_header.size_upsampled()
236+
+ frame_header.size()
237+
} else {
238+
image_size
239+
};
240+
@@ -229,7 +231,7 @@ impl Frame {
241+
let lf_frame_data = if frame_header.lf_level != 0 {
242+
Some(
243+
(0..3)
244+
- .map(|_| Image::new(frame_header.size_upsampled()))
245+
+ .map(|_| Image::new(frame_header.size()))
246+
.collect::<Result<Vec<_>, _>>()?
247+
.try_into()
248+
.unwrap(),
133249
@@ -243,8 +245,8 @@ impl Frame {
134250
Ok(Self {
135251
#[cfg(test)]
@@ -141,11 +257,21 @@ index 82d091e..51ea9d2 100644
141257
header: frame_header,
142258
color_channels,
143259
toc,
260+
@@ -337,7 +339,8 @@ impl Frame {
261+
262+
if self.header.has_splines() {
263+
info!("decoding splines");
264+
- let s = Splines::read(br, self.header.width * self.header.height)?;
265+
+ let spline_area = self.header.size().0.saturating_mul(self.header.size().1);
266+
+ let s = Splines::read(br, u32::try_from(spline_area).unwrap_or(u32::MAX))?;
267+
*self.splines.borrow_mut() = s;
268+
}
269+
144270
diff --git a/jxl/src/frame/group.rs b/jxl/src/frame/group.rs
145-
index 26f0e8f..86eb153 100644
271+
index b7d8021..952eeea 100644
146272
--- a/jxl/src/frame/group.rs
147273
+++ b/jxl/src/frame/group.rs
148-
@@ -223,7 +223,10 @@ fn dequant_and_transform_to_pixels<D: Simd>(
274+
@@ -223,7 +223,10 @@ fn dequant_and_transform_to_pixels<D: SimdDescriptor>(
149275
{
150276
let xs = covered_blocks_x(transform_type) as usize;
151277
let ys = covered_blocks_y(transform_type) as usize;
@@ -157,19 +283,72 @@ index 26f0e8f..86eb153 100644
157283
for (y, lf) in lf.chunks_exact_mut(xs).enumerate().take(ys) {
158284
lf.copy_from_slice(&rect.row(y)[0..xs]);
159285
}
160-
diff --git a/jxl/src/api/inner/box_parser.rs b/jxl/src/api/inner/box_parser.rs
161-
index fce0f7f..020443f 100644
162-
--- a/jxl/src/api/inner/box_parser.rs
163-
+++ b/jxl/src/api/inner/box_parser.rs
164-
@@ -360,7 +360,10 @@ impl BoxParser {
165-
if self.ooo_jxlp.buffered.contains_key(&idx) {
166-
return Err(Error::InvalidBox);
167-
}
168-
- if content_len == u64::MAX {
169-
+ const MAX_BUFFERED_OOO_JXLP: u64 = 16 * 1024 * 1024;
170-
+ if content_len == u64::MAX
171-
+ || content_len > MAX_BUFFERED_OOO_JXLP
172-
+ {
173-
return Err(Error::InvalidBox);
174-
}
175-
self.state = ParseState::BufferingOooJxlp {
286+
diff --git a/jxl/src/headers/permutation.rs b/jxl/src/headers/permutation.rs
287+
index c189c0b..c14e0cd 100644
288+
--- a/jxl/src/headers/permutation.rs
289+
+++ b/jxl/src/headers/permutation.rs
290+
@@ -39,12 +39,17 @@ impl Permutation {
291+
})
292+
}
293+
294+
+ #[inline(never)]
295+
fn decode_inner(
296+
size: u32,
297+
skip: u32,
298+
end: u32,
299+
mut read: impl FnMut(usize) -> Result<u32>,
300+
) -> Result<Self> {
301+
+ const MAX_PERM: u32 = 1 << 22;
302+
+ if size > MAX_PERM {
303+
+ return Err(Error::ImageDimensionTooLarge(size as u64));
304+
+ }
305+
if end > size - skip {
306+
return Err(Error::InvalidPermutationSize { size, skip, end });
307+
}
308+
diff --git a/jxl/src/headers/toc.rs b/jxl/src/headers/toc.rs
309+
index eecbe8e..6d30c5f 100644
310+
--- a/jxl/src/headers/toc.rs
311+
+++ b/jxl/src/headers/toc.rs
312+
@@ -43,6 +43,10 @@ pub struct IncrementalTocReader {
313+
314+
impl IncrementalTocReader {
315+
pub fn new(num_entries: u32, br: &mut BitReader) -> Result<Self> {
316+
+ const MAX_TOC_ENTRIES: u32 = 1 << 22;
317+
+ if num_entries > MAX_TOC_ENTRIES {
318+
+ return Err(Error::ImageDimensionTooLarge(num_entries as u64));
319+
+ }
320+
let permuted = bool::read_unconditional(&(), br, &Empty {})?;
321+
let mut entries = Vec::new();
322+
entries.try_reserve(num_entries as usize)?;
323+
diff --git a/jxl/src/frame/render.rs b/jxl/src/frame/render.rs
324+
index d20d693..edd57df 100644
325+
--- a/jxl/src/frame/render.rs
326+
+++ b/jxl/src/frame/render.rs
327+
@@ -23,7 +23,7 @@ use crate::headers::frame_header::FrameType;
328+
use crate::headers::{Orientation, color_encoding::ColorSpace, extra_channels::ExtraChannel};
329+
use crate::image::Image;
330+
use crate::image::Rect;
331+
-use crate::util::AtomicRefCell;
332+
+use crate::util::{AtomicRefCell, ShiftRightCeil};
333+
use std::sync::Arc;
334+
335+
#[cfg(test)]
336+
@@ -360,6 +360,18 @@ impl Frame {
337+
let num_channels = frame_header.num_extra_channels as usize + 3;
338+
let num_temp_channels = if frame_header.has_noise() { 3 } else { 0 };
339+
let metadata = &decoder_state.file_header.image_metadata;
340+
+ // Match `RenderPipelineBuilder::new_with_chunk_size`: pipeline allocates
341+
+ // O(group_chan_complete.len()) structures; bound before constructing the builder.
342+
+ const MAX_RENDER_PIPELINE_GRID_CELLS: usize = 1 << 22;
343+
+ let downsampling_shift = frame_header.upsampling.ilog2() as usize;
344+
+ let log_group_size = frame_header.log_group_dim() + downsampling_shift;
345+
+ let (uw, uh) = frame_header.size_upsampled();
346+
+ let gw = uw.shrc(log_group_size);
347+
+ let gh = uh.shrc(log_group_size);
348+
+ let grid_cells = gw.checked_mul(gh).ok_or(Error::SizeOverflow)?;
349+
+ if grid_cells >= MAX_RENDER_PIPELINE_GRID_CELLS {
350+
+ return Err(Error::ImageDimensionTooLarge(grid_cells as u64));
351+
+ }
352+
let mut pipeline = RenderPipelineBuilder::<T>::new(
353+
num_channels + num_temp_channels,
354+
frame_header.size_upsampled(),

0 commit comments

Comments
 (0)