summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/apprentice.c152
-rw-r--r--src/ascmagic.c14
-rw-r--r--src/buffer.c6
-rw-r--r--src/compress.c56
-rw-r--r--src/der.c78
-rw-r--r--src/file.c90
-rw-r--r--src/file.h94
-rw-r--r--src/file_opts.h97
-rw-r--r--src/funcs.c138
-rw-r--r--src/is_json.c17
-rw-r--r--src/magic.c5
-rw-r--r--src/print.c29
-rw-r--r--src/readelf.c45
-rw-r--r--src/seccomp.c13
-rw-r--r--src/softmagic.c158
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;