/src/libexif/libexif/canon/exif-mnote-data-canon.c
Line | Count | Source |
1 | | /* exif-mnote-data-canon.c |
2 | | * |
3 | | * Copyright (c) 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> |
4 | | * Copyright (c) 2003 Matthieu Castet <mat-c@users.sourceforge.net> |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the |
18 | | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | | * Boston, MA 02110-1301 USA. |
20 | | * |
21 | | * SPDX-License-Identifier: LGPL-2.0-or-later |
22 | | */ |
23 | | |
24 | | #include <config.h> |
25 | | #include "exif-mnote-data-canon.h" |
26 | | |
27 | | #include <stdlib.h> |
28 | | #include <stdio.h> |
29 | | #include <string.h> |
30 | | |
31 | | #include <libexif/exif-byte-order.h> |
32 | | #include <libexif/exif-utils.h> |
33 | | #include <libexif/exif-data.h> |
34 | | |
35 | 169k | #define CHECKOVERFLOW(offset,datasize,structsize) (( (offset) >= (datasize)) || ((structsize) > (datasize)) || ((offset) > (datasize) - (structsize) )) |
36 | | |
37 | | /* Total size limit to prevent abuse by DoS */ |
38 | 25.2k | #define FAILSAFE_SIZE_MAX 1000000L |
39 | | |
40 | | static void |
41 | | exif_mnote_data_canon_clear (ExifMnoteDataCanon *n) |
42 | 4.14k | { |
43 | 4.14k | ExifMnoteData *d = (ExifMnoteData *) n; |
44 | 4.14k | unsigned int i; |
45 | | |
46 | 4.14k | if (!n) return; |
47 | | |
48 | 4.14k | if (n->entries) { |
49 | 27.3k | for (i = 0; i < n->count; i++) |
50 | 25.2k | if (n->entries[i].data) { |
51 | 25.2k | exif_mem_free (d->mem, n->entries[i].data); |
52 | 25.2k | n->entries[i].data = NULL; |
53 | 25.2k | } |
54 | 2.05k | exif_mem_free (d->mem, n->entries); |
55 | 2.05k | n->entries = NULL; |
56 | 2.05k | n->count = 0; |
57 | 2.05k | } |
58 | 4.14k | } |
59 | | |
60 | | static void |
61 | | exif_mnote_data_canon_free (ExifMnoteData *n) |
62 | 2.09k | { |
63 | 2.09k | if (!n) return; |
64 | | |
65 | 2.09k | exif_mnote_data_canon_clear ((ExifMnoteDataCanon *) n); |
66 | 2.09k | } |
67 | | |
68 | | static void |
69 | | exif_mnote_data_canon_get_tags (ExifMnoteDataCanon *dc, unsigned int n, |
70 | | unsigned int *m, unsigned int *s) |
71 | 21.3M | { |
72 | 21.3M | unsigned int from = 0, to; |
73 | | |
74 | 21.3M | if (!dc || !m) return; |
75 | 506M | for (*m = 0; *m < dc->count; (*m)++) { |
76 | 506M | to = from + mnote_canon_entry_count_values (&dc->entries[*m]); |
77 | 506M | if (to > n) { |
78 | 21.3M | if (s) *s = n - from; |
79 | 21.3M | break; |
80 | 21.3M | } |
81 | 485M | from = to; |
82 | 485M | } |
83 | 21.3M | } |
84 | | |
85 | | static char * |
86 | | exif_mnote_data_canon_get_value (ExifMnoteData *note, unsigned int n, char *val, unsigned int maxlen) |
87 | 14.9M | { |
88 | 14.9M | ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; |
89 | 14.9M | unsigned int m, s; |
90 | | |
91 | 14.9M | if (!dc) return NULL; |
92 | 14.9M | exif_mnote_data_canon_get_tags (dc, n, &m, &s); |
93 | 14.9M | if (m >= dc->count) return NULL; |
94 | 14.9M | return mnote_canon_entry_get_value (&dc->entries[m], s, val, maxlen); |
95 | 14.9M | } |
96 | | |
97 | | static void |
98 | | exif_mnote_data_canon_set_byte_order (ExifMnoteData *d, ExifByteOrder o) |
99 | 2.09k | { |
100 | 2.09k | ExifByteOrder o_orig; |
101 | 2.09k | ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) d; |
102 | 2.09k | unsigned int i; |
103 | | |
104 | 2.09k | if (!n) return; |
105 | | |
106 | 2.09k | o_orig = n->order; |
107 | 2.09k | n->order = o; |
108 | 2.09k | for (i = 0; i < n->count; i++) { |
109 | 0 | if (n->entries[i].components && (n->entries[i].size/n->entries[i].components < exif_format_get_size (n->entries[i].format))) |
110 | 0 | continue; |
111 | 0 | n->entries[i].order = o; |
112 | 0 | exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, |
113 | 0 | n->entries[i].components, o_orig, o); |
114 | 0 | } |
115 | 2.09k | } |
116 | | |
117 | | static void |
118 | | exif_mnote_data_canon_set_offset (ExifMnoteData *n, unsigned int o) |
119 | 3.26k | { |
120 | 3.26k | if (n) ((ExifMnoteDataCanon *) n)->offset = o; |
121 | 3.26k | } |
122 | | |
123 | | static void |
124 | | exif_mnote_data_canon_save (ExifMnoteData *ne, |
125 | | unsigned char **buf, unsigned int *buf_size) |
126 | 1.16k | { |
127 | 1.16k | ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; |
128 | 1.16k | size_t i, o, s, doff; |
129 | 1.16k | unsigned char *t; |
130 | 1.16k | size_t ts; |
131 | | |
132 | 1.16k | if (!n || !buf || !buf_size) return; |
133 | | |
134 | | /* |
135 | | * Allocate enough memory for all entries and the number |
136 | | * of entries. |
137 | | */ |
138 | 1.16k | *buf_size = 2 + n->count * 12 + 4; |
139 | 1.16k | *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size); |
140 | 1.16k | if (!*buf) { |
141 | 0 | EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", *buf_size); |
142 | 0 | return; |
143 | 0 | } |
144 | | |
145 | | /* Save the number of entries */ |
146 | 1.16k | exif_set_short (*buf, n->order, (ExifShort) n->count); |
147 | | |
148 | | /* Save each entry */ |
149 | 15.7k | for (i = 0; i < n->count; i++) { |
150 | 14.5k | o = 2 + i * 12; |
151 | 14.5k | exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); |
152 | 14.5k | exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); |
153 | 14.5k | exif_set_long (*buf + o + 4, n->order, |
154 | 14.5k | n->entries[i].components); |
155 | 14.5k | o += 8; |
156 | 14.5k | s = exif_format_get_size (n->entries[i].format) * |
157 | 14.5k | n->entries[i].components; |
158 | 14.5k | if (s > 65536) { |
159 | | /* Corrupt data: EXIF data size is limited to the |
160 | | * maximum size of a JPEG segment (64 kb). |
161 | | */ |
162 | 736 | continue; |
163 | 736 | } |
164 | 13.7k | if (s > 4) { |
165 | 10.5k | ts = *buf_size + s; |
166 | | |
167 | | /* Ensure even offsets. Set padding bytes to 0. */ |
168 | 10.5k | if (s & 1) ts += 1; |
169 | 10.5k | t = exif_mem_realloc (ne->mem, *buf, |
170 | 10.5k | sizeof (char) * ts); |
171 | 10.5k | if (!t) { |
172 | 0 | EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", ts); |
173 | 0 | return; |
174 | 0 | } |
175 | 10.5k | *buf = t; |
176 | 10.5k | *buf_size = ts; |
177 | 10.5k | doff = *buf_size - s; |
178 | 10.5k | if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } |
179 | 10.5k | exif_set_long (*buf + o, n->order, n->offset + doff); |
180 | 10.5k | } else |
181 | 3.26k | doff = o; |
182 | | |
183 | | /* |
184 | | * Write the data. Fill unneeded bytes with 0. Do not |
185 | | * crash if data is NULL. |
186 | | */ |
187 | 13.7k | if (!n->entries[i].data) memset (*buf + doff, 0, s); |
188 | 13.7k | else memcpy (*buf + doff, n->entries[i].data, s); |
189 | 13.7k | if (s < 4) memset (*buf + doff + s, 0, (4 - s)); |
190 | 13.7k | } |
191 | 1.16k | } |
192 | | |
193 | | /* XXX |
194 | | * FIXME: exif_mnote_data_canon_load() may fail and there is no |
195 | | * semantics to express that. |
196 | | * See bug #1054323 for details, especially the comment by liblit |
197 | | * after it has supposedly been fixed: |
198 | | * |
199 | | * https://sourceforge.net/tracker/?func=detail&aid=1054323&group_id=12272&atid=112272 |
200 | | * Unfortunately, the "return" statements aren't commented at |
201 | | * all, so it isn't trivial to find out what is a normal |
202 | | * return, and what is a reaction to an error condition. |
203 | | */ |
204 | | |
205 | | static void |
206 | | exif_mnote_data_canon_load (ExifMnoteData *ne, |
207 | | const unsigned char *buf, unsigned int buf_size) |
208 | 2.09k | { |
209 | 2.09k | ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; |
210 | 2.09k | ExifShort c; |
211 | 2.09k | size_t i, tcount, o, datao; |
212 | 2.09k | long failsafe_size = 0; |
213 | | |
214 | 2.09k | if (!n) return; |
215 | | |
216 | 2.09k | if (!buf || !buf_size) { |
217 | 0 | exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, |
218 | 0 | "ExifMnoteCanon", "Short MakerNote"); |
219 | 0 | return; |
220 | 0 | } |
221 | 2.09k | if (CHECKOVERFLOW(n->offset, buf_size, 8)) { |
222 | 0 | exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, |
223 | 0 | "ExifMnoteCanon", "Short MakerNote"); |
224 | 0 | return; |
225 | 0 | } |
226 | 2.09k | datao = 6 + n->offset; |
227 | | |
228 | | /* Read the number of tags */ |
229 | 2.09k | c = exif_get_short (buf + datao, n->order); |
230 | 2.09k | datao += 2; |
231 | | /* Just use an arbitrary max tag limit here to avoid needing to much memory or time. There are 24 named tags currently. |
232 | | * current 2020 camera EOS M6 Mark 2 had 156 entries. |
233 | | * The format allows specifying the same range of memory as often as it can, so this multiplies quickly. */ |
234 | 2.09k | if (c > 250) { |
235 | 35 | exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteCanon", "Too much tags (%d) in Canon MakerNote", c); |
236 | 35 | return; |
237 | 35 | } |
238 | | |
239 | | /* Remove any old entries */ |
240 | 2.05k | exif_mnote_data_canon_clear (n); |
241 | | |
242 | | /* Reserve enough space for all the possible MakerNote tags */ |
243 | 2.05k | n->entries = exif_mem_alloc (ne->mem, sizeof (MnoteCanonEntry) * c); |
244 | 2.05k | if (!n->entries) { |
245 | 0 | EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", sizeof (MnoteCanonEntry) * c); |
246 | 0 | return; |
247 | 0 | } |
248 | | |
249 | | /* Parse the entries */ |
250 | 2.05k | tcount = 0; |
251 | 139k | for (i = c, o = datao; i; --i, o += 12) { |
252 | 138k | size_t s; |
253 | | |
254 | 138k | memset(&n->entries[tcount], 0, sizeof(MnoteCanonEntry)); |
255 | 138k | if (CHECKOVERFLOW(o,buf_size,12)) { |
256 | 1.59k | exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, |
257 | 1.59k | "ExifMnoteCanon", "Short MakerNote"); |
258 | 1.59k | break; |
259 | 1.59k | } |
260 | | |
261 | 137k | n->entries[tcount].tag = exif_get_short (buf + o, n->order); |
262 | 137k | n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); |
263 | 137k | n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); |
264 | 137k | n->entries[tcount].order = n->order; |
265 | | |
266 | 137k | exif_log (ne->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteCanon", |
267 | 137k | "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, |
268 | 137k | mnote_canon_tag_get_name (n->entries[tcount].tag)); |
269 | | |
270 | | /* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection, |
271 | | * we will check the buffer sizes closer later. */ |
272 | 137k | if ( exif_format_get_size (n->entries[tcount].format) && |
273 | 40.1k | buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components |
274 | 137k | ) { |
275 | 10.0k | exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, |
276 | 10.0k | "ExifMnoteCanon", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components); |
277 | 10.0k | continue; |
278 | 10.0k | } |
279 | | |
280 | | /* |
281 | | * Size? If bigger than 4 bytes, the actual data is not |
282 | | * in the entry but somewhere else (offset). |
283 | | */ |
284 | 127k | s = exif_format_get_size (n->entries[tcount].format) * |
285 | 127k | n->entries[tcount].components; |
286 | 127k | n->entries[tcount].size = s; |
287 | 127k | if (!s) { |
288 | 98.5k | exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, |
289 | 98.5k | "ExifMnoteCanon", |
290 | 98.5k | "Invalid zero-length tag size"); |
291 | 98.5k | continue; |
292 | | |
293 | 98.5k | } else { |
294 | 28.7k | size_t dataofs = o + 8; |
295 | 28.7k | if (s > 4) dataofs = exif_get_long (buf + dataofs, n->order) + 6; |
296 | | |
297 | 28.7k | if (CHECKOVERFLOW(dataofs, buf_size, s)) { |
298 | 3.53k | exif_log (ne->log, EXIF_LOG_CODE_DEBUG, |
299 | 3.53k | "ExifMnoteCanon", |
300 | 3.53k | "Tag data past end of buffer (%u > %u)", |
301 | 3.53k | (unsigned)(dataofs + s), buf_size); |
302 | 3.53k | continue; |
303 | 3.53k | } |
304 | | |
305 | 25.2k | n->entries[tcount].data = exif_mem_alloc (ne->mem, s); |
306 | 25.2k | if (!n->entries[tcount].data) { |
307 | 0 | EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", s); |
308 | 0 | continue; |
309 | 0 | } |
310 | 25.2k | memcpy (n->entries[tcount].data, buf + dataofs, s); |
311 | 25.2k | } |
312 | | |
313 | | /* Track the size of decoded tag data. A malicious file could |
314 | | * be crafted to cause extremely large values here without |
315 | | * tripping any buffer range checks. This is especially bad |
316 | | * with the libexif representation of Canon MakerNotes because |
317 | | * some arrays are turned into individual tags that the |
318 | | * application must loop around. */ |
319 | 25.2k | failsafe_size += mnote_canon_entry_count_values(&n->entries[tcount]); |
320 | | |
321 | 25.2k | if (failsafe_size > FAILSAFE_SIZE_MAX) { |
322 | | /* Abort if the total size of the data in the tags extraordinarily large, */ |
323 | 15 | exif_mem_free (ne->mem, n->entries[tcount].data); |
324 | 15 | exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, |
325 | 15 | "ExifMnoteCanon", "Failsafe tag size overflow (%lu > %ld)", |
326 | 15 | failsafe_size, FAILSAFE_SIZE_MAX); |
327 | 15 | break; |
328 | 15 | } |
329 | | |
330 | | /* Tag was successfully parsed */ |
331 | 25.2k | ++tcount; |
332 | 25.2k | } |
333 | | /* Store the count of successfully parsed tags */ |
334 | 2.05k | n->count = tcount; |
335 | 2.05k | } |
336 | | |
337 | | static unsigned int |
338 | | exif_mnote_data_canon_count (ExifMnoteData *n) |
339 | 2.09k | { |
340 | 2.09k | ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) n; |
341 | 2.09k | unsigned int i, c; |
342 | | |
343 | 27.3k | for (i = c = 0; dc && (i < dc->count); i++) |
344 | 25.2k | c += mnote_canon_entry_count_values (&dc->entries[i]); |
345 | 2.09k | return c; |
346 | 2.09k | } |
347 | | |
348 | | static unsigned int |
349 | | exif_mnote_data_canon_get_id (ExifMnoteData *d, unsigned int i) |
350 | 0 | { |
351 | 0 | ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) d; |
352 | 0 | unsigned int m; |
353 | |
|
354 | 0 | if (!dc) return 0; |
355 | 0 | exif_mnote_data_canon_get_tags (dc, i, &m, NULL); |
356 | 0 | if (m >= dc->count) return 0; |
357 | 0 | return dc->entries[m].tag; |
358 | 0 | } |
359 | | |
360 | | static const char * |
361 | | exif_mnote_data_canon_get_name (ExifMnoteData *note, unsigned int i) |
362 | 2.12M | { |
363 | 2.12M | ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; |
364 | 2.12M | unsigned int m, s; |
365 | | |
366 | 2.12M | if (!dc) return NULL; |
367 | 2.12M | exif_mnote_data_canon_get_tags (dc, i, &m, &s); |
368 | 2.12M | if (m >= dc->count) return NULL; |
369 | 2.12M | return mnote_canon_tag_get_name_sub (dc->entries[m].tag, s, dc->options); |
370 | 2.12M | } |
371 | | |
372 | | static const char * |
373 | | exif_mnote_data_canon_get_title (ExifMnoteData *note, unsigned int i) |
374 | 2.12M | { |
375 | 2.12M | ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; |
376 | 2.12M | unsigned int m, s; |
377 | | |
378 | 2.12M | if (!dc) return NULL; |
379 | 2.12M | exif_mnote_data_canon_get_tags (dc, i, &m, &s); |
380 | 2.12M | if (m >= dc->count) return NULL; |
381 | 2.12M | return mnote_canon_tag_get_title_sub (dc->entries[m].tag, s, dc->options); |
382 | 2.12M | } |
383 | | |
384 | | static const char * |
385 | | exif_mnote_data_canon_get_description (ExifMnoteData *note, unsigned int i) |
386 | 2.12M | { |
387 | 2.12M | ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; |
388 | 2.12M | unsigned int m; |
389 | | |
390 | 2.12M | if (!dc) return NULL; |
391 | 2.12M | exif_mnote_data_canon_get_tags (dc, i, &m, NULL); |
392 | 2.12M | if (m >= dc->count) return NULL; |
393 | 2.12M | return mnote_canon_tag_get_description (dc->entries[m].tag); |
394 | 2.12M | } |
395 | | |
396 | | int |
397 | | exif_mnote_data_canon_identify (const ExifData *ed, const ExifEntry *e) |
398 | 6.89k | { |
399 | 6.89k | char value[8]; |
400 | | |
401 | 6.89k | ExifEntry *em = exif_data_get_entry (ed, EXIF_TAG_MAKE); |
402 | 6.89k | if (!em) |
403 | 4.44k | return 0; |
404 | | |
405 | 2.44k | (void) e; /* unused */ |
406 | 2.44k | return !strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon"); |
407 | 6.89k | } |
408 | | |
409 | | ExifMnoteData * |
410 | | exif_mnote_data_canon_new (ExifMem *mem, ExifDataOption o) |
411 | 2.09k | { |
412 | 2.09k | ExifMnoteData *d; |
413 | 2.09k | ExifMnoteDataCanon *dc; |
414 | | |
415 | 2.09k | if (!mem) return NULL; |
416 | | |
417 | 2.09k | d = exif_mem_alloc (mem, sizeof (ExifMnoteDataCanon)); |
418 | 2.09k | if (!d) |
419 | 0 | return NULL; |
420 | | |
421 | 2.09k | exif_mnote_data_construct (d, mem); |
422 | | |
423 | | /* Set up function pointers */ |
424 | 2.09k | d->methods.free = exif_mnote_data_canon_free; |
425 | 2.09k | d->methods.set_byte_order = exif_mnote_data_canon_set_byte_order; |
426 | 2.09k | d->methods.set_offset = exif_mnote_data_canon_set_offset; |
427 | 2.09k | d->methods.load = exif_mnote_data_canon_load; |
428 | 2.09k | d->methods.save = exif_mnote_data_canon_save; |
429 | 2.09k | d->methods.count = exif_mnote_data_canon_count; |
430 | 2.09k | d->methods.get_id = exif_mnote_data_canon_get_id; |
431 | 2.09k | d->methods.get_name = exif_mnote_data_canon_get_name; |
432 | 2.09k | d->methods.get_title = exif_mnote_data_canon_get_title; |
433 | 2.09k | d->methods.get_description = exif_mnote_data_canon_get_description; |
434 | 2.09k | d->methods.get_value = exif_mnote_data_canon_get_value; |
435 | | |
436 | 2.09k | dc = (ExifMnoteDataCanon*)d; |
437 | 2.09k | dc->options = o; |
438 | 2.09k | return d; |
439 | 2.09k | } |