EXIF library (libexif) Internals 0.6.26
exif-mnote-data-canon.c
Go to the documentation of this file.
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>
26
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30
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
40static void
42{
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
60static void
62{
63 if (!n) return;
64
66}
67
68static void
70 unsigned int *m, unsigned int *s)
71{
72 unsigned int from = 0, to;
73
74 if (s) *s = 0;
75
76 if (!dc || !m) return;
77 for (*m = 0; *m < dc->count; (*m)++) {
78 to = from + mnote_canon_entry_count_values (&dc->entries[*m]);
79 if (to > n) {
80 if (s) *s = n - from;
81 break;
82 }
83 from = to;
84 }
85}
86
87static char *
88exif_mnote_data_canon_get_value (ExifMnoteData *note, unsigned int n, char *val, unsigned int maxlen)
89{
91 unsigned int m, s;
92
93 if (!dc) return NULL;
94 exif_mnote_data_canon_get_tags (dc, n, &m, &s);
95 if (m >= dc->count) return NULL;
96 return mnote_canon_entry_get_value (&dc->entries[m], s, val, maxlen);
97}
98
99static void
101{
102 ExifByteOrder o_orig;
104 unsigned int i;
105
106 if (!n) return;
107
108 o_orig = n->order;
109 n->order = o;
110 for (i = 0; i < n->count; i++) {
112 continue;
113 n->entries[i].order = o;
115 n->entries[i].components, o_orig, o);
116 }
117}
118
119static void
121{
122 if (n) ((ExifMnoteDataCanon *) n)->offset = o;
123}
124
125static void
127 unsigned char **buf, unsigned int *buf_size)
128{
130 size_t i, o, s, doff;
131 unsigned char *t;
132 size_t ts;
133
134 if (!n || !buf || !buf_size) return;
135
136 /*
137 * Allocate enough memory for all entries and the number
138 * of entries.
139 */
140 *buf_size = 2 + n->count * 12 + 4;
141 *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size);
142 if (!*buf) {
143 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", *buf_size);
144 return;
145 }
146
147 /* Save the number of entries */
148 exif_set_short (*buf, n->order, (ExifShort) n->count);
149
150 /* Save each entry */
151 for (i = 0; i < n->count; i++) {
152 o = 2 + i * 12;
153 exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag);
154 exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format);
155 exif_set_long (*buf + o + 4, n->order,
156 n->entries[i].components);
157 o += 8;
159 n->entries[i].components;
160 if (s > 65536) {
161 /* Corrupt data: EXIF data size is limited to the
162 * maximum size of a JPEG segment (64 kb).
163 */
164 continue;
165 }
166 if (s > 4) {
167 ts = *buf_size + s;
168
169 /* Ensure even offsets. Set padding bytes to 0. */
170 if (s & 1) ts += 1;
171 t = exif_mem_realloc (ne->mem, *buf,
172 sizeof (char) * ts);
173 if (!t) {
174 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", ts);
175 return;
176 }
177 *buf = t;
178 *buf_size = ts;
179 doff = *buf_size - s;
180 if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; }
181 exif_set_long (*buf + o, n->order, n->offset + doff);
182 } else
183 doff = o;
184
185 /*
186 * Write the data. Fill unneeded bytes with 0. Do not
187 * crash if data is NULL.
188 */
189 if (!n->entries[i].data) memset (*buf + doff, 0, s);
190 else memcpy (*buf + doff, n->entries[i].data, s);
191 if (s < 4) memset (*buf + doff + s, 0, (4 - s));
192 }
193}
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
207static void
209 const unsigned char *buf, unsigned int buf_size)
210{
212 ExifShort c;
213 size_t i, tcount, o, datao;
214 long failsafe_size = 0;
215
216 if (!n) return;
217
218 if (!buf || !buf_size) {
220 "ExifMnoteCanon", "Short MakerNote");
221 return;
222 }
223 if (CHECKOVERFLOW(n->offset, buf_size, 8)) {
225 "ExifMnoteCanon", "Short MakerNote");
226 return;
227 }
228 datao = 6 + n->offset;
229
230 /* Read the number of tags */
231 c = exif_get_short (buf + datao, n->order);
232 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 if (c > 250) {
237 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteCanon", "Too much tags (%d) in Canon MakerNote", c);
238 return;
239 }
240
241 /* Remove any old entries */
243
244 /* Reserve enough space for all the possible MakerNote tags */
245 n->entries = exif_mem_alloc (ne->mem, sizeof (MnoteCanonEntry) * c);
246 if (!n->entries) {
247 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", sizeof (MnoteCanonEntry) * c);
248 return;
249 }
250
251 /* Parse the entries */
252 tcount = 0;
253 for (i = c, o = datao; i; --i, o += 12) {
254 size_t s;
255
256 memset(&n->entries[tcount], 0, sizeof(MnoteCanonEntry));
257 if (CHECKOVERFLOW(o,buf_size,12)) {
259 "ExifMnoteCanon", "Short MakerNote");
260 break;
261 }
262
263 n->entries[tcount].tag = exif_get_short (buf + o, n->order);
264 n->entries[tcount].format = exif_get_short (buf + o + 2, n->order);
265 n->entries[tcount].components = exif_get_long (buf + o + 4, n->order);
266 n->entries[tcount].order = n->order;
267
268 exif_log (ne->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteCanon",
269 "Loading entry 0x%x ('%s')...", 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 if ( exif_format_get_size (n->entries[tcount].format) &&
275 buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
276 ) {
278 "ExifMnoteCanon", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
279 continue;
280 }
281
282 /*
283 * Size? If bigger than 4 bytes, the actual data is not
284 * in the entry but somewhere else (offset).
285 */
286 s = exif_format_get_size (n->entries[tcount].format) *
287 n->entries[tcount].components;
288 n->entries[tcount].size = s;
289 if (!s) {
291 "ExifMnoteCanon",
292 "Invalid zero-length tag size");
293 continue;
294
295 } else {
296 size_t dataofs = o + 8;
297 if (s > 4) dataofs = exif_get_long (buf + dataofs, n->order) + 6;
298
299 if (CHECKOVERFLOW(dataofs, buf_size, s)) {
301 "ExifMnoteCanon",
302 "Tag data past end of buffer (%u > %u)",
303 (unsigned)(dataofs + s), buf_size);
304 continue;
305 }
306
307 n->entries[tcount].data = exif_mem_alloc (ne->mem, s);
308 if (!n->entries[tcount].data) {
309 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", s);
310 continue;
311 }
312 memcpy (n->entries[tcount].data, buf + dataofs, s);
313 }
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 failsafe_size += mnote_canon_entry_count_values(&n->entries[tcount]);
322
323 if (failsafe_size > FAILSAFE_SIZE_MAX) {
324 /* Abort if the total size of the data in the tags extraordinarily large, */
325 exif_mem_free (ne->mem, n->entries[tcount].data);
327 "ExifMnoteCanon", "Failsafe tag size overflow (%lu > %ld)",
328 failsafe_size, FAILSAFE_SIZE_MAX);
329 break;
330 }
331
332 /* Tag was successfully parsed */
333 ++tcount;
334 }
335 /* Store the count of successfully parsed tags */
336 n->count = tcount;
337}
338
339static unsigned int
341{
343 unsigned int i, c;
344
345 for (i = c = 0; dc && (i < dc->count); i++)
347 return c;
348}
349
350static unsigned int
352{
354 unsigned int m;
355
356 if (!dc) return 0;
357 exif_mnote_data_canon_get_tags (dc, i, &m, NULL);
358 if (m >= dc->count) return 0;
359 return dc->entries[m].tag;
360}
361
362static const char *
364{
366 unsigned int m, s;
367
368 if (!dc) return NULL;
369 exif_mnote_data_canon_get_tags (dc, i, &m, &s);
370 if (m >= dc->count) return NULL;
371 return mnote_canon_tag_get_name_sub (dc->entries[m].tag, s, dc->options);
372}
373
374static const char *
376{
378 unsigned int m, s;
379
380 if (!dc) return NULL;
381 exif_mnote_data_canon_get_tags (dc, i, &m, &s);
382 if (m >= dc->count) return NULL;
383 return mnote_canon_tag_get_title_sub (dc->entries[m].tag, s, dc->options);
384}
385
386static const char *
388{
390 unsigned int m;
391
392 if (!dc) return NULL;
393 exif_mnote_data_canon_get_tags (dc, i, &m, NULL);
394 if (m >= dc->count) return NULL;
396}
397
398int
400{
401 char value[8];
402
404 if (!em)
405 return 0;
406
407 (void) e; /* unused */
408 return !strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon");
409}
410
413{
414 ExifMnoteData *d;
416
417 if (!mem) return NULL;
418
419 d = exif_mem_alloc (mem, sizeof (ExifMnoteDataCanon));
420 if (!d)
421 return NULL;
422
424
425 /* Set up function pointers */
437
438 dc = (ExifMnoteDataCanon*)d;
439 dc->options = o;
440 return d;
441}
Defines the ExifByteOrder enum and the associated functions.
ExifByteOrder
Which byte order to use.
Defines the ExifData type and the associated functions.
ExifDataOption
Options to configure the behaviour of ExifData.
Definition exif-data.h:175
#define exif_data_get_entry(d, t)
Return an ExifEntry for the given tag if found in any IFD.
Definition exif-data.h:252
const char * exif_entry_get_value(ExifEntry *e, char *val, unsigned int maxlen)
Return a localized textual representation of the value of the EXIF entry.
Definition exif-entry.c:854
unsigned char exif_format_get_size(ExifFormat format)
Return the raw size of the given EXIF data type.
Definition exif-format.c:68
void exif_log(ExifLog *log, ExifLogCode code, const char *domain, const char *format,...)
Definition exif-log.c:137
@ EXIF_LOG_CODE_CORRUPT_DATA
Definition exif-log.h:60
@ EXIF_LOG_CODE_DEBUG
Definition exif-log.h:58
#define EXIF_LOG_NO_MEMORY(l, d, s)
Definition exif-log.h:112
void exif_mem_free(ExifMem *mem, void *d)
Definition exif-mem.c:91
void * exif_mem_alloc(ExifMem *mem, ExifLong ds)
Definition exif-mem.c:101
void * exif_mem_realloc(ExifMem *mem, void *d, ExifLong ds)
Definition exif-mem.c:111
#define FAILSAFE_SIZE_MAX
static void exif_mnote_data_canon_set_offset(ExifMnoteData *n, unsigned int o)
ExifMnoteData * exif_mnote_data_canon_new(ExifMem *mem, ExifDataOption o)
static const char * exif_mnote_data_canon_get_title(ExifMnoteData *note, unsigned int i)
static unsigned int exif_mnote_data_canon_get_id(ExifMnoteData *d, unsigned int i)
static void exif_mnote_data_canon_save(ExifMnoteData *ne, unsigned char **buf, unsigned int *buf_size)
int exif_mnote_data_canon_identify(const ExifData *ed, const ExifEntry *e)
Detect if MakerNote is recognized as one handled by the Canon module.
static char * exif_mnote_data_canon_get_value(ExifMnoteData *note, unsigned int n, char *val, unsigned int maxlen)
static const char * exif_mnote_data_canon_get_description(ExifMnoteData *note, unsigned int i)
static void exif_mnote_data_canon_clear(ExifMnoteDataCanon *n)
static void exif_mnote_data_canon_free(ExifMnoteData *n)
static unsigned int exif_mnote_data_canon_count(ExifMnoteData *n)
#define CHECKOVERFLOW(offset, datasize, structsize)
static const char * exif_mnote_data_canon_get_name(ExifMnoteData *note, unsigned int i)
static void exif_mnote_data_canon_load(ExifMnoteData *ne, const unsigned char *buf, unsigned int buf_size)
static void exif_mnote_data_canon_get_tags(ExifMnoteDataCanon *dc, unsigned int n, unsigned int *m, unsigned int *s)
static void exif_mnote_data_canon_set_byte_order(ExifMnoteData *d, ExifByteOrder o)
void exif_mnote_data_construct(ExifMnoteData *, ExifMem *mem)
@ EXIF_TAG_MAKE
Definition exif-tag.h:48
ExifLong exif_get_long(const unsigned char *buf, ExifByteOrder order)
Retrieve an ExifLong value from memory.
Definition exif-utils.c:167
ExifShort exif_get_short(const unsigned char *buf, ExifByteOrder order)
Retrieve an ExifShort value from memory.
Definition exif-utils.c:104
void exif_array_set_byte_order(ExifFormat f, unsigned char *b, unsigned int n, ExifByteOrder o_orig, ExifByteOrder o_new)
Definition exif-utils.c:28
void exif_set_long(unsigned char *b, ExifByteOrder order, ExifLong value)
Store an ExifLong value into memory in EXIF format.
Definition exif-utils.c:173
void exif_set_short(unsigned char *b, ExifByteOrder order, ExifShort value)
Store an ExifShort value into memory in EXIF format.
Definition exif-utils.c:126
EXIF data manipulation functions and types.
uint16_t ExifShort
EXIF Unsigned Short data type.
Definition exif-utils.h:50
char * mnote_canon_entry_get_value(const MnoteCanonEntry *entry, unsigned int t, char *val, unsigned int maxlen)
unsigned int mnote_canon_entry_count_values(const MnoteCanonEntry *entry)
const char * mnote_canon_tag_get_title_sub(MnoteCanonTag t, unsigned int s, ExifDataOption o)
const char * mnote_canon_tag_get_name(MnoteCanonTag t)
const char * mnote_canon_tag_get_name_sub(MnoteCanonTag t, unsigned int s, ExifDataOption o)
const char * mnote_canon_tag_get_description(MnoteCanonTag t)
Represents the entire EXIF data found in an image.
Definition exif-data.h:48
Data found in one EXIF tag.
Definition exif-entry.h:45
MnoteCanonEntry * entries
const char *(* get_name)(ExifMnoteData *, unsigned int)
const char *(* get_description)(ExifMnoteData *, unsigned int)
void(* load)(ExifMnoteData *, const unsigned char *, unsigned int)
char *(* get_value)(ExifMnoteData *, unsigned int, char *val, unsigned int maxlen)
unsigned int(* get_id)(ExifMnoteData *, unsigned int)
void(* save)(ExifMnoteData *, unsigned char **, unsigned int *)
unsigned int(* count)(ExifMnoteData *)
void(* set_offset)(ExifMnoteData *, unsigned int)
const char *(* get_title)(ExifMnoteData *, unsigned int)
void(* set_byte_order)(ExifMnoteData *, ExifByteOrder)
void(* free)(ExifMnoteData *)
ExifMnoteDataMethods methods
ExifByteOrder order
unsigned long components
unsigned char * data

libexif Generated by doxygen