https://github.com/file/file/commit/6f737ddfadb596d7d4a993f7ed2141ffd664a81c https://github.com/file/file/commit/90018fe22ff8b74a22fcd142225b0a00f3f12677 https://github.com/file/file/commit/6bf45271eb8e0e6577b92042ce2003ba998d1686 diff -uNrp file-5.19.orig/src/apprentice.c file-5.19/src/apprentice.c --- file-5.19.orig/src/apprentice.c 2014-06-03 15:01:34.000000000 -0400 +++ file-5.19/src/apprentice.c 2014-12-16 10:19:24.637673122 -0500 @@ -506,6 +506,7 @@ file_ms_alloc(int flags) ms->mlist[i] = NULL; ms->file = "unknown"; ms->line = 0; + ms->max_recursion = FILE_MAX_RECURSION; return ms; free: free(ms); diff -uNrp file-5.19.orig/src/file.c file-5.19/src/file.c --- file-5.19.orig/src/file.c 2014-02-11 10:41:04.000000000 -0500 +++ file-5.19/src/file.c 2014-12-16 10:19:24.637673122 -0500 @@ -101,7 +101,7 @@ private const struct option long_options #undef OPT_LONGONLY {0, 0, NULL, 0} }; -#define OPTSTRING "bcCde:Ef:F:hiklLm:nNprsvz0" +#define OPTSTRING "bcCde:Ef:F:hiklLm:nNprR:svz0" private const struct { const char *name; @@ -140,6 +140,7 @@ main(int argc, char *argv[]) size_t i; int action = 0, didsomefiles = 0, errflg = 0; int flags = 0, e = 0; + size_t max_recursion = 0; struct magic_set *magic = NULL; int longindex; const char *magicfile = NULL; /* where the magic is */ @@ -246,6 +247,9 @@ main(int argc, char *argv[]) case 'r': flags |= MAGIC_RAW; break; + case 'R': + max_recursion = atoi(optarg); + break; case 's': flags |= MAGIC_DEVICES; break; @@ -298,6 +302,8 @@ main(int argc, char *argv[]) strerror(errno)); return 1; } + + switch(action) { case FILE_CHECK: c = magic_check(magic, magicfile); @@ -321,6 +327,15 @@ main(int argc, char *argv[]) if (magic == NULL) if ((magic = load(magicfile, flags)) == NULL) return 1; + if (max_recursion) { + if (magic_setparam(magic, MAGIC_PARAM_MAX_RECURSION, + &max_recursion) == -1) { + (void)fprintf(stderr, + "%s: Can't set recurision %s\n", progname, + strerror(errno)); + return 1; + } + } break; } diff -uNrp file-5.19.orig/src/file.h file-5.19/src/file.h --- file-5.19.orig/src/file.h 2014-06-03 15:01:34.000000000 -0400 +++ file-5.19/src/file.h 2014-12-16 10:19:24.637673122 -0500 @@ -401,6 +401,8 @@ struct magic_set { /* FIXME: Make the string dynamically allocated so that e.g. strings matched in files can be longer than MAXstring */ union VALUETYPE ms_value; /* either number or string */ + size_t max_recursion; +#define FILE_MAX_RECURSION 15 }; /* Type for Unicode characters */ @@ -482,6 +484,14 @@ protected int file_regexec(file_regex_t protected void file_regfree(file_regex_t *); protected void file_regerror(file_regex_t *, int, struct magic_set *); +typedef struct { + char *buf; + uint32_t offset; +} file_pushbuf_t; + +protected file_pushbuf_t *file_push_buffer(struct magic_set *); +protected char *file_pop_buffer(struct magic_set *, file_pushbuf_t *); + #ifndef COMPILE_ONLY extern const char *file_names[]; extern const size_t file_nnames; diff -uNrp file-5.19.orig/src/file_opts.h file-5.19/src/file_opts.h --- file-5.19.orig/src/file_opts.h 2013-04-02 12:25:42.000000000 -0400 +++ file-5.19/src/file_opts.h 2014-12-16 10:19:24.637673122 -0500 @@ -44,6 +44,7 @@ OPT('0', "print0", 0, " te OPT('p', "preserve-date", 0, " preserve access times on files\n") #endif OPT('r', "raw", 0, " don't translate unprintable chars to \\ooo\n") +OPT('R', "recursion", 0, " set maximum recursion level\n") OPT('s', "special-files", 0, " treat special (block/char devices) files as\n" " ordinary ones\n") OPT('C', "compile", 0, " compile file specified by -m\n") diff -uNrp file-5.19.orig/src/funcs.c file-5.19/src/funcs.c --- file-5.19.orig/src/funcs.c 2014-05-14 19:15:42.000000000 -0400 +++ file-5.19/src/funcs.c 2014-12-16 10:18:50.467516983 -0500 @@ -491,3 +491,43 @@ file_regerror(file_regex_t *rx, int rc, file_magerror(ms, "regex error %d for `%s', (%s)", rc, rx->pat, errmsg); } + +protected file_pushbuf_t * +file_push_buffer(struct magic_set *ms) +{ + file_pushbuf_t *pb; + + if (ms->event_flags & EVENT_HAD_ERR) + return NULL; + + if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL) + return NULL; + + pb->buf = ms->o.buf; + pb->offset = ms->offset; + + ms->o.buf = NULL; + ms->offset = 0; + + return pb; +} + +protected char * +file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb) +{ + char *rbuf; + + if (ms->event_flags & EVENT_HAD_ERR) { + free(pb->buf); + free(pb); + return NULL; + } + + rbuf = ms->o.buf; + + ms->o.buf = pb->buf; + ms->offset = pb->offset; + + free(pb); + return rbuf; +} diff -uNrp file-5.19.orig/src/magic.c file-5.19/src/magic.c --- file-5.19.orig/src/magic.c 2014-05-14 19:15:42.000000000 -0400 +++ file-5.19/src/magic.c 2014-12-16 10:19:24.637673122 -0500 @@ -522,3 +522,29 @@ magic_version(void) { return MAGIC_VERSION; } + +public int +magic_setparam(struct magic_set *ms, int param, const void *val) +{ + switch (param) { + case MAGIC_PARAM_MAX_RECURSION: + ms->max_recursion = *(const size_t *)val; + return 0; + default: + errno = EINVAL; + return -1; + } +} + +public int +magic_getparam(struct magic_set *ms, int param, void *val) +{ + switch (param) { + case MAGIC_PARAM_MAX_RECURSION: + *(size_t *)val = ms->max_recursion; + return 0; + default: + errno = EINVAL; + return -1; + } +} diff -uNrp file-5.19.orig/src/magic.h.in file-5.19/src/magic.h.in --- file-5.19.orig/src/magic.h.in 2013-09-10 15:57:14.000000000 -0400 +++ file-5.19/src/magic.h.in 2014-12-16 10:22:46.788591402 -0500 @@ -101,6 +101,10 @@ int magic_check(magic_t, const char *); int magic_list(magic_t, const char *); int magic_errno(magic_t); +#define MAGIC_PARAM_MAX_RECURSION 0 +int magic_setparam(magic_t, int, const void *); +int magic_getparam(magic_t, int, void *); + #ifdef __cplusplus }; #endif diff -uNrp file-5.19.orig/src/softmagic.c file-5.19/src/softmagic.c --- file-5.19.orig/src/softmagic.c 2014-06-04 13:36:34.000000000 -0400 +++ file-5.19/src/softmagic.c 2014-12-16 10:22:57.918643312 -0500 @@ -47,10 +47,10 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.1 private int match(struct magic_set *, struct magic *, uint32_t, - const unsigned char *, size_t, size_t, int, int, int, int, int *, int *, + const unsigned char *, size_t, size_t, int, int, int, size_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 *, + struct magic *, size_t, size_t, unsigned int, int, int, int, size_t, int *, int *, int *); private int magiccheck(struct magic_set *, struct magic *); private int32_t mprint(struct magic_set *, struct magic *); @@ -67,6 +67,7 @@ private void cvt_32(union VALUETYPE *, c 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. @@ -136,8 +137,8 @@ file_fmtcheck(struct magic_set *ms, cons 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, size_t recursion_level, int *printed_something, + int *need_separator, int *returnval) { uint32_t magindex = 0; unsigned int cont_level = 0; @@ -1190,18 +1191,20 @@ mcopy(struct magic_set *ms, union VALUET 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 flip, size_t recursion_level, int *printed_something, int *need_separator, int *returnval) { - uint32_t soffset, offset = ms->offset; + uint32_t offset = ms->offset; uint32_t lhs; + file_pushbuf_t *pb; int rv, oneed_separator, in_type; - char *sbuf, *rbuf; + char *rbuf; union VALUETYPE *p = &ms->ms_value; struct mlist ml; - if (recursion_level >= 20) { - file_error(ms, 0, "recursion nesting exceeded"); + if (recursion_level >= ms->max_recursion) { + file_error(ms, 0, "recursion nesting (%zu) exceeded", + recursion_level); return -1; } @@ -1644,19 +1647,23 @@ mget(struct magic_set *ms, const unsigne case FILE_INDIRECT: if (offset == 0) return 0; + if (nbytes < offset) return 0; - sbuf = ms->o.buf; - soffset = ms->offset; - ms->o.buf = NULL; - ms->offset = 0; + + if ((pb = file_push_buffer(ms)) == NULL) + return -1; + rv = file_softmagic(ms, s + offset, nbytes - offset, recursion_level, BINTEST, text); + if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); - rbuf = ms->o.buf; - ms->o.buf = sbuf; - ms->offset = soffset; + + rbuf = file_pop_buffer(ms, pb); + if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR) + return -1; + if (rv == 1) { if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 && file_printf(ms, F(ms, m, "%u"), offset) == -1) { @@ -1674,13 +1681,13 @@ mget(struct magic_set *ms, const unsigne case FILE_USE: if (nbytes < offset) return 0; - sbuf = m->value.s; - if (*sbuf == '^') { - sbuf++; + rbuf = m->value.s; + if (*rbuf == '^') { + rbuf++; flip = !flip; } - if (file_magicfind(ms, sbuf, &ml) == -1) { - file_error(ms, 0, "cannot find entry `%s'", sbuf); + if (file_magicfind(ms, rbuf, &ml) == -1) { + file_error(ms, 0, "cannot find entry `%s'", rbuf); return -1; }