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