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 #define CHECKOVERFLOW(offset,datasize,structsize) (( (offset) >= (datasize)) || ((structsize) > (datasize)) || ((offset) > (datasize) - (structsize) ))
36
37 /* Total size limit to prevent abuse by DoS */
38 #define FAILSAFE_SIZE_MAX 1000000L
39
40 static void
exif_mnote_data_canon_clear(ExifMnoteDataCanon * n)41 exif_mnote_data_canon_clear (ExifMnoteDataCanon *n)
42 {
43 ExifMnoteData *d = (ExifMnoteData *) n;
44 unsigned int i;
45
46 if (!n) return;
47
48 if (n->entries) {
49 for (i = 0; i < n->count; i++)
50 if (n->entries[i].data) {
51 exif_mem_free (d->mem, n->entries[i].data);
52 n->entries[i].data = NULL;
53 }
54 exif_mem_free (d->mem, n->entries);
55 n->entries = NULL;
56 n->count = 0;
57 }
58 }
59
60 static void
exif_mnote_data_canon_free(ExifMnoteData * n)61 exif_mnote_data_canon_free (ExifMnoteData *n)
62 {
63 if (!n) return;
64
65 exif_mnote_data_canon_clear ((ExifMnoteDataCanon *) n);
66 }
67
68 static void
exif_mnote_data_canon_get_tags(ExifMnoteDataCanon * dc,unsigned int n,unsigned int * m,unsigned int * s)69 exif_mnote_data_canon_get_tags (ExifMnoteDataCanon *dc, unsigned int n,
70 unsigned int *m, unsigned int *s)
71 {
72 unsigned int from = 0, to;
73
74 if (!dc || !m) return;
75 for (*m = 0; *m < dc->count; (*m)++) {
76 to = from + mnote_canon_entry_count_values (&dc->entries[*m]);
77 if (to > n) {
78 if (s) *s = n - from;
79 break;
80 }
81 from = to;
82 }
83 }
84
85 static char *
exif_mnote_data_canon_get_value(ExifMnoteData * note,unsigned int n,char * val,unsigned int maxlen)86 exif_mnote_data_canon_get_value (ExifMnoteData *note, unsigned int n, char *val, unsigned int maxlen)
87 {
88 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note;
89 unsigned int m, s;
90
91 if (!dc) return NULL;
92 exif_mnote_data_canon_get_tags (dc, n, &m, &s);
93 if (m >= dc->count) return NULL;
94 return mnote_canon_entry_get_value (&dc->entries[m], s, val, maxlen);
95 }
96
97 static void
exif_mnote_data_canon_set_byte_order(ExifMnoteData * d,ExifByteOrder o)98 exif_mnote_data_canon_set_byte_order (ExifMnoteData *d, ExifByteOrder o)
99 {
100 ExifByteOrder o_orig;
101 ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) d;
102 unsigned int i;
103
104 if (!n) return;
105
106 o_orig = n->order;
107 n->order = o;
108 for (i = 0; i < n->count; i++) {
109 if (n->entries[i].components && (n->entries[i].size/n->entries[i].components < exif_format_get_size (n->entries[i].format)))
110 continue;
111 n->entries[i].order = o;
112 exif_array_set_byte_order (n->entries[i].format, n->entries[i].data,
113 n->entries[i].components, o_orig, o);
114 }
115 }
116
117 static void
exif_mnote_data_canon_set_offset(ExifMnoteData * n,unsigned int o)118 exif_mnote_data_canon_set_offset (ExifMnoteData *n, unsigned int o)
119 {
120 if (n) ((ExifMnoteDataCanon *) n)->offset = o;
121 }
122
123 static void
exif_mnote_data_canon_save(ExifMnoteData * ne,unsigned char ** buf,unsigned int * buf_size)124 exif_mnote_data_canon_save (ExifMnoteData *ne,
125 unsigned char **buf, unsigned int *buf_size)
126 {
127 ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne;
128 size_t i, o, s, doff;
129 unsigned char *t;
130 size_t ts;
131
132 if (!n || !buf || !buf_size) return;
133
134 /*
135 * Allocate enough memory for all entries and the number
136 * of entries.
137 */
138 *buf_size = 2 + n->count * 12 + 4;
139 *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size);
140 if (!*buf) {
141 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", *buf_size);
142 return;
143 }
144
145 /* Save the number of entries */
146 exif_set_short (*buf, n->order, (ExifShort) n->count);
147
148 /* Save each entry */
149 for (i = 0; i < n->count; i++) {
150 o = 2 + i * 12;
151 exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag);
152 exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format);
153 exif_set_long (*buf + o + 4, n->order,
154 n->entries[i].components);
155 o += 8;
156 s = exif_format_get_size (n->entries[i].format) *
157 n->entries[i].components;
158 if (s > 65536) {
159 /* Corrupt data: EXIF data size is limited to the
160 * maximum size of a JPEG segment (64 kb).
161 */
162 continue;
163 }
164 if (s > 4) {
165 ts = *buf_size + s;
166
167 /* Ensure even offsets. Set padding bytes to 0. */
168 if (s & 1) ts += 1;
169 t = exif_mem_realloc (ne->mem, *buf,
170 sizeof (char) * ts);
171 if (!t) {
172 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", ts);
173 return;
174 }
175 *buf = t;
176 *buf_size = ts;
177 doff = *buf_size - s;
178 if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; }
179 exif_set_long (*buf + o, n->order, n->offset + doff);
180 } else
181 doff = o;
182
183 /*
184 * Write the data. Fill unneeded bytes with 0. Do not
185 * crash if data is NULL.
186 */
187 if (!n->entries[i].data) memset (*buf + doff, 0, s);
188 else memcpy (*buf + doff, n->entries[i].data, s);
189 if (s < 4) memset (*buf + doff + s, 0, (4 - s));
190 }
191 }
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
exif_mnote_data_canon_load(ExifMnoteData * ne,const unsigned char * buf,unsigned int buf_size)206 exif_mnote_data_canon_load (ExifMnoteData *ne,
207 const unsigned char *buf, unsigned int buf_size)
208 {
209 ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne;
210 ExifShort c;
211 size_t i, tcount, o, datao;
212 long failsafe_size = 0;
213
214 if (!n) return;
215
216 if (!buf || !buf_size) {
217 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
218 "ExifMnoteCanon", "Short MakerNote");
219 return;
220 }
221 if (CHECKOVERFLOW(n->offset, buf_size, 8)) {
222 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
223 "ExifMnoteCanon", "Short MakerNote");
224 return;
225 }
226 datao = 6 + n->offset;
227
228 /* Read the number of tags */
229 c = exif_get_short (buf + datao, n->order);
230 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 if (c > 250) {
235 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteCanon", "Too much tags (%d) in Canon MakerNote", c);
236 return;
237 }
238
239 /* Remove any old entries */
240 exif_mnote_data_canon_clear (n);
241
242 /* Reserve enough space for all the possible MakerNote tags */
243 n->entries = exif_mem_alloc (ne->mem, sizeof (MnoteCanonEntry) * c);
244 if (!n->entries) {
245 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", sizeof (MnoteCanonEntry) * c);
246 return;
247 }
248
249 /* Parse the entries */
250 tcount = 0;
251 for (i = c, o = datao; i; --i, o += 12) {
252 size_t s;
253
254 memset(&n->entries[tcount], 0, sizeof(MnoteCanonEntry));
255 if (CHECKOVERFLOW(o,buf_size,12)) {
256 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
257 "ExifMnoteCanon", "Short MakerNote");
258 break;
259 }
260
261 n->entries[tcount].tag = exif_get_short (buf + o, n->order);
262 n->entries[tcount].format = exif_get_short (buf + o + 2, n->order);
263 n->entries[tcount].components = exif_get_long (buf + o + 4, n->order);
264 n->entries[tcount].order = n->order;
265
266 exif_log (ne->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteCanon",
267 "Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
268 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 if ( exif_format_get_size (n->entries[tcount].format) &&
273 buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
274 ) {
275 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
276 "ExifMnoteCanon", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
277 continue;
278 }
279
280 /*
281 * Size? If bigger than 4 bytes, the actual data is not
282 * in the entry but somewhere else (offset).
283 */
284 s = exif_format_get_size (n->entries[tcount].format) *
285 n->entries[tcount].components;
286 n->entries[tcount].size = s;
287 if (!s) {
288 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
289 "ExifMnoteCanon",
290 "Invalid zero-length tag size");
291 continue;
292
293 } else {
294 size_t dataofs = o + 8;
295 if (s > 4) dataofs = exif_get_long (buf + dataofs, n->order) + 6;
296
297 if (CHECKOVERFLOW(dataofs, buf_size, s)) {
298 exif_log (ne->log, EXIF_LOG_CODE_DEBUG,
299 "ExifMnoteCanon",
300 "Tag data past end of buffer (%u > %u)",
301 (unsigned)(dataofs + s), buf_size);
302 continue;
303 }
304
305 n->entries[tcount].data = exif_mem_alloc (ne->mem, s);
306 if (!n->entries[tcount].data) {
307 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", s);
308 continue;
309 }
310 memcpy (n->entries[tcount].data, buf + dataofs, s);
311 }
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 failsafe_size += mnote_canon_entry_count_values(&n->entries[tcount]);
320
321 if (failsafe_size > FAILSAFE_SIZE_MAX) {
322 /* Abort if the total size of the data in the tags extraordinarily large, */
323 exif_mem_free (ne->mem, n->entries[tcount].data);
324 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
325 "ExifMnoteCanon", "Failsafe tag size overflow (%lu > %ld)",
326 failsafe_size, FAILSAFE_SIZE_MAX);
327 break;
328 }
329
330 /* Tag was successfully parsed */
331 ++tcount;
332 }
333 /* Store the count of successfully parsed tags */
334 n->count = tcount;
335 }
336
337 static unsigned int
exif_mnote_data_canon_count(ExifMnoteData * n)338 exif_mnote_data_canon_count (ExifMnoteData *n)
339 {
340 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) n;
341 unsigned int i, c;
342
343 for (i = c = 0; dc && (i < dc->count); i++)
344 c += mnote_canon_entry_count_values (&dc->entries[i]);
345 return c;
346 }
347
348 static unsigned int
exif_mnote_data_canon_get_id(ExifMnoteData * d,unsigned int i)349 exif_mnote_data_canon_get_id (ExifMnoteData *d, unsigned int i)
350 {
351 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) d;
352 unsigned int m;
353
354 if (!dc) return 0;
355 exif_mnote_data_canon_get_tags (dc, i, &m, NULL);
356 if (m >= dc->count) return 0;
357 return dc->entries[m].tag;
358 }
359
360 static const char *
exif_mnote_data_canon_get_name(ExifMnoteData * note,unsigned int i)361 exif_mnote_data_canon_get_name (ExifMnoteData *note, unsigned int i)
362 {
363 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note;
364 unsigned int m, s;
365
366 if (!dc) return NULL;
367 exif_mnote_data_canon_get_tags (dc, i, &m, &s);
368 if (m >= dc->count) return NULL;
369 return mnote_canon_tag_get_name_sub (dc->entries[m].tag, s, dc->options);
370 }
371
372 static const char *
exif_mnote_data_canon_get_title(ExifMnoteData * note,unsigned int i)373 exif_mnote_data_canon_get_title (ExifMnoteData *note, unsigned int i)
374 {
375 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note;
376 unsigned int m, s;
377
378 if (!dc) return NULL;
379 exif_mnote_data_canon_get_tags (dc, i, &m, &s);
380 if (m >= dc->count) return NULL;
381 return mnote_canon_tag_get_title_sub (dc->entries[m].tag, s, dc->options);
382 }
383
384 static const char *
exif_mnote_data_canon_get_description(ExifMnoteData * note,unsigned int i)385 exif_mnote_data_canon_get_description (ExifMnoteData *note, unsigned int i)
386 {
387 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note;
388 unsigned int m;
389
390 if (!dc) return NULL;
391 exif_mnote_data_canon_get_tags (dc, i, &m, NULL);
392 if (m >= dc->count) return NULL;
393 return mnote_canon_tag_get_description (dc->entries[m].tag);
394 }
395
396 int
exif_mnote_data_canon_identify(const ExifData * ed,const ExifEntry * e)397 exif_mnote_data_canon_identify (const ExifData *ed, const ExifEntry *e)
398 {
399 char value[8];
400
401 ExifEntry *em = exif_data_get_entry (ed, EXIF_TAG_MAKE);
402 if (!em)
403 return 0;
404
405 (void) e; /* unused */
406 return !strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon");
407 }
408
409 ExifMnoteData *
exif_mnote_data_canon_new(ExifMem * mem,ExifDataOption o)410 exif_mnote_data_canon_new (ExifMem *mem, ExifDataOption o)
411 {
412 ExifMnoteData *d;
413 ExifMnoteDataCanon *dc;
414
415 if (!mem) return NULL;
416
417 d = exif_mem_alloc (mem, sizeof (ExifMnoteDataCanon));
418 if (!d)
419 return NULL;
420
421 exif_mnote_data_construct (d, mem);
422
423 /* Set up function pointers */
424 d->methods.free = exif_mnote_data_canon_free;
425 d->methods.set_byte_order = exif_mnote_data_canon_set_byte_order;
426 d->methods.set_offset = exif_mnote_data_canon_set_offset;
427 d->methods.load = exif_mnote_data_canon_load;
428 d->methods.save = exif_mnote_data_canon_save;
429 d->methods.count = exif_mnote_data_canon_count;
430 d->methods.get_id = exif_mnote_data_canon_get_id;
431 d->methods.get_name = exif_mnote_data_canon_get_name;
432 d->methods.get_title = exif_mnote_data_canon_get_title;
433 d->methods.get_description = exif_mnote_data_canon_get_description;
434 d->methods.get_value = exif_mnote_data_canon_get_value;
435
436 dc = (ExifMnoteDataCanon*)d;
437 dc->options = o;
438 return d;
439 }
440