diff options
Diffstat (limited to 'src/softmagic.c')
-rw-r--r-- | src/softmagic.c | 695 |
1 files changed, 352 insertions, 343 deletions
diff --git a/src/softmagic.c b/src/softmagic.c index 038a1ff..5e277e3 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -32,26 +32,28 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.159 2013/02/17 22:28:27 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.206 2015/01/01 17:07:34 christos Exp $") #endif /* lint */ #include "magic.h" +#include <assert.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <time.h> - private int match(struct magic_set *, struct magic *, uint32_t, - const unsigned char *, size_t, size_t, int, int, int, int *); + const unsigned char *, size_t, size_t, int, int, int, uint16_t, + uint16_t *, int *, int *, int *); private int mget(struct magic_set *, const unsigned char *, - struct magic *, size_t, size_t, unsigned int, int, int, int, int *); + struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t, + uint16_t *, int *, int *, int *); private int magiccheck(struct magic_set *, struct magic *); private int32_t mprint(struct magic_set *, struct magic *); private int32_t moffset(struct magic_set *, struct magic *); private void mdebug(uint32_t, const char *, size_t); private int mcopy(struct magic_set *, union VALUETYPE *, int, int, - const unsigned char *, uint32_t, size_t, size_t); + const unsigned char *, uint32_t, size_t, struct magic *); private int mconvert(struct magic_set *, struct magic *, int); private int print_sep(struct magic_set *, int); private int handle_annotation(struct magic_set *, struct magic *); @@ -60,6 +62,8 @@ private void cvt_16(union VALUETYPE *, const struct magic *); private void cvt_32(union VALUETYPE *, const struct magic *); private void cvt_64(union VALUETYPE *, const struct magic *); +#define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o))) + /* * softmagic - lookup one file in parsed, in-memory copy of database * Passed the name and FILE * of one file to be typed. @@ -67,18 +71,45 @@ private void cvt_64(union VALUETYPE *, const struct magic *); /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ protected int file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, - int mode, int text) + uint16_t indir_level, uint16_t *name_count, int mode, int text) { struct mlist *ml; - int rv; + int rv, printed_something = 0, need_separator = 0; + uint16_t nc; + + if (name_count == NULL) { + nc = 0; + name_count = &nc; + } + for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode, - text, 0, NULL)) != 0) + text, 0, indir_level, name_count, + &printed_something, &need_separator, NULL)) != 0) return rv; return 0; } +#define FILE_FMTDEBUG +#ifdef FILE_FMTDEBUG +#define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) + +private const char * __attribute__((__format_arg__(3))) +file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def, + const char *file, size_t line) +{ + const char *ptr = fmtcheck(m->desc, def); + if (ptr == def) + file_magerror(ms, + "%s, %" SIZE_T_FORMAT "u: format `%s' does not match" + " with `%s'", file, line, m->desc, def); + return ptr; +} +#else +#define F(a, b, c) fmtcheck((b)->desc, (c)) +#endif + /* * Go through the whole list, stopping if you find a match. Process all * the continuations of that match before returning. @@ -109,14 +140,13 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, private int match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, const unsigned char *s, size_t nbytes, size_t offset, int mode, int text, - int flip, int *returnval) + int flip, uint16_t indir_level, uint16_t *name_count, + int *printed_something, int *need_separator, int *returnval) { uint32_t magindex = 0; unsigned int cont_level = 0; - int need_separator = 0; int returnvalv = 0, e; /* if a match is found it is set to 1*/ int firstline = 1; /* a flag to print X\n X\n- X */ - int printed_something = 0; int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0; if (returnval == NULL) @@ -131,8 +161,9 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (m->type != FILE_NAME) if ((IS_STRING(m->type) && - ((text && (m->str_flags & (STRING_BINTEST | STRING_TEXTTEST)) == STRING_BINTEST) || - (!text && (m->str_flags & (STRING_TEXTTEST | STRING_BINTEST)) == STRING_TEXTTEST))) || +#define FLT (STRING_BINTEST | STRING_TEXTTEST) + ((text && (m->str_flags & FLT) == STRING_BINTEST) || + (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || (m->flag & mode) != mode) { /* Skip sub-tests */ while (magindex + 1 < nmagic && @@ -147,7 +178,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, /* if main entry matches, print it... */ switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text, - flip, returnval)) { + flip, indir_level, name_count, + printed_something, need_separator, returnval)) { case -1: return -1; case 0: @@ -181,6 +213,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, } if ((e = handle_annotation(ms, m)) != 0) { + *need_separator = 1; + *printed_something = 1; *returnval = 1; return e; } @@ -189,8 +223,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, * a blank before we print something else. */ if (*m->desc) { - need_separator = 1; - printed_something = 1; + *need_separator = 1; + *printed_something = 1; if (print_sep(ms, firstline) == -1) return -1; } @@ -205,9 +239,9 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (file_check_mem(ms, ++cont_level) == -1) return -1; - while (magic[magindex+1].cont_level != 0 && - ++magindex < nmagic) { - m = &magic[magindex]; + while (magindex + 1 < nmagic && + magic[magindex + 1].cont_level != 0) { + m = &magic[++magindex]; ms->line = m->lineno; /* for messages */ if (cont_level < m->cont_level) @@ -233,7 +267,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, } #endif switch (mget(ms, s, m, nbytes, offset, cont_level, mode, - text, flip, returnval)) { + text, flip, indir_level, name_count, + printed_something, need_separator, returnval)) { case -1: return -1; case 0: @@ -260,13 +295,16 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, #ifdef ENABLE_CONDITIONALS ms->c.li[cont_level].last_match = 1; #endif - if (m->type != FILE_DEFAULT) - ms->c.li[cont_level].got_match = 1; - else if (ms->c.li[cont_level].got_match) { + if (m->type == FILE_CLEAR) ms->c.li[cont_level].got_match = 0; - break; - } + else if (ms->c.li[cont_level].got_match) { + if (m->type == FILE_DEFAULT) + break; + } else + ms->c.li[cont_level].got_match = 1; if ((e = handle_annotation(ms, m)) != 0) { + *need_separator = 1; + *printed_something = 1; *returnval = 1; return e; } @@ -275,8 +313,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, * make sure that we have a separator first. */ if (*m->desc) { - if (!printed_something) { - printed_something = 1; + if (!*printed_something) { + *printed_something = 1; if (print_sep(ms, firstline) == -1) return -1; @@ -289,13 +327,13 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, * this item isn't empty. */ /* space if previous printed */ - if (need_separator + if (*need_separator && ((m->flag & NOSPACE) == 0) && *m->desc) { if (print && file_printf(ms, " ") == -1) return -1; - need_separator = 0; + *need_separator = 0; } if (print && mprint(ms, m) == -1) return -1; @@ -303,7 +341,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, ms->c.li[cont_level].off = moffset(ms, m); if (*m->desc) - need_separator = 1; + *need_separator = 1; /* * If we see any continuations @@ -315,12 +353,12 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, break; } } - if (printed_something) { + if (*printed_something) { firstline = 0; if (print) *returnval = 1; } - if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) { + if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) { return *returnval; /* don't keep searching */ } } @@ -330,23 +368,21 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, private int check_fmt(struct magic_set *ms, struct magic *m) { - regex_t rx; - int rc; + file_regex_t rx; + int rc, rv = -1; if (strchr(m->desc, '%') == NULL) return 0; - rc = regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); + rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); if (rc) { - char errmsg[512]; - (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); - file_magerror(ms, "regex error %d, (%s)", rc, errmsg); - return -1; + file_regerror(&rx, rc, ms); } else { - rc = regexec(&rx, m->desc, 0, 0, 0); - regfree(&rx); - return !rc; + rc = file_regexec(&rx, m->desc, 0, 0, 0); + rv = !rc; } + file_regfree(&rx); + return rv; } #ifndef HAVE_STRNDUP @@ -375,7 +411,7 @@ mprint(struct magic_set *ms, struct magic *m) float vf; double vd; int64_t t = 0; - char buf[128], tbuf[26]; + char buf[128], tbuf[26], sbuf[512]; union VALUETYPE *p = &ms->ms_value; switch (m->type) { @@ -385,13 +421,14 @@ mprint(struct magic_set *ms, struct magic *m) case -1: return -1; case 1: - (void)snprintf(buf, sizeof(buf), "%c", + (void)snprintf(buf, sizeof(buf), "%d", (unsigned char)v); - if (file_printf(ms, m->desc, buf) == -1) + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, m->desc, (unsigned char) v) == -1) + if (file_printf(ms, F(ms, m, "%d"), + (unsigned char) v) == -1) return -1; break; } @@ -406,14 +443,14 @@ mprint(struct magic_set *ms, struct magic *m) case -1: return -1; case 1: - (void)snprintf(buf, sizeof(buf), "%hu", + (void)snprintf(buf, sizeof(buf), "%u", (unsigned short)v); - if (file_printf(ms, m->desc, buf) == -1) + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if ( - file_printf(ms, m->desc, (unsigned short) v) == -1) + if (file_printf(ms, F(ms, m, "%u"), + (unsigned short) v) == -1) return -1; break; } @@ -429,12 +466,12 @@ mprint(struct magic_set *ms, struct magic *m) case -1: return -1; case 1: - (void)snprintf(buf, sizeof(buf), "%u", (uint32_t)v); - if (file_printf(ms, m->desc, buf) == -1) + (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v); + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, m->desc, (uint32_t) v) == -1) + if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1) return -1; break; } @@ -445,8 +482,21 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEQUAD: case FILE_LEQUAD: v = file_signextend(ms, m, p->q); - if (file_printf(ms, m->desc, (uint64_t) v) == -1) + switch (check_fmt(ms, m)) { + case -1: return -1; + case 1: + (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u", + (unsigned long long)v); + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + return -1; + break; + default: + if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"), + (unsigned long long) v) == -1) + return -1; + break; + } t = ms->offset + sizeof(int64_t); break; @@ -455,7 +505,9 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BESTRING16: case FILE_LESTRING16: if (m->reln == '=' || m->reln == '!') { - if (file_printf(ms, m->desc, m->value.s) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), m->value.s)) + == -1) return -1; t = ms->offset + m->vallen; } @@ -481,7 +533,8 @@ mprint(struct magic_set *ms, struct magic *m) *++last = '\0'; } - if (file_printf(ms, m->desc, str) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), str)) == -1) return -1; if (m->type == FILE_PSTRING) @@ -493,8 +546,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEDATE: case FILE_LEDATE: case FILE_MEDATE: - if (file_printf(ms, m->desc, file_fmttime(p->l, FILE_T_LOCAL, - tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->l + m->num_mask, FILE_T_LOCAL, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint32_t); break; @@ -503,7 +556,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BELDATE: case FILE_LELDATE: case FILE_MELDATE: - if (file_printf(ms, m->desc, file_fmttime(p->l, 0, tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->l + m->num_mask, 0, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint32_t); break; @@ -511,8 +565,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QDATE: case FILE_BEQDATE: case FILE_LEQDATE: - if (file_printf(ms, m->desc, file_fmttime(p->q, FILE_T_LOCAL, - tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->q + m->num_mask, FILE_T_LOCAL, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -520,7 +574,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QLDATE: case FILE_BEQLDATE: case FILE_LEQLDATE: - if (file_printf(ms, m->desc, file_fmttime(p->q, 0, tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->q + m->num_mask, 0, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -528,8 +583,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QWDATE: case FILE_BEQWDATE: case FILE_LEQWDATE: - if (file_printf(ms, m->desc, file_fmttime(p->q, FILE_T_WINDOWS, - tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->q + m->num_mask, FILE_T_WINDOWS, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -543,11 +598,11 @@ mprint(struct magic_set *ms, struct magic *m) return -1; case 1: (void)snprintf(buf, sizeof(buf), "%g", vf); - if (file_printf(ms, m->desc, buf) == -1) + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, m->desc, vf) == -1) + if (file_printf(ms, F(ms, m, "%g"), vf) == -1) return -1; break; } @@ -563,11 +618,11 @@ mprint(struct magic_set *ms, struct magic *m) return -1; case 1: (void)snprintf(buf, sizeof(buf), "%g", vd); - if (file_printf(ms, m->desc, buf) == -1) + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, m->desc, vd) == -1) + if (file_printf(ms, F(ms, m, "%g"), vd) == -1) return -1; break; } @@ -583,7 +638,8 @@ mprint(struct magic_set *ms, struct magic *m) file_oomem(ms, ms->search.rm_len); return -1; } - rval = file_printf(ms, m->desc, cp); + rval = file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), cp)); free(cp); if (rval == -1) @@ -597,7 +653,8 @@ mprint(struct magic_set *ms, struct magic *m) } case FILE_SEARCH: - if (file_printf(ms, m->desc, m->value.s) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), m->value.s)) == -1) return -1; if ((m->str_flags & REGEX_OFFSET_START)) t = ms->search.offset; @@ -606,7 +663,8 @@ mprint(struct magic_set *ms, struct magic *m) break; case FILE_DEFAULT: - if (file_printf(ms, m->desc, m->value.s) == -1) + case FILE_CLEAR: + if (file_printf(ms, "%s", m->desc) == -1) return -1; t = ms->offset; break; @@ -710,9 +768,8 @@ moffset(struct magic_set *ms, struct magic *m) else return CAST(int32_t, (ms->search.offset + m->vallen)); + case FILE_CLEAR: case FILE_DEFAULT: - return ms->offset; - case FILE_INDIRECT: return ms->offset; @@ -864,8 +921,9 @@ private int mconvert(struct magic_set *ms, struct magic *m, int flip) { union VALUETYPE *p = &ms->ms_value; + uint8_t type; - switch (cvt_flip(m->type, flip)) { + switch (type = cvt_flip(m->type, flip)) { case FILE_BYTE: cvt_8(p, m); return 1; @@ -891,10 +949,21 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) return 1; } case FILE_PSTRING: { - char *ptr1 = p->s, *ptr2 = ptr1 + file_pstring_length_size(m); + size_t sz = file_pstring_length_size(m); + char *ptr1 = p->s, *ptr2 = ptr1 + sz; size_t len = file_pstring_get_length(m, ptr1); - if (len >= sizeof(p->s)) - len = sizeof(p->s) - 1; + sz = sizeof(p->s) - sz; /* maximum length of string */ + if (len >= sz) { + /* + * The size of the pascal string length (sz) + * is 1, 2, or 4. We need at least 1 byte for NUL + * termination, but we've already truncated the + * string by p->s, so we need to deduct sz. + * Because we can use one of the bytes of the length + * after we shifted as NUL termination. + */ + len = sz; + } while (len--) *ptr1++ = *ptr2++; *ptr1 = '\0'; @@ -909,7 +978,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_BELDATE: p->l = (int32_t) ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3])); - cvt_32(p, m); + if (type == FILE_BELONG) + cvt_32(p, m); return 1; case FILE_BEQUAD: case FILE_BEQDATE: @@ -920,7 +990,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)| ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)| ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7])); - cvt_64(p, m); + if (type == FILE_BEQUAD) + cvt_64(p, m); return 1; case FILE_LESHORT: p->h = (short)((p->hs[1]<<8)|(p->hs[0])); @@ -931,7 +1002,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_LELDATE: p->l = (int32_t) ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0])); - cvt_32(p, m); + if (type == FILE_LELONG) + cvt_32(p, m); return 1; case FILE_LEQUAD: case FILE_LEQDATE: @@ -942,14 +1014,16 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)| ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)| ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0])); - cvt_64(p, m); + if (type == FILE_LEQUAD) + cvt_64(p, m); return 1; case FILE_MELONG: case FILE_MEDATE: case FILE_MELDATE: p->l = (int32_t) ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2])); - cvt_32(p, m); + if (type == FILE_MELONG) + cvt_32(p, m); return 1; case FILE_FLOAT: cvt_float(p, m); @@ -984,6 +1058,7 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_REGEX: case FILE_SEARCH: case FILE_DEFAULT: + case FILE_CLEAR: case FILE_NAME: case FILE_USE: return 1; @@ -997,7 +1072,7 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) private void mdebug(uint32_t offset, const char *str, size_t len) { - (void) fprintf(stderr, "mget/%zu @%d: ", len, offset); + (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset); file_showstr(stderr, str, len); (void) fputc('\n', stderr); (void) fputc('\n', stderr); @@ -1005,7 +1080,7 @@ mdebug(uint32_t offset, const char *str, size_t len) private int mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, - const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt) + const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m) { /* * Note: FILE_SEARCH and FILE_REGEX do not actually copy @@ -1025,15 +1100,29 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, const char *last; /* end of search region */ const char *buf; /* start of search region */ const char *end; - size_t lines; + size_t lines, linecnt, bytecnt; if (s == NULL) { ms->search.s_len = 0; ms->search.s = NULL; return 0; } + + if (m->str_flags & REGEX_LINE_COUNT) { + linecnt = m->str_range; + bytecnt = linecnt * 80; + } else { + linecnt = 0; + bytecnt = m->str_range; + } + + if (bytecnt == 0) + bytecnt = 8192; + if (bytecnt > nbytes) + bytecnt = nbytes; + buf = RCAST(const char *, s) + offset; - end = last = RCAST(const char *, s) + nbytes; + end = last = RCAST(const char *, s) + bytecnt; /* mget() guarantees buf <= last */ for (lines = linecnt, b = buf; lines && b < end && ((b = CAST(const char *, @@ -1046,7 +1135,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, b++; } if (lines) - last = RCAST(const char *, s) + nbytes; + last = RCAST(const char *, s) + bytecnt; ms->search.s = buf; ms->search.s_len = last - buf; @@ -1065,11 +1154,8 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, src++; /* check that offset is within range */ - if (offset >= nbytes) { - file_magerror(ms, "invalid offset %u in mcopy()", - offset); - return -1; - } + if (offset >= nbytes) + break; for (/*EMPTY*/; src < esrc; src += 2, dst++) { if (dst < edst) *dst = *src; @@ -1116,23 +1202,39 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, private int mget(struct magic_set *ms, const unsigned char *s, struct magic *m, size_t nbytes, size_t o, unsigned int cont_level, int mode, int text, - int flip, int *returnval) + int flip, uint16_t indir_level, uint16_t *name_count, + int *printed_something, int *need_separator, int *returnval) { uint32_t offset = ms->offset; - uint32_t count = m->str_range; - int rv; - char *sbuf, *rbuf; + uint32_t lhs; + file_pushbuf_t *pb; + int rv, oneed_separator, in_type; + char *rbuf; union VALUETYPE *p = &ms->ms_value; struct mlist ml; + if (indir_level >= ms->indir_max) { + file_error(ms, 0, "indirect recursion nesting (%hu) exceeded", + indir_level); + return -1; + } + + if (*name_count >= ms->name_max) { + file_error(ms, 0, "name use count (%hu) exceeded", + *name_count); + return -1; + } + if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o), - (uint32_t)nbytes, count) == -1) + (uint32_t)nbytes, m) == -1) return -1; if ((ms->flags & MAGIC_DEBUG) != 0) { - fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, " - "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o, - nbytes, count); + fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%" + SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT + "u, il=%hu, nc=%hu)\n", + m->type, m->flag, offset, o, nbytes, + indir_level, *name_count); mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE)); #ifndef COMPILE_ONLY file_mdump(m); @@ -1178,9 +1280,9 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect offs=%u\n", off); } - switch (cvt_flip(m->in_type, flip)) { + switch (in_type = cvt_flip(m->in_type, flip)) { case FILE_BYTE: - if (nbytes < (offset + 1)) + if (OFFSET_OOB(nbytes, offset, 1)) return 0; if (off) { switch (m->in_op & FILE_OPS_MASK) { @@ -1215,111 +1317,79 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, offset = ~offset; break; case FILE_BESHORT: - if (nbytes < (offset + 2)) + if (OFFSET_OOB(nbytes, offset, 2)) return 0; + lhs = (p->hs[0] << 8) | p->hs[1]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) % - off; + offset = lhs % off; break; } } else - offset = (short)((p->hs[0]<<8)| - (p->hs[1])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_LESHORT: - if (nbytes < (offset + 2)) + if (OFFSET_OOB(nbytes, offset, 2)) return 0; + lhs = (p->hs[1] << 8) | p->hs[0]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) % - off; + offset = lhs % off; break; } } else - offset = (short)((p->hs[1]<<8)| - (p->hs[0])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_SHORT: - if (nbytes < (offset + 2)) + if (OFFSET_OOB(nbytes, offset, 2)) return 0; if (off) { switch (m->in_op & FILE_OPS_MASK) { @@ -1356,218 +1426,119 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, break; case FILE_BELONG: case FILE_BEID3: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; + lhs = (p->hl[0] << 24) | (p->hl[1] << 16) | + (p->hl[2] << 8) | p->hl[3]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) % - off; + offset = lhs % off; break; } } else - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_LELONG: case FILE_LEID3: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; + lhs = (p->hl[3] << 24) | (p->hl[2] << 16) | + (p->hl[1] << 8) | p->hl[0]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) % - off; + offset = lhs % off; break; } } else - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_MELONG: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; + lhs = (p->hl[1] << 24) | (p->hl[0] << 16) | + (p->hl[3] << 8) | p->hl[2]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) % - off; + offset = lhs % off; break; } } else - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_LONG: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; if (off) { switch (m->in_op & FILE_OPS_MASK) { @@ -1601,9 +1572,11 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; + default: + break; } - switch (cvt_flip(m->in_type, flip)) { + switch (in_type) { case FILE_LEID3: case FILE_BEID3: offset = ((((offset >> 0) & 0x7f) << 0) | @@ -1617,10 +1590,16 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (m->flag & INDIROFFADD) { offset += ms->c.li[cont_level-1].off; + if (offset == 0) { + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, + "indirect *zero* offset\n"); + return 0; + } if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect +offs=%u\n", offset); } - if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1) + if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1) return -1; ms->offset = offset; @@ -1636,14 +1615,14 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, /* Verify we have enough data to match magic type */ switch (m->type) { case FILE_BYTE: - if (nbytes < (offset + 1)) /* should alway be true */ + if (OFFSET_OOB(nbytes, offset, 1)) return 0; break; case FILE_SHORT: case FILE_BESHORT: case FILE_LESHORT: - if (nbytes < (offset + 2)) + if (OFFSET_OOB(nbytes, offset, 2)) return 0; break; @@ -1662,21 +1641,21 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, case FILE_FLOAT: case FILE_BEFLOAT: case FILE_LEFLOAT: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; break; case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: - if (nbytes < (offset + 8)) + if (OFFSET_OOB(nbytes, offset, 8)) return 0; break; case FILE_STRING: case FILE_PSTRING: case FILE_SEARCH: - if (nbytes < (offset + m->vallen)) + if (OFFSET_OOB(nbytes, offset, m->vallen)) return 0; break; @@ -1686,49 +1665,70 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, break; case FILE_INDIRECT: + if (m->str_flags & INDIRECT_RELATIVE) + offset += o; + if (offset == 0) + return 0; + if (nbytes < offset) return 0; - sbuf = ms->o.buf; - ms->o.buf = NULL; - ms->offset = 0; + + if ((pb = file_push_buffer(ms)) == NULL) + return -1; + rv = file_softmagic(ms, s + offset, nbytes - offset, - BINTEST, text); + indir_level + 1, name_count, BINTEST, text); + if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); + + rbuf = file_pop_buffer(ms, pb); + if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR) + return -1; + if (rv == 1) { - rbuf = ms->o.buf; - ms->o.buf = sbuf; if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 && - file_printf(ms, m->desc, offset) == -1) + file_printf(ms, F(ms, m, "%u"), offset) == -1) { + free(rbuf); return -1; - if (file_printf(ms, "%s", rbuf) == -1) + } + if (file_printf(ms, "%s", rbuf) == -1) { + free(rbuf); return -1; - free(rbuf); - } else - ms->o.buf = sbuf; + } + } + free(rbuf); return rv; case FILE_USE: if (nbytes < offset) return 0; - sbuf = m->value.s; - if (*sbuf == '^') { - sbuf++; - flip = 1; - } else - flip = 0; - if (file_magicfind(ms, sbuf, &ml) == -1) { - file_error(ms, 0, "cannot find entry `%s'", sbuf); + rbuf = m->value.s; + if (*rbuf == '^') { + rbuf++; + flip = !flip; + } + if (file_magicfind(ms, rbuf, &ml) == -1) { + file_error(ms, 0, "cannot find entry `%s'", rbuf); return -1; } - return match(ms, ml.magic, ml.nmagic, s, nbytes, offset, - mode, text, flip, returnval); + (*name_count)++; + oneed_separator = *need_separator; + if (m->flag & NOSPACE) + *need_separator = 0; + rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o, + mode, text, flip, indir_level, name_count, + printed_something, need_separator, returnval); + if (rv != 1) + *need_separator = oneed_separator; + return rv; case FILE_NAME: if (file_printf(ms, "%s", m->desc) == -1) return -1; return 1; case FILE_DEFAULT: /* nothing to check */ + case FILE_CLEAR: default: break; } @@ -1890,7 +1890,6 @@ magiccheck(struct magic_set *ms, struct magic *m) break; default: - matched = 0; file_magerror(ms, "cannot happen with float: invalid relation `%c'", m->reln); return -1; @@ -1924,13 +1923,13 @@ magiccheck(struct magic_set *ms, struct magic *m) break; default: - matched = 0; file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln); return -1; } return matched; case FILE_DEFAULT: + case FILE_CLEAR: l = 0; v = 0; break; @@ -1962,7 +1961,8 @@ magiccheck(struct magic_set *ms, struct magic *m) if (slen + idx > ms->search.s_len) break; - v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags); + v = file_strncmp(m->value.s, ms->search.s + idx, slen, + m->str_flags); if (v == 0) { /* found match */ ms->search.offset += idx; break; @@ -1972,37 +1972,49 @@ magiccheck(struct magic_set *ms, struct magic *m) } case FILE_REGEX: { int rc; - regex_t rx; - char errmsg[512]; + file_regex_t rx; + const char *search; if (ms->search.s == NULL) return 0; l = 0; - rc = regcomp(&rx, m->value.s, + rc = file_regcomp(&rx, m->value.s, REG_EXTENDED|REG_NEWLINE| ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); if (rc) { - (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); - file_magerror(ms, "regex error %d, (%s)", - rc, errmsg); + file_regerror(&rx, rc, ms); v = (uint64_t)-1; - } - else { + } else { regmatch_t pmatch[1]; + size_t slen = ms->search.s_len; #ifndef REG_STARTEND #define REG_STARTEND 0 - size_t l = ms->search.s_len - 1; - char c = ms->search.s[l]; - ((char *)(intptr_t)ms->search.s)[l] = '\0'; + char *copy; + if (slen != 0) { + copy = malloc(slen); + if (copy == NULL) { + file_error(ms, errno, + "can't allocate %" SIZE_T_FORMAT "u bytes", + slen); + return -1; + } + memcpy(copy, ms->search.s, slen); + copy[--slen] = '\0'; + search = copy; + } else { + search = ms->search.s; + copy = NULL; + } #else + search = ms->search.s; pmatch[0].rm_so = 0; - pmatch[0].rm_eo = ms->search.s_len; + pmatch[0].rm_eo = slen; #endif - rc = regexec(&rx, (const char *)ms->search.s, + rc = file_regexec(&rx, (const char *)search, 1, pmatch, REG_STARTEND); #if REG_STARTEND == 0 - ((char *)(intptr_t)ms->search.s)[l] = c; + free(copy); #endif switch (rc) { case 0: @@ -2018,14 +2030,12 @@ magiccheck(struct magic_set *ms, struct magic *m) break; default: - (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); - file_magerror(ms, "regexec error %d, (%s)", - rc, errmsg); + file_regerror(&rx, rc, ms); v = (uint64_t)-1; break; } - regfree(&rx); } + file_regfree(&rx); if (v == (uint64_t)-1) return -1; break; @@ -2122,7 +2132,6 @@ magiccheck(struct magic_set *ms, struct magic *m) break; default: - matched = 0; file_magerror(ms, "cannot happen: invalid relation `%c'", m->reln); return -1; |