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