diff options
| author | Xin LI <delphij@FreeBSD.org> | 2020-06-17 01:11:26 +0000 | 
|---|---|---|
| committer | Xin LI <delphij@FreeBSD.org> | 2020-06-17 01:11:26 +0000 | 
| commit | 2d24dbcf45a851fa5c7960160b7b4a28ff373558 (patch) | |
| tree | 6ed1c5484166da73032c8f6ed3bb82a5dadf914a /src | |
| parent | f210d1e9efd4183d390c24c9ea576896222d4540 (diff) | |
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 7ebd6897bd048..1437bcc1179ea 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 3bb7359777b93..9d383be32163c 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 0a27e57884837..227015ae3e5fc 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 33ce2bc936d63..67f21583c1a06 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 8867c568034dd..78a056b90d7eb 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 89d8cfb99a137..aca5852163737 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 947f2089d0af8..28ebc0c18ace9 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 4f894cc551b3f..24909917fe1bd 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 9cdec0182661a..09b965e9a9c24 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 206ec3795e54e..0b12438ff2a96 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 da5baf108e5d9..17a7077d8428e 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 391a7fbe15621..09f6481136c46 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 40bcfab11dca9..cf1dc91b71013 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 902a3eba78621..e667adfe4e3c7 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 2edae41df4da3..95061e56fc899 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; | 
