diff options
Diffstat (limited to 'src/softmagic.c')
| -rw-r--r-- | src/softmagic.c | 273 |
1 files changed, 202 insertions, 71 deletions
diff --git a/src/softmagic.c b/src/softmagic.c index b9e975374b40..00d5aac6000f 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.249 2017/06/19 18:30:25 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.259 2018/03/11 01:23:52 christos Exp $") #endif /* lint */ #include "magic.h" @@ -44,20 +44,26 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.249 2017/06/19 18:30:25 christos Exp $") #include "der.h" private int match(struct magic_set *, struct magic *, uint32_t, - const unsigned char *, size_t, size_t, int, int, int, uint16_t *, + const struct buffer *, 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, uint16_t *, +private int mget(struct magic_set *, struct magic *, const struct buffer *, + const unsigned char *, size_t, + size_t, unsigned int, int, int, int, uint16_t *, uint16_t *, int *, int *, int *); +private int msetoffset(struct magic_set *, struct magic *, struct buffer *, + const struct buffer *, size_t, unsigned int); private int magiccheck(struct magic_set *, struct magic *); -private int32_t mprint(struct magic_set *, struct magic *); -private int moffset(struct magic_set *, struct magic *, size_t, int32_t *); +private int32_t mprint(struct magic_set *, struct magic *, + const struct buffer *); +private int moffset(struct magic_set *, struct magic *, const struct buffer *, + int32_t *); 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, 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 *, int); +private int handle_annotation(struct magic_set *, struct magic *, + const struct buffer *, int); private int cvt_8(union VALUETYPE *, const struct magic *); private int cvt_16(union VALUETYPE *, const struct magic *); private int cvt_32(union VALUETYPE *, const struct magic *); @@ -88,7 +94,7 @@ private int 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, +file_softmagic(struct magic_set *ms, const struct buffer *b, uint16_t *indir_count, uint16_t *name_count, int mode, int text) { struct mlist *ml; @@ -105,7 +111,7 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, } 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, + if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode, text, 0, indir_count, name_count, &printed_something, &need_separator, NULL)) != 0) return rv; @@ -118,18 +124,18 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, #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, +file_fmtcheck(struct magic_set *ms, const char *desc, const char *def, const char *file, size_t line) { - const char *ptr = fmtcheck(m->desc, def); + const char *ptr = fmtcheck(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); + " with `%s'", file, line, desc, def); return ptr; } #else -#define F(a, b, c) fmtcheck((b)->desc, (c)) +#define F(a, b, c) fmtcheck((b), (c)) #endif /* @@ -161,7 +167,7 @@ file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def, */ 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, + const struct buffer *b, size_t offset, int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count, int *printed_something, int *need_separator, int *returnval) { @@ -169,6 +175,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, unsigned int cont_level = 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 */ + struct buffer bb; int print = (ms->flags & MAGIC_NODESC) == 0; if (returnval == NULL) @@ -196,12 +203,13 @@ flush: continue; /* Skip to next top-level test*/ } - ms->offset = m->offset; + if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) + goto flush; ms->line = m->lineno; /* if main entry matches, print it... */ - switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text, - flip, indir_count, name_count, + switch (mget(ms, m, b, bb.fbuf, bb.flen, offset, cont_level, + mode, text, flip, indir_count, name_count, printed_something, need_separator, returnval)) { case -1: return -1; @@ -232,7 +240,7 @@ flush: goto flush; } - if ((e = handle_annotation(ms, m, firstline)) != 0) { + if ((e = handle_annotation(ms, m, b, firstline)) != 0) { *need_separator = 1; *printed_something = 1; *returnval = 1; @@ -250,11 +258,10 @@ flush: return -1; } - - if (print && mprint(ms, m) == -1) + if (print && mprint(ms, m, b) == -1) return -1; - switch (moffset(ms, m, nbytes, &ms->c.li[cont_level].off)) { + switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) { case -1: case 0: goto flush; @@ -280,7 +287,8 @@ flush: */ cont_level = m->cont_level; } - ms->offset = m->offset; + if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) + goto flush; if (m->flag & OFFADD) { ms->offset += ms->c.li[cont_level - 1].off; @@ -293,9 +301,10 @@ flush: continue; } #endif - switch (mget(ms, s, m, nbytes, offset, cont_level, mode, - text, flip, indir_count, name_count, - printed_something, need_separator, returnval)) { + switch (mget(ms, m, b, bb.fbuf, bb.flen, offset, + cont_level, mode, text, flip, indir_count, + name_count, printed_something, need_separator, + returnval)) { case -1: return -1; case 0: @@ -330,7 +339,8 @@ flush: } else ms->c.li[cont_level].got_match = 1; - if ((e = handle_annotation(ms, m, firstline)) != 0) { + if ((e = handle_annotation(ms, m, b, firstline)) + != 0) { *need_separator = 1; *printed_something = 1; *returnval = 1; @@ -363,10 +373,10 @@ flush: return -1; *need_separator = 0; } - if (print && mprint(ms, m) == -1) + if (print && mprint(ms, m, b) == -1) return -1; - switch (moffset(ms, m, nbytes, + switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) { case -1: case 0: @@ -404,19 +414,19 @@ flush: } private int -check_fmt(struct magic_set *ms, struct magic *m) +check_fmt(struct magic_set *ms, const char *fmt) { file_regex_t rx; int rc, rv = -1; - if (strchr(m->desc, '%') == NULL) + if (strchr(fmt, '%') == NULL) return 0; rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); if (rc) { file_regerror(&rx, rc, ms); } else { - rc = file_regexec(&rx, m->desc, 0, 0, 0); + rc = file_regexec(&rx, fmt, 0, 0, 0); rv = !rc; } file_regfree(&rx); @@ -442,30 +452,91 @@ strndup(const char *str, size_t n) } #endif /* HAVE_STRNDUP */ +static int +varexpand(char *buf, size_t len, const struct buffer *b, const char *str) +{ + const char *ptr, *sptr, *e, *t, *ee, *et; + size_t l; + + for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) { + l = (size_t)(ptr - sptr); + if (l >= len) + return -1; + memcpy(buf, sptr, l); + buf += l; + len -= l; + ptr += 2; + if (!*ptr || ptr[1] != '?') + return -1; + for (et = t = ptr + 2; *et && *et != ':'; et++) + continue; + if (*et != ':') + return -1; + for (ee = e = et + 1; *ee && *ee != '}'; ee++) + continue; + if (*ee != '}') + return -1; + switch (*ptr) { + case 'x': + if (b->st.st_mode & 0111) { + ptr = t; + l = et - t; + } else { + ptr = e; + l = ee - e; + } + break; + default: + return -1; + } + if (l >= len) + return -1; + memcpy(buf, ptr, l); + buf += l; + len -= l; + sptr = ee + 1; + } + + l = strlen(sptr); + if (l >= len) + return -1; + + memcpy(buf, sptr, l); + buf[l] = '\0'; + return 0; +} + + private int32_t -mprint(struct magic_set *ms, struct magic *m) +mprint(struct magic_set *ms, struct magic *m, const struct buffer *b) { uint64_t v; float vf; double vd; int64_t t = 0; - char buf[128], tbuf[26], sbuf[512]; + char buf[128], tbuf[26], sbuf[512], ebuf[512]; + const char *desc; union VALUETYPE *p = &ms->ms_value; + if (varexpand(ebuf, sizeof(ebuf), b, m->desc) == -1) + desc = m->desc; + else + desc = ebuf; + switch (m->type) { case FILE_BYTE: v = file_signextend(ms, m, (uint64_t)p->b); - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%d", (unsigned char)v); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%d"), + if (file_printf(ms, F(ms, desc, "%d"), (unsigned char) v) == -1) return -1; break; @@ -477,17 +548,17 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BESHORT: case FILE_LESHORT: v = file_signextend(ms, m, (uint64_t)p->h); - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%u", (unsigned short)v); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%u"), + if (file_printf(ms, F(ms, desc, "%u"), (unsigned short) v) == -1) return -1; break; @@ -500,16 +571,16 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_LELONG: case FILE_MELONG: v = file_signextend(ms, m, (uint64_t)p->l); - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1) + if (file_printf(ms, F(ms, desc, "%u"), (uint32_t) v) == -1) return -1; break; } @@ -520,17 +591,17 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEQUAD: case FILE_LEQUAD: v = file_signextend(ms, m, p->q); - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { 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) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"), + if (file_printf(ms, F(ms, desc, "%" INT64_T_FORMAT "u"), (unsigned long long) v) == -1) return -1; break; @@ -543,7 +614,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BESTRING16: case FILE_LESTRING16: if (m->reln == '=' || m->reln == '!') { - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_printable(sbuf, sizeof(sbuf), m->value.s)) == -1) return -1; @@ -571,7 +642,7 @@ mprint(struct magic_set *ms, struct magic *m) *++last = '\0'; } - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_printable(sbuf, sizeof(sbuf), str)) == -1) return -1; @@ -584,7 +655,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEDATE: case FILE_LEDATE: case FILE_MEDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->l, 0, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint32_t); @@ -594,7 +665,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BELDATE: case FILE_LELDATE: case FILE_MELDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint32_t); @@ -603,7 +674,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QDATE: case FILE_BEQDATE: case FILE_LEQDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->q, 0, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); @@ -612,7 +683,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QLDATE: case FILE_BEQLDATE: case FILE_LEQLDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); @@ -621,7 +692,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QWDATE: case FILE_BEQWDATE: case FILE_LEQWDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); @@ -631,16 +702,16 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEFLOAT: case FILE_LEFLOAT: vf = p->f; - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%g", vf); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%g"), vf) == -1) + if (file_printf(ms, F(ms, desc, "%g"), vf) == -1) return -1; break; } @@ -651,16 +722,16 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEDOUBLE: case FILE_LEDOUBLE: vd = p->d; - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%g", vd); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%g"), vd) == -1) + if (file_printf(ms, F(ms, desc, "%g"), vd) == -1) return -1; break; } @@ -677,7 +748,7 @@ mprint(struct magic_set *ms, struct magic *m) file_oomem(ms, ms->search.rm_len); return -1; } - rval = file_printf(ms, F(ms, m, "%s"), + rval = file_printf(ms, F(ms, desc, "%s"), file_printable(sbuf, sizeof(sbuf), cp)); free(cp); @@ -704,7 +775,7 @@ mprint(struct magic_set *ms, struct magic *m) t = ms->offset; break; case FILE_DER: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1) return -1; t = ms->offset; @@ -717,8 +788,10 @@ mprint(struct magic_set *ms, struct magic *m) } private int -moffset(struct magic_set *ms, struct magic *m, size_t nbytes, int32_t *op) +moffset(struct magic_set *ms, struct magic *m, const struct buffer *b, + int32_t *op) { + size_t nbytes = b->flen; int32_t o; switch (m->type) { @@ -1232,7 +1305,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, b++; } if (lines) - last = RCAST(const char *, s) + bytecnt; + last = end; ms->search.s = buf; ms->search.s_len = last - buf; @@ -1337,12 +1410,58 @@ do_ops(struct magic *m, intmax_t lhs, intmax_t off) } 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, uint16_t *indir_count, uint16_t *name_count, +msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb, + const struct buffer *b, size_t o, unsigned int cont_level) +{ + if (m->offset < 0) { + if (cont_level > 0) { + if (m->flag & (OFFADD|INDIROFFADD)) + goto normal; +#if 0 + file_error(ms, 0, "negative offset %d at continuation" + "level %u", m->offset, cont_level); + return -1; +#endif + } + if (buffer_fill(b) == -1) + return -1; + if (o != 0) { + // Not yet! + file_magerror(ms, "non zero offset %zu at" + " level %u", o, cont_level); + return -1; + } + if ((size_t)-m->offset > b->elen) + return -1; + buffer_init(bb, -1, b->ebuf, b->elen); + ms->eoffset = ms->offset = b->elen + m->offset; + } else { + if (cont_level == 0) { +normal: + // XXX: Pass real fd, then who frees bb? + buffer_init(bb, -1, b->fbuf, b->flen); + ms->offset = m->offset; + ms->eoffset = 0; + } else { + ms->offset = ms->eoffset + m->offset; + } + } + if ((ms->flags & MAGIC_DEBUG) != 0) { + fprintf(stderr, "bb=[%p,%zu], %d [b=%p,%zu], [o=%#x, c=%d]\n", + bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen, + m->offset, cont_level); + } + return 0; +} + +private int +mget(struct magic_set *ms, struct magic *m, const struct buffer *b, + const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level, + int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count, int *printed_something, int *need_separator, int *returnval) { uint32_t offset = ms->offset; + struct buffer bb; intmax_t lhs; file_pushbuf_t *pb; int rv, oneed_separator, in_type; @@ -1362,6 +1481,8 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return -1; } + + if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o), (uint32_t)nbytes, m) == -1) return -1; @@ -1559,7 +1680,10 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return -1; (*indir_count)++; - rv = file_softmagic(ms, s + offset, nbytes - offset, + bb = *b; + bb.fbuf = s + offset; + bb.flen = nbytes - offset; + rv = file_softmagic(ms, &bb, indir_count, name_count, BINTEST, text); if ((ms->flags & MAGIC_DEBUG) != 0) @@ -1571,7 +1695,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (rv == 1) { if ((ms->flags & MAGIC_NODESC) == 0 && - file_printf(ms, F(ms, m, "%u"), offset) == -1) { + file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) { free(rbuf); return -1; } @@ -1599,12 +1723,12 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, oneed_separator = *need_separator; if (m->flag & NOSPACE) *need_separator = 0; - rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o, + rv = match(ms, ml.magic, ml.nmagic, b, offset + o, mode, text, flip, indir_count, name_count, printed_something, need_separator, returnval); if (rv != 1) *need_separator = oneed_separator; - return 1; + return rv; case FILE_NAME: if (ms->flags & MAGIC_NODESC) @@ -2035,7 +2159,8 @@ magiccheck(struct magic_set *ms, struct magic *m) } private int -handle_annotation(struct magic_set *ms, struct magic *m, int firstline) +handle_annotation(struct magic_set *ms, struct magic *m, const struct buffer *b, + int firstline) { if ((ms->flags & MAGIC_APPLE) && m->apple[0]) { if (!firstline && file_printf(ms, "\n- ") == -1) @@ -2052,9 +2177,15 @@ handle_annotation(struct magic_set *ms, struct magic *m, int firstline) return 1; } if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) { + char buf[1024]; + const char *p; if (!firstline && file_printf(ms, "\n- ") == -1) return -1; - if (file_printf(ms, "%s", m->mimetype) == -1) + if (varexpand(buf, sizeof(buf), b, m->mimetype) == -1) + p = m->mimetype; + else + p = buf; + if (file_printf(ms, "%s", p) == -1) return -1; return 1; } |
