• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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