1 /*
2 * Copyright (c) Ian F. Darwin 1986-1995.
3 * Software written by Ian F. Darwin and others;
4 * maintained 1995-present by Christos Zoulas and others.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice immediately at the beginning of the file, without modification,
11 * this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 /*
29 * softmagic - interpret variable magic from MAGIC
30 */
31
32 #include "file.h"
33
34 #ifndef lint
35 FILE_RCSID("@(#)$File: softmagic.c,v 1.345 2023/07/02 12:48:39 christos Exp $")
36 #endif /* lint */
37
38 #include "magic.h"
39 #include <assert.h>
40 #include <math.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <stdlib.h>
44 #include <limits.h>
45 #include <time.h>
46 #include "der.h"
47
48 file_private int match(struct magic_set *, struct magic *, size_t,
49 const struct buffer *, size_t, int, int, int, uint16_t *,
50 uint16_t *, int *, int *, int *, int *, int *);
51 file_private int mget(struct magic_set *, struct magic *, const struct buffer *,
52 const unsigned char *, size_t,
53 size_t, unsigned int, int, int, int, uint16_t *,
54 uint16_t *, int *, int *, int *, int *, int *);
55 file_private int msetoffset(struct magic_set *, struct magic *, struct buffer *,
56 const struct buffer *, size_t, unsigned int);
57 file_private int magiccheck(struct magic_set *, struct magic *);
58 file_private int mprint(struct magic_set *, struct magic *);
59 file_private int moffset(struct magic_set *, struct magic *, const struct buffer *,
60 int32_t *);
61 file_private void mdebug(uint32_t, const char *, size_t);
62 file_private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
63 const unsigned char *, uint32_t, size_t, struct magic *);
64 file_private int mconvert(struct magic_set *, struct magic *, int);
65 file_private int print_sep(struct magic_set *, int);
66 file_private int handle_annotation(struct magic_set *, struct magic *, int);
67 file_private int cvt_8(union VALUETYPE *, const struct magic *);
68 file_private int cvt_16(union VALUETYPE *, const struct magic *);
69 file_private int cvt_32(union VALUETYPE *, const struct magic *);
70 file_private int cvt_64(union VALUETYPE *, const struct magic *);
71
72 #define OFFSET_OOB(n, o, i) ((n) < CAST(uint32_t, (o)) || (i) > ((n) - (o)))
73 #define BE64(p) ( \
74 (CAST(uint64_t, (p)->hq[0])<<56)| \
75 (CAST(uint64_t, (p)->hq[1])<<48)| \
76 (CAST(uint64_t, (p)->hq[2])<<40)| \
77 (CAST(uint64_t, (p)->hq[3])<<32)| \
78 (CAST(uint64_t, (p)->hq[4])<<24)| \
79 (CAST(uint64_t, (p)->hq[5])<<16)| \
80 (CAST(uint64_t, (p)->hq[6])<<8)| \
81 (CAST(uint64_t, (p)->hq[7])))
82 #define LE64(p) ( \
83 (CAST(uint64_t, (p)->hq[7])<<56)| \
84 (CAST(uint64_t, (p)->hq[6])<<48)| \
85 (CAST(uint64_t, (p)->hq[5])<<40)| \
86 (CAST(uint64_t, (p)->hq[4])<<32)| \
87 (CAST(uint64_t, (p)->hq[3])<<24)| \
88 (CAST(uint64_t, (p)->hq[2])<<16)| \
89 (CAST(uint64_t, (p)->hq[1])<<8)| \
90 (CAST(uint64_t, (p)->hq[0])))
91 #define LE32(p) ( \
92 (CAST(uint32_t, (p)->hl[3])<<24)| \
93 (CAST(uint32_t, (p)->hl[2])<<16)| \
94 (CAST(uint32_t, (p)->hl[1])<<8)| \
95 (CAST(uint32_t, (p)->hl[0])))
96 #define BE32(p) ( \
97 (CAST(uint32_t, (p)->hl[0])<<24)| \
98 (CAST(uint32_t, (p)->hl[1])<<16)| \
99 (CAST(uint32_t, (p)->hl[2])<<8)| \
100 (CAST(uint32_t, (p)->hl[3])))
101 #define ME32(p) ( \
102 (CAST(uint32_t, (p)->hl[1])<<24)| \
103 (CAST(uint32_t, (p)->hl[0])<<16)| \
104 (CAST(uint32_t, (p)->hl[3])<<8)| \
105 (CAST(uint32_t, (p)->hl[2])))
106
107 #define BE16(p) ((CAST(uint16_t, (p)->hs[0])<<8)|(CAST(uint16_t, (p)->hs[1])))
108 #define LE16(p) ((CAST(uint16_t, (p)->hs[1])<<8)|(CAST(uint16_t, (p)->hs[0])))
109 #define SEXT(s,v,p) ((s) ? \
110 CAST(intmax_t, CAST(int##v##_t, p)) : \
111 CAST(intmax_t, CAST(uint##v##_t, p)))
112
113 /*
114 * softmagic - lookup one file in parsed, in-memory copy of database
115 * Passed the name and FILE * of one file to be typed.
116 */
117 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
118 file_protected int
file_softmagic(struct magic_set * ms,const struct buffer * b,uint16_t * indir_count,uint16_t * name_count,int mode,int text)119 file_softmagic(struct magic_set *ms, const struct buffer *b,
120 uint16_t *indir_count, uint16_t *name_count, int mode, int text)
121 {
122 struct mlist *ml;
123 int rv = 0, printed_something = 0, need_separator = 0, firstline = 1;
124 uint16_t nc, ic;
125
126 if (name_count == NULL) {
127 nc = 0;
128 name_count = &nc;
129 }
130 if (indir_count == NULL) {
131 ic = 0;
132 indir_count = ⁣
133 }
134
135 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) {
136 int ret = match(ms, ml->magic, ml->nmagic, b,
137 0, mode, text, 0, indir_count, name_count,
138 &printed_something, &need_separator, &firstline,
139 NULL, NULL);
140 switch (ret) {
141 case -1:
142 return ret;
143 case 0:
144 continue;
145 default:
146 if ((ms->flags & MAGIC_CONTINUE) == 0)
147 return ret;
148 rv = ret;
149 break;
150 }
151 }
152
153 return rv;
154 }
155
156
157 #if defined(FILE_FMTDEBUG) && defined(HAVE_FMTCHECK)
158 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
159
160 file_private const char * __attribute__((__format_arg__(3)))
file_fmtcheck(struct magic_set * ms,const char * desc,const char * def,const char * file,size_t line)161 file_fmtcheck(struct magic_set *ms, const char *desc, const char *def,
162 const char *file, size_t line)
163 {
164 const char *ptr;
165
166 if (strchr(desc, '%') == NULL)
167 return desc;
168
169 ptr = fmtcheck(desc, def);
170 if (ptr == def)
171 file_magerror(ms,
172 "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
173 " with `%s'", file, line, desc, def);
174 return ptr;
175 }
176 #elif defined(HAVE_FMTCHECK)
177 #define F(a, b, c) fmtcheck((b), (c))
178 #else
179 #define F(a, b, c) ((b))
180 #endif
181
182 /* NOTE this function has been kept an the state of 5.39 for BC. Observe
183 * further as the upgrade to 5.41 or above goes. */
184 /*
185 * Go through the whole list, stopping if you find a match. Process all
186 * the continuations of that match before returning.
187 *
188 * We support multi-level continuations:
189 *
190 * At any time when processing a successful top-level match, there is a
191 * current continuation level; it represents the level of the last
192 * successfully matched continuation.
193 *
194 * Continuations above that level are skipped as, if we see one, it
195 * means that the continuation that controls them - i.e, the
196 * lower-level continuation preceding them - failed to match.
197 *
198 * Continuations below that level are processed as, if we see one,
199 * it means we've finished processing or skipping higher-level
200 * continuations under the control of a successful or unsuccessful
201 * lower-level continuation, and are now seeing the next lower-level
202 * continuation and should process it. The current continuation
203 * level reverts to the level of the one we're seeing.
204 *
205 * Continuations at the current level are processed as, if we see
206 * one, there's no lower-level continuation that may have failed.
207 *
208 * If a continuation matches, we bump the current continuation level
209 * so that higher-level continuations are processed.
210 */
211 file_private int
match(struct magic_set * ms,struct magic * magic,size_t nmagic,const struct buffer * b,size_t offset,int mode,int text,int flip,uint16_t * indir_count,uint16_t * name_count,int * printed_something,int * need_separator,int * firstline,int * returnval,int * found_match)212 match(struct magic_set *ms, struct magic *magic,
213 size_t nmagic, const struct buffer *b, size_t offset, int mode, int text,
214 int flip, uint16_t *indir_count, uint16_t *name_count,
215 int *printed_something, int *need_separator, int *firstline,
216 int *returnval, int *found_match)
217 {
218 uint32_t magindex = 0;
219 unsigned int cont_level = 0;
220 int found_matchv = 0; /* if a match is found it is set to 1*/
221 int returnvalv = 0, e;
222 struct buffer bb;
223 int print = (ms->flags & MAGIC_NODESC) == 0;
224
225 /*
226 * returnval can be 0 if a match is found, but there was no
227 * annotation to be printed.
228 */
229 if (returnval == NULL)
230 returnval = &returnvalv;
231 if (found_match == NULL)
232 found_match = &found_matchv;
233
234 if (file_check_mem(ms, cont_level) == -1)
235 return -1;
236
237 for (magindex = 0; magindex < nmagic; magindex++) {
238 int flush = 0;
239 struct magic *m = &magic[magindex];
240
241 if (m->type != FILE_NAME)
242 if ((IS_LIBMAGIC_STRING(m->type) &&
243 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
244 ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
245 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
246 (m->flag & mode) != mode) {
247 flush:
248 /* Skip sub-tests */
249 while (magindex < nmagic - 1 &&
250 magic[magindex + 1].cont_level != 0)
251 magindex++;
252 cont_level = 0;
253 continue; /* Skip to next top-level test*/
254 }
255
256 if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
257 goto flush;
258 ms->line = m->lineno;
259
260 /* if main entry matches, print it... */
261 switch (mget(ms, m, b, CAST(const unsigned char *, bb.fbuf),
262 bb.flen, offset, cont_level,
263 mode, text, flip, indir_count, name_count,
264 printed_something, need_separator, firstline, returnval,
265 found_match))
266 {
267 case -1:
268 return -1;
269 case 0:
270 flush = m->reln != '!';
271 break;
272 default:
273 if (m->type == FILE_INDIRECT) {
274 *found_match = 1;
275 *returnval = 1;
276 }
277
278 switch (magiccheck(ms, m)) {
279 case -1:
280 return -1;
281 case 0:
282 flush++;
283 break;
284 default:
285 flush = 0;
286 break;
287 }
288 break;
289 }
290 if (flush) {
291 /*
292 * main entry didn't match,
293 * flush its continuations
294 */
295 goto flush;
296 }
297
298 if ((e = handle_annotation(ms, m, *firstline)) != 0)
299 {
300 *found_match = 1;
301 *need_separator = 1;
302 *printed_something = 1;
303 *returnval = 1;
304 *firstline = 0;
305 return e;
306 }
307
308 /*
309 * If we are going to print something, we'll need to print
310 * a blank before we print something else.
311 */
312 if (*m->desc) {
313 *found_match = 1;
314 if (print) {
315 *returnval = 1;
316 *need_separator = 1;
317 *printed_something = 1;
318 if (print_sep(ms, *firstline) == -1)
319 return -1;
320 if (mprint(ms, m) == -1)
321 return -1;
322 }
323 }
324
325 switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) {
326 case -1:
327 case 0:
328 goto flush;
329 default:
330 break;
331 }
332
333 /* and any continuations that match */
334 if (file_check_mem(ms, ++cont_level) == -1)
335 return -1;
336
337 while (magindex + 1 < nmagic &&
338 magic[magindex + 1].cont_level != 0) {
339 m = &magic[++magindex];
340 ms->line = m->lineno; /* for messages */
341
342 if (cont_level < m->cont_level)
343 continue;
344 if (cont_level > m->cont_level) {
345 /*
346 * We're at the end of the level
347 * "cont_level" continuations.
348 */
349 cont_level = m->cont_level;
350 }
351 if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
352 goto flush;
353 if (m->flag & OFFADD) {
354 if (cont_level == 0) {
355 if ((ms->flags & MAGIC_DEBUG) != 0)
356 fprintf(stderr,
357 "direct *zero*"
358 " cont_level\n");
359 return 0;
360 }
361 ms->offset +=
362 ms->c.li[cont_level - 1].off;
363 }
364
365 #ifdef ENABLE_CONDITIONALS
366 if (m->cond == COND_ELSE ||
367 m->cond == COND_ELIF) {
368 if (ms->c.li[cont_level].last_match == 1)
369 continue;
370 }
371 #endif
372 switch (mget(ms, m, b, CAST(const unsigned char *,
373 bb.fbuf), bb.flen, offset,
374 cont_level, mode, text, flip, indir_count,
375 name_count, printed_something, need_separator,
376 firstline, returnval, found_match)) {
377 case -1:
378 return -1;
379 case 0:
380 if (m->reln != '!')
381 continue;
382 flush = 1;
383 break;
384 default:
385 if (m->type == FILE_INDIRECT) {
386 *found_match = 1;
387 *returnval = 1;
388 }
389 flush = 0;
390 break;
391 }
392
393 switch (flush ? 1 : magiccheck(ms, m)) {
394 case -1:
395 return -1;
396 case 0:
397 #ifdef ENABLE_CONDITIONALS
398 ms->c.li[cont_level].last_match = 0;
399 #endif
400 break;
401 default:
402 #ifdef ENABLE_CONDITIONALS
403 ms->c.li[cont_level].last_match = 1;
404 #endif
405 if (m->type == FILE_CLEAR)
406 ms->c.li[cont_level].got_match = 0;
407 else if (ms->c.li[cont_level].got_match) {
408 if (m->type == FILE_DEFAULT)
409 break;
410 } else
411 ms->c.li[cont_level].got_match = 1;
412
413 if ((e = handle_annotation(ms, m, *firstline))
414 != 0) {
415 *found_match = 1;
416 *need_separator = 1;
417 *printed_something = 1;
418 *returnval = 1;
419 return e;
420 }
421 if (*m->desc) {
422 *found_match = 1;
423 }
424 if (print && *m->desc) {
425 *returnval = 1;
426 /*
427 * This continuation matched. Print
428 * its message, with a blank before it
429 * if the previous item printed and
430 * this item isn't empty.
431 */
432 /*
433 * If we are going to print something,
434 * make sure that we have a separator
435 * first.
436 */
437 if (!*printed_something) {
438 *printed_something = 1;
439 if (print_sep(ms, *firstline)
440 == -1)
441 return -1;
442 }
443 /* space if previous printed */
444 if (*need_separator
445 && (m->flag & NOSPACE) == 0) {
446 if (file_printf(ms, " ") == -1)
447 return -1;
448 }
449 if (mprint(ms, m) == -1)
450 return -1;
451 *need_separator = 1;
452 }
453
454 switch (moffset(ms, m, &bb,
455 &ms->c.li[cont_level].off)) {
456 case -1:
457 case 0:
458 cont_level--;
459 break;
460 default:
461 break;
462 }
463
464 /*
465 * If we see any continuations
466 * at a higher level,
467 * process them.
468 */
469 if (file_check_mem(ms, ++cont_level) == -1)
470 return -1;
471 break;
472 }
473 }
474 if (*printed_something) {
475 *firstline = 0;
476 }
477 if (*found_match) {
478 if ((ms->flags & MAGIC_CONTINUE) == 0)
479 return *returnval;
480 // So that we print a separator
481 *printed_something = 0;
482 *firstline = 0;
483 }
484 cont_level = 0;
485 }
486 return *returnval;
487 }
488
489 file_private int
check_fmt(struct magic_set * ms,const char * fmt)490 check_fmt(struct magic_set *ms, const char *fmt)
491 {
492 pcre_cache_entry *pce;
493 int rv = -1;
494 zend_string *pattern;
495
496 if (strchr(fmt, '%') == NULL)
497 return 0;
498
499 pattern = ZSTR_INIT_LITERAL("~%[-0-9\\.]*s~", 0);
500 if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) {
501 rv = -1;
502 } else {
503 pcre2_code *re = php_pcre_pce_re(pce);
504 pcre2_match_data *match_data = php_pcre_create_match_data(0, re);
505 if (match_data) {
506 rv = pcre2_match(re, (PCRE2_SPTR)fmt, strlen(fmt), 0, 0, match_data, php_pcre_mctx()) > 0;
507 php_pcre_free_match_data(match_data);
508 }
509 }
510 zend_string_release_ex(pattern, 0);
511 return rv;
512 }
513
514 #if !defined(HAVE_STRNDUP) || defined(__aiws__) || defined(_AIX)
515 # if defined(__aiws__) || defined(_AIX)
516 # define strndup aix_strndup /* aix is broken */
517 # endif
518 char *strndup(const char *, size_t);
519
520 char *
strndup(const char * str,size_t n)521 strndup(const char *str, size_t n)
522 {
523 size_t len;
524 char *copy;
525
526 for (len = 0; len < n && str[len]; len++)
527 continue;
528 if ((copy = CAST(char *, emalloc(len + 1))) == NULL)
529 return NULL;
530 (void)memcpy(copy, str, len);
531 copy[len] = '\0';
532 return copy;
533 }
534 #endif /* HAVE_STRNDUP */
535
536 static int
varexpand(struct magic_set * ms,char * buf,size_t len,const char * str)537 varexpand(struct magic_set *ms, char *buf, size_t len, const char *str)
538 {
539 const char *ptr, *sptr, *e, *t, *ee, *et;
540 size_t l;
541
542 for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) {
543 l = CAST(size_t, ptr - sptr);
544 if (l >= len)
545 return -1;
546 memcpy(buf, sptr, l);
547 buf += l;
548 len -= l;
549 ptr += 2;
550 if (!*ptr || ptr[1] != '?')
551 return -1;
552 for (et = t = ptr + 2; *et && *et != ':'; et++)
553 continue;
554 if (*et != ':')
555 return -1;
556 for (ee = e = et + 1; *ee && *ee != '}'; ee++)
557 continue;
558 if (*ee != '}')
559 return -1;
560 switch (*ptr) {
561 case 'x':
562 if (ms->mode & 0111) {
563 ptr = t;
564 l = et - t;
565 } else {
566 ptr = e;
567 l = ee - e;
568 }
569 break;
570 default:
571 return -1;
572 }
573 if (l >= len)
574 return -1;
575 memcpy(buf, ptr, l);
576 buf += l;
577 len -= l;
578 sptr = ee + 1;
579 }
580
581 l = strlen(sptr);
582 if (l >= len)
583 return -1;
584
585 memcpy(buf, sptr, l);
586 buf[l] = '\0';
587 return 0;
588 }
589
590
591 file_private int
mprint(struct magic_set * ms,struct magic * m)592 mprint(struct magic_set *ms, struct magic *m)
593 {
594 uint64_t v;
595 float vf;
596 double vd;
597 char buf[128], tbuf[26], sbuf[512], ebuf[512];
598 const char *desc;
599 union VALUETYPE *p = &ms->ms_value;
600
601 if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1)
602 desc = m->desc;
603 else
604 desc = ebuf;
605
606 #define PRINTER(value, format, stype, utype) \
607 v = file_signextend(ms, m, CAST(uint64_t, value)); \
608 switch (check_fmt(ms, desc)) { \
609 case -1: \
610 return -1; \
611 case 1: \
612 if (m->flag & UNSIGNED) { \
613 (void)snprintf(buf, sizeof(buf), "%" format "u", \
614 CAST(utype, v)); \
615 } else { \
616 (void)snprintf(buf, sizeof(buf), "%" format "d", \
617 CAST(stype, v)); \
618 } \
619 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) \
620 return -1; \
621 break; \
622 default: \
623 if (m->flag & UNSIGNED) { \
624 if (file_printf(ms, F(ms, desc, "%" format "u"), \
625 CAST(utype, v)) == -1) \
626 return -1; \
627 } else { \
628 if (file_printf(ms, F(ms, desc, "%" format "d"), \
629 CAST(stype, v)) == -1) \
630 return -1; \
631 } \
632 break; \
633 } \
634 break
635
636 switch (m->type) {
637 case FILE_BYTE:
638 PRINTER(p->b, "", int8_t, uint8_t);
639
640 case FILE_SHORT:
641 case FILE_BESHORT:
642 case FILE_LESHORT:
643 PRINTER(p->h, "", int16_t, uint16_t);
644
645 case FILE_LONG:
646 case FILE_BELONG:
647 case FILE_LELONG:
648 case FILE_MELONG:
649 PRINTER(p->l, "", int32_t, uint32_t);
650
651 case FILE_QUAD:
652 case FILE_BEQUAD:
653 case FILE_LEQUAD:
654 case FILE_OFFSET:
655 PRINTER(p->q, INT64_T_FORMAT, long long, unsigned long long);
656
657 case FILE_STRING:
658 case FILE_PSTRING:
659 case FILE_BESTRING16:
660 case FILE_LESTRING16:
661 if (m->reln == '=' || m->reln == '!') {
662 if (file_printf(ms, F(ms, desc, "%s"),
663 file_printable(ms, sbuf, sizeof(sbuf), m->value.s,
664 sizeof(m->value.s))) == -1)
665 return -1;
666 }
667 else {
668 char *str = p->s;
669
670 /* compute t before we mangle the string? */
671
672 if (*m->value.s == '\0')
673 str[strcspn(str, "\r\n")] = '\0';
674
675 if (m->str_flags & STRING_TRIM)
676 str = file_strtrim(str);
677
678 if (file_printf(ms, F(ms, desc, "%s"),
679 file_printable(ms, sbuf, sizeof(sbuf), str,
680 sizeof(p->s) - (str - p->s))) == -1)
681 return -1;
682
683 if (m->type == FILE_PSTRING) {
684 size_t l = file_pstring_length_size(ms, m);
685 if (l == FILE_BADSIZE)
686 return -1;
687 }
688 }
689 break;
690
691 case FILE_DATE:
692 case FILE_BEDATE:
693 case FILE_LEDATE:
694 case FILE_MEDATE:
695 if (file_printf(ms, F(ms, desc, "%s"),
696 file_fmtdatetime(tbuf, sizeof(tbuf), p->l, 0)) == -1)
697 return -1;
698 break;
699
700 case FILE_LDATE:
701 case FILE_BELDATE:
702 case FILE_LELDATE:
703 case FILE_MELDATE:
704 if (file_printf(ms, F(ms, desc, "%s"),
705 file_fmtdatetime(tbuf, sizeof(tbuf), p->l, FILE_T_LOCAL))
706 == -1)
707 return -1;
708 break;
709
710 case FILE_QDATE:
711 case FILE_BEQDATE:
712 case FILE_LEQDATE:
713 if (file_printf(ms, F(ms, desc, "%s"),
714 file_fmtdatetime(tbuf, sizeof(tbuf), p->q, 0)) == -1)
715 return -1;
716 break;
717
718 case FILE_QLDATE:
719 case FILE_BEQLDATE:
720 case FILE_LEQLDATE:
721 if (file_printf(ms, F(ms, desc, "%s"),
722 file_fmtdatetime(tbuf, sizeof(tbuf), p->q, FILE_T_LOCAL)) == -1)
723 return -1;
724 break;
725
726 case FILE_QWDATE:
727 case FILE_BEQWDATE:
728 case FILE_LEQWDATE:
729 if (file_printf(ms, F(ms, desc, "%s"),
730 file_fmtdatetime(tbuf, sizeof(tbuf), p->q, FILE_T_WINDOWS))
731 == -1)
732 return -1;
733 break;
734
735 case FILE_FLOAT:
736 case FILE_BEFLOAT:
737 case FILE_LEFLOAT:
738 vf = p->f;
739 switch (check_fmt(ms, desc)) {
740 case -1:
741 return -1;
742 case 1:
743 (void)snprintf(buf, sizeof(buf), "%g", vf);
744 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
745 return -1;
746 break;
747 default:
748 if (file_printf(ms, F(ms, desc, "%g"), vf) == -1)
749 return -1;
750 break;
751 }
752 break;
753
754 case FILE_DOUBLE:
755 case FILE_BEDOUBLE:
756 case FILE_LEDOUBLE:
757 vd = p->d;
758 switch (check_fmt(ms, desc)) {
759 case -1:
760 return -1;
761 case 1:
762 (void)snprintf(buf, sizeof(buf), "%g", vd);
763 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
764 return -1;
765 break;
766 default:
767 if (file_printf(ms, F(ms, desc, "%g"), vd) == -1)
768 return -1;
769 break;
770 }
771 break;
772
773 case FILE_SEARCH:
774 case FILE_REGEX: {
775 char *cp, *scp;
776 int rval;
777
778 cp = estrndup(RCAST(const char *, ms->search.s),
779 ms->search.rm_len);
780 if (cp == NULL) {
781 file_oomem(ms, ms->search.rm_len);
782 return -1;
783 }
784 scp = (m->str_flags & STRING_TRIM) ? file_strtrim(cp) : cp;
785
786 rval = file_printf(ms, F(ms, desc, "%s"), file_printable(ms,
787 sbuf, sizeof(sbuf), scp, ms->search.rm_len));
788 efree(cp);
789
790 if (rval == -1)
791 return -1;
792 break;
793 }
794
795 case FILE_DEFAULT:
796 case FILE_CLEAR:
797 if (file_printf(ms, "%s", m->desc) == -1)
798 return -1;
799 break;
800
801 case FILE_INDIRECT:
802 case FILE_USE:
803 case FILE_NAME:
804 break;
805 case FILE_DER:
806 if (file_printf(ms, F(ms, desc, "%s"),
807 file_printable(ms, sbuf, sizeof(sbuf), ms->ms_value.s,
808 sizeof(ms->ms_value.s))) == -1)
809 return -1;
810 break;
811 case FILE_GUID:
812 (void) file_print_guid(buf, sizeof(buf), ms->ms_value.guid);
813 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
814 return -1;
815 break;
816 case FILE_MSDOSDATE:
817 case FILE_BEMSDOSDATE:
818 case FILE_LEMSDOSDATE:
819 if (file_printf(ms, F(ms, desc, "%s"),
820 file_fmtdate(tbuf, sizeof(tbuf), p->h)) == -1)
821 return -1;
822 break;
823 case FILE_MSDOSTIME:
824 case FILE_BEMSDOSTIME:
825 case FILE_LEMSDOSTIME:
826 if (file_printf(ms, F(ms, desc, "%s"),
827 file_fmttime(tbuf, sizeof(tbuf), p->h)) == -1)
828 return -1;
829 break;
830 case FILE_OCTAL:
831 file_fmtnum(buf, sizeof(buf), m->value.s, 8);
832 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
833 return -1;
834 break;
835 default:
836 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
837 return -1;
838 }
839 return 0;
840 }
841
842 file_private int
moffset(struct magic_set * ms,struct magic * m,const struct buffer * b,int32_t * op)843 moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
844 int32_t *op)
845 {
846 size_t nbytes = b->flen;
847 int32_t o;
848
849 switch (m->type) {
850 case FILE_BYTE:
851 o = CAST(int32_t, (ms->offset + sizeof(char)));
852 break;
853
854 case FILE_SHORT:
855 case FILE_BESHORT:
856 case FILE_LESHORT:
857 case FILE_MSDOSDATE:
858 case FILE_LEMSDOSDATE:
859 case FILE_BEMSDOSDATE:
860 case FILE_MSDOSTIME:
861 case FILE_LEMSDOSTIME:
862 case FILE_BEMSDOSTIME:
863 o = CAST(int32_t, (ms->offset + sizeof(short)));
864 break;
865
866 case FILE_LONG:
867 case FILE_BELONG:
868 case FILE_LELONG:
869 case FILE_MELONG:
870 o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
871 break;
872
873 case FILE_QUAD:
874 case FILE_BEQUAD:
875 case FILE_LEQUAD:
876 o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
877 break;
878
879 case FILE_STRING:
880 case FILE_PSTRING:
881 case FILE_BESTRING16:
882 case FILE_LESTRING16:
883 case FILE_OCTAL:
884 if (m->reln == '=' || m->reln == '!') {
885 o = ms->offset + m->vallen;
886 } else {
887 union VALUETYPE *p = &ms->ms_value;
888
889 if (*m->value.s == '\0')
890 p->s[strcspn(p->s, "\r\n")] = '\0';
891 o = CAST(uint32_t, (ms->offset + strlen(p->s)));
892 if (m->type == FILE_PSTRING) {
893 size_t l = file_pstring_length_size(ms, m);
894 if (l == FILE_BADSIZE)
895 return -1;
896 o += CAST(uint32_t, l);
897 }
898 }
899 break;
900
901 case FILE_DATE:
902 case FILE_BEDATE:
903 case FILE_LEDATE:
904 case FILE_MEDATE:
905 o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
906 break;
907
908 case FILE_LDATE:
909 case FILE_BELDATE:
910 case FILE_LELDATE:
911 case FILE_MELDATE:
912 o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
913 break;
914
915 case FILE_QDATE:
916 case FILE_BEQDATE:
917 case FILE_LEQDATE:
918 o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
919 break;
920
921 case FILE_QLDATE:
922 case FILE_BEQLDATE:
923 case FILE_LEQLDATE:
924 o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
925 break;
926
927 case FILE_FLOAT:
928 case FILE_BEFLOAT:
929 case FILE_LEFLOAT:
930 o = CAST(int32_t, (ms->offset + sizeof(float)));
931 break;
932
933 case FILE_DOUBLE:
934 case FILE_BEDOUBLE:
935 case FILE_LEDOUBLE:
936 o = CAST(int32_t, (ms->offset + sizeof(double)));
937 break;
938
939 case FILE_REGEX:
940 if ((m->str_flags & REGEX_OFFSET_START) != 0)
941 o = CAST(int32_t, ms->search.offset);
942 else
943 o = CAST(int32_t,
944 (ms->search.offset + ms->search.rm_len));
945 break;
946
947 case FILE_SEARCH:
948 if ((m->str_flags & REGEX_OFFSET_START) != 0)
949 o = CAST(int32_t, ms->search.offset);
950 else
951 o = CAST(int32_t, (ms->search.offset + m->vallen));
952 break;
953
954 case FILE_CLEAR:
955 case FILE_DEFAULT:
956 case FILE_INDIRECT:
957 case FILE_OFFSET:
958 case FILE_USE:
959 o = ms->offset;
960 break;
961
962 case FILE_DER:
963 o = der_offs(ms, m, nbytes);
964 if (o == -1 || CAST(size_t, o) > nbytes) {
965 if ((ms->flags & MAGIC_DEBUG) != 0) {
966 (void)fprintf(stderr,
967 "Bad DER offset %d nbytes=%"
968 SIZE_T_FORMAT "u", o, nbytes);
969 }
970 *op = 0;
971 return 0;
972 }
973 break;
974
975 case FILE_GUID:
976 o = CAST(int32_t, (ms->offset + 2 * sizeof(uint64_t)));
977 break;
978
979 default:
980 o = 0;
981 break;
982 }
983
984 if (CAST(size_t, o) > nbytes) {
985 #if 0
986 file_error(ms, 0, "Offset out of range %" SIZE_T_FORMAT
987 "u > %" SIZE_T_FORMAT "u", (size_t)o, nbytes);
988 #endif
989 return -1;
990 }
991 *op = o;
992 return 1;
993 }
994
995 file_private uint32_t
cvt_id3(struct magic_set * ms,uint32_t v)996 cvt_id3(struct magic_set *ms, uint32_t v)
997 {
998 v = ((((v >> 0) & 0x7f) << 0) |
999 (((v >> 8) & 0x7f) << 7) |
1000 (((v >> 16) & 0x7f) << 14) |
1001 (((v >> 24) & 0x7f) << 21));
1002 if ((ms->flags & MAGIC_DEBUG) != 0)
1003 fprintf(stderr, "id3 offs=%u\n", v);
1004 return v;
1005 }
1006
1007 file_private int
cvt_flip(int type,int flip)1008 cvt_flip(int type, int flip)
1009 {
1010 if (flip == 0)
1011 return type;
1012 switch (type) {
1013 case FILE_BESHORT:
1014 return FILE_LESHORT;
1015 case FILE_BELONG:
1016 return FILE_LELONG;
1017 case FILE_BEDATE:
1018 return FILE_LEDATE;
1019 case FILE_BELDATE:
1020 return FILE_LELDATE;
1021 case FILE_BEQUAD:
1022 return FILE_LEQUAD;
1023 case FILE_BEQDATE:
1024 return FILE_LEQDATE;
1025 case FILE_BEQLDATE:
1026 return FILE_LEQLDATE;
1027 case FILE_BEQWDATE:
1028 return FILE_LEQWDATE;
1029 case FILE_LESHORT:
1030 return FILE_BESHORT;
1031 case FILE_LELONG:
1032 return FILE_BELONG;
1033 case FILE_LEDATE:
1034 return FILE_BEDATE;
1035 case FILE_LELDATE:
1036 return FILE_BELDATE;
1037 case FILE_LEQUAD:
1038 return FILE_BEQUAD;
1039 case FILE_LEQDATE:
1040 return FILE_BEQDATE;
1041 case FILE_LEQLDATE:
1042 return FILE_BEQLDATE;
1043 case FILE_LEQWDATE:
1044 return FILE_BEQWDATE;
1045 case FILE_BEFLOAT:
1046 return FILE_LEFLOAT;
1047 case FILE_LEFLOAT:
1048 return FILE_BEFLOAT;
1049 case FILE_BEDOUBLE:
1050 return FILE_LEDOUBLE;
1051 case FILE_LEDOUBLE:
1052 return FILE_BEDOUBLE;
1053 default:
1054 return type;
1055 }
1056 }
1057 #define DO_CVT(fld, type) \
1058 if (m->num_mask) \
1059 switch (m->mask_op & FILE_OPS_MASK) { \
1060 case FILE_OPAND: \
1061 p->fld &= CAST(type, m->num_mask); \
1062 break; \
1063 case FILE_OPOR: \
1064 p->fld |= CAST(type, m->num_mask); \
1065 break; \
1066 case FILE_OPXOR: \
1067 p->fld ^= CAST(type, m->num_mask); \
1068 break; \
1069 case FILE_OPADD: \
1070 p->fld += CAST(type, m->num_mask); \
1071 break; \
1072 case FILE_OPMINUS: \
1073 p->fld -= CAST(type, m->num_mask); \
1074 break; \
1075 case FILE_OPMULTIPLY: \
1076 p->fld *= CAST(type, m->num_mask); \
1077 break; \
1078 case FILE_OPDIVIDE: \
1079 if (CAST(type, m->num_mask) == 0) \
1080 return -1; \
1081 p->fld /= CAST(type, m->num_mask); \
1082 break; \
1083 case FILE_OPMODULO: \
1084 if (CAST(type, m->num_mask) == 0) \
1085 return -1; \
1086 p->fld %= CAST(type, m->num_mask); \
1087 break; \
1088 } \
1089 if (m->mask_op & FILE_OPINVERSE) \
1090 p->fld = ~p->fld \
1091
1092 file_private int
cvt_8(union VALUETYPE * p,const struct magic * m)1093 cvt_8(union VALUETYPE *p, const struct magic *m)
1094 {
1095 DO_CVT(b, uint8_t);
1096 return 0;
1097 }
1098
1099 file_private int
cvt_16(union VALUETYPE * p,const struct magic * m)1100 cvt_16(union VALUETYPE *p, const struct magic *m)
1101 {
1102 DO_CVT(h, uint16_t);
1103 return 0;
1104 }
1105
1106 file_private int
cvt_32(union VALUETYPE * p,const struct magic * m)1107 cvt_32(union VALUETYPE *p, const struct magic *m)
1108 {
1109 DO_CVT(l, uint32_t);
1110 return 0;
1111 }
1112
1113 file_private int
cvt_64(union VALUETYPE * p,const struct magic * m)1114 cvt_64(union VALUETYPE *p, const struct magic *m)
1115 {
1116 DO_CVT(q, uint64_t);
1117 return 0;
1118 }
1119
1120 #define DO_CVT2(fld, type) \
1121 if (m->num_mask) \
1122 switch (m->mask_op & FILE_OPS_MASK) { \
1123 case FILE_OPADD: \
1124 p->fld += CAST(type, m->num_mask); \
1125 break; \
1126 case FILE_OPMINUS: \
1127 p->fld -= CAST(type, m->num_mask); \
1128 break; \
1129 case FILE_OPMULTIPLY: \
1130 p->fld *= CAST(type, m->num_mask); \
1131 break; \
1132 case FILE_OPDIVIDE: \
1133 if (CAST(type, m->num_mask) == 0) \
1134 return -1; \
1135 p->fld /= CAST(type, m->num_mask); \
1136 break; \
1137 } \
1138
1139 file_private int
cvt_float(union VALUETYPE * p,const struct magic * m)1140 cvt_float(union VALUETYPE *p, const struct magic *m)
1141 {
1142 DO_CVT2(f, float);
1143 return 0;
1144 }
1145
1146 file_private int
cvt_double(union VALUETYPE * p,const struct magic * m)1147 cvt_double(union VALUETYPE *p, const struct magic *m)
1148 {
1149 DO_CVT2(d, double);
1150 return 0;
1151 }
1152
1153 /*
1154 * Convert the byte order of the data we are looking at
1155 * While we're here, let's apply the mask operation
1156 * (unless you have a better idea)
1157 */
1158 file_private int
mconvert(struct magic_set * ms,struct magic * m,int flip)1159 mconvert(struct magic_set *ms, struct magic *m, int flip)
1160 {
1161 union VALUETYPE *p = &ms->ms_value;
1162
1163 switch (cvt_flip(m->type, flip)) {
1164 case FILE_BYTE:
1165 if (cvt_8(p, m) == -1)
1166 goto out;
1167 return 1;
1168 case FILE_SHORT:
1169 case FILE_MSDOSDATE:
1170 case FILE_LEMSDOSDATE:
1171 case FILE_BEMSDOSDATE:
1172 case FILE_MSDOSTIME:
1173 case FILE_LEMSDOSTIME:
1174 case FILE_BEMSDOSTIME:
1175 if (cvt_16(p, m) == -1)
1176 goto out;
1177 return 1;
1178 case FILE_LONG:
1179 case FILE_DATE:
1180 case FILE_LDATE:
1181 if (cvt_32(p, m) == -1)
1182 goto out;
1183 return 1;
1184 case FILE_QUAD:
1185 case FILE_QDATE:
1186 case FILE_QLDATE:
1187 case FILE_QWDATE:
1188 case FILE_OFFSET:
1189 if (cvt_64(p, m) == -1)
1190 goto out;
1191 return 1;
1192 case FILE_STRING:
1193 case FILE_BESTRING16:
1194 case FILE_LESTRING16:
1195 case FILE_OCTAL: {
1196 /* Null terminate and eat *trailing* return */
1197 p->s[sizeof(p->s) - 1] = '\0';
1198 return 1;
1199 }
1200 case FILE_PSTRING: {
1201 char *ptr1, *ptr2;
1202 size_t len, sz = file_pstring_length_size(ms, m);
1203 if (sz == FILE_BADSIZE)
1204 return 0;
1205 ptr1 = p->s;
1206 ptr2 = ptr1 + sz;
1207 len = file_pstring_get_length(ms, m, ptr1);
1208 if (len == FILE_BADSIZE)
1209 return 0;
1210 sz = sizeof(p->s) - sz; /* maximum length of string */
1211 if (len >= sz) {
1212 /*
1213 * The size of the pascal string length (sz)
1214 * is 1, 2, or 4. We need at least 1 byte for NUL
1215 * termination, but we've already truncated the
1216 * string by p->s, so we need to deduct sz.
1217 * Because we can use one of the bytes of the length
1218 * after we shifted as NUL termination.
1219 */
1220 len = sz;
1221 }
1222 while (len--)
1223 *ptr1++ = *ptr2++;
1224 *ptr1 = '\0';
1225 return 1;
1226 }
1227 case FILE_BESHORT:
1228 p->h = CAST(short, BE16(p));
1229 if (cvt_16(p, m) == -1)
1230 goto out;
1231 return 1;
1232 case FILE_BELONG:
1233 case FILE_BEDATE:
1234 case FILE_BELDATE:
1235 p->l = CAST(int32_t, BE32(p));
1236 if (cvt_32(p, m) == -1)
1237 goto out;
1238 return 1;
1239 case FILE_BEQUAD:
1240 case FILE_BEQDATE:
1241 case FILE_BEQLDATE:
1242 case FILE_BEQWDATE:
1243 p->q = CAST(uint64_t, BE64(p));
1244 if (cvt_64(p, m) == -1)
1245 goto out;
1246 return 1;
1247 case FILE_LESHORT:
1248 p->h = CAST(short, LE16(p));
1249 if (cvt_16(p, m) == -1)
1250 goto out;
1251 return 1;
1252 case FILE_LELONG:
1253 case FILE_LEDATE:
1254 case FILE_LELDATE:
1255 p->l = CAST(int32_t, LE32(p));
1256 if (cvt_32(p, m) == -1)
1257 goto out;
1258 return 1;
1259 case FILE_LEQUAD:
1260 case FILE_LEQDATE:
1261 case FILE_LEQLDATE:
1262 case FILE_LEQWDATE:
1263 p->q = CAST(uint64_t, LE64(p));
1264 if (cvt_64(p, m) == -1)
1265 goto out;
1266 return 1;
1267 case FILE_MELONG:
1268 case FILE_MEDATE:
1269 case FILE_MELDATE:
1270 p->l = CAST(int32_t, ME32(p));
1271 if (cvt_32(p, m) == -1)
1272 goto out;
1273 return 1;
1274 case FILE_FLOAT:
1275 if (cvt_float(p, m) == -1)
1276 goto out;
1277 return 1;
1278 case FILE_BEFLOAT:
1279 p->l = BE32(p);
1280 if (cvt_float(p, m) == -1)
1281 goto out;
1282 return 1;
1283 case FILE_LEFLOAT:
1284 p->l = LE32(p);
1285 if (cvt_float(p, m) == -1)
1286 goto out;
1287 return 1;
1288 case FILE_DOUBLE:
1289 if (cvt_double(p, m) == -1)
1290 goto out;
1291 return 1;
1292 case FILE_BEDOUBLE:
1293 p->q = BE64(p);
1294 if (cvt_double(p, m) == -1)
1295 goto out;
1296 return 1;
1297 case FILE_LEDOUBLE:
1298 p->q = LE64(p);
1299 if (cvt_double(p, m) == -1)
1300 goto out;
1301 return 1;
1302 case FILE_REGEX:
1303 case FILE_SEARCH:
1304 case FILE_DEFAULT:
1305 case FILE_CLEAR:
1306 case FILE_NAME:
1307 case FILE_USE:
1308 case FILE_DER:
1309 case FILE_GUID:
1310 return 1;
1311 default:
1312 file_magerror(ms, "invalid type %d in mconvert()", m->type);
1313 return 0;
1314 }
1315 out:
1316 file_magerror(ms, "zerodivide in mconvert()");
1317 return 0;
1318 }
1319
1320
1321 file_private void
mdebug(uint32_t offset,const char * str,size_t len)1322 mdebug(uint32_t offset, const char *str, size_t len)
1323 {
1324 (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1325 file_showstr(stderr, str, len);
1326 (void) fputc('\n', stderr);
1327 (void) fputc('\n', stderr);
1328 }
1329
1330 file_private int
mcopy(struct magic_set * ms,union VALUETYPE * p,int type,int indir,const unsigned char * s,uint32_t offset,size_t nbytes,struct magic * m)1331 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1332 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1333 {
1334 size_t size = sizeof(*p);
1335 /*
1336 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1337 * anything, but setup pointers into the source
1338 */
1339 if (indir == 0) {
1340 switch (type) {
1341 case FILE_DER:
1342 case FILE_SEARCH:
1343 if (offset > nbytes)
1344 offset = CAST(uint32_t, nbytes);
1345 ms->search.s = RCAST(const char *, s) + offset;
1346 ms->search.s_len = nbytes - offset;
1347 ms->search.offset = offset;
1348 return 0;
1349
1350 case FILE_REGEX: {
1351 const char *b;
1352 const char *c;
1353 const char *last; /* end of search region */
1354 const char *buf; /* start of search region */
1355 const char *end;
1356 size_t lines, linecnt, bytecnt;
1357
1358 if (s == NULL || nbytes < offset) {
1359 ms->search.s_len = 0;
1360 ms->search.s = NULL;
1361 return 0;
1362 }
1363
1364 if (m->str_flags & REGEX_LINE_COUNT) {
1365 linecnt = m->str_range;
1366 bytecnt = linecnt * 80;
1367 } else {
1368 linecnt = 0;
1369 bytecnt = m->str_range;
1370 }
1371
1372 if (bytecnt == 0 || bytecnt > nbytes - offset)
1373 bytecnt = nbytes - offset;
1374 if (bytecnt > ms->regex_max)
1375 bytecnt = ms->regex_max;
1376
1377 buf = RCAST(const char *, s) + offset;
1378 end = last = RCAST(const char *, s) + bytecnt + offset;
1379 /* mget() guarantees buf <= last */
1380 for (lines = linecnt, b = buf; lines && b < end &&
1381 ((b = CAST(const char *,
1382 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1383 || (b = CAST(const char *,
1384 memchr(c, '\r', CAST(size_t, (end - c))))));
1385 lines--, b++) {
1386 if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1387 b++;
1388 if (b < end - 1 && b[0] == '\n')
1389 b++;
1390 last = b;
1391 }
1392 if (lines)
1393 last = end;
1394
1395 ms->search.s = buf;
1396 ms->search.s_len = last - buf;
1397 ms->search.offset = offset;
1398 ms->search.rm_len = 0;
1399 return 0;
1400 }
1401 case FILE_BESTRING16:
1402 case FILE_LESTRING16: {
1403 const unsigned char *src = s + offset;
1404 const unsigned char *esrc = s + nbytes;
1405 char *dst = p->s;
1406 char *edst = &p->s[sizeof(p->s) - 1];
1407
1408 if (type == FILE_BESTRING16)
1409 src++;
1410
1411 /* check that offset is within range */
1412 if (offset >= nbytes)
1413 break;
1414 for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1415 if (dst < edst)
1416 *dst = *src;
1417 else
1418 break;
1419 if (*dst == '\0') {
1420 if (type == FILE_BESTRING16 ?
1421 *(src - 1) != '\0' :
1422 ((src + 1 < esrc) &&
1423 *(src + 1) != '\0'))
1424 *dst = ' ';
1425 }
1426 }
1427 *edst = '\0';
1428 return 0;
1429 }
1430 case FILE_STRING: /* XXX - these two should not need */
1431 case FILE_PSTRING: /* to copy anything, but do anyway. */
1432 if (m->str_range != 0 && m->str_range < sizeof(*p))
1433 size = m->str_range;
1434 break;
1435 default:
1436 break;
1437 }
1438 }
1439
1440 if (type == FILE_OFFSET) {
1441 (void)memset(p, '\0', sizeof(*p));
1442 p->q = offset;
1443 return 0;
1444 }
1445
1446 if (offset >= nbytes) {
1447 (void)memset(p, '\0', sizeof(*p));
1448 return 0;
1449 }
1450 if (nbytes - offset < size)
1451 nbytes = nbytes - offset;
1452 else
1453 nbytes = size;
1454
1455 (void)memcpy(p, s + offset, nbytes);
1456
1457 /*
1458 * the usefulness of padding with zeroes eludes me, it
1459 * might even cause problems
1460 */
1461 if (nbytes < sizeof(*p))
1462 (void)memset(RCAST(char *, RCAST(void *, p)) + nbytes, '\0',
1463 sizeof(*p) - nbytes);
1464 return 0;
1465 }
1466
1467 file_private int
do_ops(struct magic_set * ms,struct magic * m,uint32_t * rv,intmax_t lhs,intmax_t off)1468 do_ops(struct magic_set *ms, struct magic *m, uint32_t *rv, intmax_t lhs,
1469 intmax_t off)
1470 {
1471 intmax_t offset;
1472 // On purpose not INTMAX_MAX
1473 if (lhs >= UINT_MAX || lhs <= INT_MIN ||
1474 off >= UINT_MAX || off <= INT_MIN) {
1475 if ((ms->flags & MAGIC_DEBUG) != 0)
1476 fprintf(stderr, "lhs/off overflow %jd %jd\n", lhs, off);
1477 return 1;
1478 }
1479
1480 if (off) {
1481 switch (m->in_op & FILE_OPS_MASK) {
1482 case FILE_OPAND:
1483 offset = lhs & off;
1484 break;
1485 case FILE_OPOR:
1486 offset = lhs | off;
1487 break;
1488 case FILE_OPXOR:
1489 offset = lhs ^ off;
1490 break;
1491 case FILE_OPADD:
1492 offset = lhs + off;
1493 break;
1494 case FILE_OPMINUS:
1495 offset = lhs - off;
1496 break;
1497 case FILE_OPMULTIPLY:
1498 offset = lhs * off;
1499 break;
1500 case FILE_OPDIVIDE:
1501 offset = lhs / off;
1502 break;
1503 case FILE_OPMODULO:
1504 offset = lhs % off;
1505 break;
1506 }
1507 } else
1508 offset = lhs;
1509 if (m->in_op & FILE_OPINVERSE)
1510 offset = ~offset;
1511 if (offset >= UINT_MAX) {
1512 if ((ms->flags & MAGIC_DEBUG) != 0)
1513 fprintf(stderr, "offset overflow %jd\n", offset);
1514 return 1;
1515 }
1516 *rv = CAST(uint32_t, offset);
1517 return 0;
1518 }
1519
1520 file_private int
msetoffset(struct magic_set * ms,struct magic * m,struct buffer * bb,const struct buffer * b,size_t o,unsigned int cont_level)1521 msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
1522 const struct buffer *b, size_t o, unsigned int cont_level)
1523 {
1524 int32_t offset;
1525 if (m->flag & OFFNEGATIVE) {
1526 offset = -m->offset;
1527 if (cont_level > 0) {
1528 if (m->flag & (OFFADD|INDIROFFADD))
1529 goto normal;
1530 #if 0
1531 file_error(ms, 0, "negative offset %d at continuation"
1532 "level %u", m->offset, cont_level);
1533 return -1;
1534 #endif
1535 }
1536 if (buffer_fill(b) == -1)
1537 return -1;
1538 if (o != 0) {
1539 // Not yet!
1540 file_magerror(ms, "non zero offset %" SIZE_T_FORMAT
1541 "u at level %u", o, cont_level);
1542 return -1;
1543 }
1544 if (CAST(size_t, m->offset) > b->elen)
1545 return -1;
1546 buffer_init(bb, -1, NULL, b->ebuf, b->elen);
1547 ms->eoffset = ms->offset = CAST(int32_t, b->elen - m->offset);
1548 } else {
1549 offset = m->offset;
1550 if (cont_level == 0) {
1551 normal:
1552 // XXX: Pass real fd, then who frees bb?
1553 buffer_init(bb, -1, NULL, b->fbuf, b->flen);
1554 ms->offset = offset;
1555 ms->eoffset = 0;
1556 } else {
1557 ms->offset = ms->eoffset + offset;
1558 }
1559 }
1560 if ((ms->flags & MAGIC_DEBUG) != 0) {
1561 fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u,%"
1562 SIZE_T_FORMAT "u], %d [b=%p,%"
1563 SIZE_T_FORMAT "u,%" SIZE_T_FORMAT "u], [o=%#x, c=%d]\n",
1564 bb->fbuf, bb->flen, bb->elen, ms->offset, b->fbuf,
1565 b->flen, b->elen, offset, cont_level);
1566 }
1567 return 0;
1568 }
1569
1570 file_private int
save_cont(struct magic_set * ms,struct cont * c)1571 save_cont(struct magic_set *ms, struct cont *c)
1572 {
1573 size_t len;
1574 *c = ms->c;
1575 len = c->len * sizeof(*c->li);
1576 ms->c.li = CAST(struct level_info *, emalloc(len));
1577 if (ms->c.li == NULL) {
1578 ms->c = *c;
1579 return -1;
1580 }
1581 memcpy(ms->c.li, c->li, len);
1582 return 0;
1583 }
1584
1585 file_private void
restore_cont(struct magic_set * ms,struct cont * c)1586 restore_cont(struct magic_set *ms, struct cont *c)
1587 {
1588 efree(ms->c.li);
1589 ms->c = *c;
1590 }
1591
1592 file_private int
mget(struct magic_set * ms,struct magic * m,const struct buffer * b,const unsigned char * s,size_t nbytes,size_t o,unsigned int cont_level,int mode,int text,int flip,uint16_t * indir_count,uint16_t * name_count,int * printed_something,int * need_separator,int * firstline,int * returnval,int * found_match)1593 mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
1594 const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level,
1595 int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count,
1596 int *printed_something, int *need_separator, int *firstline, int *returnval,
1597 int *found_match)
1598 {
1599 uint32_t eoffset, offset = ms->offset;
1600 struct buffer bb;
1601 intmax_t lhs;
1602 file_pushbuf_t *pb;
1603 int rv, oneed_separator, in_type, nfound_match;
1604 char *rbuf;
1605 union VALUETYPE *p = &ms->ms_value;
1606 struct mlist ml, *mlp;
1607 struct cont c;
1608
1609 if (*indir_count >= ms->indir_max) {
1610 file_error(ms, 0, "indirect count (%hu) exceeded",
1611 *indir_count);
1612 return -1;
1613 }
1614
1615 if (*name_count >= ms->name_max) {
1616 file_error(ms, 0, "name use count (%hu) exceeded",
1617 *name_count);
1618 return -1;
1619 }
1620
1621
1622
1623 if (mcopy(ms, p, m->type, m->flag & INDIR, s,
1624 CAST(uint32_t, offset + o), CAST(uint32_t, nbytes), m) == -1)
1625 return -1;
1626
1627 if ((ms->flags & MAGIC_DEBUG) != 0) {
1628 fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1629 SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1630 "u, il=%hu, nc=%hu)\n",
1631 m->type, m->flag, offset, o, nbytes,
1632 *indir_count, *name_count);
1633 mdebug(offset, RCAST(char *, RCAST(void *, p)),
1634 sizeof(union VALUETYPE));
1635 #ifndef COMPILE_ONLY
1636 file_mdump(m);
1637 #endif
1638 }
1639
1640 if (m->flag & INDIR) {
1641 intmax_t off = m->in_offset;
1642 const int sgn = m->in_op & FILE_OPSIGNED;
1643 if (m->in_op & FILE_OPINDIRECT) {
1644 const union VALUETYPE *q = CAST(const union VALUETYPE *,
1645 RCAST(const void *, s + offset + off));
1646 int op;
1647 switch (op = cvt_flip(m->in_type, flip)) {
1648 case FILE_BYTE:
1649 if (OFFSET_OOB(nbytes, offset + off, 1))
1650 return 0;
1651 off = SEXT(sgn,8,q->b);
1652 break;
1653 case FILE_SHORT:
1654 if (OFFSET_OOB(nbytes, offset + off, 2))
1655 return 0;
1656 off = SEXT(sgn,16,q->h);
1657 break;
1658 case FILE_BESHORT:
1659 if (OFFSET_OOB(nbytes, offset + off, 2))
1660 return 0;
1661 off = SEXT(sgn,16,BE16(q));
1662 break;
1663 case FILE_LESHORT:
1664 if (OFFSET_OOB(nbytes, offset + off, 2))
1665 return 0;
1666 off = SEXT(sgn,16,LE16(q));
1667 break;
1668 case FILE_LONG:
1669 if (OFFSET_OOB(nbytes, offset + off, 4))
1670 return 0;
1671 off = SEXT(sgn,32,q->l);
1672 break;
1673 case FILE_BELONG:
1674 case FILE_BEID3:
1675 if (OFFSET_OOB(nbytes, offset + off, 4))
1676 return 0;
1677 off = SEXT(sgn,32,BE32(q));
1678 break;
1679 case FILE_LEID3:
1680 case FILE_LELONG:
1681 if (OFFSET_OOB(nbytes, offset + off, 4))
1682 return 0;
1683 off = SEXT(sgn,32,LE32(q));
1684 break;
1685 case FILE_MELONG:
1686 if (OFFSET_OOB(nbytes, offset + off, 4))
1687 return 0;
1688 off = SEXT(sgn,32,ME32(q));
1689 break;
1690 case FILE_BEQUAD:
1691 if (OFFSET_OOB(nbytes, offset + off, 8))
1692 return 0;
1693 off = SEXT(sgn,64,BE64(q));
1694 break;
1695 case FILE_LEQUAD:
1696 if (OFFSET_OOB(nbytes, offset + off, 8))
1697 return 0;
1698 off = SEXT(sgn,64,LE64(q));
1699 break;
1700 case FILE_OCTAL:
1701 if (OFFSET_OOB(nbytes, offset, m->vallen))
1702 return 0;
1703 off = SEXT(sgn,64,strtoull(p->s, NULL, 8));
1704 break;
1705 default:
1706 if ((ms->flags & MAGIC_DEBUG) != 0)
1707 fprintf(stderr, "bad op=%d\n", op);
1708 return 0;
1709 }
1710 if ((ms->flags & MAGIC_DEBUG) != 0)
1711 fprintf(stderr, "indirect offs=%jd\n", off);
1712 }
1713 switch (in_type = cvt_flip(m->in_type, flip)) {
1714 case FILE_BYTE:
1715 if (OFFSET_OOB(nbytes, offset, 1))
1716 return 0;
1717 if (do_ops(ms, m, &offset, SEXT(sgn,8,p->b), off))
1718 return 0;
1719 break;
1720 case FILE_BESHORT:
1721 if (OFFSET_OOB(nbytes, offset, 2))
1722 return 0;
1723 if (do_ops(ms, m, &offset, SEXT(sgn,16,BE16(p)), off))
1724 return 0;
1725 break;
1726 case FILE_LESHORT:
1727 if (OFFSET_OOB(nbytes, offset, 2))
1728 return 0;
1729 if (do_ops(ms, m, &offset, SEXT(sgn,16,LE16(p)), off))
1730 return 0;
1731 break;
1732 case FILE_SHORT:
1733 if (OFFSET_OOB(nbytes, offset, 2))
1734 return 0;
1735 if (do_ops(ms, m, &offset, SEXT(sgn,16,p->h), off))
1736 return 0;
1737 break;
1738 case FILE_BELONG:
1739 case FILE_BEID3:
1740 if (OFFSET_OOB(nbytes, offset, 4))
1741 return 0;
1742 lhs = BE32(p);
1743 if (in_type == FILE_BEID3)
1744 lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1745 if (do_ops(ms, m, &offset, SEXT(sgn,32,lhs), off))
1746 return 0;
1747 break;
1748 case FILE_LELONG:
1749 case FILE_LEID3:
1750 if (OFFSET_OOB(nbytes, offset, 4))
1751 return 0;
1752 lhs = LE32(p);
1753 if (in_type == FILE_LEID3)
1754 lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1755 if (do_ops(ms, m, &offset, SEXT(sgn,32,lhs), off))
1756 return 0;
1757 break;
1758 case FILE_MELONG:
1759 if (OFFSET_OOB(nbytes, offset, 4))
1760 return 0;
1761 if (do_ops(ms, m, &offset, SEXT(sgn,32,ME32(p)), off))
1762 return 0;
1763 break;
1764 case FILE_LONG:
1765 if (OFFSET_OOB(nbytes, offset, 4))
1766 return 0;
1767 if (do_ops(ms, m, &offset, SEXT(sgn,32,p->l), off))
1768 return 0;
1769 break;
1770 case FILE_LEQUAD:
1771 if (OFFSET_OOB(nbytes, offset, 8))
1772 return 0;
1773 if (do_ops(ms, m, &offset, SEXT(sgn,64,LE64(p)), off))
1774 return 0;
1775 break;
1776 case FILE_BEQUAD:
1777 if (OFFSET_OOB(nbytes, offset, 8))
1778 return 0;
1779 if (do_ops(ms, m, &offset, SEXT(sgn,64,BE64(p)), off))
1780 return 0;
1781 break;
1782 case FILE_OCTAL:
1783 if (OFFSET_OOB(nbytes, offset, m->vallen))
1784 return 0;
1785 if(do_ops(ms, m, &offset,
1786 SEXT(sgn,64,strtoull(p->s, NULL, 8)), off))
1787 return 0;
1788 break;
1789 default:
1790 if ((ms->flags & MAGIC_DEBUG) != 0)
1791 fprintf(stderr, "bad in_type=%d\n", in_type);
1792 return 0;
1793 }
1794
1795 if (m->flag & INDIROFFADD) {
1796 if (cont_level == 0) {
1797 if ((ms->flags & MAGIC_DEBUG) != 0)
1798 fprintf(stderr,
1799 "indirect *zero* cont_level\n");
1800 return 0;
1801 }
1802 offset += ms->c.li[cont_level - 1].off;
1803 if (offset == 0) {
1804 if ((ms->flags & MAGIC_DEBUG) != 0)
1805 fprintf(stderr,
1806 "indirect *zero* offset\n");
1807 return 0;
1808 }
1809 if ((ms->flags & MAGIC_DEBUG) != 0)
1810 fprintf(stderr, "indirect +offs=%u\n", offset);
1811 }
1812 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1813 return -1;
1814 ms->offset = offset;
1815
1816 if ((ms->flags & MAGIC_DEBUG) != 0) {
1817 mdebug(offset, RCAST(char *, RCAST(void *, p)),
1818 sizeof(union VALUETYPE));
1819 #ifndef COMPILE_ONLY
1820 file_mdump(m);
1821 #endif
1822 }
1823 }
1824
1825 /* Verify we have enough data to match magic type */
1826 switch (m->type) {
1827 case FILE_BYTE:
1828 if (OFFSET_OOB(nbytes, offset, 1))
1829 return 0;
1830 break;
1831
1832 case FILE_SHORT:
1833 case FILE_BESHORT:
1834 case FILE_LESHORT:
1835 if (OFFSET_OOB(nbytes, offset, 2))
1836 return 0;
1837 break;
1838
1839 case FILE_LONG:
1840 case FILE_BELONG:
1841 case FILE_LELONG:
1842 case FILE_MELONG:
1843 case FILE_DATE:
1844 case FILE_BEDATE:
1845 case FILE_LEDATE:
1846 case FILE_MEDATE:
1847 case FILE_LDATE:
1848 case FILE_BELDATE:
1849 case FILE_LELDATE:
1850 case FILE_MELDATE:
1851 case FILE_FLOAT:
1852 case FILE_BEFLOAT:
1853 case FILE_LEFLOAT:
1854 if (OFFSET_OOB(nbytes, offset, 4))
1855 return 0;
1856 break;
1857
1858 case FILE_DOUBLE:
1859 case FILE_BEDOUBLE:
1860 case FILE_LEDOUBLE:
1861 if (OFFSET_OOB(nbytes, offset, 8))
1862 return 0;
1863 break;
1864
1865 case FILE_GUID:
1866 if (OFFSET_OOB(nbytes, offset, 16))
1867 return 0;
1868 break;
1869
1870 case FILE_STRING:
1871 case FILE_PSTRING:
1872 case FILE_SEARCH:
1873 case FILE_OCTAL:
1874 if (OFFSET_OOB(nbytes, offset, m->vallen))
1875 return 0;
1876 break;
1877
1878 case FILE_REGEX:
1879 if (nbytes < offset)
1880 return 0;
1881 break;
1882
1883 case FILE_INDIRECT:
1884 if (m->str_flags & INDIRECT_RELATIVE)
1885 offset += CAST(uint32_t, o);
1886 if (offset == 0)
1887 return 0;
1888
1889 if (nbytes < offset)
1890 return 0;
1891
1892 if ((pb = file_push_buffer(ms)) == NULL)
1893 return -1;
1894
1895 (*indir_count)++;
1896 bb = *b;
1897 bb.fbuf = s + offset;
1898 bb.flen = nbytes - offset;
1899 bb.ebuf = NULL;
1900 bb.elen = 0;
1901 rv = -1;
1902 for (mlp = ms->mlist[0]->next; mlp != ms->mlist[0];
1903 mlp = mlp->next)
1904 {
1905 if ((rv = match(ms, mlp->magic,
1906 mlp->nmagic, &bb, 0, BINTEST, text, 0, indir_count,
1907 name_count, printed_something, need_separator,
1908 firstline, NULL, NULL)) != 0)
1909 break;
1910 }
1911 buffer_fini(&bb);
1912
1913 if ((ms->flags & MAGIC_DEBUG) != 0)
1914 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1915
1916 rbuf = file_pop_buffer(ms, pb);
1917 if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1918 return -1;
1919
1920 if (rv == 1) {
1921 if ((ms->flags & MAGIC_NODESC) == 0 &&
1922 file_printf(ms, F(ms, m->desc, "%u"), offset) == -1)
1923 {
1924 if (rbuf) efree(rbuf);
1925 return -1;
1926 }
1927 if (file_printf(ms, "%s", rbuf) == -1) {
1928 if (rbuf) efree(rbuf);
1929 return -1;
1930 }
1931 }
1932 if (rbuf) efree(rbuf);
1933 return rv;
1934
1935 case FILE_USE:
1936 if (nbytes < offset)
1937 return 0;
1938 rbuf = m->value.s;
1939 if (*rbuf == '^') {
1940 rbuf++;
1941 flip = !flip;
1942 }
1943 if (file_magicfind(ms, rbuf, &ml) == -1) {
1944 file_error(ms, 0, "cannot find entry `%s'", rbuf);
1945 return -1;
1946 }
1947 if (save_cont(ms, &c) == -1) {
1948 file_error(ms, errno, "can't allocate continuation");
1949 return -1;
1950 }
1951
1952 oneed_separator = *need_separator;
1953 if (m->flag & NOSPACE)
1954 *need_separator = 0;
1955
1956 nfound_match = 0;
1957 (*name_count)++;
1958 eoffset = ms->eoffset;
1959 rv = match(ms, ml.magic, ml.nmagic, b,
1960 offset + o, mode, text, flip, indir_count, name_count,
1961 printed_something, need_separator, firstline, returnval,
1962 &nfound_match);
1963 ms->ms_value.q = nfound_match;
1964 (*name_count)--;
1965 *found_match |= nfound_match;
1966
1967 restore_cont(ms, &c);
1968
1969 if (rv != 1)
1970 *need_separator = oneed_separator;
1971 ms->offset = offset;
1972 ms->eoffset = eoffset;
1973 return rv || *found_match;
1974
1975 case FILE_NAME:
1976 if (ms->flags & MAGIC_NODESC)
1977 return 1;
1978 if (file_printf(ms, "%s", m->desc) == -1)
1979 return -1;
1980 return 1;
1981 case FILE_DER:
1982 case FILE_DEFAULT: /* nothing to check */
1983 case FILE_CLEAR:
1984 default:
1985 break;
1986 }
1987 if (!mconvert(ms, m, flip))
1988 return 0;
1989 return 1;
1990 }
1991
1992 file_private uint64_t
file_strncmp(const char * s1,const char * s2,size_t len,size_t maxlen,uint32_t flags)1993 file_strncmp(const char *s1, const char *s2, size_t len, size_t maxlen,
1994 uint32_t flags)
1995 {
1996 /*
1997 * Convert the source args to unsigned here so that (1) the
1998 * compare will be unsigned as it is in strncmp() and (2) so
1999 * the ctype functions will work correctly without extra
2000 * casting.
2001 */
2002 const unsigned char *a = RCAST(const unsigned char *, s1);
2003 const unsigned char *b = RCAST(const unsigned char *, s2);
2004 uint32_t ws = flags & (STRING_COMPACT_WHITESPACE |
2005 STRING_COMPACT_OPTIONAL_WHITESPACE);
2006 const unsigned char *eb = b + (ws ? maxlen : len);
2007 uint64_t v;
2008
2009 /*
2010 * What we want here is v = strncmp(s1, s2, len),
2011 * but ignoring any nulls.
2012 */
2013 v = 0;
2014 len++;
2015 if (0L == flags) { /* normal string: do it fast */
2016 while (--len > 0)
2017 if ((v = *b++ - *a++) != '\0')
2018 break;
2019 }
2020 else { /* combine the others */
2021 while (--len > 0) {
2022 if (b >= eb) {
2023 v = 1;
2024 break;
2025 }
2026 if ((flags & STRING_IGNORE_LOWERCASE) &&
2027 islower(*a)) {
2028 if ((v = tolower(*b++) - *a++) != '\0')
2029 break;
2030 }
2031 else if ((flags & STRING_IGNORE_UPPERCASE) &&
2032 isupper(*a)) {
2033 if ((v = toupper(*b++) - *a++) != '\0')
2034 break;
2035 }
2036 else if ((flags & STRING_COMPACT_WHITESPACE) &&
2037 isspace(*a)) {
2038 /* XXX Dirty. The data and the pattern is what is causing this.
2039 Revert _i for the next port and see if it still matters. */
2040 uint32_t _i = 0;
2041 a++;
2042 if (isspace(*b++)) {
2043 if (!isspace(*a))
2044 while (EXPECTED(_i++ < 2048) && b < eb && isspace(*b))
2045 b++;
2046 }
2047 else {
2048 v = 1;
2049 break;
2050 }
2051 }
2052 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
2053 isspace(*a)) {
2054 a++;
2055 while (b < eb && isspace(*b))
2056 b++;
2057 }
2058 else {
2059 if ((v = *b++ - *a++) != '\0')
2060 break;
2061 }
2062 }
2063 if (len == 0 && v == 0 && (flags & STRING_FULL_WORD)) {
2064 if (*b && !isspace(*b))
2065 v = 1;
2066 }
2067 }
2068 return v;
2069 }
2070
2071 file_private uint64_t
file_strncmp16(const char * a,const char * b,size_t len,size_t maxlen,uint32_t flags)2072 file_strncmp16(const char *a, const char *b, size_t len, size_t maxlen,
2073 uint32_t flags)
2074 {
2075 /*
2076 * XXX - The 16-bit string compare probably needs to be done
2077 * differently, especially if the flags are to be supported.
2078 * At the moment, I am unsure.
2079 */
2080 flags = 0;
2081 return file_strncmp(a, b, len, maxlen, flags);
2082 }
2083
2084 file_private int
magiccheck(struct magic_set * ms,struct magic * m)2085 magiccheck(struct magic_set *ms, struct magic *m)
2086 {
2087 uint64_t l = m->value.q;
2088 uint64_t v;
2089 float fl, fv;
2090 double dl, dv;
2091 int matched;
2092 union VALUETYPE *p = &ms->ms_value;
2093
2094 switch (m->type) {
2095 case FILE_BYTE:
2096 v = p->b;
2097 break;
2098
2099 case FILE_SHORT:
2100 case FILE_BESHORT:
2101 case FILE_LESHORT:
2102 case FILE_MSDOSDATE:
2103 case FILE_LEMSDOSDATE:
2104 case FILE_BEMSDOSDATE:
2105 case FILE_MSDOSTIME:
2106 case FILE_LEMSDOSTIME:
2107 case FILE_BEMSDOSTIME:
2108 v = p->h;
2109 break;
2110
2111 case FILE_LONG:
2112 case FILE_BELONG:
2113 case FILE_LELONG:
2114 case FILE_MELONG:
2115 case FILE_DATE:
2116 case FILE_BEDATE:
2117 case FILE_LEDATE:
2118 case FILE_MEDATE:
2119 case FILE_LDATE:
2120 case FILE_BELDATE:
2121 case FILE_LELDATE:
2122 case FILE_MELDATE:
2123 v = p->l;
2124 break;
2125
2126 case FILE_QUAD:
2127 case FILE_LEQUAD:
2128 case FILE_BEQUAD:
2129 case FILE_QDATE:
2130 case FILE_BEQDATE:
2131 case FILE_LEQDATE:
2132 case FILE_QLDATE:
2133 case FILE_BEQLDATE:
2134 case FILE_LEQLDATE:
2135 case FILE_QWDATE:
2136 case FILE_BEQWDATE:
2137 case FILE_LEQWDATE:
2138 case FILE_OFFSET:
2139 v = p->q;
2140 break;
2141
2142 case FILE_FLOAT:
2143 case FILE_BEFLOAT:
2144 case FILE_LEFLOAT:
2145 fl = m->value.f;
2146 fv = p->f;
2147 switch (m->reln) {
2148 case 'x':
2149 matched = 1;
2150 break;
2151
2152 case '!':
2153 matched = isunordered(fl, fv) ? 1 : fv != fl;
2154 break;
2155
2156 case '=':
2157 matched = isunordered(fl, fv) ? 0 : fv == fl;
2158 break;
2159
2160 case '>':
2161 matched = isgreater(fv, fl);
2162 break;
2163
2164 case '<':
2165 matched = isless(fv, fl);
2166 break;
2167
2168 default:
2169 file_magerror(ms, "cannot happen with float: "
2170 "invalid relation `%c'", m->reln);
2171 return -1;
2172 }
2173 return matched;
2174
2175 case FILE_DOUBLE:
2176 case FILE_BEDOUBLE:
2177 case FILE_LEDOUBLE:
2178 dl = m->value.d;
2179 dv = p->d;
2180 switch (m->reln) {
2181 case 'x':
2182 matched = 1;
2183 break;
2184
2185 case '!':
2186 matched = isunordered(dv, dl) ? 1 : dv != dl;
2187 break;
2188
2189 case '=':
2190 matched = isunordered(dv, dl) ? 0 : dv == dl;
2191 break;
2192
2193 case '>':
2194 matched = isgreater(dv, dl);
2195 break;
2196
2197 case '<':
2198 matched = isless(dv, dl);
2199 break;
2200
2201 default:
2202 file_magerror(ms, "cannot happen with double: "
2203 "invalid relation `%c'", m->reln);
2204 return -1;
2205 }
2206 return matched;
2207
2208 case FILE_DEFAULT:
2209 case FILE_CLEAR:
2210 l = 0;
2211 v = 0;
2212 break;
2213
2214 case FILE_STRING:
2215 case FILE_PSTRING:
2216 case FILE_OCTAL:
2217 l = 0;
2218 v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen),
2219 sizeof(p->s), m->str_flags);
2220 break;
2221
2222 case FILE_BESTRING16:
2223 case FILE_LESTRING16:
2224 l = 0;
2225 v = file_strncmp16(m->value.s, p->s, CAST(size_t, m->vallen),
2226 sizeof(p->s), m->str_flags);
2227 break;
2228
2229 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
2230 size_t slen;
2231 size_t idx;
2232
2233 if (ms->search.s == NULL)
2234 return 0;
2235
2236 slen = MIN(m->vallen, sizeof(m->value.s));
2237 l = 0;
2238 v = 0;
2239 #ifdef HAVE_MEMMEM
2240 if (slen > 0 && m->str_flags == 0) {
2241 const char *found;
2242 idx = m->str_range + slen;
2243 if (m->str_range == 0 || ms->search.s_len < idx)
2244 idx = ms->search.s_len;
2245 found = CAST(const char *, php_memnstr(ms->search.s,
2246 m->value.s, slen, ms->search.s + idx));
2247 if (!found) {
2248 v = 1;
2249 break;
2250 }
2251 idx = found - ms->search.s;
2252 ms->search.offset += idx;
2253 ms->search.rm_len = ms->search.s_len - idx;
2254 break;
2255 }
2256 #endif
2257
2258 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
2259 if (slen + idx > ms->search.s_len) {
2260 v = 1;
2261 break;
2262 }
2263
2264 v = file_strncmp(m->value.s, ms->search.s + idx, slen,
2265 ms->search.s_len - idx, m->str_flags);
2266 if (v == 0) { /* found match */
2267 ms->search.offset += idx;
2268 ms->search.rm_len = ms->search.s_len - idx;
2269 break;
2270 }
2271 }
2272 break;
2273 }
2274 case FILE_REGEX: {
2275 zend_string *pattern;
2276 uint32_t options = 0;
2277 pcre_cache_entry *pce;
2278
2279 options |= PCRE2_MULTILINE;
2280
2281 if (m->str_flags & STRING_IGNORE_CASE) {
2282 options |= PCRE2_CASELESS;
2283 }
2284
2285 pattern = convert_libmagic_pattern((char *)m->value.s, m->vallen, options);
2286
2287 l = v = 0;
2288 if ((pce = pcre_get_compiled_regex_cache(pattern)) == NULL) {
2289 zend_string_release(pattern);
2290 return -1;
2291 } else {
2292 /* pce now contains the compiled regex */
2293 zval retval;
2294 zval subpats;
2295 zend_string *haystack;
2296
2297 ZVAL_NULL(&retval);
2298 ZVAL_NULL(&subpats);
2299
2300 /* Cut the search len from haystack, equals to REG_STARTEND */
2301 haystack = zend_string_init(ms->search.s, ms->search.s_len, 0);
2302
2303 /* match v = 0, no match v = 1 */
2304 php_pcre_match_impl(pce, haystack, &retval, &subpats, 0, PREG_OFFSET_CAPTURE, 0);
2305 /* Free haystack */
2306 zend_string_release(haystack);
2307
2308 if (Z_LVAL(retval) < 0) {
2309 zval_ptr_dtor(&subpats);
2310 zend_string_release(pattern);
2311 return -1;
2312 } else if ((Z_LVAL(retval) > 0) && (Z_TYPE(subpats) == IS_ARRAY)) {
2313 /* Need to fetch global match which equals pmatch[0] */
2314 zval *pzval;
2315 HashTable *ht = Z_ARRVAL(subpats);
2316 if ((pzval = zend_hash_index_find(ht, 0)) != NULL && Z_TYPE_P(pzval) == IS_ARRAY) {
2317 /* If everything goes according to the master plan
2318 tmpcopy now contains two elements:
2319 0 = the match
2320 1 = starting position of the match */
2321 zval *match, *offset;
2322 if ((match = zend_hash_index_find(Z_ARRVAL_P(pzval), 0)) &&
2323 (offset = zend_hash_index_find(Z_ARRVAL_P(pzval), 1))) {
2324 if (Z_TYPE_P(match) != IS_STRING && Z_TYPE_P(offset) != IS_LONG) {
2325 goto error_out;
2326 }
2327 ms->search.s += Z_LVAL_P(offset); /* this is where the match starts */
2328 ms->search.offset += Z_LVAL_P(offset); /* this is where the match starts as size_t */
2329 ms->search.rm_len = Z_STRLEN_P(match) /* This is the length of the matched pattern */;
2330 v = 0;
2331 } else {
2332 goto error_out;
2333 }
2334 } else {
2335 error_out:
2336 zval_ptr_dtor(&subpats);
2337 zend_string_release(pattern);
2338 return -1;
2339 }
2340 } else {
2341 v = 1;
2342 }
2343 zval_ptr_dtor(&subpats);
2344 zend_string_release(pattern);
2345 }
2346 break;
2347 }
2348 case FILE_USE:
2349 return ms->ms_value.q != 0;
2350 case FILE_NAME:
2351 case FILE_INDIRECT:
2352 return 1;
2353 case FILE_DER:
2354 matched = der_cmp(ms, m);
2355 if (matched == -1) {
2356 if ((ms->flags & MAGIC_DEBUG) != 0) {
2357 (void) fprintf(stderr,
2358 "EOF comparing DER entries\n");
2359 }
2360 return 0;
2361 }
2362 return matched;
2363 case FILE_GUID:
2364 l = 0;
2365 v = memcmp(m->value.guid, p->guid, sizeof(p->guid));
2366 break;
2367 default:
2368 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2369 return -1;
2370 }
2371
2372 v = file_signextend(ms, m, v);
2373
2374 switch (m->reln) {
2375 case 'x':
2376 if ((ms->flags & MAGIC_DEBUG) != 0)
2377 (void) fprintf(stderr, "%" INT64_T_FORMAT
2378 "u == *any* = 1", CAST(unsigned long long, v));
2379 matched = 1;
2380 break;
2381
2382 case '!':
2383 matched = v != l;
2384 if ((ms->flags & MAGIC_DEBUG) != 0)
2385 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2386 INT64_T_FORMAT "u = %d",
2387 CAST(unsigned long long, v),
2388 CAST(unsigned long long, l), matched);
2389 break;
2390
2391 case '=':
2392 matched = v == l;
2393 if ((ms->flags & MAGIC_DEBUG) != 0)
2394 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2395 INT64_T_FORMAT "u = %d",
2396 CAST(unsigned long long, v),
2397 CAST(unsigned long long, l), matched);
2398 break;
2399
2400 case '>':
2401 if (m->flag & UNSIGNED) {
2402 matched = v > l;
2403 if ((ms->flags & MAGIC_DEBUG) != 0)
2404 (void) fprintf(stderr, "%" INT64_T_FORMAT
2405 "u > %" INT64_T_FORMAT "u = %d",
2406 CAST(unsigned long long, v),
2407 CAST(unsigned long long, l), matched);
2408 }
2409 else {
2410 matched = CAST(int64_t, v) > CAST(int64_t, l);
2411 if ((ms->flags & MAGIC_DEBUG) != 0)
2412 (void) fprintf(stderr, "%" INT64_T_FORMAT
2413 "d > %" INT64_T_FORMAT "d = %d",
2414 CAST(long long, v),
2415 CAST(long long, l), matched);
2416 }
2417 break;
2418
2419 case '<':
2420 if (m->flag & UNSIGNED) {
2421 matched = v < l;
2422 if ((ms->flags & MAGIC_DEBUG) != 0)
2423 (void) fprintf(stderr, "%" INT64_T_FORMAT
2424 "u < %" INT64_T_FORMAT "u = %d",
2425 CAST(unsigned long long, v),
2426 CAST(unsigned long long, l), matched);
2427 }
2428 else {
2429 matched = CAST(int64_t, v) < CAST(int64_t, l);
2430 if ((ms->flags & MAGIC_DEBUG) != 0)
2431 (void) fprintf(stderr, "%" INT64_T_FORMAT
2432 "d < %" INT64_T_FORMAT "d = %d",
2433 CAST(long long, v),
2434 CAST(long long, l), matched);
2435 }
2436 break;
2437
2438 case '&':
2439 matched = (v & l) == l;
2440 if ((ms->flags & MAGIC_DEBUG) != 0)
2441 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2442 INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2443 "x) = %d", CAST(unsigned long long, v),
2444 CAST(unsigned long long, l),
2445 CAST(unsigned long long, l),
2446 matched);
2447 break;
2448
2449 case '^':
2450 matched = (v & l) != l;
2451 if ((ms->flags & MAGIC_DEBUG) != 0)
2452 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2453 INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2454 "x) = %d", CAST(unsigned long long, v),
2455 CAST(unsigned long long, l),
2456 CAST(unsigned long long, l), matched);
2457 break;
2458
2459 default:
2460 file_magerror(ms, "cannot happen: invalid relation `%c'",
2461 m->reln);
2462 return -1;
2463 }
2464 if ((ms->flags & MAGIC_DEBUG) != 0) {
2465 (void) fprintf(stderr, " strength=%zu\n",
2466 file_magic_strength(m, 1));
2467 }
2468
2469 return matched;
2470 }
2471
2472 file_private int
handle_annotation(struct magic_set * ms,struct magic * m,int firstline)2473 handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2474 {
2475 if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2476 if (print_sep(ms, firstline) == -1)
2477 return -1;
2478 if (file_printf(ms, "%.8s", m->apple) == -1)
2479 return -1;
2480 return 1;
2481 }
2482 if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2483 if (print_sep(ms, firstline) == -1)
2484 return -1;
2485 if (file_printf(ms, "%s", m->ext) == -1)
2486 return -1;
2487 return 1;
2488 }
2489 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2490 char buf[1024];
2491 const char *p;
2492 if (print_sep(ms, firstline) == -1)
2493 return -1;
2494 if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1)
2495 p = m->mimetype;
2496 else
2497 p = buf;
2498 if (file_printf(ms, "%s", p) == -1)
2499 return -1;
2500 return 1;
2501 }
2502 return 0;
2503 }
2504
2505 file_private int
print_sep(struct magic_set * ms,int firstline)2506 print_sep(struct magic_set *ms, int firstline)
2507 {
2508 if (firstline)
2509 return 0;
2510 /*
2511 * we found another match
2512 * put a newline and '-' to do some simple formatting
2513 */
2514 return file_separator(ms);
2515 }
2516