diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/apprentice.c | 152 | ||||
-rw-r--r-- | src/ascmagic.c | 14 | ||||
-rw-r--r-- | src/buffer.c | 6 | ||||
-rw-r--r-- | src/compress.c | 56 | ||||
-rw-r--r-- | src/der.c | 78 | ||||
-rw-r--r-- | src/file.c | 90 | ||||
-rw-r--r-- | src/file.h | 94 | ||||
-rw-r--r-- | src/file_opts.h | 97 | ||||
-rw-r--r-- | src/funcs.c | 138 | ||||
-rw-r--r-- | src/is_json.c | 17 | ||||
-rw-r--r-- | src/magic.c | 5 | ||||
-rw-r--r-- | src/print.c | 29 | ||||
-rw-r--r-- | src/readelf.c | 45 | ||||
-rw-r--r-- | src/seccomp.c | 13 | ||||
-rw-r--r-- | src/softmagic.c | 158 |
15 files changed, 708 insertions, 284 deletions
diff --git a/src/apprentice.c b/src/apprentice.c index 7ebd6897bd04..1437bcc1179e 100644 --- a/src/apprentice.c +++ b/src/apprentice.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: apprentice.c,v 1.284 2019/06/29 22:31:04 christos Exp $") +FILE_RCSID("@(#)$File: apprentice.c,v 1.297 2020/05/09 18:57:15 christos Exp $") #endif /* lint */ #include "magic.h" @@ -120,6 +120,7 @@ private void apprentice_list(struct mlist *, int ); private struct magic_map *apprentice_load(struct magic_set *, const char *, int); private struct mlist *mlist_alloc(void); +private void mlist_free_all(struct magic_set *); private void mlist_free(struct mlist *); private void byteswap(struct magic *, uint32_t); private void bs1(struct magic *); @@ -137,10 +138,14 @@ private int apprentice_compile(struct magic_set *, struct magic_map *, private int check_format_type(const char *, int, const char **); private int check_format(struct magic_set *, struct magic *); private int get_op(char); -private int parse_mime(struct magic_set *, struct magic_entry *, const char *); -private int parse_strength(struct magic_set *, struct magic_entry *, const char *); -private int parse_apple(struct magic_set *, struct magic_entry *, const char *); -private int parse_ext(struct magic_set *, struct magic_entry *, const char *); +private int parse_mime(struct magic_set *, struct magic_entry *, const char *, + size_t); +private int parse_strength(struct magic_set *, struct magic_entry *, + const char *, size_t); +private int parse_apple(struct magic_set *, struct magic_entry *, const char *, + size_t); +private int parse_ext(struct magic_set *, struct magic_entry *, const char *, + size_t); private size_t magicsize = sizeof(struct magic); @@ -150,7 +155,8 @@ private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; private struct { const char *name; size_t len; - int (*fun)(struct magic_set *, struct magic_entry *, const char *); + int (*fun)(struct magic_set *, struct magic_entry *, const char *, + size_t); } bang[] = { #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name } DECLARE_FIELD(mime), @@ -260,6 +266,8 @@ static const struct type_tbl_s type_tbl[] = { { XX("use"), FILE_USE, FILE_FMT_NONE }, { XX("clear"), FILE_CLEAR, FILE_FMT_NONE }, { XX("der"), FILE_DER, FILE_FMT_STR }, + { XX("guid"), FILE_GUID, FILE_FMT_STR }, + { XX("offset"), FILE_OFFSET, FILE_FMT_QUAD }, { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, }; @@ -451,8 +459,6 @@ apprentice_1(struct magic_set *ms, const char *fn, int action) #ifndef COMPILE_ONLY map = apprentice_map(ms, fn); - if (map == RCAST(struct magic_map *, -1)) - return -1; if (map == NULL) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "using regular magic file `%s'", fn); @@ -463,6 +469,11 @@ apprentice_1(struct magic_set *ms, const char *fn, int action) for (i = 0; i < MAGIC_SETS; i++) { if (add_mlist(ms->mlist[i], map, i) == -1) { + /* failed to add to any list, free explicitly */ + if (i == 0) + apprentice_unmap(map); + else + mlist_free_all(ms); file_oomem(ms, sizeof(*ml)); return -1; } @@ -513,6 +524,7 @@ file_ms_alloc(int flags) } ms->o.buf = ms->o.pbuf = NULL; + ms->o.blen = 0; len = (ms->c.len = 10) * sizeof(*ms->c.li); if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) @@ -582,6 +594,17 @@ mlist_alloc(void) } private void +mlist_free_all(struct magic_set *ms) +{ + size_t i; + + for (i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + ms->mlist[i] = NULL; + } +} + +private void mlist_free_one(struct mlist *ml) { if (ml->map) @@ -597,9 +620,10 @@ mlist_free(struct mlist *mlist) if (mlist == NULL) return; - for (ml = mlist->next; ml != mlist; ml = next) { + for (ml = mlist->next; ml != mlist;) { next = ml->next; mlist_free_one(ml); + ml = next; } mlist_free_one(mlist); } @@ -644,10 +668,7 @@ buffer_apprentice(struct magic_set *ms, struct magic **bufs, return 0; fail: - for (i = 0; i < MAGIC_SETS; i++) { - mlist_free(ms->mlist[i]); - ms->mlist[i] = NULL; - } + mlist_free_all(ms); return -1; } #endif @@ -658,7 +679,7 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) { char *p, *mfn; int fileerr, errs = -1; - size_t i; + size_t i, j; (void)file_reset(ms, 0); @@ -676,9 +697,9 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) mlist_free(ms->mlist[i]); if ((ms->mlist[i] = mlist_alloc()) == NULL) { file_oomem(ms, sizeof(*ms->mlist[i])); - while (i-- > 0) { - mlist_free(ms->mlist[i]); - ms->mlist[i] = NULL; + for (j = 0; j < i; j++) { + mlist_free(ms->mlist[j]); + ms->mlist[j] = NULL; } free(mfn); return -1; @@ -829,9 +850,14 @@ typesize(int type) case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: + case FILE_OFFSET: return 8; + + case FILE_GUID: + return 16; + default: - return CAST(size_t, ~0); + return FILE_BADSIZE; } } @@ -885,8 +911,10 @@ apprentice_magic_strength(const struct magic *m) case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: + case FILE_GUID: + case FILE_OFFSET: ts = typesize(m->type); - if (ts == CAST(size_t, ~0)) + if (ts == FILE_BADSIZE) abort(); val += ts * MULT; break; @@ -1077,6 +1105,8 @@ set_test_type(struct magic *mstart, struct magic *m) case FILE_BEDOUBLE: case FILE_LEDOUBLE: case FILE_DER: + case FILE_GUID: + case FILE_OFFSET: mstart->flag |= BINTEST; break; case FILE_STRING: @@ -1201,7 +1231,8 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, continue; } if ((*bang[i].fun)(ms, &me, - line + bang[i].len + 2) != 0) { + line + bang[i].len + 2, + len - bang[i].len - 2) != 0) { (*errs)++; continue; } @@ -1381,9 +1412,10 @@ apprentice_load(struct magic_set *ms, const char *fn, int action) } if (files >= maxfiles) { size_t mlen; + char **nfilearr; maxfiles = (maxfiles + 1) * 2; mlen = maxfiles * sizeof(*filearr); - if ((filearr = CAST(char **, + if ((nfilearr = CAST(char **, realloc(filearr, mlen))) == NULL) { file_oomem(ms, mlen); free(mfn); @@ -1391,6 +1423,7 @@ apprentice_load(struct magic_set *ms, const char *fn, int action) errs++; goto out; } + filearr = nfilearr; } filearr[files++] = mfn; } @@ -1402,6 +1435,7 @@ apprentice_load(struct magic_set *ms, const char *fn, int action) free(filearr[i]); } free(filearr); + filearr = NULL; } } else load_1(ms, action, fn, &errs, mset); @@ -1436,6 +1470,7 @@ apprentice_load(struct magic_set *ms, const char *fn, int action) } out: + free(filearr); for (j = 0; j < MAGIC_SETS; j++) magic_entry_free(mset[j].me, mset[j].count); @@ -1499,6 +1534,7 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: + case FILE_OFFSET: v = CAST(int64_t, v); break; case FILE_STRING: @@ -1513,12 +1549,13 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) case FILE_USE: case FILE_CLEAR: case FILE_DER: + case FILE_GUID: break; default: if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "cannot happen: m->type=%d\n", m->type); - return ~0U; + return FILE_BADSIZE; } } return v; @@ -1920,6 +1957,10 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, } /* get offset, then skip over it */ + if (*l == '-') { + ++l; /* step over */ + m->flag |= OFFNEGATIVE; + } m->offset = CAST(int32_t, strtol(l, &t, 0)); if (l == t) { if (ms->flags & MAGIC_CHECK) @@ -2224,7 +2265,8 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, * if valid */ private int -parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line) +parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line, + size_t len __attribute__((__unused__))) { const char *l = line; char *el; @@ -2286,7 +2328,8 @@ goodchar(unsigned char x, const char *extra) private int parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, - off_t off, size_t len, const char *name, const char *extra, int nt) + size_t llen, off_t off, size_t len, const char *name, const char *extra, + int nt) { size_t i; const char *l = line; @@ -2307,7 +2350,8 @@ parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, } EATAB; - for (i = 0; *l && i < len && goodchar(*l, extra); buf[i++] = *l++) + for (i = 0; *l && i < llen && i < len && goodchar(*l, extra); + buf[i++] = *l++) continue; if (i == len && *l) { @@ -2336,11 +2380,12 @@ parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, * magic[index - 1] */ private int -parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) +parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line, + size_t len) { struct magic *m = &me->mp[0]; - return parse_extra(ms, me, line, + return parse_extra(ms, me, line, len, CAST(off_t, offsetof(struct magic, apple)), sizeof(m->apple), "APPLE", "!+-./?", 0); } @@ -2349,11 +2394,12 @@ parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) * Parse a comma-separated list of extensions */ private int -parse_ext(struct magic_set *ms, struct magic_entry *me, const char *line) +parse_ext(struct magic_set *ms, struct magic_entry *me, const char *line, + size_t len) { struct magic *m = &me->mp[0]; - return parse_extra(ms, me, line, + return parse_extra(ms, me, line, len, CAST(off_t, offsetof(struct magic, ext)), sizeof(m->ext), "EXTENSION", ",!+-/@?_$", 0); } @@ -2363,11 +2409,12 @@ parse_ext(struct magic_set *ms, struct magic_entry *me, const char *line) * if valid */ private int -parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line) +parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line, + size_t len) { struct magic *m = &me->mp[0]; - return parse_extra(ms, me, line, + return parse_extra(ms, me, line, len, CAST(off_t, offsetof(struct magic, mimetype)), sizeof(m->mimetype), "MIME", "+-/.$?:{}", 1); } @@ -2684,6 +2731,11 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) if (errno == 0) *p = ep; return 0; + case FILE_GUID: + if (file_parse_guid(*p, m->value.guid) == -1) + return -1; + *p += FILE_GUID_SIZE - 1; + return 0; default: errno = 0; ull = CAST(uint64_t, strtoull(*p, &ep, 0)); @@ -2695,7 +2747,7 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) uint64_t x; const char *q; - if (ts == CAST(size_t, ~0)) { + if (ts == FILE_BADSIZE) { file_magwarn(ms, "Expected numeric type got `%s'", type_tbl[m->type].name); @@ -2892,8 +2944,12 @@ getstr(struct magic_set *ms, struct magic *m, const char *s, int warn) out: *p = '\0'; m->vallen = CAST(unsigned char, (p - origp)); - if (m->type == FILE_PSTRING) - m->vallen += CAST(unsigned char, file_pstring_length_size(m)); + if (m->type == FILE_PSTRING) { + size_t l = file_pstring_length_size(ms, m); + if (l == FILE_BADSIZE) + return NULL; + m->vallen += CAST(unsigned char, l); + } return s; } @@ -2923,7 +2979,7 @@ file_showstr(FILE *fp, const char *s, size_t len) char c; for (;;) { - if (len == ~0U) { + if (len == FILE_BADSIZE) { c = *s++; if (c == '\0') break; @@ -3077,13 +3133,11 @@ apprentice_map(struct magic_set *ms, const char *fn) file_badread(ms); goto error; } -#define RET 1 #endif (void)close(fd); fd = -1; if (check_buffer(ms, map, dbname) != 0) { - rv = RCAST(struct magic_map *, -1); goto error; } #ifdef QUICK @@ -3357,7 +3411,7 @@ bs1(struct magic *m) } protected size_t -file_pstring_length_size(const struct magic *m) +file_pstring_length_size(struct magic_set *ms, const struct magic *m) { switch (m->str_flags & PSTRING_LEN) { case PSTRING_1_LE: @@ -3369,12 +3423,15 @@ file_pstring_length_size(const struct magic *m) case PSTRING_4_BE: return 4; default: - abort(); /* Impossible */ - return 1; + file_error(ms, 0, "corrupt magic file " + "(bad pascal string length %d)", + m->str_flags & PSTRING_LEN); + return FILE_BADSIZE; } } protected size_t -file_pstring_get_length(const struct magic *m, const char *ss) +file_pstring_get_length(struct magic_set *ms, const struct magic *m, + const char *ss) { size_t len = 0; const unsigned char *s = RCAST(const unsigned char *, ss); @@ -3409,11 +3466,18 @@ file_pstring_get_length(const struct magic *m, const char *ss) len = (s0 << 24) | (s1 << 16) | (s2 << 8) | s3; break; default: - abort(); /* Impossible */ + file_error(ms, 0, "corrupt magic file " + "(bad pascal string length %d)", + m->str_flags & PSTRING_LEN); + return FILE_BADSIZE; } - if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF) - len -= file_pstring_length_size(m); + if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF) { + size_t l = file_pstring_length_size(ms, m); + if (l == FILE_BADSIZE) + return l; + len -= l; + } return len; } diff --git a/src/ascmagic.c b/src/ascmagic.c index 3bb7359777b9..9d383be32163 100644 --- a/src/ascmagic.c +++ b/src/ascmagic.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: ascmagic.c,v 1.105 2019/06/08 20:49:14 christos Exp $") +FILE_RCSID("@(#)$File: ascmagic.c,v 1.107 2020/06/08 19:58:36 christos Exp $") #endif /* lint */ #include "magic.h" @@ -115,7 +115,6 @@ file_ascmagic_with_encoding(struct magic_set *ms, int need_separator = 0; const char *subtype = NULL; - const char *subtype_mime = NULL; int has_escapes = 0; int has_backspace = 0; @@ -164,8 +163,11 @@ file_ascmagic_with_encoding(struct magic_set *ms, goto done; } } - if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))) - return 0; + + if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))) { + rv = 0; + goto done; + } /* Now try to discover other details about the file. */ for (i = 0; i < ulen; i++) { @@ -222,10 +224,6 @@ file_ascmagic_with_encoding(struct magic_set *ms, } if (need_separator && file_separator(ms) == -1) goto done; - } - if (subtype_mime) { - if (file_printf(ms, "%s", subtype_mime) == -1) - goto done; } else { if (file_printf(ms, "text/plain") == -1) goto done; diff --git a/src/buffer.c b/src/buffer.c index 0a27e5788483..227015ae3e5f 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: buffer.c,v 1.7 2019/06/10 21:35:26 christos Exp $") +FILE_RCSID("@(#)$File: buffer.c,v 1.8 2020/02/16 15:52:49 christos Exp $") #endif /* lint */ #include "magic.h" @@ -64,7 +64,7 @@ buffer_fill(const struct buffer *bb) struct buffer *b = CCAST(struct buffer *, bb); if (b->elen != 0) - return b->elen == CAST(size_t, ~0) ? -1 : 0; + return b->elen == FILE_BADSIZE ? -1 : 0; if (!S_ISREG(b->st.st_mode)) goto out; @@ -83,6 +83,6 @@ buffer_fill(const struct buffer *bb) return 0; out: - b->elen = CAST(size_t, ~0); + b->elen = FILE_BADSIZE; return -1; } diff --git a/src/compress.c b/src/compress.c index 33ce2bc936d6..67f21583c1a0 100644 --- a/src/compress.c +++ b/src/compress.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: compress.c,v 1.124 2019/07/21 11:42:09 christos Exp $") +FILE_RCSID("@(#)$File: compress.c,v 1.127 2020/05/31 00:11:06 christos Exp $") #endif #include "magic.h" @@ -51,7 +51,7 @@ FILE_RCSID("@(#)$File: compress.c,v 1.124 2019/07/21 11:42:09 christos Exp $") #ifndef HAVE_SIG_T typedef void (*sig_t)(int); #endif /* HAVE_SIG_T */ -#if !defined(__MINGW32__) && !defined(WIN32) +#if !defined(__MINGW32__) && !defined(WIN32) && !defined(__MINGW64__) #include <sys/ioctl.h> #endif #ifdef HAVE_SYS_WAIT_H @@ -66,12 +66,12 @@ typedef void (*sig_t)(int); #include <zlib.h> #endif -#if defined(HAVE_BZLIB_H) || defined(BZLIBSUPPORT) +#if defined(HAVE_BZLIB_H) && defined(BZLIBSUPPORT) #define BUILTIN_BZLIB #include <bzlib.h> #endif -#if defined(HAVE_XZLIB_H) || defined(XZLIBSUPPORT) +#if defined(HAVE_XZLIB_H) && defined(XZLIBSUPPORT) #define BUILTIN_XZLIB #include <lzma.h> #endif @@ -161,7 +161,10 @@ static const char *zstd_args[] = { #define do_bzlib NULL private const struct { - const void *magic; + union { + const char *magic; + int (*func)(const unsigned char *); + } u; int maglen; const char **argv; void *unused; @@ -171,26 +174,26 @@ private const struct { #define METH_XZ 9 #define METH_LZMA 13 #define METH_ZLIB 14 - { "\037\235", 2, gzip_args, NULL }, /* 0, compressed */ - /* Uncompress can get stuck; so use gzip first if we have it - * Idea from Damien Clark, thanks! */ - { "\037\235", 2, uncompress_args, NULL }, /* 1, compressed */ - { "\037\213", 2, gzip_args, do_zlib }, /* 2, gzipped */ - { "\037\236", 2, gzip_args, NULL }, /* 3, frozen */ - { "\037\240", 2, gzip_args, NULL }, /* 4, SCO LZH */ - /* the standard pack utilities do not accept standard input */ - { "\037\036", 2, gzip_args, NULL }, /* 5, packed */ - { "PK\3\4", 4, gzip_args, NULL }, /* 6, pkzipped, */ - /* ...only first file examined */ - { "BZh", 3, bzip2_args, do_bzlib }, /* 7, bzip2-ed */ - { "LZIP", 4, lzip_args, NULL }, /* 8, lzip-ed */ - { "\3757zXZ\0", 6, xz_args, NULL }, /* 9, XZ Utils */ - { "LRZI", 4, lrzip_args, NULL }, /* 10, LRZIP */ - { "\004\"M\030",4, lz4_args, NULL }, /* 11, LZ4 */ - { "\x28\xB5\x2F\xFD", 4, zstd_args, NULL }, /* 12, zstd */ - { RCAST(const void *, lzmacmp), -13, xz_args, NULL }, /* 13, lzma */ + { { .magic = "\037\235" }, 2, gzip_args, NULL }, /* 0, compressed */ + /* Uncompress can get stuck; so use gzip first if we have it + * Idea from Damien Clark, thanks! */ + { { .magic = "\037\235" }, 2, uncompress_args, NULL },/* 1, compressed */ + { { .magic = "\037\213" }, 2, gzip_args, do_zlib },/* 2, gzipped */ + { { .magic = "\037\236" }, 2, gzip_args, NULL }, /* 3, frozen */ + { { .magic = "\037\240" }, 2, gzip_args, NULL }, /* 4, SCO LZH */ + /* the standard pack utilities do not accept standard input */ + { { .magic = "\037\036" }, 2, gzip_args, NULL }, /* 5, packed */ + { { .magic = "PK\3\4" }, 4, gzip_args, NULL }, /* 6, pkziped */ + /* ...only first file examined */ + { { .magic = "BZh" }, 3, bzip2_args, do_bzlib },/* 7, bzip2-ed */ + { { .magic = "LZIP" }, 4, lzip_args, NULL }, /* 8, lzip-ed */ + { { .magic = "\3757zXZ\0" },6, xz_args, NULL }, /* 9, XZ Util */ + { { .magic = "LRZI" }, 4, lrzip_args, NULL }, /* 10, LRZIP */ + { { .magic = "\004\"M\030" },4, lz4_args, NULL }, /* 11, LZ4 */ + { { .magic = "\x28\xB5\x2F\xFD" }, 4, zstd_args, NULL },/* 12, zstd */ + { { .func = lzmacmp }, -13, xz_args, NULL }, /* 13, lzma */ #ifdef ZLIBSUPPORT - { RCAST(const void *, zlibcmp), -2, zlib_args, NULL }, /* 14, zlib */ + { { .func = zlibcmp }, -2, zlib_args, NULL }, /* 14, zlib */ #endif }; @@ -262,10 +265,9 @@ file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name) if (nbytes < CAST(size_t, abs(compr[i].maglen))) continue; if (compr[i].maglen < 0) { - zm = (RCAST(int (*)(const unsigned char *), - CCAST(void *, compr[i].magic)))(buf); + zm = (*compr[i].u.func)(buf); } else { - zm = memcmp(buf, compr[i].magic, + zm = memcmp(buf, compr[i].u.magic, CAST(size_t, compr[i].maglen)) == 0; } diff --git a/src/der.c b/src/der.c index 8867c568034d..78a056b90d7e 100644 --- a/src/der.c +++ b/src/der.c @@ -35,8 +35,11 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: der.c,v 1.16 2019/02/20 02:35:27 christos Exp $") +FILE_RCSID("@(#)$File: der.c,v 1.20 2020/06/07 19:10:37 christos Exp $") #endif +#else +#define SIZE_T_FORMAT "z" +#define CAST(a, b) ((a)(b)) #endif #include <sys/types.h> @@ -62,13 +65,13 @@ FILE_RCSID("@(#)$File: der.c,v 1.16 2019/02/20 02:35:27 christos Exp $") #define DER_CLASS_APPLICATION 1 #define DER_CLASS_CONTEXT 2 #define DER_CLASS_PRIVATE 3 -#ifdef DEBUG_DER +#if defined(DEBUG_DER) || defined(TEST_DER) static const char der_class[] = "UACP"; #endif #define DER_TYPE_PRIMITIVE 0 #define DER_TYPE_CONSTRUCTED 1 -#ifdef DEBUG_DER +#if defined(DEBUG_DER) || defined(TEST_DER) static const char der_type[] = "PC"; #endif @@ -86,7 +89,7 @@ static const char der_type[] = "PC"; #define DER_TAG_EMBEDDED_PDV 0x0b #define DER_TAG_UTF8_STRING 0x0c #define DER_TAG_RELATIVE_OID 0x0d -#define DER_TAG_RESERVED_1 0x0e +#define DER_TAG_TIME 0x0e #define DER_TAG_RESERVED_2 0x0f #define DER_TAG_SEQUENCE 0x10 #define DER_TAG_SET 0x11 @@ -103,16 +106,23 @@ static const char der_type[] = "PC"; #define DER_TAG_UNIVERSAL_STRING 0x1c #define DER_TAG_CHARACTER_STRING 0x1d #define DER_TAG_BMP_STRING 0x1e -#define DER_TAG_LONG 0x1f +#define DER_TAG_DATE 0x1f +#define DER_TAG_TIME_OF_DAY 0x20 +#define DER_TAG_DATE_TIME 0x21 +#define DER_TAG_DURATION 0x22 +#define DER_TAG_OID_IRI 0x23 +#define DER_TAG_RELATIVE_OID_IRI 0x24 +#define DER_TAG_LAST 0x25 static const char *der__tag[] = { "eoc", "bool", "int", "bit_str", "octet_str", "null", "obj_id", "obj_desc", "ext", "real", - "enum", "embed", "utf8_str", "oid", "res1", + "enum", "embed", "utf8_str", "rel_oid", "time", "res2", "seq", "set", "num_str", "prt_str", - "t61_str", "vid_str", "ia5_str", "utc_time", - "gen_time", "gr_str", "vis_str", "gen_str", - "char_str", "bmp_str", "long" + "t61_str", "vid_str", "ia5_str", "utc_time", "gen_time", + "gr_str", "vis_str", "gen_str", "univ_str", "char_str", + "bmp_str", "date", "tod", "datetime", "duration", + "oid-iri", "rel-oid-iri", }; #ifdef DEBUG_DER @@ -175,8 +185,10 @@ getlength(const uint8_t *c, size_t *p, size_t l) size_t len; int is_onebyte_result; - if (*p >= l) + if (*p >= l) { + DPRINTF(("%s:[1] %zu >= %zu\n", __func__, *p, l)); return DER_BAD; + } /* * Digits can either be 0b0 followed by the result, or 0b1 @@ -185,8 +197,10 @@ getlength(const uint8_t *c, size_t *p, size_t l) */ is_onebyte_result = (c[*p] & 0x80) == 0; digits = c[(*p)++] & 0x7f; - if (*p + digits >= l) + if (*p + digits >= l) { + DPRINTF(("%s:[2] %zu + %u >= %zu\n", __func__, *p, digits, l)); return DER_BAD; + } if (is_onebyte_result) return digits; @@ -199,15 +213,18 @@ getlength(const uint8_t *c, size_t *p, size_t l) for (i = 0; i < digits; i++) len = (len << 8) | c[(*p)++]; - if (len > UINT32_MAX - *p || *p + len >= l) + if (len > UINT32_MAX - *p || *p + len > l) { + DPRINTF(("%s:[3] bad len %zu + %zu >= %zu\n", + __func__, *p, len, l)); return DER_BAD; + } return CAST(uint32_t, len); } static const char * der_tag(char *buf, size_t len, uint32_t tag) { - if (tag < DER_TAG_LONG) + if (tag < DER_TAG_LAST) strlcpy(buf, der__tag[tag], len); else snprintf(buf, len, "%#x", tag); @@ -223,8 +240,14 @@ der_data(char *buf, size_t blen, uint32_t tag, const void *q, uint32_t len) case DER_TAG_PRINTABLE_STRING: case DER_TAG_UTF8_STRING: case DER_TAG_IA5_STRING: - case DER_TAG_UTCTIME: return snprintf(buf, blen, "%.*s", len, RCAST(const char *, q)); + case DER_TAG_UTCTIME: + if (len < 12) + break; + return snprintf(buf, blen, + "20%c%c-%c%c-%c%c %c%c:%c%c:%c%c GMT", d[0], d[1], d[2], + d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11]); + break; default: break; } @@ -243,14 +266,18 @@ der_offs(struct magic_set *ms, struct magic *m, size_t nbytes) const uint8_t *b = RCAST(const uint8_t *, ms->search.s); size_t offs = 0, len = ms->search.s_len ? ms->search.s_len : nbytes; - if (gettag(b, &offs, len) == DER_BAD) + if (gettag(b, &offs, len) == DER_BAD) { + DPRINTF(("%s: bad tag 1\n", __func__)); return -1; + } DPRINTF(("%s1: %d %" SIZE_T_FORMAT "u %u\n", __func__, ms->offset, offs, m->offset)); uint32_t tlen = getlength(b, &offs, len); - if (tlen == DER_BAD) + if (tlen == DER_BAD) { + DPRINTF(("%s: bad tag 2\n", __func__)); return -1; + } DPRINTF(("%s2: %d %" SIZE_T_FORMAT "u %u\n", __func__, ms->offset, offs, tlen)); @@ -280,13 +307,22 @@ der_cmp(struct magic_set *ms, struct magic *m) uint32_t tag, tlen; char buf[128]; + DPRINTF(("%s: compare %zu bytes\n", __func__, len)); + tag = gettag(b, &offs, len); - if (tag == DER_BAD) + if (tag == DER_BAD) { + DPRINTF(("%s: bad tag 1\n", __func__)); return -1; + } + + DPRINTF(("%s1: %d %" SIZE_T_FORMAT "u %u\n", __func__, ms->offset, + offs, m->offset)); tlen = getlength(b, &offs, len); - if (tlen == DER_BAD) + if (tlen == DER_BAD) { + DPRINTF(("%s: bad tag 2\n", __func__)); return -1; + } der_tag(buf, sizeof(buf), tag); if ((ms->flags & MAGIC_DEBUG) != 0) @@ -342,6 +378,8 @@ printtag(uint32_t tag, const void *q, uint32_t len) switch (tag) { case DER_TAG_PRINTABLE_STRING: case DER_TAG_UTF8_STRING: + case DER_TAG_IA5_STRING: + case DER_TAG_UTCTIME: printf("%.*s\n", len, (const char *)q); return; default: @@ -365,8 +403,8 @@ printdata(size_t level, const void *v, size_t x, size_t l) uint8_t c = getclass(p[x]); uint8_t t = gettype(p[x]); ox = x; - if (x != 0) - printf("%.2x %.2x %.2x\n", p[x - 1], p[x], p[x + 1]); +// if (x != 0) +// printf("%.2x %.2x %.2x\n", p[x - 1], p[x], p[x + 1]); uint32_t tag = gettag(p, &x, ep - p + x); if (p + x >= ep) break; diff --git a/src/file.c b/src/file.c index 89d8cfb99a13..aca585216373 100644 --- a/src/file.c +++ b/src/file.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: file.c,v 1.184 2019/08/03 11:51:59 christos Exp $") +FILE_RCSID("@(#)$File: file.c,v 1.187 2020/06/07 17:38:30 christos Exp $") #endif /* lint */ #include "magic.h" @@ -83,7 +83,8 @@ int getopt_long(int, char * const *, const char *, "Usage: %s [-" FILE_FLAGS "] [--apple] [--extension] [--mime-encoding]\n" \ " [--mime-type] [-e <testname>] [-F <separator>] " \ " [-f <namefile>]\n" \ - " [-m <magicfiles>] [-P <parameter=value>] <file> ...\n" \ + " [-m <magicfiles>] [-P <parameter=value>] [--exclude-quiet]\n" \ + " <file> ...\n" \ " %s -C [-m <magicfiles>]\n" \ " %s [--help]\n" @@ -100,9 +101,10 @@ private const struct option long_options[] = { #define OPT_EXTENSIONS 3 #define OPT_MIME_TYPE 4 #define OPT_MIME_ENCODING 5 -#define OPT(shortname, longname, opt, def, doc) \ +#define OPT_EXCLUDE_QUIET 6 +#define OPT(shortname, longname, opt, def, doc) \ {longname, opt, NULL, shortname}, -#define OPT_LONGONLY(longname, opt, def, doc, id) \ +#define OPT_LONGONLY(longname, opt, def, doc, id) \ {longname, opt, NULL, id}, #include "file_opts.h" #undef OPT @@ -133,14 +135,23 @@ private struct { int tag; size_t value; int set; + size_t def; + const char *desc; } pm[] = { - { "indir", MAGIC_PARAM_INDIR_MAX, 0, 0 }, - { "name", MAGIC_PARAM_NAME_MAX, 0, 0 }, - { "elf_phnum", MAGIC_PARAM_ELF_PHNUM_MAX, 0, 0 }, - { "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0, 0 }, - { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0, 0 }, - { "regex", MAGIC_PARAM_REGEX_MAX, 0, 0 }, - { "bytes", MAGIC_PARAM_BYTES_MAX, 0, 0 }, + { "bytes", MAGIC_PARAM_BYTES_MAX, 0, 0, FILE_BYTES_MAX, + "max bytes to look inside file" }, + { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0, 0, FILE_ELF_NOTES_MAX, + "max ELF notes processed" }, + { "elf_phnum", MAGIC_PARAM_ELF_PHNUM_MAX, 0, 0, FILE_ELF_PHNUM_MAX, + "max ELF prog sections processed" }, + { "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0, 0, FILE_ELF_SHNUM_MAX, + "max ELF sections processed" }, + { "indir", MAGIC_PARAM_INDIR_MAX, 0, 0, FILE_INDIR_MAX, + "recursion limit for indirection" }, + { "name", MAGIC_PARAM_NAME_MAX, 0, 0, FILE_NAME_MAX, + "use limit for name/use magic" }, + { "regex", MAGIC_PARAM_REGEX_MAX, 0, 0, FILE_REGEX_MAX, + "length limit for REGEX searches" }, }; private int posixly; @@ -237,13 +248,15 @@ main(int argc, char *argv[]) flags |= MAGIC_ERROR; break; case 'e': + case OPT_EXCLUDE_QUIET: for (i = 0; i < __arraycount(nv); i++) if (strcmp(nv[i].name, optarg) == 0) break; - if (i == __arraycount(nv)) - errflg++; - else + if (i == __arraycount(nv)) { + if (c != OPT_EXCLUDE_QUIET) + errflg++; + } else flags |= nv[i].value; break; @@ -609,10 +622,10 @@ private void docprint(const char *opts, int def) { size_t i; - int comma; + int comma, pad; char *sp, *p; - p = strstr(opts, "%o"); + p = strchr(opts, '%'); if (p == NULL) { fprintf(stdout, "%s", opts); defprint(def); @@ -623,17 +636,34 @@ docprint(const char *opts, int def) continue; fprintf(stdout, "%.*s", CAST(int, p - opts), opts); - - comma = 0; - for (i = 0; i < __arraycount(nv); i++) { - fprintf(stdout, "%s%s", comma++ ? ", " : "", nv[i].name); - if (i && i % 5 == 0 && i != __arraycount(nv) - 1) { - fprintf(stdout, ",\n%*s", CAST(int, p - sp - 1), ""); - comma = 0; + pad = (int)CAST(int, p - sp - 1); + + switch (*++p) { + case 'e': + comma = 0; + for (i = 0; i < __arraycount(nv); i++) { + fprintf(stdout, "%s%s", comma++ ? ", " : "", nv[i].name); + if (i && i % 5 == 0 && i != __arraycount(nv) - 1) { + fprintf(stdout, ",\n%*s", pad, ""); + comma = 0; + } + } + break; + case 'P': + for (i = 0; i < __arraycount(pm); i++) { + fprintf(stdout, "%9s %7zu %s", pm[i].name, pm[i].def, + pm[i].desc); + if (i != __arraycount(pm) - 1) + fprintf(stdout, "\n%*s", pad, ""); } + break; + default: + file_errx(EXIT_FAILURE, "Unknown escape `%c' in long options", + *p); + break; } + fprintf(stdout, "%s", opts + (p - opts) + 1); - fprintf(stdout, "%s", opts + (p - opts) + 2); } private void @@ -646,7 +676,7 @@ help(void) #define OPT(shortname, longname, opt, def, doc) \ fprintf(stdout, " -%c, --" longname, shortname), \ docprint(doc, def); -#define OPT_LONGONLY(longname, opt, def, doc, id) \ +#define OPT_LONGONLY(longname, opt, def, doc, id) \ fprintf(stdout, " --" longname), \ docprint(doc, def); #include "file_opts.h" @@ -680,7 +710,10 @@ file_err(int e, const char *fmt, ...) fprintf(stderr, "%s: ", file_progname); vfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr, " (%s)\n", strerror(se)); + if (se) + fprintf(stderr, " (%s)\n", strerror(se)); + else + fputc('\n', stderr); exit(e); } @@ -707,7 +740,10 @@ file_warn(const char *fmt, ...) fprintf(stderr, "%s: ", file_progname); vfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr, " (%s)\n", strerror(se)); + if (se) + fprintf(stderr, " (%s)\n", strerror(se)); + else + fputc('\n', stderr); errno = se; } diff --git a/src/file.h b/src/file.h index 947f2089d0af..28ebc0c18ace 100644 --- a/src/file.h +++ b/src/file.h @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.208 2019/06/26 20:31:31 christos Exp $ + * @(#)$File: file.h,v 1.220 2020/06/08 17:38:27 christos Exp $ */ #ifndef __file_h__ @@ -36,7 +36,15 @@ #ifdef HAVE_CONFIG_H #include <config.h> #endif + #ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif @@ -44,28 +52,33 @@ #define __STDC_FORMAT_MACROS #endif -#ifdef WIN32 - #ifdef _WIN64 - #define SIZE_T_FORMAT "I64" - #else - #define SIZE_T_FORMAT "" - #endif - #define INT64_T_FORMAT "I64" - #define INTMAX_T_FORMAT "I64" +#ifdef _WIN32 +# ifdef PRIu32 +# ifdef _WIN64 +# define SIZE_T_FORMAT PRIu64 +# else +# define SIZE_T_FORMAT PRIu32 +# endif +# define INT64_T_FORMAT PRIi64 +# define INTMAX_T_FORMAT PRIiMAX +# else +# ifdef _WIN64 +# define SIZE_T_FORMAT "I64" +# else +# define SIZE_T_FORMAT "" +# endif +# define INT64_T_FORMAT "I64" +# define INTMAX_T_FORMAT "I64" +# endif #else - #define SIZE_T_FORMAT "z" - #define INT64_T_FORMAT "ll" - #define INTMAX_T_FORMAT "j" -#endif -#include <stdint.h> +# define SIZE_T_FORMAT "z" +# define INT64_T_FORMAT "ll" +# define INTMAX_T_FORMAT "j" #endif #include <stdio.h> /* Include that here, to make sure __P gets defined */ #include <errno.h> #include <fcntl.h> /* For open and flags */ -#ifdef HAVE_INTTYPES_H -#include <inttypes.h> -#endif #include <regex.h> #include <time.h> #include <sys/types.h> @@ -130,18 +143,16 @@ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif -#ifndef FILE_BYTES_MAX -# define FILE_BYTES_MAX (1024 * 1024) /* how much of the file to look at */ -#endif -#define MAXMAGIS 8192 /* max entries in any one magic file - or directory */ +#define FILE_BADSIZE CAST(size_t, ~0ul) #define MAXDESC 64 /* max len of text description/MIME type */ #define MAXMIME 80 /* max len of text MIME type */ -#define MAXstring 96 /* max len of "string" types */ +#define MAXstring 128 /* max len of "string" types */ #define MAGICNO 0xF11E041C -#define VERSIONNO 14 -#define FILE_MAGICSIZE 344 +#define VERSIONNO 16 +#define FILE_MAGICSIZE 376 + +#define FILE_GUID_SIZE sizeof("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") #define FILE_LOAD 0 #define FILE_CHECK 1 @@ -168,6 +179,7 @@ union VALUETYPE { uint8_t hq[8]; /* 8 bytes of a fixed-endian "quad" */ char s[MAXstring]; /* the search string or regex pattern */ unsigned char us[MAXstring]; + uint64_t guid[2]; float f; double d; }; @@ -184,6 +196,7 @@ struct magic { #define BINTEST 0x20 /* test is for a binary type (set only for top-level tests) */ #define TEXTTEST 0x40 /* for passing to file_softmagic */ +#define OFFNEGATIVE 0x80 /* relative to the end of file */ uint8_t factor; @@ -241,7 +254,9 @@ struct magic { #define FILE_USE 46 #define FILE_CLEAR 47 #define FILE_DER 48 -#define FILE_NAMES_SIZE 49 /* size of array to contain all names */ +#define FILE_GUID 49 +#define FILE_OFFSET 50 +#define FILE_NAMES_SIZE 51 /* size of array to contain all names */ #define IS_STRING(t) \ ((t) == FILE_STRING || \ @@ -405,9 +420,10 @@ struct magic_set { } c; struct out { char *buf; /* Accumulation buffer */ + size_t blen; /* Length of buffer */ char *pbuf; /* Printable buffer */ } o; - uint32_t offset; /* a copy of m->offset while we */ + uint32_t offset; /* a copy of m->offset while we */ /* are working on the magic entry */ uint32_t eoffset; /* offset from end of file */ int error; @@ -436,11 +452,14 @@ struct magic_set { uint16_t elf_notes_max; uint16_t regex_max; size_t bytes_max; /* number of bytes to read from file */ -#define FILE_INDIR_MAX 50 -#define FILE_NAME_MAX 30 -#define FILE_ELF_SHNUM_MAX 32768 -#define FILE_ELF_PHNUM_MAX 2048 +#ifndef FILE_BYTES_MAX +# define FILE_BYTES_MAX (1024 * 1024) /* how much of the file to look at */ +#endif #define FILE_ELF_NOTES_MAX 256 +#define FILE_ELF_PHNUM_MAX 2048 +#define FILE_ELF_SHNUM_MAX 32768 +#define FILE_INDIR_MAX 50 +#define FILE_NAME_MAX 50 #define FILE_REGEX_MAX 8192 }; @@ -450,7 +469,7 @@ typedef unsigned long unichar; struct stat; #define FILE_T_LOCAL 1 #define FILE_T_WINDOWS 2 -protected const char *file_fmttime(uint64_t, int, char *); +protected const char *file_fmttime(char *, size_t, uint64_t, int); protected struct magic_set *file_ms_alloc(int); protected void file_ms_free(struct magic_set *); protected int file_default(struct magic_set *, size_t); @@ -461,7 +480,11 @@ protected int file_pipe2file(struct magic_set *, int, const void *, size_t); protected int file_vprintf(struct magic_set *, const char *, va_list) __attribute__((__format__(__printf__, 2, 0))); protected int file_separator(struct magic_set *); +protected char *file_copystr(char *, size_t, size_t, const char *); +protected int file_checkfmt(char *, size_t, const char *); protected size_t file_printedlen(const struct magic_set *); +protected int file_print_guid(char *, size_t, const uint64_t *); +protected int file_parse_guid(const char *, uint64_t *); protected int file_replace(struct magic_set *, const char *, const char *); protected int file_printf(struct magic_set *, const char *, ...) __attribute__((__format__(__printf__, 2, 3))); @@ -506,8 +529,10 @@ protected ssize_t sread(int, void *, size_t, int); protected int file_check_mem(struct magic_set *, unsigned int); protected int file_looks_utf8(const unsigned char *, size_t, unichar *, size_t *); -protected size_t file_pstring_length_size(const struct magic *); -protected size_t file_pstring_get_length(const struct magic *, const char *); +protected size_t file_pstring_length_size(struct magic_set *, + const struct magic *); +protected size_t file_pstring_get_length(struct magic_set *, + const struct magic *, const char *); protected char * file_printable(char *, size_t, const char *, size_t); #ifdef __EMX__ protected int file_os2_apptype(struct magic_set *, const char *, const void *, @@ -545,6 +570,7 @@ protected void file_regerror(file_regex_t *, int, struct magic_set *); typedef struct { char *buf; + size_t blen; uint32_t offset; } file_pushbuf_t; diff --git a/src/file_opts.h b/src/file_opts.h index 4f894cc551b3..24909917fe1b 100644 --- a/src/file_opts.h +++ b/src/file_opts.h @@ -15,48 +15,75 @@ * switch statement! */ -OPT_LONGONLY("help", 0, 0, " display this help and exit\n", OPT_HELP) -OPT('v', "version", 0, 0, " output version information and exit\n") -OPT('m', "magic-file", 1, 0, " LIST use LIST as a colon-separated list of magic\n" +OPT_LONGONLY("help", 0, 0, + " display this help and exit\n", OPT_HELP) +OPT('v', "version", 0, 0, + " output version information and exit\n") +OPT('m', "magic-file", 1, 0, + " LIST use LIST as a colon-separated list of magic\n" " number files\n") -OPT('z', "uncompress", 0, 0, " try to look inside compressed files\n") -OPT('Z', "uncompress-noreport", 0, 0, " only print the contents of compressed files\n") -OPT('b', "brief", 0, 0, " do not prepend filenames to output lines\n") -OPT('c', "checking-printout", 0, 0, " print the parsed form of the magic file, use in\n" +OPT('z', "uncompress", 0, 0, + " try to look inside compressed files\n") +OPT('Z', "uncompress-noreport", 0, 0, + " only print the contents of compressed files\n") +OPT('b', "brief", 0, 0, + " do not prepend filenames to output lines\n") +OPT('c', "checking-printout", 0, 0, + " print the parsed form of the magic file, use in\n" " conjunction with -m to debug a new magic file\n" " before installing it\n") -OPT('e', "exclude", 1, 0, " TEST exclude TEST from the list of test to be\n" +OPT('e', "exclude", 1, 0, + " TEST exclude TEST from the list of test to be\n" " performed for file. Valid tests are:\n" - " %o\n") -OPT('f', "files-from", 1, 0, " FILE read the filenames to be examined from FILE\n") -OPT('F', "separator", 1, 0, " STRING use string as separator instead of `:'\n") -OPT('i', "mime", 0, 0, " output MIME type strings (--mime-type and\n" + " %e\n") +OPT_LONGONLY("exclude-quiet", 1, 0, + " TEST like exclude, but ignore unknown tests\n", OPT_EXCLUDE_QUIET) +OPT('f', "files-from", 1, 0, + " FILE read the filenames to be examined from FILE\n") +OPT('F', "separator", 1, 0, + " STRING use string as separator instead of `:'\n") +OPT('i', "mime", 0, 0, + " output MIME type strings (--mime-type and\n" " --mime-encoding)\n") -OPT_LONGONLY("apple", 0, 0, " output the Apple CREATOR/TYPE\n", OPT_APPLE) -OPT_LONGONLY("extension", 0, 0, " output a slash-separated list of extensions\n", OPT_EXTENSIONS) -OPT_LONGONLY("mime-type", 0, 0, " output the MIME type\n", OPT_MIME_TYPE) -OPT_LONGONLY("mime-encoding", 0, 0, " output the MIME encoding\n", OPT_MIME_ENCODING) -OPT('k', "keep-going", 0, 0, " don't stop at the first match\n") -OPT('l', "list", 0, 0, " list magic strength\n") +OPT_LONGONLY("apple", 0, 0, + " output the Apple CREATOR/TYPE\n", OPT_APPLE) +OPT_LONGONLY("extension", 0, 0, + " output a slash-separated list of extensions\n", OPT_EXTENSIONS) +OPT_LONGONLY("mime-type", 0, 0, + " output the MIME type\n", OPT_MIME_TYPE) +OPT_LONGONLY("mime-encoding", 0, 0, + " output the MIME encoding\n", OPT_MIME_ENCODING) +OPT('k', "keep-going", 0, 0, + " don't stop at the first match\n") +OPT('l', "list", 0, 0, + " list magic strength\n") #ifdef S_IFLNK -OPT('L', "dereference", 0, 1, " follow symlinks") -OPT('h', "no-dereference", 0, 2, " don't follow symlinks") +OPT('L', "dereference", 0, 1, + " follow symlinks") +OPT('h', "no-dereference", 0, 2, + " don't follow symlinks") #endif -OPT('n', "no-buffer", 0, 0, " do not buffer output\n") -OPT('N', "no-pad", 0, 0, " do not pad output\n") -OPT('0', "print0", 0, 0, " terminate filenames with ASCII NUL\n") +OPT('n', "no-buffer", 0, 0, + " do not buffer output\n") +OPT('N', "no-pad", 0, 0, + " do not pad output\n") +OPT('0', "print0", 0, 0, + " terminate filenames with ASCII NUL\n") #if defined(HAVE_UTIME) || defined(HAVE_UTIMES) -OPT('p', "preserve-date", 0, 0, " preserve access times on files\n") +OPT('p', "preserve-date", 0, 0, + " preserve access times on files\n") #endif -OPT('P', "parameter", 1, 0, " set file engine parameter limits\n" - " indir 15 recursion limit for indirection\n" - " name 30 use limit for name/use magic\n" - " elf_notes 256 max ELF notes processed\n" - " elf_phnum 128 max ELF prog sections processed\n" - " elf_shnum 32768 max ELF sections processed\n") -OPT('r', "raw", 0, 0, " don't translate unprintable chars to \\ooo\n") -OPT('s', "special-files", 0, 0, " treat special (block/char devices) files as\n" +OPT('P', "parameter", 1, 0, + " set file engine parameter limits\n" + " %P\n") +OPT('r', "raw", 0, 0, + " don't translate unprintable chars to \\ooo\n") +OPT('s', "special-files", 0, 0, + " treat special (block/char devices) files as\n" " ordinary ones\n") -OPT('S', "no-sandbox", 0, 0, " disable system call sandboxing\n") -OPT('C', "compile", 0, 0, " compile file specified by -m\n") -OPT('d', "debug", 0, 0, " print debugging messages\n") +OPT('S', "no-sandbox", 0, 0, + " disable system call sandboxing\n") +OPT('C', "compile", 0, 0, + " compile file specified by -m\n") +OPT('d', "debug", 0, 0, + " print debugging messages\n") diff --git a/src/funcs.c b/src/funcs.c index 9cdec0182661..09b965e9a9c2 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: funcs.c,v 1.108 2019/11/09 00:35:46 christos Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.115 2020/02/20 15:50:20 christos Exp $") #endif /* lint */ #include "magic.h" @@ -48,6 +48,77 @@ FILE_RCSID("@(#)$File: funcs.c,v 1.108 2019/11/09 00:35:46 christos Exp $") #define SIZE_MAX ((size_t)~0) #endif +protected char * +file_copystr(char *buf, size_t blen, size_t width, const char *str) +{ + if (++width > blen) + width = blen; + strlcpy(buf, str, width); + return buf; +} + +private void +file_clearbuf(struct magic_set *ms) +{ + free(ms->o.buf); + ms->o.buf = NULL; + ms->o.blen = 0; +} + +private int +file_checkfield(char *msg, size_t mlen, const char *what, const char **pp) +{ + const char *p = *pp; + int fw = 0; + + while (*p && isdigit((unsigned char)*p)) + fw = fw * 10 + (*p++ - '0'); + + *pp = p; + + if (fw < 1024) + return 1; + if (msg) + snprintf(msg, mlen, "field %s too large: %d", what, fw); + + return 0; +} + +protected int +file_checkfmt(char *msg, size_t mlen, const char *fmt) +{ + for (const char *p = fmt; *p; p++) { + if (*p != '%') + continue; + if (*++p == '%') + continue; + // Skip uninteresting. + while (strchr("0.'+- ", *p) != NULL) + p++; + if (*p == '*') { + if (msg) + snprintf(msg, mlen, "* not allowed in format"); + return -1; + } + + if (!file_checkfield(msg, mlen, "width", &p)) + return -1; + + if (*p == '.') { + p++; + if (!file_checkfield(msg, mlen, "precision", &p)) + return -1; + } + + if (!isalpha((unsigned char)*p)) { + if (msg) + snprintf(msg, mlen, "bad format char: %c", *p); + return -1; + } + } + return 0; +} + /* * Like printf, only we append to a buffer. */ @@ -56,12 +127,26 @@ file_vprintf(struct magic_set *ms, const char *fmt, va_list ap) { int len; char *buf, *newstr; + char tbuf[1024]; if (ms->event_flags & EVENT_HAD_ERR) return 0; + + if (file_checkfmt(tbuf, sizeof(tbuf), fmt)) { + file_clearbuf(ms); + file_error(ms, 0, "Bad magic format `%s' (%s)", fmt, tbuf); + return -1; + } + len = vasprintf(&buf, fmt, ap); - if (len < 0) - goto out; + if (len < 0 || (size_t)len > 1024 || len + ms->o.blen > 1024 * 1024) { + size_t blen = ms->o.blen; + free(buf); + file_clearbuf(ms); + file_error(ms, 0, "Output buffer space exceeded %d+%zu", len, + blen); + return -1; + } if (ms->o.buf != NULL) { len = asprintf(&newstr, "%s%s", ms->o.buf, buf); @@ -72,9 +157,11 @@ file_vprintf(struct magic_set *ms, const char *fmt, va_list ap) buf = newstr; } ms->o.buf = buf; + ms->o.blen = len; return 0; out: - fprintf(stderr, "vasprintf failed (%s)", strerror(errno)); + file_clearbuf(ms); + file_error(ms, errno, "vasprintf failed"); return -1; } @@ -103,8 +190,7 @@ file_error_core(struct magic_set *ms, int error, const char *f, va_list va, if (ms->event_flags & EVENT_HAD_ERR) return; if (lineno != 0) { - free(ms->o.buf); - ms->o.buf = NULL; + file_clearbuf(ms); (void)file_printf(ms, "line %" SIZE_T_FORMAT "u:", lineno); } if (ms->o.buf && *ms->o.buf) @@ -393,10 +479,7 @@ file_reset(struct magic_set *ms, int checkloaded) file_error(ms, 0, "no magic files loaded"); return -1; } - if (ms->o.buf) { - free(ms->o.buf); - ms->o.buf = NULL; - } + file_clearbuf(ms); if (ms->o.pbuf) { free(ms->o.pbuf); ms->o.pbuf = NULL; @@ -518,7 +601,7 @@ file_check_mem(struct magic_set *ms, unsigned int level) protected size_t file_printedlen(const struct magic_set *ms) { - return ms->o.buf == NULL ? 0 : strlen(ms->o.buf); + return ms->o.blen; } protected int @@ -614,9 +697,11 @@ file_push_buffer(struct magic_set *ms) return NULL; pb->buf = ms->o.buf; + pb->blen = ms->o.blen; pb->offset = ms->offset; ms->o.buf = NULL; + ms->o.blen = 0; ms->offset = 0; return pb; @@ -636,6 +721,7 @@ file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb) rbuf = ms->o.buf; ms->o.buf = pb->buf; + ms->o.blen = pb->blen; ms->offset = pb->offset; free(pb); @@ -667,3 +753,33 @@ file_printable(char *buf, size_t bufsiz, const char *str, size_t slen) *ptr = '\0'; return buf; } + +struct guid { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +}; + +protected int +file_parse_guid(const char *s, uint64_t *guid) +{ + struct guid *g = CAST(struct guid *, guid); + return sscanf(s, + "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", + &g->data1, &g->data2, &g->data3, &g->data4[0], &g->data4[1], + &g->data4[2], &g->data4[3], &g->data4[4], &g->data4[5], + &g->data4[6], &g->data4[7]) == 11 ? 0 : -1; +} + +protected int +file_print_guid(char *str, size_t len, const uint64_t *guid) +{ + const struct guid *g = CAST(const struct guid *, guid); + + return snprintf(str, len, "%.8X-%.4hX-%.4hX-%.2hhX%.2hhX-" + "%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX", + g->data1, g->data2, g->data3, g->data4[0], g->data4[1], + g->data4[2], g->data4[3], g->data4[4], g->data4[5], + g->data4[6], g->data4[7]); +} diff --git a/src/is_json.c b/src/is_json.c index 206ec3795e54..0b12438ff2a9 100644 --- a/src/is_json.c +++ b/src/is_json.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: is_json.c,v 1.13 2019/03/02 01:08:10 christos Exp $") +FILE_RCSID("@(#)$File: is_json.c,v 1.15 2020/06/07 19:05:47 christos Exp $") #endif #include <string.h> @@ -156,6 +156,7 @@ json_parse_string(const unsigned char **ucp, const unsigned char *ue) } case '"': *ucp = uc; + DPRINTF("Good string: ", uc, *ucp); return 1; default: continue; @@ -172,23 +173,24 @@ json_parse_array(const unsigned char **ucp, const unsigned char *ue, size_t *st, size_t lvl) { const unsigned char *uc = *ucp; - int more = 0; /* Array has more than 1 element */ DPRINTF("Parse array: ", uc, *ucp); while (uc < ue) { + if (*uc == ']') + goto done; if (!json_parse(&uc, ue, st, lvl + 1)) goto out; if (uc == ue) goto out; switch (*uc) { case ',': - more++; uc++; continue; case ']': - if (more) - st[JSON_ARRAYN]++; + done: + st[JSON_ARRAYN]++; *ucp = uc + 1; + DPRINTF("Good array: ", uc, *ucp); return 1; default: goto out; @@ -210,6 +212,10 @@ json_parse_object(const unsigned char **ucp, const unsigned char *ue, uc = json_skip_space(uc, ue); if (uc == ue) goto out; + if (*uc == '}') { + uc++; + goto done; + } if (*uc++ != '"') { DPRINTF("not string", uc, *ucp); goto out; @@ -236,6 +242,7 @@ json_parse_object(const unsigned char **ucp, const unsigned char *ue, case ',': continue; case '}': /* { */ + done: *ucp = uc; DPRINTF("Good object: ", uc, *ucp); return 1; diff --git a/src/magic.c b/src/magic.c index da5baf108e5d..17a7077d8428 100644 --- a/src/magic.c +++ b/src/magic.c @@ -33,7 +33,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: magic.c,v 1.111 2019/05/07 02:27:11 christos Exp $") +FILE_RCSID("@(#)$File: magic.c,v 1.112 2020/06/08 19:44:10 christos Exp $") #endif /* lint */ #include "magic.h" @@ -463,8 +463,7 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) } if (fd != -1) { - if (!okstat) - okstat = fstat(fd, &sb) == 0; + okstat = fstat(fd, &sb) == 0; if (okstat && S_ISFIFO(sb.st_mode)) ispipe = 1; if (inname == NULL) diff --git a/src/print.c b/src/print.c index 391a7fbe1562..09f6481136c4 100644 --- a/src/print.c +++ b/src/print.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: print.c,v 1.85 2019/03/12 20:43:05 christos Exp $") +FILE_RCSID("@(#)$File: print.c,v 1.88 2020/05/09 18:57:15 christos Exp $") #endif /* lint */ #include <string.h> @@ -50,7 +50,7 @@ protected void file_mdump(struct magic *m) { static const char optyp[] = { FILE_OPS }; - char tbuf[26]; + char tbuf[256]; (void) fprintf(stderr, "%u: %.*s %u", m->lineno, (m->cont_level & 7) + 1, ">>>>>>>>", m->offset); @@ -139,6 +139,7 @@ file_mdump(struct magic *m) case FILE_BEQUAD: case FILE_LEQUAD: case FILE_QUAD: + case FILE_OFFSET: (void) fprintf(stderr, "%" INT64_T_FORMAT "d", CAST(long long, m->value.q)); break; @@ -156,32 +157,35 @@ file_mdump(struct magic *m) case FILE_BEDATE: case FILE_MEDATE: (void)fprintf(stderr, "%s,", - file_fmttime(m->value.l, 0, tbuf)); + file_fmttime(tbuf, sizeof(tbuf), m->value.l, 0)); break; case FILE_LDATE: case FILE_LELDATE: case FILE_BELDATE: case FILE_MELDATE: (void)fprintf(stderr, "%s,", - file_fmttime(m->value.l, FILE_T_LOCAL, tbuf)); + file_fmttime(tbuf, sizeof(tbuf), m->value.l, + FILE_T_LOCAL)); break; case FILE_QDATE: case FILE_LEQDATE: case FILE_BEQDATE: (void)fprintf(stderr, "%s,", - file_fmttime(m->value.q, 0, tbuf)); + file_fmttime(tbuf, sizeof(tbuf), m->value.q, 0)); break; case FILE_QLDATE: case FILE_LEQLDATE: case FILE_BEQLDATE: (void)fprintf(stderr, "%s,", - file_fmttime(m->value.q, FILE_T_LOCAL, tbuf)); + file_fmttime(tbuf, sizeof(tbuf), m->value.q, + FILE_T_LOCAL)); break; case FILE_QWDATE: case FILE_LEQWDATE: case FILE_BEQWDATE: (void)fprintf(stderr, "%s,", - file_fmttime(m->value.q, FILE_T_WINDOWS, tbuf)); + file_fmttime(tbuf, sizeof(tbuf), m->value.q, + FILE_T_WINDOWS)); break; case FILE_FLOAT: case FILE_BEFLOAT: @@ -201,6 +205,12 @@ file_mdump(struct magic *m) case FILE_DER: (void) fprintf(stderr, "'%s'", m->value.s); break; + case FILE_GUID: + (void) file_print_guid(tbuf, sizeof(tbuf), + m->value.guid); + (void) fprintf(stderr, "%s", tbuf); + break; + default: (void) fprintf(stderr, "*bad type %d*", m->type); break; @@ -230,7 +240,7 @@ file_magwarn(struct magic_set *ms, const char *f, ...) } protected const char * -file_fmttime(uint64_t v, int flags, char *buf) +file_fmttime(char *buf, size_t bsize, uint64_t v, int flags) { char *pp; time_t t; @@ -260,5 +270,6 @@ file_fmttime(uint64_t v, int flags, char *buf) pp[strcspn(pp, "\n")] = '\0'; return pp; out: - return strcpy(buf, "*Invalid time*"); + strlcpy(buf, "*Invalid time*", bsize); + return buf; } diff --git a/src/readelf.c b/src/readelf.c index 40bcfab11dca..cf1dc91b7101 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readelf.c,v 1.168 2019/12/16 03:49:19 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.173 2020/06/07 22:12:54 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -67,6 +67,8 @@ private uint64_t getu64(int, uint64_t); private int toomany(struct magic_set *ms, const char *name, uint16_t num) { + if (ms->flags & MAGIC_MIME) + return 1; if (file_printf(ms, ", too many %s (%u)", name, num) == -1) return -1; return 1; @@ -355,6 +357,9 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, off_t ph_off = off; int ph_num = num; + if (ms->flags & MAGIC_MIME) + return 0; + if (num == 0) { if (file_printf(ms, ", no program header") == -1) return -1; @@ -568,8 +573,10 @@ do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, } if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "Go") == 0 && type == NT_GO_BUILD_ID && descsz < 128) { - if (file_printf(ms, ", Go BuildID=%.*s", - CAST(int, descsz), RCAST(char *, &nbuf[doff])) == -1) + char buf[256]; + if (file_printf(ms, ", Go BuildID=%s", + file_copystr(buf, sizeof(buf), descsz, + RCAST(const char *, &nbuf[doff]))) == -1) return -1; return 1; } @@ -721,6 +728,7 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, size_t noff, size_t doff, int *flags, size_t size, int clazz) { #ifdef ELFCORE + char buf[256]; const char *name = RCAST(const char *, &nbuf[noff]); int os_style = -1; @@ -901,8 +909,10 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, */ while (cp > cname && isspace(cp[-1])) cp--; - if (file_printf(ms, ", from '%.*s'", - CAST(int, cp - cname), cname) == -1) + if (file_printf(ms, ", from '%s'", + file_copystr(buf, sizeof(buf), + CAST(size_t, cp - cname), + CAST(const char *, cname))) == -1) return -1; *flags |= FLAGS_DID_CORE; return 1; @@ -1128,6 +1138,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, Elf64_Nhdr nh64; size_t noff, doff; uint32_t namesz, descsz; + char buf[256]; unsigned char *nbuf = CAST(unsigned char *, vbuf); if (*notecount == 0) @@ -1255,7 +1266,8 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, str = RCAST(const char *, &nbuf[doff]); descw = CAST(int, descsz); *flags |= flag; - file_printf(ms, ", %s: %.*s", tag, descw, str); + file_printf(ms, ", %s: %s", tag, + file_copystr(buf, sizeof(buf), descw, str)); return offset; } @@ -1328,6 +1340,9 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, char name[50]; ssize_t namesize; + if (ms->flags & MAGIC_MIME) + return 0; + if (num == 0) { if (file_printf(ms, ", no section header") == -1) return -1; @@ -1349,8 +1364,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, name_off = xsh_offset; if (fsize != SIZE_UNKNOWN && fsize < name_off) { - if (file_printf(ms, ", too large section header offset %td", - name_off) == -1) + if (file_printf(ms, ", too large section header offset %jd", + (intmax_t)name_off) == -1) return -1; return 0; } @@ -1639,6 +1654,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, switch (xph_type) { case PT_DYNAMIC: doread = 1; + linking_style = "dynamically"; break; case PT_NOTE: if (sh_num) /* Did this through section headers */ @@ -1653,7 +1669,6 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, } /*FALLTHROUGH*/ case PT_INTERP: - linking_style = "dynamically"; doread = 1; break; default: @@ -1690,9 +1705,13 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, if (offset == 0) break; } + if (ms->flags & MAGIC_MIME) + continue; break; case PT_INTERP: + if (ms->flags & MAGIC_MIME) + continue; if (bufsize && nbuf[0]) { nbuf[bufsize - 1] = '\0'; memcpy(interp, nbuf, CAST(size_t, bufsize)); @@ -1700,6 +1719,8 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, strlcpy(interp, "*empty*", sizeof(interp)); break; case PT_NOTE: + if (ms->flags & MAGIC_MIME) + return 0; /* * This is a PT_NOTE section; loop through all the notes * in the section. @@ -1716,9 +1737,13 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, } break; default: + if (ms->flags & MAGIC_MIME) + continue; break; } } + if (ms->flags & MAGIC_MIME) + return 0; if (file_printf(ms, ", %s linked", linking_style) == -1) return -1; @@ -1751,7 +1776,7 @@ file_tryelf(struct magic_set *ms, const struct buffer *b) Elf64_Ehdr elf64hdr; uint16_t type, phnum, shnum, notecount; - if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION)) + if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) return 0; /* * ELF executables have multiple section headers in arbitrary diff --git a/src/seccomp.c b/src/seccomp.c index 902a3eba7862..e667adfe4e3c 100644 --- a/src/seccomp.c +++ b/src/seccomp.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: seccomp.c,v 1.11 2019/07/18 20:32:06 christos Exp $") +FILE_RCSID("@(#)$File: seccomp.c,v 1.15 2020/05/30 23:56:26 christos Exp $") #endif /* lint */ #if HAVE_LIBSECCOMP @@ -186,9 +186,13 @@ enable_sandbox_full(void) ALLOW_IOCTL_RULE(FIONREAD); #endif #ifdef TIOCGWINSZ - // musl libc may call ioctl TIOCGWINSZ when calling stdout + // musl libc may call ioctl TIOCGWINSZ on stdout ALLOW_IOCTL_RULE(TIOCGWINSZ); #endif +#ifdef TCGETS + // glibc may call ioctl TCGETS on stdout on physical terminal + ALLOW_IOCTL_RULE(TCGETS); +#endif ALLOW_RULE(lseek); ALLOW_RULE(_llseek); ALLOW_RULE(lstat); @@ -207,6 +211,9 @@ enable_sandbox_full(void) ALLOW_RULE(pread64); ALLOW_RULE(read); ALLOW_RULE(readlink); +#ifdef __NR_readlinkat + ALLOW_RULE(readlinkat); +#endif ALLOW_RULE(rt_sigaction); ALLOW_RULE(rt_sigprocmask); ALLOW_RULE(rt_sigreturn); @@ -215,6 +222,7 @@ enable_sandbox_full(void) ALLOW_RULE(stat64); ALLOW_RULE(sysinfo); ALLOW_RULE(umask); // Used in file_pipe2file() + ALLOW_RULE(getpid); // Used by glibc in file_pipe2file() ALLOW_RULE(unlink); ALLOW_RULE(write); @@ -222,7 +230,6 @@ enable_sandbox_full(void) #if 0 // needed by valgrind ALLOW_RULE(gettid); - ALLOW_RULE(getpid); ALLOW_RULE(rt_sigtimedwait); #endif diff --git a/src/softmagic.c b/src/softmagic.c index 2edae41df4da..95061e56fc89 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.286 2019/05/17 02:24:59 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.299 2020/06/07 21:58:01 christos Exp $") #endif /* lint */ #include "magic.h" @@ -331,6 +331,13 @@ flush: if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) goto flush; if (m->flag & OFFADD) { + if (cont_level == 0) { + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, + "direct *zero*" + " cont_level\n"); + return 0; + } ms->offset += ms->c.li[cont_level - 1].off; } @@ -642,6 +649,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QUAD: case FILE_BEQUAD: case FILE_LEQUAD: + case FILE_OFFSET: v = file_signextend(ms, m, p->q); switch (check_fmt(ms, desc)) { case -1: @@ -699,8 +707,12 @@ mprint(struct magic_set *ms, struct magic *m) sizeof(p->s) - (str - p->s))) == -1) return -1; - if (m->type == FILE_PSTRING) - t += file_pstring_length_size(m); + if (m->type == FILE_PSTRING) { + size_t l = file_pstring_length_size(ms, m); + if (l == FILE_BADSIZE) + return -1; + t += l; + } } break; @@ -709,7 +721,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_LEDATE: case FILE_MEDATE: if (file_printf(ms, F(ms, desc, "%s"), - file_fmttime(p->l, 0, tbuf)) == -1) + file_fmttime(tbuf, sizeof(tbuf), p->l, 0)) == -1) return -1; t = ms->offset + sizeof(uint32_t); break; @@ -719,7 +731,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_LELDATE: case FILE_MELDATE: if (file_printf(ms, F(ms, desc, "%s"), - file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1) + file_fmttime(tbuf, sizeof(tbuf), p->l, FILE_T_LOCAL)) == -1) return -1; t = ms->offset + sizeof(uint32_t); break; @@ -728,7 +740,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEQDATE: case FILE_LEQDATE: if (file_printf(ms, F(ms, desc, "%s"), - file_fmttime(p->q, 0, tbuf)) == -1) + file_fmttime(tbuf, sizeof(tbuf), p->q, 0)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -737,7 +749,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEQLDATE: case FILE_LEQLDATE: if (file_printf(ms, F(ms, desc, "%s"), - file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1) + file_fmttime(tbuf, sizeof(tbuf), p->q, FILE_T_LOCAL)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -746,7 +758,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEQWDATE: case FILE_LEQWDATE: if (file_printf(ms, F(ms, desc, "%s"), - file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1) + file_fmttime(tbuf, sizeof(tbuf), p->q, FILE_T_WINDOWS)) + == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -835,6 +848,12 @@ mprint(struct magic_set *ms, struct magic *m) return -1; t = ms->offset; break; + case FILE_GUID: + (void) file_print_guid(buf, sizeof(buf), ms->ms_value.guid); + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) + return -1; + t = ms->offset; + break; default: file_magerror(ms, "invalid m->type (%d) in mprint()", m->type); return -1; @@ -885,9 +904,12 @@ moffset(struct magic_set *ms, struct magic *m, const struct buffer *b, if (*m->value.s == '\0') p->s[strcspn(p->s, "\r\n")] = '\0'; o = CAST(uint32_t, (ms->offset + strlen(p->s))); - if (m->type == FILE_PSTRING) - o += CAST(uint32_t, - file_pstring_length_size(m)); + if (m->type == FILE_PSTRING) { + size_t l = file_pstring_length_size(ms, m); + if (l == FILE_BADSIZE) + return -1; + o += CAST(uint32_t, l); + } } break; @@ -947,23 +969,26 @@ moffset(struct magic_set *ms, struct magic *m, const struct buffer *b, case FILE_CLEAR: case FILE_DEFAULT: case FILE_INDIRECT: + case FILE_OFFSET: o = ms->offset; break; case FILE_DER: - { - o = der_offs(ms, m, nbytes); - if (o == -1 || CAST(size_t, o) > nbytes) { - if ((ms->flags & MAGIC_DEBUG) != 0) { - (void)fprintf(stderr, - "Bad DER offset %d nbytes=%" - SIZE_T_FORMAT "u", o, nbytes); - } - *op = 0; - return 0; + o = der_offs(ms, m, nbytes); + if (o == -1 || CAST(size_t, o) > nbytes) { + if ((ms->flags & MAGIC_DEBUG) != 0) { + (void)fprintf(stderr, + "Bad DER offset %d nbytes=%" + SIZE_T_FORMAT "u", o, nbytes); } - break; + *op = 0; + return 0; } + break; + + case FILE_GUID: + o = CAST(int32_t, (ms->offset + 2 * sizeof(uint64_t))); + break; default: o = 0; @@ -1168,6 +1193,7 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_QDATE: case FILE_QLDATE: case FILE_QWDATE: + case FILE_OFFSET: if (cvt_64(p, m) == -1) goto out; return 1; @@ -1179,9 +1205,15 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) return 1; } case FILE_PSTRING: { - size_t sz = file_pstring_length_size(m); - char *ptr1 = p->s, *ptr2 = ptr1 + sz; - size_t len = file_pstring_get_length(m, ptr1); + char *ptr1, *ptr2; + size_t len, sz = file_pstring_length_size(ms, m); + if (sz == FILE_BADSIZE) + return 0; + ptr1 = p->s; + ptr2 = ptr1 + sz; + len = file_pstring_get_length(ms, m, ptr1); + if (len == FILE_BADSIZE) + return 0; sz = sizeof(p->s) - sz; /* maximum length of string */ if (len >= sz) { /* @@ -1281,6 +1313,7 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_NAME: case FILE_USE: case FILE_DER: + case FILE_GUID: return 1; default: file_magerror(ms, "invalid type %d in mconvert()", m->type); @@ -1407,6 +1440,12 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, } } + if (type == FILE_OFFSET) { + (void)memset(p, '\0', sizeof(*p)); + p->q = offset; + return 0; + } + if (offset >= nbytes) { (void)memset(p, '\0', sizeof(*p)); return 0; @@ -1471,7 +1510,9 @@ private int 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) { + int32_t offset; + if (m->flag & OFFNEGATIVE) { + offset = -m->offset; if (cont_level > 0) { if (m->flag & (OFFADD|INDIROFFADD)) goto normal; @@ -1489,26 +1530,28 @@ msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb, "u at level %u", o, cont_level); return -1; } - if (CAST(size_t, -m->offset) > b->elen) + if (CAST(size_t, m->offset) > b->elen) return -1; buffer_init(bb, -1, NULL, b->ebuf, b->elen); - ms->eoffset = ms->offset = CAST(int32_t, b->elen + m->offset); + ms->eoffset = ms->offset = CAST(int32_t, b->elen - m->offset); } else { + offset = m->offset; if (cont_level == 0) { normal: // XXX: Pass real fd, then who frees bb? buffer_init(bb, -1, NULL, b->fbuf, b->flen); - ms->offset = m->offset; + ms->offset = offset; ms->eoffset = 0; } else { - ms->offset = ms->eoffset + m->offset; + ms->offset = ms->eoffset + offset; } } if ((ms->flags & MAGIC_DEBUG) != 0) { - fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u], %d [b=%p,%" - SIZE_T_FORMAT "u], [o=%#x, c=%d]\n", - bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen, - m->offset, cont_level); + fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u,%" + SIZE_T_FORMAT "u], %d [b=%p,%" + SIZE_T_FORMAT "u,%" SIZE_T_FORMAT "u], [o=%#x, c=%d]\n", + bb->fbuf, bb->flen, bb->elen, ms->offset, b->fbuf, + b->flen, b->elen, offset, cont_level); } return 0; } @@ -1566,7 +1609,8 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, if (m->in_op & FILE_OPINDIRECT) { const union VALUETYPE *q = CAST(const union VALUETYPE *, RCAST(const void *, s + offset + off)); - switch (cvt_flip(m->in_type, flip)) { + int op; + switch (op = cvt_flip(m->in_type, flip)) { case FILE_BYTE: if (OFFSET_OOB(nbytes, offset + off, 1)) return 0; @@ -1620,7 +1664,9 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, off = SEXT(sgn,64,LE64(q)); break; default: - abort(); + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "bad op=%d\n", op); + return 0; } if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect offs=%jd\n", off); @@ -1685,11 +1731,19 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, offset = do_ops(m, SEXT(sgn,64,BE64(p)), off); break; default: - abort(); + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "bad in_type=%d\n", in_type); + return 0; } if (m->flag & INDIROFFADD) { - offset += ms->c.li[cont_level-1].off; + if (cont_level == 0) { + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, + "indirect *zero* cont_level\n"); + return 0; + } + offset += ms->c.li[cont_level - 1].off; if (offset == 0) { if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, @@ -1752,6 +1806,11 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, return 0; break; + case FILE_GUID: + if (OFFSET_OOB(nbytes, offset, 16)) + return 0; + break; + case FILE_STRING: case FILE_PSTRING: case FILE_SEARCH: @@ -1847,7 +1906,8 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, } private uint64_t -file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags) +file_strncmp(const char *s1, const char *s2, size_t len, size_t maxlen, + uint32_t flags) { /* * Convert the source args to unsigned here so that (1) the @@ -1857,7 +1917,9 @@ file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags) */ const unsigned char *a = RCAST(const unsigned char *, s1); const unsigned char *b = RCAST(const unsigned char *, s2); - const unsigned char *eb = b + len; + uint32_t ws = flags & (STRING_COMPACT_WHITESPACE | + STRING_COMPACT_OPTIONAL_WHITESPACE); + const unsigned char *eb = b + (ws ? maxlen : len); uint64_t v; /* @@ -1915,7 +1977,8 @@ file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags) } private uint64_t -file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags) +file_strncmp16(const char *a, const char *b, size_t len, size_t maxlen, + uint32_t flags) { /* * XXX - The 16-bit string compare probably needs to be done @@ -1923,7 +1986,7 @@ file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags) * At the moment, I am unsure. */ flags = 0; - return file_strncmp(a, b, len, flags); + return file_strncmp(a, b, len, maxlen, flags); } private int @@ -1974,6 +2037,7 @@ magiccheck(struct magic_set *ms, struct magic *m) case FILE_QWDATE: case FILE_BEQWDATE: case FILE_LEQWDATE: + case FILE_OFFSET: v = p->q; break; @@ -2052,14 +2116,14 @@ magiccheck(struct magic_set *ms, struct magic *m) case FILE_PSTRING: l = 0; v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen), - m->str_flags); + sizeof(p->s), m->str_flags); break; case FILE_BESTRING16: case FILE_LESTRING16: l = 0; v = file_strncmp16(m->value.s, p->s, CAST(size_t, m->vallen), - m->str_flags); + sizeof(p->s), m->str_flags); break; case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */ @@ -2094,7 +2158,7 @@ magiccheck(struct magic_set *ms, struct magic *m) return 0; v = file_strncmp(m->value.s, ms->search.s + idx, slen, - m->str_flags); + ms->search.s_len - idx, m->str_flags); if (v == 0) { /* found match */ ms->search.offset += idx; ms->search.rm_len = ms->search.s_len - idx; @@ -2179,6 +2243,10 @@ magiccheck(struct magic_set *ms, struct magic *m) return 0; } return matched; + case FILE_GUID: + l = 0; + v = memcmp(m->value.guid, p->guid, sizeof(p->guid)); + break; default: file_magerror(ms, "invalid type %d in magiccheck()", m->type); return -1; |