xref: /php-src/ext/fileinfo/libmagic/softmagic.c (revision b7c5813c)
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 = &ic;
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