1 /*
2 * Jpeg XL header verification
3 * Copyright (c) 2022 Leo Izen <leo.izen@gmail.com>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "jpegxl_probe.h"
23
24 #define UNCHECKED_BITSTREAM_READER 0
25 #define BITSTREAM_READER_LE
26 #include "libavcodec/get_bits.h"
27
28 enum JpegXLExtraChannelType {
29 FF_JPEGXL_CT_ALPHA = 0,
30 FF_JPEGXL_CT_DEPTH,
31 FF_JPEGXL_CT_SPOT_COLOR,
32 FF_JPEGXL_CT_SELECTION_MASK,
33 FF_JPEGXL_CT_BLACK,
34 FF_JPEGXL_CT_CFA,
35 FF_JPEGXL_CT_THERMAL,
36 FF_JPEGXL_CT_NON_OPTIONAL = 15,
37 FF_JPEGXL_CT_OPTIONAL
38 };
39
40 enum JpegXLColorSpace {
41 FF_JPEGXL_CS_RGB = 0,
42 FF_JPEGXL_CS_GRAY,
43 FF_JPEGXL_CS_XYB,
44 FF_JPEGXL_CS_UNKNOWN
45 };
46
47 enum JpegXLWhitePoint {
48 FF_JPEGXL_WP_D65 = 1,
49 FF_JPEGXL_WP_CUSTOM,
50 FF_JPEGXL_WP_E = 10,
51 FF_JPEGXL_WP_DCI = 11
52 };
53
54 enum JpegXLPrimaries {
55 FF_JPEGXL_PR_SRGB = 1,
56 FF_JPEGXL_PR_CUSTOM,
57 FF_JPEGXL_PR_2100 = 9,
58 FF_JPEGXL_PR_P3 = 11,
59 };
60
61 /* read a U32(c_i + u(u_i)) */
jxl_u32(GetBitContext * gb,uint32_t c0,uint32_t c1,uint32_t c2,uint32_t c3,uint32_t u0,uint32_t u1,uint32_t u2,uint32_t u3)62 static av_always_inline uint32_t jxl_u32(GetBitContext *gb,
63 uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3,
64 uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3)
65 {
66 const uint32_t constants[4] = {c0, c1, c2, c3};
67 const uint32_t ubits [4] = {u0, u1, u2, u3};
68 uint32_t ret, choice = get_bits(gb, 2);
69
70 ret = constants[choice];
71 if (ubits[choice])
72 ret += get_bits_long(gb, ubits[choice]);
73
74 return ret;
75 }
76
jxl_enum(GetBitContext * gb)77 static av_always_inline uint32_t jxl_enum(GetBitContext *gb)
78 {
79 return jxl_u32(gb, 0, 1, 2, 18, 0, 0, 4, 6);
80 }
81
82 /* read a U64() */
jpegxl_u64(GetBitContext * gb)83 static uint64_t jpegxl_u64(GetBitContext *gb)
84 {
85 uint64_t shift = 12, ret;
86
87 switch (get_bits(gb, 2)) {
88 case 0:
89 ret = 0;
90 break;
91 case 1:
92 ret = 1 + get_bits(gb, 4);
93 break;
94 case 2:
95 ret = 17 + get_bits(gb, 8);
96 break;
97 case 3:
98 ret = get_bits(gb, 12);
99 while (get_bits1(gb)) {
100 if (shift < 60) {
101 ret |= (uint64_t)get_bits(gb, 8) << shift;
102 shift += 8;
103 } else {
104 ret |= (uint64_t)get_bits(gb, 4) << shift;
105 break;
106 }
107 }
108 break;
109 }
110
111 return ret;
112 }
113
jpegxl_width_from_ratio(uint32_t height,int ratio)114 static uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio)
115 {
116 uint64_t height64 = height; /* avoid integer overflow */
117 switch (ratio) {
118 case 1:
119 return height;
120 case 2:
121 return (uint32_t)((height64 * 12) / 10);
122 case 3:
123 return (uint32_t)((height64 * 4) / 3);
124 case 4:
125 return (uint32_t)((height64 * 3) / 2);
126 case 5:
127 return (uint32_t)((height64 * 16) / 9);
128 case 6:
129 return (uint32_t)((height64 * 5) / 4);
130 case 7:
131 return (uint32_t)(height64 * 2);
132 default:
133 break;
134 }
135
136 return 0; /* manual width */
137 }
138
139 /**
140 * validate a Jpeg XL Size Header
141 * @return >= 0 upon valid size, < 0 upon invalid size found
142 */
jpegxl_read_size_header(GetBitContext * gb)143 static int jpegxl_read_size_header(GetBitContext *gb)
144 {
145 uint32_t width, height;
146
147 if (get_bits1(gb)) {
148 /* small size header */
149 height = (get_bits(gb, 5) + 1) << 3;
150 width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
151 if (!width)
152 width = (get_bits(gb, 5) + 1) << 3;
153 } else {
154 /* large size header */
155 height = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
156 width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
157 if (!width)
158 width = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
159 }
160 if (width > (1 << 18) || height > (1 << 18)
161 || (width >> 4) * (height >> 4) > (1 << 20))
162 return -1;
163
164 return 0;
165 }
166
167 /**
168 * validate a Jpeg XL Preview Header
169 * @return >= 0 upon valid size, < 0 upon invalid size found
170 */
jpegxl_read_preview_header(GetBitContext * gb)171 static int jpegxl_read_preview_header(GetBitContext *gb)
172 {
173 uint32_t width, height;
174
175 if (get_bits1(gb)) {
176 /* coded height and width divided by eight */
177 height = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3;
178 width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
179 if (!width)
180 width = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3;
181 } else {
182 /* full height and width coded */
183 height = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12);
184 width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
185 if (!width)
186 width = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12);
187 }
188 if (width > 4096 || height > 4096)
189 return -1;
190
191 return 0;
192 }
193
194 /**
195 * skip a Jpeg XL BitDepth Header. These cannot be invalid.
196 */
jpegxl_skip_bit_depth(GetBitContext * gb)197 static void jpegxl_skip_bit_depth(GetBitContext *gb)
198 {
199 if (get_bits1(gb)) {
200 /* float samples */
201 jxl_u32(gb, 32, 16, 24, 1, 0, 0, 0, 6); /* mantissa */
202 skip_bits_long(gb, 4); /* exponent */
203 } else {
204 /* integer samples */
205 jxl_u32(gb, 8, 10, 12, 1, 0, 0, 0, 6);
206 }
207 }
208
209 /**
210 * validate a Jpeg XL Extra Channel Info bundle
211 * @return >= 0 upon valid, < 0 upon invalid
212 */
jpegxl_read_extra_channel_info(GetBitContext * gb)213 static int jpegxl_read_extra_channel_info(GetBitContext *gb)
214 {
215 int all_default = get_bits1(gb);
216 uint32_t type, name_len = 0;
217
218 if (!all_default) {
219 type = jxl_enum(gb);
220 if (type > 63)
221 return -1; /* enum types cannot be 64+ */
222 if (type == FF_JPEGXL_CT_BLACK)
223 return -1;
224 jpegxl_skip_bit_depth(gb);
225 jxl_u32(gb, 0, 3, 4, 1, 0, 0, 0, 3); /* dim-shift */
226 /* max of name_len is 1071 = 48 + 2^10 - 1 */
227 name_len = jxl_u32(gb, 0, 0, 16, 48, 0, 4, 5, 10);
228 } else {
229 type = FF_JPEGXL_CT_ALPHA;
230 }
231
232 /* skip over the name */
233 skip_bits_long(gb, 8 * name_len);
234
235 if (!all_default && type == FF_JPEGXL_CT_ALPHA)
236 skip_bits1(gb);
237
238 if (type == FF_JPEGXL_CT_SPOT_COLOR)
239 skip_bits_long(gb, 16 * 4);
240
241 if (type == FF_JPEGXL_CT_CFA)
242 jxl_u32(gb, 1, 0, 3, 19, 0, 2, 4, 8);
243
244 return 0;
245 }
246
247 /* verify that a codestream header is valid */
ff_jpegxl_verify_codestream_header(const uint8_t * buf,int buflen)248 int ff_jpegxl_verify_codestream_header(const uint8_t *buf, int buflen)
249 {
250 GetBitContext gbi, *gb = &gbi;
251 int all_default, extra_fields = 0;
252 int xyb_encoded = 1, have_icc_profile = 0;
253 uint32_t num_extra_channels;
254 uint64_t extensions;
255 int ret;
256
257 ret = init_get_bits8(gb, buf, buflen);
258 if (ret < 0)
259 return ret;
260
261 if (get_bits_long(gb, 16) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE)
262 return -1;
263
264 if ((ret = jpegxl_read_size_header(gb)) < 0)
265 return ret;
266
267 all_default = get_bits1(gb);
268 if (!all_default)
269 extra_fields = get_bits1(gb);
270
271 if (extra_fields) {
272 skip_bits_long(gb, 3); /* orientation */
273
274 /*
275 * intrinstic size
276 * any size header here is valid, but as it
277 * is variable length we have to read it
278 */
279 if (get_bits1(gb))
280 jpegxl_read_size_header(gb);
281
282 /* preview header */
283 if (get_bits1(gb)) {
284 ret = jpegxl_read_preview_header(gb);
285 if (ret < 0)
286 return ret;
287 }
288
289 /* animation header */
290 if (get_bits1(gb)) {
291 jxl_u32(gb, 100, 1000, 1, 1, 0, 0, 10, 30);
292 jxl_u32(gb, 1, 1001, 1, 1, 0, 0, 8, 10);
293 jxl_u32(gb, 0, 0, 0, 0, 0, 3, 16, 32);
294 skip_bits_long(gb, 1);
295 }
296 }
297 if (get_bits_left(gb) < 1)
298 return AVERROR_INVALIDDATA;
299
300 if (!all_default) {
301 jpegxl_skip_bit_depth(gb);
302
303 /* modular_16bit_buffers must equal 1 */
304 if (!get_bits1(gb))
305 return -1;
306
307 num_extra_channels = jxl_u32(gb, 0, 1, 2, 1, 0, 0, 4, 12);
308 if (num_extra_channels > 4)
309 return -1;
310 for (uint32_t i = 0; i < num_extra_channels; i++) {
311 ret = jpegxl_read_extra_channel_info(gb);
312 if (ret < 0)
313 return ret;
314 if (get_bits_left(gb) < 1)
315 return AVERROR_INVALIDDATA;
316 }
317
318 xyb_encoded = get_bits1(gb);
319
320 /* color encoding bundle */
321 if (!get_bits1(gb)) {
322 uint32_t color_space;
323 have_icc_profile = get_bits1(gb);
324 color_space = jxl_enum(gb);
325 if (color_space > 63)
326 return -1;
327
328 if (!have_icc_profile) {
329 if (color_space != FF_JPEGXL_CS_XYB) {
330 uint32_t white_point = jxl_enum(gb);
331 if (white_point > 63)
332 return -1;
333 if (white_point == FF_JPEGXL_WP_CUSTOM) {
334 /* ux and uy values */
335 jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
336 jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
337 }
338 if (color_space != FF_JPEGXL_CS_GRAY) {
339 /* primaries */
340 uint32_t primaries = jxl_enum(gb);
341 if (primaries > 63)
342 return -1;
343 if (primaries == FF_JPEGXL_PR_CUSTOM) {
344 /* ux/uy values for r,g,b */
345 for (int i = 0; i < 6; i++) {
346 jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
347 if (get_bits_left(gb) < 1)
348 return AVERROR_INVALIDDATA;
349 }
350 }
351 }
352 }
353
354 /* transfer characteristics */
355 if (get_bits1(gb)) {
356 /* gamma */
357 skip_bits_long(gb, 24);
358 } else {
359 /* transfer function */
360 if (jxl_enum(gb) > 63)
361 return -1;
362 }
363
364 /* rendering intent */
365 if (jxl_enum(gb) > 63)
366 return -1;
367 }
368 }
369
370 /* tone mapping bundle */
371 if (extra_fields && !get_bits1(gb))
372 skip_bits_long(gb, 16 + 16 + 1 + 16);
373
374 extensions = jpegxl_u64(gb);
375 if (get_bits_left(gb) < 1)
376 return AVERROR_INVALIDDATA;
377 if (extensions) {
378 for (int i = 0; i < 64; i++) {
379 if (extensions & (UINT64_C(1) << i))
380 jpegxl_u64(gb);
381 if (get_bits_left(gb) < 1)
382 return AVERROR_INVALIDDATA;
383 }
384 }
385 }
386
387 /* default transform */
388 if (!get_bits1(gb)) {
389 /* opsin inverse matrix */
390 if (xyb_encoded && !get_bits1(gb))
391 skip_bits_long(gb, 16 * 16);
392 /* cw_mask and default weights */
393 if (get_bits1(gb))
394 skip_bits_long(gb, 16 * 15);
395 if (get_bits1(gb))
396 skip_bits_long(gb, 16 * 55);
397 if (get_bits1(gb))
398 skip_bits_long(gb, 16 * 210);
399 }
400
401 if (!have_icc_profile) {
402 int bits_remaining = 7 - (get_bits_count(gb) - 1) % 8;
403 if (bits_remaining && get_bits(gb, bits_remaining))
404 return -1;
405 }
406
407 if (get_bits_left(gb) < 0)
408 return -1;
409
410 return 0;
411 }
412