diff options
Diffstat (limited to 'contrib/file/src/softmagic.c')
-rw-r--r-- | contrib/file/src/softmagic.c | 143 |
1 files changed, 97 insertions, 46 deletions
diff --git a/contrib/file/src/softmagic.c b/contrib/file/src/softmagic.c index b0f193d..c20ae67 100644 --- a/contrib/file/src/softmagic.c +++ b/contrib/file/src/softmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.191 2014/06/04 17:36:34 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.203 2014/12/04 15:22:05 christos Exp $") #endif /* lint */ #include "magic.h" @@ -41,17 +41,13 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.191 2014/06/04 17:36:34 christos Exp $") #include <ctype.h> #include <stdlib.h> #include <time.h> -#if defined(HAVE_LOCALE_H) -#include <locale.h> -#endif - private int match(struct magic_set *, struct magic *, uint32_t, - const unsigned char *, size_t, size_t, int, int, int, 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, 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 *); @@ -68,8 +64,6 @@ private void cvt_64(union VALUETYPE *, const struct magic *); #define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o))) -#define MAX_RECURSION_LEVEL 10 - /* * softmagic - lookup one file in parsed, in-memory copy of database * Passed the name and FILE * of one file to be typed. @@ -77,14 +71,21 @@ 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, - size_t level, int mode, int text) + uint16_t indir_level, uint16_t *name_count, int mode, int text) { struct mlist *ml; 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, level, &printed_something, &need_separator, - NULL)) != 0) + text, 0, indir_level, name_count, + &printed_something, &need_separator, NULL)) != 0) return rv; return 0; @@ -101,8 +102,8 @@ file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def, const char *ptr = fmtcheck(m->desc, def); if (ptr == def) file_magerror(ms, - "%s, %zu: format `%s' does not match with `%s'", - file, line, m->desc, def); + "%s, %" SIZE_T_FORMAT "u: format `%s' does not match" + " with `%s'", file, line, m->desc, def); return ptr; } #else @@ -139,8 +140,8 @@ 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, - int flip, int recursion_level, int *printed_something, int *need_separator, - 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; @@ -177,8 +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, recursion_level + 1, printed_something, - need_separator, returnval)) { + flip, indir_level, name_count, + printed_something, need_separator, returnval)) { case -1: return -1; case 0: @@ -238,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 (++magindex < nmagic && - magic[magindex].cont_level != 0) { - 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) @@ -266,8 +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, recursion_level + 1, printed_something, - need_separator, returnval)) { + text, flip, indir_level, name_count, + printed_something, need_separator, returnval)) { case -1: return -1; case 0: @@ -403,6 +404,28 @@ strndup(const char *str, size_t n) } #endif /* HAVE_STRNDUP */ +static char * +printable(char *buf, size_t bufsiz, const char *str) +{ + char *ptr, *eptr; + const unsigned char *s = (const unsigned char *)str; + + for (ptr = buf, eptr = ptr + bufsiz - 1; ptr < eptr && *s; s++) { + if (isprint(*s)) { + *ptr++ = *s; + continue; + } + if (ptr >= eptr + 4) + break; + *ptr++ = '\\'; + *ptr++ = ((*s >> 6) & 7) + '0'; + *ptr++ = ((*s >> 3) & 7) + '0'; + *ptr++ = ((*s >> 0) & 7) + '0'; + } + *ptr = '\0'; + return buf; +} + private int32_t mprint(struct magic_set *ms, struct magic *m) { @@ -509,6 +532,7 @@ mprint(struct magic_set *ms, struct magic *m) t = ms->offset + m->vallen; } else { + char sbuf[512]; char *str = p->s; /* compute t before we mangle the string? */ @@ -530,7 +554,8 @@ mprint(struct magic_set *ms, struct magic *m) *++last = '\0'; } - if (file_printf(ms, F(ms, m, "%s"), str) == -1) + if (file_printf(ms, F(ms, m, "%s"), + printable(sbuf, sizeof(sbuf), str)) == -1) return -1; if (m->type == FILE_PSTRING) @@ -946,14 +971,17 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) 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)) { + 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 = sizeof(p->s) - sz; + len = sz; } while (len--) *ptr1++ = *ptr2++; @@ -1063,7 +1091,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); @@ -1193,8 +1221,8 @@ 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 recursion_level, int *printed_something, - int *need_separator, 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 lhs; @@ -1204,8 +1232,15 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, union VALUETYPE *p = &ms->ms_value; struct mlist ml; - if (recursion_level >= MAX_RECURSION_LEVEL) { - file_error(ms, 0, "recursion nesting exceeded"); + 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; } @@ -1214,8 +1249,11 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return -1; if ((ms->flags & MAGIC_DEBUG) != 0) { - fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, " - "nbytes=%zu)\n", m->type, m->flag, offset, o, nbytes); + 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); @@ -1656,7 +1694,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return -1; rv = file_softmagic(ms, s + offset, nbytes - offset, - recursion_level, BINTEST, text); + indir_level + 1, name_count, BINTEST, text); if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); @@ -1691,13 +1729,13 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, file_error(ms, 0, "cannot find entry `%s'", rbuf); return -1; } - + (*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, recursion_level, printed_something, - need_separator, returnval); + mode, text, flip, indir_level, name_count, + printed_something, need_separator, returnval); if (rv != 1) *need_separator = oneed_separator; return rv; @@ -1952,6 +1990,7 @@ magiccheck(struct magic_set *ms, struct magic *m) case FILE_REGEX: { int rc; file_regex_t rx; + const char *search; if (ms->search.s == NULL) return 0; @@ -1968,19 +2007,31 @@ magiccheck(struct magic_set *ms, struct magic *m) size_t slen = ms->search.s_len; #ifndef REG_STARTEND #define REG_STARTEND 0 - char c; - if (slen != 0) - slen--; - c = ms->search.s[slen]; - ((char *)(intptr_t)ms->search.s)[slen] = '\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 = slen; #endif - rc = file_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: |