diff options
author | delphij <delphij@FreeBSD.org> | 2016-04-18 07:36:24 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2016-04-18 07:36:24 +0000 |
commit | 1852c3675cd08e58d07e956f9023f5b3eee5ca3c (patch) | |
tree | 7811b5b9831ebf5066c7eae2d213b5e48f66deb7 /contrib/file/src | |
parent | cb410646fdaa9c6e3285e1d015ad0095ba9b012b (diff) | |
parent | 3c98cb6b19e2270fd5235eb16a8ae98de4fb0b5f (diff) | |
download | FreeBSD-src-1852c3675cd08e58d07e956f9023f5b3eee5ca3c.zip FreeBSD-src-1852c3675cd08e58d07e956f9023f5b3eee5ca3c.tar.gz |
MFV r298178:
Update file to 5.26.
MFC after: 2 weeks
Relnotes: yes
Diffstat (limited to 'contrib/file/src')
-rw-r--r-- | contrib/file/src/Makefile.am | 2 | ||||
-rw-r--r-- | contrib/file/src/Makefile.in | 14 | ||||
-rw-r--r-- | contrib/file/src/apprentice.c | 121 | ||||
-rw-r--r-- | contrib/file/src/ascmagic.c | 8 | ||||
-rw-r--r-- | contrib/file/src/compress.c | 589 | ||||
-rw-r--r-- | contrib/file/src/der.c | 379 | ||||
-rw-r--r-- | contrib/file/src/der.h | 28 | ||||
-rw-r--r-- | contrib/file/src/dprintf.c | 58 | ||||
-rw-r--r-- | contrib/file/src/file.c | 52 | ||||
-rw-r--r-- | contrib/file/src/file.h | 25 | ||||
-rw-r--r-- | contrib/file/src/file_opts.h | 56 | ||||
-rw-r--r-- | contrib/file/src/fmtcheck.c | 17 | ||||
-rw-r--r-- | contrib/file/src/funcs.c | 26 | ||||
-rw-r--r-- | contrib/file/src/magic.c | 20 | ||||
-rw-r--r-- | contrib/file/src/magic.h | 3 | ||||
-rw-r--r-- | contrib/file/src/print.c | 3 | ||||
-rw-r--r-- | contrib/file/src/readcdf.c | 12 | ||||
-rw-r--r-- | contrib/file/src/readelf.c | 219 | ||||
-rw-r--r-- | contrib/file/src/readelf.h | 36 | ||||
-rw-r--r-- | contrib/file/src/softmagic.c | 289 |
20 files changed, 1522 insertions, 435 deletions
diff --git a/contrib/file/src/Makefile.am b/contrib/file/src/Makefile.am index e3196ce..5891feb 100644 --- a/contrib/file/src/Makefile.am +++ b/contrib/file/src/Makefile.am @@ -9,7 +9,7 @@ AM_CFLAGS = $(CFLAG_VISIBILITY) @WARNINGS@ libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \ encoding.c compress.c is_tar.c readelf.c print.c fsmagic.c \ - funcs.c file.h readelf.h tar.h apptype.c \ + funcs.c file.h readelf.h tar.h apptype.c der.c der.h \ file_opts.h elfclass.h mygetopt.h cdf.c cdf_time.c readcdf.c cdf.h libmagic_la_LDFLAGS = -no-undefined -version-info 1:0:0 if MINGW diff --git a/contrib/file/src/Makefile.in b/contrib/file/src/Makefile.in index 5e69c00..a44bf88 100644 --- a/contrib/file/src/Makefile.in +++ b/contrib/file/src/Makefile.in @@ -138,8 +138,8 @@ am__DEPENDENCIES_1 = libmagic_la_DEPENDENCIES = $(LTLIBOBJS) $(am__DEPENDENCIES_1) am_libmagic_la_OBJECTS = magic.lo apprentice.lo softmagic.lo \ ascmagic.lo encoding.lo compress.lo is_tar.lo readelf.lo \ - print.lo fsmagic.lo funcs.lo apptype.lo cdf.lo cdf_time.lo \ - readcdf.lo + print.lo fsmagic.lo funcs.lo apptype.lo der.lo cdf.lo \ + cdf_time.lo readcdf.lo libmagic_la_OBJECTS = $(am_libmagic_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -214,9 +214,9 @@ am__define_uniq_tagged_files = \ ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ - asctime_r.c asprintf.c ctime_r.c fmtcheck.c getline.c \ - getopt_long.c gmtime_r.c localtime_r.c pread.c strcasestr.c \ - strlcat.c strlcpy.c vasprintf.c + asctime_r.c asprintf.c ctime_r.c dprintf.c fmtcheck.c \ + getline.c getopt_long.c gmtime_r.c localtime_r.c pread.c \ + strcasestr.c strlcat.c strlcpy.c vasprintf.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) pkgdatadir = @pkgdatadir@ ACLOCAL = @ACLOCAL@ @@ -345,7 +345,7 @@ AM_CPPFLAGS = -DMAGIC='"$(MAGIC)"' AM_CFLAGS = $(CFLAG_VISIBILITY) @WARNINGS@ libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \ encoding.c compress.c is_tar.c readelf.c print.c fsmagic.c \ - funcs.c file.h readelf.h tar.h apptype.c \ + funcs.c file.h readelf.h tar.h apptype.c der.c der.h \ file_opts.h elfclass.h mygetopt.h cdf.c cdf_time.c readcdf.c cdf.h libmagic_la_LDFLAGS = -no-undefined -version-info 1:0:0 @@ -493,6 +493,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asctime_r.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asprintf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ctime_r.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/dprintf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/fmtcheck.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getline.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getopt_long.Plo@am__quote@ @@ -509,6 +510,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdf_time.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compress.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/der.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encoding.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsmagic.Plo@am__quote@ diff --git a/contrib/file/src/apprentice.c b/contrib/file/src/apprentice.c index 66f64bd..f8956de 100644 --- a/contrib/file/src/apprentice.c +++ b/contrib/file/src/apprentice.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: apprentice.c,v 1.238 2015/09/12 18:10:42 christos Exp $") +FILE_RCSID("@(#)$File: apprentice.c,v 1.248 2016/03/31 17:51:12 christos Exp $") #endif /* lint */ #include "magic.h" @@ -86,9 +86,9 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.238 2015/09/12 18:10:42 christos Exp $") #define ALLOC_CHUNK (size_t)10 #define ALLOC_INCR (size_t)200 -#define MAP_TYPE_MMAP 0 +#define MAP_TYPE_USER 0 #define MAP_TYPE_MALLOC 1 -#define MAP_TYPE_USER 2 +#define MAP_TYPE_MMAP 2 struct magic_entry { struct magic *mp; @@ -143,7 +143,7 @@ private int check_buffer(struct magic_set *, struct magic_map *, const char *); private void apprentice_unmap(struct magic_map *); private int apprentice_compile(struct magic_set *, struct magic_map *, const char *); -private int check_format_type(const char *, int); +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 *); @@ -268,6 +268,7 @@ static const struct type_tbl_s type_tbl[] = { { XX("name"), FILE_NAME, FILE_FMT_NONE }, { XX("use"), FILE_USE, FILE_FMT_NONE }, { XX("clear"), FILE_CLEAR, FILE_FMT_NONE }, + { XX("der"), FILE_DER, FILE_FMT_STR }, { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, }; @@ -276,6 +277,7 @@ static const struct type_tbl_s type_tbl[] = { * unsigned. */ static const struct type_tbl_s special_tbl[] = { + { XX("der"), FILE_DER, FILE_FMT_STR }, { XX("name"), FILE_NAME, FILE_FMT_STR }, { XX("use"), FILE_USE, FILE_FMT_STR }, { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, @@ -532,6 +534,7 @@ file_ms_alloc(int flags) ms->elf_phnum_max = FILE_ELF_PHNUM_MAX; ms->elf_notes_max = FILE_ELF_NOTES_MAX; ms->regex_max = FILE_REGEX_MAX; + ms->bytes_max = FILE_BYTES_MAX; return ms; free: free(ms); @@ -546,19 +549,23 @@ apprentice_unmap(struct magic_map *map) return; switch (map->type) { -#ifdef QUICK - case MAP_TYPE_MMAP: - if (map->p) - (void)munmap(map->p, map->len); + case MAP_TYPE_USER: break; -#endif case MAP_TYPE_MALLOC: - free(map->p); - for (i = 0; i < MAGIC_SETS; i++) + for (i = 0; i < MAGIC_SETS; i++) { + if ((char *)map->magic[i] >= (char *)map->p && + (char *)map->magic[i] < (char *)map->p + map->len) + continue; free(map->magic[i]); + } + free(map->p); break; - case MAP_TYPE_USER: +#ifdef QUICK + case MAP_TYPE_MMAP: + if (map->p && map->p != MAP_FAILED) + (void)munmap(map->p, map->len); break; +#endif default: abort(); } @@ -862,6 +869,10 @@ apprentice_magic_strength(const struct magic *m) case FILE_USE: break; + case FILE_DER: + val += MULT; + break; + default: (void)fprintf(stderr, "Bad type %d\n", m->type); abort(); @@ -1017,6 +1028,7 @@ set_test_type(struct magic *mstart, struct magic *m) case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: + case FILE_DER: mstart->flag |= BINTEST; break; case FILE_STRING: @@ -1448,6 +1460,7 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) case FILE_NAME: case FILE_USE: case FILE_CLEAR: + case FILE_DER: break; default: if (ms->flags & MAGIC_CHECK) @@ -2103,7 +2116,7 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, /* * TODO finish this macro and start using it! - * #define offsetcheck {if (offset > HOWMANY-1) + * #define offsetcheck {if (offset > ms->bytes_max -1) * magwarn("offset too big"); } */ @@ -2267,7 +2280,7 @@ parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) return parse_extra(ms, me, line, CAST(off_t, offsetof(struct magic, apple)), - sizeof(m->apple), "APPLE", "!+-./", 0); + sizeof(m->apple), "APPLE", "!+-./?", 0); } /* @@ -2298,11 +2311,13 @@ parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line) } private int -check_format_type(const char *ptr, int type) +check_format_type(const char *ptr, int type, const char **estr) { int quad = 0, h; + size_t len, cnt; if (*ptr == '\0') { /* Missing format string; bad */ + *estr = "missing format spec"; return -1; } @@ -2339,15 +2354,22 @@ check_format_type(const char *ptr, int type) ptr++; if (*ptr == '.') ptr++; - while (isdigit((unsigned char)*ptr)) ptr++; +#define CHECKLEN() do { \ + for (len = cnt = 0; isdigit((unsigned char)*ptr); ptr++, cnt++) \ + len = len * 10 + (*ptr - '0'); \ + if (cnt > 5 || len > 1024) \ + goto toolong; \ +} while (/*CONSTCOND*/0) + + CHECKLEN(); if (*ptr == '.') ptr++; - while (isdigit((unsigned char)*ptr)) ptr++; + CHECKLEN(); if (quad) { if (*ptr++ != 'l') - return -1; + goto invalid; if (*ptr++ != 'l') - return -1; + goto invalid; } switch (*ptr++) { @@ -2361,9 +2383,11 @@ check_format_type(const char *ptr, int type) case 'o': case 'x': case 'X': - return h != 0 ? -1 : 0; + if (h == 0) + return 0; + /*FALLTHROUGH*/ default: - return -1; + goto invalid; } /* @@ -2372,11 +2396,11 @@ check_format_type(const char *ptr, int type) */ case 'h': if (h-- <= 0) - return -1; + goto invalid; switch (*ptr++) { case 'h': if (h-- <= 0) - return -1; + goto invalid; switch (*ptr++) { case 'i': case 'd': @@ -2386,7 +2410,7 @@ check_format_type(const char *ptr, int type) case 'X': return 0; default: - return -1; + goto invalid; } case 'i': case 'd': @@ -2394,13 +2418,17 @@ check_format_type(const char *ptr, int type) case 'o': case 'x': case 'X': - return h != 0 ? -1 : 0; + if (h == 0) + return 0; + /*FALLTHROUGH*/ default: - return -1; + goto invalid; } #endif case 'c': - return h != 2 ? -1 : 0; + if (h == 2) + return 0; + goto invalid; case 'i': case 'd': case 'u': @@ -2408,12 +2436,14 @@ check_format_type(const char *ptr, int type) case 'x': case 'X': #ifdef STRICT_FORMAT - return h != 0 ? -1 : 0; + if (h == 0) + return 0; + /*FALLTHROUGH*/ #else return 0; #endif default: - return -1; + goto invalid; } case FILE_FMT_FLOAT: @@ -2422,11 +2452,10 @@ check_format_type(const char *ptr, int type) ptr++; if (*ptr == '.') ptr++; - while (isdigit((unsigned char)*ptr)) ptr++; + CHECKLEN(); if (*ptr == '.') ptr++; - while (isdigit((unsigned char)*ptr)) ptr++; - + CHECKLEN(); switch (*ptr++) { case 'e': case 'E': @@ -2437,7 +2466,7 @@ check_format_type(const char *ptr, int type) return 0; default: - return -1; + goto invalid; } @@ -2456,14 +2485,17 @@ check_format_type(const char *ptr, int type) case 's': return 0; default: - return -1; + goto invalid; } default: /* internal error */ abort(); } - /*NOTREACHED*/ +invalid: + *estr = "not valid"; +toolong: + *estr = "too long"; return -1; } @@ -2475,6 +2507,7 @@ private int check_format(struct magic_set *ms, struct magic *m) { char *ptr; + const char *estr; for (ptr = m->desc; *ptr; ptr++) if (*ptr == '%') @@ -2498,13 +2531,13 @@ check_format(struct magic_set *ms, struct magic *m) } ptr++; - if (check_format_type(ptr, m->type) == -1) { + if (check_format_type(ptr, m->type, &estr) == -1) { /* * TODO: this error message is unhelpful if the format * string is not one character long */ - file_magwarn(ms, "Printf format `%c' is not valid for type " - "`%s' in description `%s'", *ptr ? *ptr : '?', + file_magwarn(ms, "Printf format is %s for type " + "`%s' in description `%s'", estr, file_names[m->type], m->desc); return -1; } @@ -2538,6 +2571,7 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) case FILE_SEARCH: case FILE_NAME: case FILE_USE: + case FILE_DER: *p = getstr(ms, m, *p, action == FILE_COMPILE); if (*p == NULL) { if (ms->flags & MAGIC_CHECK) @@ -2902,6 +2936,7 @@ apprentice_map(struct magic_set *ms, const char *fn) file_oomem(ms, sizeof(*map)); goto error; } + map->type = MAP_TYPE_USER; /* unspecified */ dbname = mkdbname(ms, fn, 0); if (dbname == NULL) @@ -2922,13 +2957,14 @@ apprentice_map(struct magic_set *ms, const char *fn) map->len = (size_t)st.st_size; #ifdef QUICK + map->type = MAP_TYPE_MMAP; if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) { file_error(ms, errno, "cannot map `%s'", dbname); goto error; } - map->type = MAP_TYPE_MMAP; #else + map->type = MAP_TYPE_MALLOC; if ((map->p = CAST(void *, malloc(map->len))) == NULL) { file_oomem(ms, map->len); goto error; @@ -2937,7 +2973,6 @@ apprentice_map(struct magic_set *ms, const char *fn) file_badread(ms); goto error; } - map->type = MAP_TYPE_MALLOC; #define RET 1 #endif (void)close(fd); @@ -2945,6 +2980,12 @@ apprentice_map(struct magic_set *ms, const char *fn) if (check_buffer(ms, map, dbname) != 0) goto error; +#ifdef QUICK + if (mprotect(map->p, (size_t)st.st_size, PROT_READ) == -1) { + file_error(ms, errno, "cannot mprotect `%s'", dbname); + goto error; + } +#endif free(dbname); return map; diff --git a/contrib/file/src/ascmagic.c b/contrib/file/src/ascmagic.c index 9e0f663..b9ab789 100644 --- a/contrib/file/src/ascmagic.c +++ b/contrib/file/src/ascmagic.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: ascmagic.c,v 1.92 2015/04/09 20:01:41 christos Exp $") +FILE_RCSID("@(#)$File: ascmagic.c,v 1.94 2016/03/31 17:51:12 christos Exp $") #endif /* lint */ #include "magic.h" @@ -147,7 +147,7 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf, == NULL) goto done; if ((rv = file_softmagic(ms, utf8_buf, - (size_t)(utf8_end - utf8_buf), 0, NULL, + (size_t)(utf8_end - utf8_buf), NULL, NULL, TEXTTEST, text)) == 0) rv = -1; } @@ -183,10 +183,10 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf, } /* Beware, if the data has been truncated, the final CR could have - been followed by a LF. If we have HOWMANY bytes, it indicates + been followed by a LF. If we have ms->bytes_max bytes, it indicates that the data might have been truncated, probably even before this function was called. */ - if (seen_cr && nbytes < HOWMANY) + if (seen_cr && nbytes < ms->bytes_max) n_cr++; if (strcmp(type, "binary") == 0) { diff --git a/contrib/file/src/compress.c b/contrib/file/src/compress.c index 539031e..ad86431 100644 --- a/contrib/file/src/compress.c +++ b/contrib/file/src/compress.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: compress.c,v 1.80 2015/06/03 18:21:24 christos Exp $") +FILE_RCSID("@(#)$File: compress.c,v 1.93 2016/03/31 17:51:12 christos Exp $") #endif #include "magic.h" @@ -45,6 +45,8 @@ FILE_RCSID("@(#)$File: compress.c,v 1.80 2015/06/03 18:21:24 christos Exp $") #endif #include <string.h> #include <errno.h> +#include <ctype.h> +#include <stdarg.h> #ifdef HAVE_SIGNAL_H #include <signal.h> # ifndef HAVE_SIG_T @@ -63,43 +65,119 @@ typedef void (*sig_t)(int); #if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) #define BUILTIN_DECOMPRESS #include <zlib.h> +#define ZLIBSUPPORT #endif +#ifdef DEBUG +int tty = -1; +#define DPRINTF(...) do { \ + if (tty == -1) \ + tty = open("/dev/tty", O_RDWR); \ + if (tty == -1) \ + abort(); \ + dprintf(tty, __VA_ARGS__); \ +} while (/*CONSTCOND*/0) +#else +#define DPRINTF(...) +#endif + +#ifdef ZLIBSUPPORT +/* + * The following python code is not really used because ZLIBSUPPORT is only + * defined if we have a built-in zlib, and the built-in zlib handles that. + */ +static const char zlibcode[] = + "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))"; + +static const char *zlib_args[] = { "python", "-c", zlibcode, NULL }; + +static int +zlibcmp(const unsigned char *buf) +{ + unsigned short x = 1; + unsigned char *s = (unsigned char *)&x; + + if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0) + return 0; + if (s[0] != 1) /* endianness test */ + x = buf[0] | (buf[1] << 8); + else + x = buf[1] | (buf[0] << 8); + if (x % 31) + return 0; + return 1; +} +#endif + +#define gzip_flags "-cd" +#define lrzip_flags "-do" +#define lzip_flags gzip_flags + +static const char *gzip_args[] = { + "gzip", gzip_flags, NULL +}; +static const char *uncompress_args[] = { + "uncompress", "-c", NULL +}; +static const char *bzip2_args[] = { + "bzip2", "-cd", NULL +}; +static const char *lzip_args[] = { + "lzip", lzip_flags, NULL +}; +static const char *xz_args[] = { + "xz", "-cd", NULL +}; +static const char *lrzip_args[] = { + "lrzip", lrzip_flags, NULL +}; +static const char *lz4_args[] = { + "lz4", "-cd", NULL +}; private const struct { - const char magic[8]; + const void *magic; size_t maglen; - const char *argv[3]; - int silent; + const char **argv; } compr[] = { - { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 }, /* compressed */ + { "\037\235", 2, gzip_args }, /* compressed */ /* Uncompress can get stuck; so use gzip first if we have it * Idea from Damien Clark, thanks! */ - { "\037\235", 2, { "uncompress", "-c", NULL }, 1 }, /* compressed */ - { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 }, /* gzipped */ - { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 }, /* frozen */ - { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */ + { "\037\235", 2, uncompress_args }, /* compressed */ + { "\037\213", 2, gzip_args }, /* gzipped */ + { "\037\236", 2, gzip_args }, /* frozen */ + { "\037\240", 2, gzip_args }, /* SCO LZH */ /* the standard pack utilities do not accept standard input */ - { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 }, /* packed */ - { "PK\3\4", 4, { "gzip", "-cdq", NULL }, 1 }, /* pkzipped, */ - /* ...only first file examined */ - { "BZh", 3, { "bzip2", "-cd", NULL }, 1 }, /* bzip2-ed */ - { "LZIP", 4, { "lzip", "-cdq", NULL }, 1 }, - { "\3757zXZ\0",6,{ "xz", "-cd", NULL }, 1 }, /* XZ Utils */ - { "LRZI", 4, { "lrzip", "-dqo-", NULL }, 1 }, /* LRZIP */ - { "\004\"M\030", 4, { "lz4", "-cd", NULL }, 1 }, /* LZ4 */ + { "\037\036", 2, gzip_args }, /* packed */ + { "PK\3\4", 4, gzip_args }, /* pkzipped, */ + /* ...only first file examined */ + { "BZh", 3, bzip2_args }, /* bzip2-ed */ + { "LZIP", 4, lzip_args }, /* lzip-ed */ + { "\3757zXZ\0", 6, xz_args }, /* XZ Utils */ + { "LRZI", 4, lrzip_args }, /* LRZIP */ + { "\004\"M\030",4, lz4_args }, /* LZ4 */ +#ifdef ZLIBSUPPORT + { zlibcmp, 0, zlib_args }, /* zlib */ +#endif }; -#define NODATA ((size_t)~0) +#define OKDATA 0 +#define NODATA 1 +#define ERRDATA 2 private ssize_t swrite(int, const void *, size_t); #if HAVE_FORK private size_t ncompr = sizeof(compr) / sizeof(compr[0]); -private size_t uncompressbuf(struct magic_set *, int, size_t, - const unsigned char *, unsigned char **, size_t); +private int uncompressbuf(int, size_t, size_t, const unsigned char *, + unsigned char **, size_t *); #ifdef BUILTIN_DECOMPRESS -private size_t uncompressgzipped(struct magic_set *, const unsigned char *, - unsigned char **, size_t); +private int uncompresszlib(const unsigned char *, unsigned char **, size_t, + size_t *, int); +private int uncompressgzipped(const unsigned char *, unsigned char **, size_t, + size_t *); #endif +static int makeerror(unsigned char **, size_t *, const char *, ...) + __attribute__((__format__(__printf__, 3, 4))); +private const char *methodname(size_t); protected int file_zmagic(struct magic_set *ms, int fd, const char *name, @@ -107,6 +185,8 @@ file_zmagic(struct magic_set *ms, int fd, const char *name, { unsigned char *newbuf = NULL; size_t i, nsz; + char *rbuf; + file_pushbuf_t *pb; int rv = 0; int mime = ms->flags & MAGIC_MIME; #ifdef HAVE_SIGNAL_H @@ -120,37 +200,72 @@ file_zmagic(struct magic_set *ms, int fd, const char *name, osigpipe = signal(SIGPIPE, SIG_IGN); #endif for (i = 0; i < ncompr; i++) { + int zm; if (nbytes < compr[i].maglen) continue; - if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 && - (nsz = uncompressbuf(ms, fd, i, buf, &newbuf, - nbytes)) != NODATA) { +#ifdef ZLIBSUPPORT + if (compr[i].maglen == 0) + zm = (CAST(int (*)(const unsigned char *), + CCAST(void *, compr[i].magic)))(buf); + else +#endif + zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0; + + if (!zm) + continue; + nsz = nbytes; + rv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz); + DPRINTF("uncompressbuf = %d, %s, %zu\n", rv, (char *)newbuf, + nsz); + switch (rv) { + case OKDATA: + case ERRDATA: + ms->flags &= ~MAGIC_COMPRESS; - rv = -1; - if (file_buffer(ms, -1, name, newbuf, nsz) == -1) + if (rv == ERRDATA) + rv = file_printf(ms, "%s ERROR: %s", + methodname(i), newbuf); + else + rv = file_buffer(ms, -1, name, newbuf, nsz); + if (rv == -1) goto error; - - if ((ms->flags & MAGIC_COMPRESS_TRANSP) == 0 && - (mime == MAGIC_MIME || mime == 0)) { - if (file_printf(ms, mime ? - " compressed-encoding=" : " (") == -1) - goto error; - if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) - goto error; - if (!mime && file_printf(ms, ")") == -1) + DPRINTF("rv = %d\n", rv); + if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0) + goto out; + if (mime != MAGIC_MIME && mime != 0) + goto out; + if ((file_printf(ms, + mime ? " compressed-encoding=" : " (")) == -1) + goto error; + if ((pb = file_push_buffer(ms)) == NULL) + goto error; + if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) + goto error; + if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { + if (file_printf(ms, "%s", rbuf) == -1) { + free(rbuf); goto error; + } + free(rbuf); } - - rv = 1; - break; + if (!mime && file_printf(ms, ")") == -1) + goto error; + goto out; + case NODATA: + goto out; + default: + abort(); } } +out: + rv = 1; error: #ifdef HAVE_SIGNAL_H (void)signal(SIGPIPE, osigpipe); #endif free(newbuf); ms->flags |= MAGIC_COMPRESS; + DPRINTF("Zmagic returns %d\n", rv); return rv; } #endif @@ -322,222 +437,314 @@ file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, #define FNAME (1 << 3) #define FCOMMENT (1 << 4) -private size_t -uncompressgzipped(struct magic_set *ms, const unsigned char *old, - unsigned char **newch, size_t n) + +private int +uncompressgzipped(const unsigned char *old, unsigned char **newch, + size_t bytes_max, size_t *n) { unsigned char flg = old[3]; size_t data_start = 10; - z_stream z; - int rc; if (flg & FEXTRA) { - if (data_start+1 >= n) - return 0; + if (data_start + 1 >= *n) + goto err; data_start += 2 + old[data_start] + old[data_start + 1] * 256; } if (flg & FNAME) { - while(data_start < n && old[data_start]) + while(data_start < *n && old[data_start]) data_start++; data_start++; } - if(flg & FCOMMENT) { - while(data_start < n && old[data_start]) + if (flg & FCOMMENT) { + while(data_start < *n && old[data_start]) data_start++; data_start++; } - if(flg & FHCRC) + if (flg & FHCRC) data_start += 2; - if (data_start >= n) - return 0; - if ((*newch = CAST(unsigned char *, malloc(HOWMANY + 1))) == NULL) { - return 0; - } - - /* XXX: const castaway, via strchr */ - z.next_in = (Bytef *)strchr((const char *)old + data_start, - old[data_start]); - z.avail_in = CAST(uint32_t, (n - data_start)); + if (data_start >= *n) + goto err; + + *n -= data_start; + old += data_start; + return uncompresszlib(old, newch, bytes_max, n, 0); +err: + return makeerror(newch, n, "File too short"); +} + +private int +uncompresszlib(const unsigned char *old, unsigned char **newch, + size_t bytes_max, size_t *n, int zlib) +{ + int rc; + z_stream z; + + if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL) + return makeerror(newch, n, "No buffer, %s", strerror(errno)); + + z.next_in = CCAST(Bytef *, old); + z.avail_in = CAST(uint32_t, *n); z.next_out = *newch; - z.avail_out = HOWMANY; + z.avail_out = bytes_max; z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; /* LINTED bug in header macro */ - rc = inflateInit2(&z, -15); - if (rc != Z_OK) { - file_error(ms, 0, "zlib: %s", z.msg); - return 0; - } + rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15); + if (rc != Z_OK) + goto err; rc = inflate(&z, Z_SYNC_FLUSH); - if (rc != Z_OK && rc != Z_STREAM_END) { - file_error(ms, 0, "zlib: %s", z.msg); - return 0; - } + if (rc != Z_OK && rc != Z_STREAM_END) + goto err; - n = (size_t)z.total_out; - (void)inflateEnd(&z); + *n = (size_t)z.total_out; + rc = inflateEnd(&z); + if (rc != Z_OK) + goto err; /* let's keep the nul-terminate tradition */ - (*newch)[n] = '\0'; + (*newch)[*n] = '\0'; - return n; + return OKDATA; +err: + strlcpy((char *)*newch, z.msg, bytes_max); + *n = strlen((char *)*newch); + return ERRDATA; } #endif -private size_t -uncompressbuf(struct magic_set *ms, int fd, size_t method, - const unsigned char *old, unsigned char **newch, size_t n) +static int +makeerror(unsigned char **buf, size_t *len, const char *fmt, ...) +{ + char *msg; + va_list ap; + int rv; + + va_start(ap, fmt); + rv = vasprintf(&msg, fmt, ap); + va_end(ap); + if (rv < 0) { + *buf = NULL; + *len = 0; + return NODATA; + } + *buf = (unsigned char *)msg; + *len = strlen(msg); + return ERRDATA; +} + +static void +closefd(int *fd, size_t i) +{ + if (fd[i] == -1) + return; + (void) close(fd[i]); + fd[i] = -1; +} + +static void +closep(int *fd) +{ + size_t i; + for (i = 0; i < 2; i++) + closefd(fd, i); +} + +static void +copydesc(int i, int *fd) +{ + int j = fd[i == STDIN_FILENO ? 0 : 1]; + if (j == i) + return; + if (dup2(j, i) == -1) { + DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno)); + exit(1); + } + closep(fd); +} + +static void +writechild(int fdp[3][2], const void *old, size_t n) { - int fdin[2], fdout[2]; int status; + + closefd(fdp[STDIN_FILENO], 0); + /* + * fork again, to avoid blocking because both + * pipes filled + */ + switch (fork()) { + case 0: /* child */ + closefd(fdp[STDOUT_FILENO], 0); + if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) { + DPRINTF("Write failed (%s)\n", strerror(errno)); + exit(1); + } + exit(0); + /*NOTREACHED*/ + + case -1: + DPRINTF("Fork failed (%s)\n", strerror(errno)); + exit(1); + /*NOTREACHED*/ + + default: /* parent */ + if (wait(&status) == -1) { + DPRINTF("Wait failed (%s)\n", strerror(errno)); + exit(1); + } + DPRINTF("Grandchild wait return %#x\n", status); + } + closefd(fdp[STDIN_FILENO], 1); +} + +static ssize_t +filter_error(unsigned char *ubuf, ssize_t n) +{ + char *p; + char *buf; + + ubuf[n] = '\0'; + buf = (char *)ubuf; + while (isspace((unsigned char)*buf)) + buf++; + DPRINTF("Filter error[[[%s]]]\n", buf); + if ((p = strchr((char *)buf, '\n')) != NULL) + *p = '\0'; + if ((p = strchr((char *)buf, ';')) != NULL) + *p = '\0'; + if ((p = strrchr((char *)buf, ':')) != NULL) { + ++p; + while (isspace((unsigned char)*p)) + p++; + n = strlen(p); + memmove(ubuf, p, n + 1); + } + DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); + if (islower(*ubuf)) + *ubuf = toupper(*ubuf); + return n; +} + +private const char * +methodname(size_t method) +{ +#ifdef BUILTIN_DECOMPRESS + /* FIXME: This doesn't cope with bzip2 */ + if (method == 2 || compr[method].maglen == 0) + return "zlib"; +#endif + return compr[method].argv[0]; +} + +private int +uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old, + unsigned char **newch, size_t* n) +{ + int fdp[3][2]; + int status, rv; + size_t i; ssize_t r; #ifdef BUILTIN_DECOMPRESS /* FIXME: This doesn't cope with bzip2 */ if (method == 2) - return uncompressgzipped(ms, old, newch, n); + return uncompressgzipped(old, newch, bytes_max, n); + if (compr[method].maglen == 0) + return uncompresszlib(old, newch, bytes_max, n, 1); #endif (void)fflush(stdout); (void)fflush(stderr); - if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) { - file_error(ms, errno, "cannot create pipe"); - return NODATA; + for (i = 0; i < __arraycount(fdp); i++) + fdp[i][0] = fdp[i][1] = -1; + + if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) || + pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) { + closep(fdp[STDIN_FILENO]); + closep(fdp[STDOUT_FILENO]); + return makeerror(newch, n, "Cannot create pipe, %s", + strerror(errno)); } switch (fork()) { case 0: /* child */ - (void) close(0); if (fd != -1) { - if (dup(fd) == -1) - _exit(1); - (void) lseek(0, (off_t)0, SEEK_SET); - } else { - if (dup(fdin[0]) == -1) - _exit(1); - (void) close(fdin[0]); - (void) close(fdin[1]); + fdp[STDIN_FILENO][0] = fd; + (void) lseek(fd, (off_t)0, SEEK_SET); } - - (void) close(1); - if (dup(fdout[1]) == -1) - _exit(1); - (void) close(fdout[0]); - (void) close(fdout[1]); -#ifndef DEBUG - if (compr[method].silent) - (void)close(2); -#endif + + for (i = 0; i < __arraycount(fdp); i++) + copydesc(i, fdp[i]); (void)execvp(compr[method].argv[0], (char *const *)(intptr_t)compr[method].argv); -#ifdef DEBUG - (void)fprintf(stderr, "exec `%s' failed (%s)\n", + dprintf(STDERR_FILENO, "exec `%s' failed, %s", compr[method].argv[0], strerror(errno)); -#endif exit(1); /*NOTREACHED*/ case -1: - file_error(ms, errno, "could not fork"); - return NODATA; + return makeerror(newch, n, "Cannot fork, %s", + strerror(errno)); default: /* parent */ - (void) close(fdout[1]); - if (fd == -1) { - (void) close(fdin[0]); - /* - * fork again, to avoid blocking because both - * pipes filled - */ - switch (fork()) { - case 0: /* child */ - (void)close(fdout[0]); - if (swrite(fdin[1], old, n) != (ssize_t)n) { -#ifdef DEBUG - (void)fprintf(stderr, - "Write failed (%s)\n", - strerror(errno)); -#endif - exit(1); - } - exit(0); - /*NOTREACHED*/ - - case -1: -#ifdef DEBUG - (void)fprintf(stderr, "Fork failed (%s)\n", - strerror(errno)); -#endif - exit(1); - /*NOTREACHED*/ + for (i = 1; i < __arraycount(fdp); i++) + closefd(fdp[i], 1); - default: /* parent */ - if (wait(&status) == -1) { -#ifdef DEBUG - (void)fprintf(stderr, - "Wait failed (%s)\n", - strerror(errno)); -#endif - exit(1); - } - exit(WIFEXITED(status) ? - WEXITSTATUS(status) : 1); - /*NOTREACHED*/ - } - (void) close(fdin[1]); - fdin[1] = -1; - } + /* Write the buffer data to the child, if we don't have fd */ + if (fd == -1) + writechild(fdp, old, *n); - if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) { -#ifdef DEBUG - (void)fprintf(stderr, "Malloc failed (%s)\n", + *newch = CAST(unsigned char *, malloc(bytes_max + 1)); + if (*newch == NULL) { + rv = makeerror(newch, n, "No buffer, %s", strerror(errno)); -#endif - n = NODATA; goto err; } - if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) { -#ifdef DEBUG - (void)fprintf(stderr, "Read failed (%s)\n", - strerror(errno)); -#endif - free(*newch); - n = NODATA; - *newch = NULL; - goto err; - } else { - n = r; + rv = OKDATA; + if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0) + break; + DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], + r != -1 ? strerror(errno) : "no data"); + + rv = ERRDATA; + if (r == 0 && + (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0) + { + r = filter_error(*newch, r); + break; } - /* NUL terminate, as every buffer is handled here. */ - (*newch)[n] = '\0'; -err: - if (fdin[1] != -1) - (void) close(fdin[1]); - (void) close(fdout[0]); - if (wait(&status) == -1) { -#ifdef DEBUG - (void)fprintf(stderr, "Wait failed (%s)\n", + free(*newch); + if (r == 0) + rv = makeerror(newch, n, "Read failed, %s", strerror(errno)); -#endif - n = NODATA; - } else if (!WIFEXITED(status)) { -#ifdef DEBUG - (void)fprintf(stderr, "Child not exited (0x%x)\n", - status); -#endif - } else if (WEXITSTATUS(status) != 0) { -#ifdef DEBUG - (void)fprintf(stderr, "Child exited (0x%d)\n", - WEXITSTATUS(status)); -#endif - } + else + rv = makeerror(newch, n, "No data"); + goto err; + } - (void) close(fdin[0]); - - return n; + *n = r; + /* NUL terminate, as every buffer is handled here. */ + (*newch)[*n] = '\0'; +err: + closefd(fdp[STDIN_FILENO], 1); + closefd(fdp[STDOUT_FILENO], 0); + closefd(fdp[STDERR_FILENO], 0); + if (wait(&status) == -1) { + free(*newch); + rv = makeerror(newch, n, "Wait failed, %s", strerror(errno)); + DPRINTF("Child wait return %#x\n", status); + } else if (!WIFEXITED(status)) { + DPRINTF("Child not exited (0x%x)\n", status); + } else if (WEXITSTATUS(status) != 0) { + DPRINTF("Child exited (0x%d)\n", WEXITSTATUS(status)); } + + closefd(fdp[STDIN_FILENO], 0); + DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv); + + return rv; } #endif diff --git a/contrib/file/src/der.c b/contrib/file/src/der.c new file mode 100644 index 0000000..e003795 --- /dev/null +++ b/contrib/file/src/der.c @@ -0,0 +1,379 @@ +/*- + * Copyright (c) 2016 Christos Zoulas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * DER (Distinguished Encoding Rules) Parser + * + * Sources: + * https://en.wikipedia.org/wiki/X.690 + * http://fm4dd.com/openssl/certexamples.htm + * http://blog.engelke.com/2014/10/17/parsing-ber-and-der-encoded-asn-1-objects/ + */ +#ifndef TEST_DER +#include "file.h" + +#ifndef lint +FILE_RCSID("@(#)$File: der.c,v 1.4 2016/03/21 23:04:40 christos Exp $") +#endif +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include <stdio.h> +#include <err.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#ifndef TEST_DER +#include "magic.h" +#include "der.h" +#endif + +#define DER_BAD ((uint32_t)-1) + +#define DER_CLASS_UNIVERSAL 0 +#define DER_CLASS_APPLICATION 1 +#define DER_CLASS_CONTEXT 2 +#define DER_CLASS_PRIVATE 3 +static const char der_class[] = "UACP"; + +#define DER_TYPE_PRIMITIVE 0 +#define DER_TYPE_CONSTRUCTED 1 +static const char der_type[] = "PC"; + +#define DER_TAG_EOC 0x00 +#define DER_TAG_BOOLEAN 0x01 +#define DER_TAG_INTEGER 0x02 +#define DER_TAG_BIT STRING 0x03 +#define DER_TAG_OCTET_STRING 0x04 +#define DER_TAG_NULL 0x05 +#define DER_TAG_OBJECT_IDENTIFIER 0x06 +#define DER_TAG_OBJECT_DESCRIPTOR 0x07 +#define DER_TAG_EXTERNAL 0x08 +#define DER_TAG_REAL 0x09 +#define DER_TAG_ENUMERATED 0x0a +#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_RESERVED_2 0x0f +#define DER_TAG_SEQUENCE 0x10 +#define DER_TAG_SET 0x11 +#define DER_TAG_NUMERIC_STRING 0x12 +#define DER_TAG_PRINTABLE_STRING 0x13 +#define DER_TAG_T61_STRING 0x14 +#define DER_TAG_VIDEOTEX_STRING 0x15 +#define DER_TAG_IA5_STRING 0x16 +#define DER_TAG_UTCTIME 0x17 +#define DER_TAG_GENERALIZED_TIME 0x18 +#define DER_TAG_GRAPHIC_STRING 0x19 +#define DER_TAG_VISIBLE_STRING 0x1a +#define DER_TAG_GENERAL_STRING 0x1b +#define DER_TAG_UNIVERSAL_STRING 0x1c +#define DER_TAG_CHARACTER_STRING 0x1d +#define DER_TAG_BMP_STRING 0x1e +#define DER_TAG_LONG 0x1f + +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", + "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" +}; + +#ifdef DEBUG_DER +#define DPRINTF(a) printf a +#else +#define DPRINTF(a) +#endif + +#ifdef TEST_DER +static uint8_t +getclass(uint8_t c) +{ + return c >> 6; +} + +static uint8_t +gettype(uint8_t c) +{ + return (c >> 5) & 1; +} +#endif + +static uint32_t +gettag(const uint8_t *c, size_t *p, size_t l) +{ + uint32_t tag; + + if (*p >= l) + return DER_BAD; + + tag = c[(*p)++] & 0x1f; + + if (tag != 0x1f) + return tag; + + if (*p >= l) + return DER_BAD; + + while (c[*p] >= 0x80) { + tag = tag * 128 + c[(*p)++] - 0x80; + if (*p >= l) + return DER_BAD; + } + return tag; +} + +static uint32_t +getlength(const uint8_t *c, size_t *p, size_t l) +{ + uint8_t digits, i; + size_t len; + + if (*p >= l) + return DER_BAD; + + digits = c[(*p)++]; + + if ((digits & 0x80) == 0) + return digits; + + digits &= 0x7f; + len = 0; + + if (*p + digits >= l) + return DER_BAD; + + for (i = 0; i < digits; i++) + len = (len << 8) | c[(*p)++]; + return len; +} + +static const char * +der_tag(char *buf, size_t len, uint32_t tag) +{ + if (tag < DER_TAG_LONG) + strlcpy(buf, der__tag[tag], len); + else + snprintf(buf, len, "%#x", tag); + return buf; +} + +#ifndef TEST_DER +static int +der_data(char *buf, size_t blen, uint32_t tag, const void *q, uint32_t len) +{ + const uint8_t *d = q; + switch (tag) { + 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, (const char *)q); + default: + break; + } + + for (uint32_t i = 0; i < len; i++) { + uint32_t z = i << 1; + if (z < blen - 2) + snprintf(buf + z, blen - z, "%.2x", d[i]); + } + return len * 2; +} + +int32_t +der_offs(struct magic_set *ms, struct magic *m, size_t nbytes) +{ + const uint8_t *b = CAST(const void *, ms->search.s); + size_t offs = 0, len = ms->search.rm_len ? ms->search.rm_len : nbytes; + + if (gettag(b, &offs, len) == DER_BAD) + return -1; + DPRINTF(("%s1: %d %zu %u\n", __func__, ms->offset, offs, m->offset)); + + uint32_t tlen = getlength(b, &offs, len); + if (tlen == DER_BAD) + return -1; + DPRINTF(("%s2: %d %zu %u\n", __func__, ms->offset, offs, tlen)); + + offs += ms->offset + m->offset; + DPRINTF(("cont_level = %d\n", m->cont_level)); +#ifdef DEBUG_DER + for (size_t i = 0; i < m->cont_level; i++) + printf("cont_level[%zu] = %u\n", i, ms->c.li[i].off); +#endif + if (m->cont_level != 0) { + if (offs + tlen > nbytes) + return DER_BAD; + ms->c.li[m->cont_level - 1].off = offs + tlen; + DPRINTF(("cont_level[%u] = %u\n", m->cont_level - 1, + ms->c.li[m->cont_level - 1].off)); + } + return offs; +} + +int +der_cmp(struct magic_set *ms, struct magic *m) +{ + const uint8_t *b = CAST(const void *, ms->search.s); + const char *s = m->value.s; + size_t offs = 0, len = ms->search.s_len; + uint32_t tag, tlen; + char buf[128]; + + tag = gettag(b, &offs, len); + if (tag == DER_BAD) + return -1; + + tlen = getlength(b, &offs, len); + if (tlen == DER_BAD) + return -1; + + der_tag(buf, sizeof(buf), tag); + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "%s: tag %p got=%s exp=%s\n", __func__, b, + buf, s); + size_t slen = strlen(buf); + + if (strncmp(buf, s, slen) != 0) + return 0; + + s += slen; + +again: + switch (*s) { + case '\0': + return 1; + case '=': + s++; + goto val; + default: + if (!isdigit((unsigned char)*s)) + return 0; + + slen = 0; + do + slen = slen * 10 + *s - '0'; + while (isdigit((unsigned char)*++s)); + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "%s: len %zu %u\n", __func__, + slen, tlen); + if (tlen != slen) + return 0; + goto again; + } +val: + DPRINTF(("%s: before data %zu %u\n", __func__, offs, tlen)); + der_data(buf, sizeof(buf), tag, b + offs, tlen); + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "%s: data %s %s\n", __func__, buf, s); + if (strcmp(buf, s) != 0 && strcmp("x", s) != 0) + return 0; + strlcpy(ms->ms_value.s, buf, sizeof(ms->ms_value.s)); + return 1; +} +#endif + +#ifdef TEST_DER +static void +printtag(uint32_t tag, const void *q, uint32_t len) +{ + const uint8_t *d = q; + switch (tag) { + case DER_TAG_PRINTABLE_STRING: + case DER_TAG_UTF8_STRING: + printf("%.*s\n", len, (const char *)q); + return; + default: + break; + } + + for (uint32_t i = 0; i < len; i++) + printf("%.2x", d[i]); + printf("\n"); +} + +static void +printdata(size_t level, const void *v, size_t x, size_t l) +{ + const uint8_t *p = v, *ep = p + l; + size_t ox; + char buf[128]; + + while (p + x < ep) { + const uint8_t *q; + 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]); + uint32_t tag = gettag(p, &x, ep - p + x); + if (p + x >= ep) + break; + uint32_t len = getlength(p, &x, ep - p + x); + + printf("%zu %zu-%zu %c,%c,%s,%u:", level, ox, x, + der_class[c], der_type[t], + der_tag(buf, sizeof(buf), tag), len); + q = p + x; + if (p + len > ep) + errx(EXIT_FAILURE, "corrupt der"); + printtag(tag, q, len); + if (t != DER_TYPE_PRIMITIVE) + printdata(level + 1, p, x, len + x); + x += len; + } +} + +int +main(int argc, char *argv[]) +{ + int fd; + struct stat st; + size_t l; + void *p; + + if ((fd = open(argv[1], O_RDONLY)) == -1) + err(EXIT_FAILURE, "open `%s'", argv[1]); + if (fstat(fd, &st) == -1) + err(EXIT_FAILURE, "stat `%s'", argv[1]); + l = (size_t)st.st_size; + if ((p = mmap(NULL, l, PROT_READ, MAP_FILE, fd, 0)) == MAP_FAILED) + err(EXIT_FAILURE, "mmap `%s'", argv[1]); + + printdata(0, p, 0, l); + munmap(p, l); + return 0; +} +#endif diff --git a/contrib/file/src/der.h b/contrib/file/src/der.h new file mode 100644 index 0000000..3333239 --- /dev/null +++ b/contrib/file/src/der.h @@ -0,0 +1,28 @@ +/*- + * Copyright (c) 2016 Christos Zoulas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +extern int der_offs(struct magic_set *, struct magic *, size_t); +extern int der_cmp(struct magic_set *, struct magic *); diff --git a/contrib/file/src/dprintf.c b/contrib/file/src/dprintf.c new file mode 100644 index 0000000..3ae1581 --- /dev/null +++ b/contrib/file/src/dprintf.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) Ian F. Darwin 1986-1995. + * Software written by Ian F. Darwin and others; + * maintained 1995-present by Christos Zoulas and others. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "file.h" + +#ifndef lint +FILE_RCSID("@(#)$File: dprintf.c,v 1.1 2015/11/13 15:36:14 christos Exp $") +#endif /* lint */ + +#include <assert.h> +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> + +int +dprintf(int fd, const char *fmt, ...) +{ + va_list ap; + /* Simpler than using vasprintf() here, since we never need more */ + char buf[1024]; + int len; + + va_start(ap, fmt); + len = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + if ((size_t)len >= sizeof(buf)) + return -1; + + if (write(fd, buf, (size_t)len) != len) + return -1; + + return len; +} diff --git a/contrib/file/src/file.c b/contrib/file/src/file.c index fa46b95..2226ec4 100644 --- a/contrib/file/src/file.c +++ b/contrib/file/src/file.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: file.c,v 1.167 2015/09/11 17:24:09 christos Exp $") +FILE_RCSID("@(#)$File: file.c,v 1.170 2016/03/31 17:51:12 christos Exp $") #endif /* lint */ #include "magic.h" @@ -94,9 +94,9 @@ 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, doc) \ +#define OPT(shortname, longname, opt, def, doc) \ {longname, opt, NULL, shortname}, -#define OPT_LONGONLY(longname, opt, doc, id) \ +#define OPT_LONGONLY(longname, opt, def, doc, id) \ {longname, opt, NULL, id}, #include "file_opts.h" #undef OPT @@ -132,15 +132,17 @@ private struct { { "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0 }, { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0 }, { "regex", MAGIC_PARAM_REGEX_MAX, 0 }, + { "bytes", MAGIC_PARAM_BYTES_MAX, 0 }, }; private char *progname; /* used throughout */ +private int posixly; #ifdef __dead __dead #endif private void usage(void); -private void docprint(const char *); +private void docprint(const char *, int); #ifdef __dead __dead #endif @@ -183,7 +185,8 @@ main(int argc, char *argv[]) progname = argv[0]; #ifdef S_IFLNK - flags |= getenv("POSIXLY_CORRECT") ? MAGIC_SYMLINK : 0; + posixly = getenv("POSIXLY_CORRECT") != NULL; + flags |= posixly ? MAGIC_SYMLINK : 0; #endif while ((c = getopt_long(argc, argv, OPTSTRING, long_options, &longindex)) != -1) @@ -204,7 +207,7 @@ main(int argc, char *argv[]) flags |= MAGIC_MIME_ENCODING; break; case '0': - nulsep = 1; + nulsep++; break; case 'b': bflag++; @@ -492,24 +495,28 @@ unwrap(struct magic_set *ms, const char *fn) private int process(struct magic_set *ms, const char *inname, int wid) { - const char *type; + const char *type, c = nulsep > 1 ? '\0' : '\n'; int std_in = strcmp(inname, "-") == 0; if (wid > 0 && !bflag) { (void)printf("%s", std_in ? "/dev/stdin" : inname); if (nulsep) (void)putc('\0', stdout); - (void)printf("%s", separator); - (void)printf("%*s ", - (int) (nopad ? 0 : (wid - file_mbswidth(inname))), ""); + if (nulsep < 2) { + (void)printf("%s", separator); + (void)printf("%*s ", + (int) (nopad ? 0 : (wid - file_mbswidth(inname))), + ""); + } } type = magic_file(ms, std_in ? NULL : inname); + if (type == NULL) { - (void)printf("ERROR: %s\n", magic_error(ms)); + (void)printf("ERROR: %s%c", magic_error(ms), c); return 1; } else { - (void)printf("%s\n", type); + (void)printf("%s%c", type, c); return 0; } } @@ -559,7 +566,17 @@ usage(void) } private void -docprint(const char *opts) +defprint(int def) +{ + if (!def) + return; + if (((def & 1) && posixly) || ((def & 2) && !posixly)) + fprintf(stdout, " (default)"); + fputc('\n', stdout); +} + +private void +docprint(const char *opts, int def) { size_t i; int comma; @@ -568,6 +585,7 @@ docprint(const char *opts) p = strstr(opts, "%o"); if (p == NULL) { fprintf(stdout, "%s", opts); + defprint(def); return; } @@ -595,12 +613,12 @@ help(void) "Usage: file [OPTION...] [FILE...]\n" "Determine type of FILEs.\n" "\n", stdout); -#define OPT(shortname, longname, opt, doc) \ +#define OPT(shortname, longname, opt, def, doc) \ fprintf(stdout, " -%c, --" longname, shortname), \ - docprint(doc); -#define OPT_LONGONLY(longname, opt, doc, id) \ + docprint(doc, def); +#define OPT_LONGONLY(longname, opt, def, doc, id) \ fprintf(stdout, " --" longname), \ - docprint(doc); + docprint(doc, def); #include "file_opts.h" #undef OPT #undef OPT_LONGONLY diff --git a/contrib/file/src/file.h b/contrib/file/src/file.h index b0f0cc1..f22fcd9 100644 --- a/contrib/file/src/file.h +++ b/contrib/file/src/file.h @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.172 2015/09/11 17:24:09 christos Exp $ + * @(#)$File: file.h,v 1.178 2016/03/31 17:51:12 christos Exp $ */ #ifndef __file_h__ @@ -127,8 +127,8 @@ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif -#ifndef HOWMANY -# define HOWMANY (1024 * 1024) /* how much of the file to look at */ +#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 */ @@ -227,7 +227,8 @@ struct magic { #define FILE_NAME 45 #define FILE_USE 46 #define FILE_CLEAR 47 -#define FILE_NAMES_SIZE 48 /* size of array to contain all names */ +#define FILE_DER 48 +#define FILE_NAMES_SIZE 49 /* size of array to contain all names */ #define IS_STRING(t) \ ((t) == FILE_STRING || \ @@ -365,9 +366,11 @@ struct mlist { #ifdef __cplusplus #define CAST(T, b) static_cast<T>(b) #define RCAST(T, b) reinterpret_cast<T>(b) +#define CCAST(T, b) const_cast<T>(b) #else -#define CAST(T, b) (T)(b) -#define RCAST(T, b) (T)(b) +#define CAST(T, b) ((T)(b)) +#define RCAST(T, b) ((T)(b)) +#define CCAST(T, b) ((T)(uintptr_t)(b)) #endif struct level_info { @@ -416,7 +419,8 @@ struct magic_set { uint16_t elf_phnum_max; uint16_t elf_notes_max; uint16_t regex_max; -#define FILE_INDIR_MAX 15 + 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 @@ -461,7 +465,7 @@ protected int file_encoding(struct magic_set *, const unsigned char *, size_t, unichar **, size_t *, const char **, const char **, const char **); protected int file_is_tar(struct magic_set *, const unsigned char *, size_t); protected int file_softmagic(struct magic_set *, const unsigned char *, size_t, - uint16_t, uint16_t *, int, int); + uint16_t *, uint16_t *, int, int); protected int file_apprentice(struct magic_set *, const char *, int); protected int buffer_apprentice(struct magic_set *, struct magic **, size_t *, size_t); @@ -506,6 +510,8 @@ typedef struct { #define USE_C_LOCALE locale_t old_lc_ctype; locale_t c_lc_ctype; +#else + char *old_lc_ctype; #endif int rc; regex_t rx; @@ -550,6 +556,9 @@ int vasprintf(char **, const char *, va_list); #ifndef HAVE_ASPRINTF int asprintf(char **, const char *, ...); #endif +#ifndef HAVE_DPRINTF +int dprintf(int, const char *, ...); +#endif #ifndef HAVE_STRLCPY size_t strlcpy(char *, const char *, size_t); diff --git a/contrib/file/src/file_opts.h b/contrib/file/src/file_opts.h index 3d9a7ce..52ace18 100644 --- a/contrib/file/src/file_opts.h +++ b/contrib/file/src/file_opts.h @@ -12,47 +12,47 @@ * switch statement! */ -OPT_LONGONLY("help", 0, " display this help and exit\n", OPT_HELP) -OPT('v', "version", 0, " output version information and exit\n") -OPT('m', "magic-file", 1, " 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, " try to look inside compressed files\n") -OPT('Z', "uncompress-noreport", 0, " only print the contents of compressed files\n") -OPT('b', "brief", 0, " do not prepend filenames to output lines\n") -OPT('c', "checking-printout", 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, " 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, " FILE read the filenames to be examined from FILE\n") -OPT('F', "separator", 1, " STRING use string as separator instead of `:'\n") -OPT('i', "mime", 0, " output MIME type strings (--mime-type and\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" " --mime-encoding)\n") -OPT_LONGONLY("apple", 0, " output the Apple CREATOR/TYPE\n", OPT_APPLE) -OPT_LONGONLY("extension", 0, " output a slash-separated list of extensions\n", OPT_EXTENSIONS) -OPT_LONGONLY("mime-type", 0, " output the MIME type\n", OPT_MIME_TYPE) -OPT_LONGONLY("mime-encoding", 0, " output the MIME encoding\n", OPT_MIME_ENCODING) -OPT('k', "keep-going", 0, " don't stop at the first match\n") -OPT('l', "list", 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, " follow symlinks (default)\n") -OPT('h', "no-dereference", 0, " don't follow symlinks\n") +OPT('L', "dereference", 0, 1, " follow symlinks") +OPT('h', "no-dereference", 0, 2, " don't follow symlinks") #endif -OPT('n', "no-buffer", 0, " do not buffer output\n") -OPT('N', "no-pad", 0, " do not pad output\n") -OPT('0', "print0", 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, " preserve access times on files\n") +OPT('p', "preserve-date", 0, 0, " preserve access times on files\n") #endif -OPT('P', "parameter", 1, " set file engine parameter limits\n" +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, " don't translate unprintable chars to \\ooo\n") -OPT('s', "special-files", 0, " treat special (block/char devices) files as\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('C', "compile", 0, " compile file specified by -m\n") -OPT('d', "debug", 0, " print debugging messages\n") +OPT('C', "compile", 0, 0, " compile file specified by -m\n") +OPT('d', "debug", 0, 0, " print debugging messages\n") diff --git a/contrib/file/src/fmtcheck.c b/contrib/file/src/fmtcheck.c index 0fc7038..486aa08 100644 --- a/contrib/file/src/fmtcheck.c +++ b/contrib/file/src/fmtcheck.c @@ -91,6 +91,23 @@ get_next_format_from_precision(const char **pf) f++; longdouble = 1; break; +#ifdef WIN32 + case 'I': + f++; + if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); + if (*f == '3' && f[1] == '2') { + f += 2; + } else if (*f == '6' && f[1] == '4') { + f += 2; + quad = 1; + } +#ifdef _WIN64 + else { + quad = 1; + } +#endif + break; +#endif default: break; } diff --git a/contrib/file/src/funcs.c b/contrib/file/src/funcs.c index 97d4a0a..df8dbae 100644 --- a/contrib/file/src/funcs.c +++ b/contrib/file/src/funcs.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: funcs.c,v 1.84 2015/09/10 13:32:19 christos Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.89 2016/03/21 15:56:53 christos Exp $") #endif /* lint */ #include "magic.h" @@ -178,7 +178,6 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u const void *buf, size_t nb) { int m = 0, rv = 0, looks_text = 0; - int mime = ms->flags & MAGIC_MIME; const unsigned char *ubuf = CAST(const unsigned char *, buf); unichar *u8buf = NULL; size_t ulen; @@ -252,7 +251,8 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u /* try soft magic tests */ if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) - m = file_softmagic(ms, ubuf, nb, 0, NULL, BINTEST, looks_text); + m = file_softmagic(ms, ubuf, nb, NULL, NULL, BINTEST, + looks_text); if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "[try softmagic %d]\n", m); if (m) { @@ -293,9 +293,19 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u simple: /* give up */ m = 1; - if ((!mime || (mime & MAGIC_MIME_TYPE)) && - file_printf(ms, "%s", mime ? type : def) == -1) { - rv = -1; + if (ms->flags & MAGIC_MIME) { + if ((ms->flags & MAGIC_MIME_TYPE) && + file_printf(ms, "%s", type) == -1) + rv = -1; + } else if (ms->flags & MAGIC_APPLE) { + if (file_printf(ms, "UNKNUNKN") == -1) + rv = -1; + } else if (ms->flags & MAGIC_EXTENSION) { + if (file_printf(ms, "???") == -1) + rv = -1; + } else { + if (file_printf(ms, "%s", def) == -1) + rv = -1; } done: if ((ms->flags & MAGIC_MIME_ENCODING) != 0) { @@ -485,6 +495,8 @@ file_regcomp(file_regex_t *rx, const char *pat, int flags) assert(rx->c_lc_ctype != NULL); rx->old_lc_ctype = uselocale(rx->c_lc_ctype); assert(rx->old_lc_ctype != NULL); +#else + rx->old_lc_ctype = setlocale(LC_CTYPE, "C"); #endif rx->pat = pat; @@ -507,6 +519,8 @@ file_regfree(file_regex_t *rx) #ifdef USE_C_LOCALE (void)uselocale(rx->old_lc_ctype); freelocale(rx->c_lc_ctype); +#else + (void)setlocale(LC_CTYPE, rx->old_lc_ctype); #endif } diff --git a/contrib/file/src/magic.c b/contrib/file/src/magic.c index 87ac1cb..315a944 100644 --- a/contrib/file/src/magic.c +++ b/contrib/file/src/magic.c @@ -33,7 +33,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: magic.c,v 1.95 2015/09/11 17:24:09 christos Exp $") +FILE_RCSID("@(#)$File: magic.c,v 1.97 2016/03/31 17:51:12 christos Exp $") #endif /* lint */ #include "magic.h" @@ -346,7 +346,7 @@ private void close_and_restore(const struct magic_set *ms, const char *name, int fd, const struct stat *sb) { - if (fd == STDIN_FILENO || name == NULL) + if (name == NULL) return; (void) close(fd); @@ -417,7 +417,7 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) * some overlapping space for matches near EOF */ #define SLOP (1 + sizeof(union VALUETYPE)) - if ((buf = CAST(unsigned char *, malloc(HOWMANY + SLOP))) == NULL) + if ((buf = CAST(unsigned char *, malloc(ms->bytes_max + SLOP))) == NULL) return NULL; switch (file_fsmagic(ms, inname, &sb)) { @@ -481,13 +481,13 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) } /* - * try looking at the first HOWMANY bytes + * try looking at the first ms->bytes_max bytes */ if (ispipe) { ssize_t r = 0; while ((r = sread(fd, (void *)&buf[nbytes], - (size_t)(HOWMANY - nbytes), 1)) > 0) { + (size_t)(ms->bytes_max - nbytes), 1)) > 0) { nbytes += r; if (r < PIPE_BUF) break; } @@ -503,10 +503,10 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) } else { /* Windows refuses to read from a big console buffer. */ size_t howmany = -#if defined(WIN32) && HOWMANY > 8 * 1024 +#if defined(WIN32) _isatty(fd) ? 8 * 1024 : #endif - HOWMANY; + ms->bytes_max; if ((nbytes = read(fd, (char *)buf, howmany)) == -1) { if (inname == NULL && fd != STDIN_FILENO) file_error(ms, errno, "cannot read fd %d", fd); @@ -606,6 +606,9 @@ magic_setparam(struct magic_set *ms, int param, const void *val) case MAGIC_PARAM_REGEX_MAX: ms->elf_notes_max = (uint16_t)*(const size_t *)val; return 0; + case MAGIC_PARAM_BYTES_MAX: + ms->bytes_max = *(const size_t *)val; + return 0; default: errno = EINVAL; return -1; @@ -634,6 +637,9 @@ magic_getparam(struct magic_set *ms, int param, void *val) case MAGIC_PARAM_REGEX_MAX: *(size_t *)val = ms->regex_max; return 0; + case MAGIC_PARAM_BYTES_MAX: + *(size_t *)val = ms->bytes_max; + return 0; default: errno = EINVAL; return -1; diff --git a/contrib/file/src/magic.h b/contrib/file/src/magic.h index eab3d3a..af6b5b6 100644 --- a/contrib/file/src/magic.h +++ b/contrib/file/src/magic.h @@ -80,7 +80,7 @@ #define MAGIC_NO_CHECK_FORTRAN 0x000000 /* Don't check ascii/fortran */ #define MAGIC_NO_CHECK_TROFF 0x000000 /* Don't check ascii/troff */ -#define MAGIC_VERSION 524 /* This implementation */ +#define MAGIC_VERSION 525 /* This implementation */ #ifdef __cplusplus @@ -114,6 +114,7 @@ int magic_errno(magic_t); #define MAGIC_PARAM_ELF_SHNUM_MAX 3 #define MAGIC_PARAM_ELF_NOTES_MAX 4 #define MAGIC_PARAM_REGEX_MAX 5 +#define MAGIC_PARAM_BYTES_MAX 6 int magic_setparam(magic_t, int, const void *); int magic_getparam(magic_t, int, void *); diff --git a/contrib/file/src/print.c b/contrib/file/src/print.c index 0d52290..a0221b1 100644 --- a/contrib/file/src/print.c +++ b/contrib/file/src/print.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: print.c,v 1.80 2015/07/16 14:28:57 christos Exp $") +FILE_RCSID("@(#)$File: print.c,v 1.81 2016/01/19 15:09:03 christos Exp $") #endif /* lint */ #include <string.h> @@ -198,6 +198,7 @@ file_mdump(struct magic *m) break; case FILE_USE: case FILE_NAME: + case FILE_DER: (void) fprintf(stderr, "'%s'", m->value.s); break; default: diff --git a/contrib/file/src/readcdf.c b/contrib/file/src/readcdf.c index 99d8ec0..f79ac99 100644 --- a/contrib/file/src/readcdf.c +++ b/contrib/file/src/readcdf.c @@ -26,7 +26,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readcdf.c,v 1.53 2015/04/09 20:01:41 christos Exp $") +FILE_RCSID("@(#)$File: readcdf.c,v 1.56 2016/03/03 22:20:03 christos Exp $") #endif #include <assert.h> @@ -60,12 +60,16 @@ static const struct nv { { "Windows Installer", "vnd.ms-msi", }, { NULL, NULL, }, }, name2mime[] = { + { "Book", "vnd.ms-excel", }, + { "Workbook", "vnd.ms-excel", }, { "WordDocument", "msword", }, { "PowerPoint", "vnd.ms-powerpoint", }, { "DigitalSignature", "vnd.ms-msi", }, { NULL, NULL, }, }, name2desc[] = { - { "WordDocument", "Microsoft Office Word",}, + { "Book", "Microsoft Excel", }, + { "Workbook", "Microsoft Excel", }, + { "WordDocument", "Microsoft Word", }, { "PowerPoint", "Microsoft PowerPoint", }, { "DigitalSignature", "Microsoft Installer", }, { NULL, NULL, }, @@ -119,6 +123,8 @@ cdf_app_to_mime(const char *vbuf, const struct nv *nv) assert(c_lc_ctype != NULL); old_lc_ctype = uselocale(c_lc_ctype); assert(old_lc_ctype != NULL); +#else + char *old_lc_ctype = setlocale(LC_CTYPE, "C"); #endif for (i = 0; nv[i].pattern != NULL; i++) if (strcasestr(vbuf, nv[i].pattern) != NULL) { @@ -131,6 +137,8 @@ cdf_app_to_mime(const char *vbuf, const struct nv *nv) #ifdef USE_C_LOCALE (void)uselocale(old_lc_ctype); freelocale(c_lc_ctype); +#else + setlocale(LC_CTYPE, old_lc_ctype); #endif return rv; } diff --git a/contrib/file/src/readelf.c b/contrib/file/src/readelf.c index 2a7fc01..39598f7 100644 --- a/contrib/file/src/readelf.c +++ b/contrib/file/src/readelf.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readelf.c,v 1.122 2015/09/10 13:59:32 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.127 2015/11/18 12:29:29 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -50,7 +50,7 @@ private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, off_t, int, int, int *, uint16_t *); private size_t donote(struct magic_set *, void *, size_t, size_t, int, - int, size_t, int *, uint16_t *); + int, size_t, int *, uint16_t *, int, off_t, int, off_t); #define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) @@ -177,6 +177,11 @@ getu64(int swap, uint64_t value) elf_getu32(swap, ph32.p_align) : 4) \ : (off_t) (ph64.p_align ? \ elf_getu64(swap, ph64.p_align) : 4))) +#define xph_vaddr (size_t)((clazz == ELFCLASS32 \ + ? (off_t) (ph32.p_vaddr ? \ + elf_getu32(swap, ph32.p_vaddr) : 4) \ + : (off_t) (ph64.p_vaddr ? \ + elf_getu64(swap, ph64.p_vaddr) : 4))) #define xph_filesz (size_t)((clazz == ELFCLASS32 \ ? elf_getu32(swap, ph32.p_filesz) \ : elf_getu64(swap, ph64.p_filesz))) @@ -187,8 +192,8 @@ getu64(int swap, uint64_t value) ? elf_getu32(swap, ph32.p_memsz) \ : elf_getu64(swap, ph64.p_memsz))) #define xnh_sizeof (clazz == ELFCLASS32 \ - ? sizeof nh32 \ - : sizeof nh64) + ? sizeof(nh32) \ + : sizeof(nh64)) #define xnh_type (clazz == ELFCLASS32 \ ? elf_getu32(swap, nh32.n_type) \ : elf_getu32(swap, nh64.n_type)) @@ -213,6 +218,18 @@ getu64(int swap, uint64_t value) #define xcap_val (clazz == ELFCLASS32 \ ? elf_getu32(swap, cap32.c_un.c_val) \ : elf_getu64(swap, cap64.c_un.c_val)) +#define xauxv_addr (clazz == ELFCLASS32 \ + ? (void *)&auxv32 \ + : (void *)&auxv64) +#define xauxv_sizeof (clazz == ELFCLASS32 \ + ? sizeof(auxv32) \ + : sizeof(auxv64)) +#define xauxv_type (clazz == ELFCLASS32 \ + ? elf_getu32(swap, auxv32.a_type) \ + : elf_getu64(swap, auxv64.a_type)) +#define xauxv_val (clazz == ELFCLASS32 \ + ? elf_getu32(swap, auxv32.a_v) \ + : elf_getu64(swap, auxv64.a_v)) #ifdef ELFCORE /* @@ -302,6 +319,7 @@ private const char os_style_names[][8] = { #define FLAGS_DID_NETBSD_CMODEL 0x040 #define FLAGS_DID_NETBSD_UNKNOWN 0x080 #define FLAGS_IS_CORE 0x100 +#define FLAGS_DID_AUXV 0x200 private int dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, @@ -312,6 +330,8 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, size_t offset, len; unsigned char nbuf[BUFSIZ]; ssize_t bufsize; + off_t ph_off = off; + int ph_num = num; if (size != xph_sizeof) { if (file_printf(ms, ", corrupted program header size") == -1) @@ -351,7 +371,8 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, if (offset >= (size_t)bufsize) break; offset = donote(ms, nbuf, offset, (size_t)bufsize, - clazz, swap, 4, flags, notecount); + clazz, swap, 4, flags, notecount, fd, ph_off, + ph_num, fsize); if (offset == 0) break; @@ -813,9 +834,157 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, return 0; } +private off_t +get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd, + off_t off, int num, off_t fsize, uint64_t virtaddr) +{ + Elf32_Phdr ph32; + Elf64_Phdr ph64; + + /* + * Loop through all the program headers and find the header with + * virtual address in which the "virtaddr" belongs to. + */ + for ( ; num; num--) { + if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { + file_badread(ms); + return -1; + } + off += xph_sizeof; + + if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { + /* Perhaps warn here */ + continue; + } + + if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz) + return xph_offset + (virtaddr - xph_vaddr); + } + return 0; +} + +private size_t +get_string_on_virtaddr(struct magic_set *ms, + int swap, int clazz, int fd, off_t ph_off, int ph_num, + off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen) +{ + char *bptr; + off_t offset; + + if (buflen == 0) + return 0; + + offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num, + fsize, virtaddr); + if ((buflen = pread(fd, buf, buflen, offset)) <= 0) { + file_badread(ms); + return 0; + } + + buf[buflen - 1] = '\0'; + + /* We expect only printable characters, so return if buffer contains + * non-printable character before the '\0' or just '\0'. */ + for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++) + continue; + if (*bptr != '\0') + return 0; + + return bptr - buf; +} + + +private int +do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, + int swap, uint32_t namesz __attribute__((__unused__)), + uint32_t descsz __attribute__((__unused__)), + size_t noff __attribute__((__unused__)), size_t doff, + int *flags, size_t size __attribute__((__unused__)), int clazz, + int fd, off_t ph_off, int ph_num, off_t fsize) +{ +#ifdef ELFCORE + Aux32Info auxv32; + Aux64Info auxv64; + size_t elsize = xauxv_sizeof; + const char *tag; + int is_string; + size_t nval; + + if (type != NT_AUXV || (*flags & FLAGS_IS_CORE) == 0) + return 0; + + *flags |= FLAGS_DID_AUXV; + + nval = 0; + for (size_t off = 0; off + elsize <= descsz; off += elsize) { + (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof); + /* Limit processing to 50 vector entries to prevent DoS */ + if (nval++ >= 50) { + file_error(ms, 0, "Too many ELF Auxv elements"); + return 1; + } + + switch(xauxv_type) { + case AT_LINUX_EXECFN: + is_string = 1; + tag = "execfn"; + break; + case AT_LINUX_PLATFORM: + is_string = 1; + tag = "platform"; + break; + case AT_LINUX_UID: + is_string = 0; + tag = "real uid"; + break; + case AT_LINUX_GID: + is_string = 0; + tag = "real gid"; + break; + case AT_LINUX_EUID: + is_string = 0; + tag = "effective uid"; + break; + case AT_LINUX_EGID: + is_string = 0; + tag = "effective gid"; + break; + default: + is_string = 0; + tag = NULL; + break; + } + + if (tag == NULL) + continue; + + if (is_string) { + char buf[256]; + ssize_t buflen; + buflen = get_string_on_virtaddr(ms, swap, clazz, fd, + ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf)); + + if (buflen == 0) + continue; + + if (file_printf(ms, ", %s: '%s'", tag, buf) == -1) + return 0; + } else { + if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val) + == -1) + return 0; + } + } + return 1; +#else + return 0; +#endif +} + private size_t donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, - int clazz, int swap, size_t align, int *flags, uint16_t *notecount) + int clazz, int swap, size_t align, int *flags, uint16_t *notecount, + int fd, off_t ph_off, int ph_num, off_t fsize) { Elf32_Nhdr nh32; Elf64_Nhdr nh64; @@ -839,6 +1008,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, namesz = xnh_namesz; descsz = xnh_descsz; + if ((namesz == 0) && (descsz == 0)) { /* * We're out of note headers. @@ -876,28 +1046,36 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, return (offset >= size) ? offset : size; } + if ((*flags & FLAGS_DID_OS_NOTE) == 0) { if (do_os_note(ms, nbuf, xnh_type, swap, namesz, descsz, noff, doff, flags)) - return size; + return offset; } if ((*flags & FLAGS_DID_BUILD_ID) == 0) { if (do_bid_note(ms, nbuf, xnh_type, swap, namesz, descsz, noff, doff, flags)) - return size; + return offset; } if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { if (do_pax_note(ms, nbuf, xnh_type, swap, namesz, descsz, noff, doff, flags)) - return size; + return offset; } if ((*flags & FLAGS_DID_CORE) == 0) { if (do_core_note(ms, nbuf, xnh_type, swap, namesz, descsz, noff, doff, flags, size, clazz)) - return size; + return offset; + } + + if ((*flags & FLAGS_DID_AUXV) == 0) { + if (do_auxv_note(ms, nbuf, xnh_type, swap, + namesz, descsz, noff, doff, flags, size, clazz, + fd, ph_off, ph_num, fsize)) + return offset; } if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { @@ -905,32 +1083,32 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, descsz = 100; switch (xnh_type) { case NT_NETBSD_VERSION: - return size; + return offset; case NT_NETBSD_MARCH: if (*flags & FLAGS_DID_NETBSD_MARCH) - return size; + return offset; *flags |= FLAGS_DID_NETBSD_MARCH; if (file_printf(ms, ", compiled for: %.*s", (int)descsz, (const char *)&nbuf[doff]) == -1) - return size; + return offset; break; case NT_NETBSD_CMODEL: if (*flags & FLAGS_DID_NETBSD_CMODEL) - return size; + return offset; *flags |= FLAGS_DID_NETBSD_CMODEL; if (file_printf(ms, ", compiler model: %.*s", (int)descsz, (const char *)&nbuf[doff]) == -1) - return size; + return offset; break; default: if (*flags & FLAGS_DID_NETBSD_UNKNOWN) - return size; + return offset; *flags |= FLAGS_DID_NETBSD_UNKNOWN; if (file_printf(ms, ", note=%u", xnh_type) == -1) - return size; + return offset; break; } - return size; + return offset; } return offset; @@ -1080,7 +1258,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, if (noff >= (off_t)xsh_size) break; noff = donote(ms, nbuf, (size_t)noff, - xsh_size, clazz, swap, 4, flags, notecount); + xsh_size, clazz, swap, 4, flags, notecount, + fd, 0, 0, 0); if (noff == 0) break; } @@ -1329,7 +1508,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, break; offset = donote(ms, nbuf, offset, (size_t)bufsize, clazz, swap, align, - flags, notecount); + flags, notecount, fd, 0, 0, 0); if (offset == 0) break; } diff --git a/contrib/file/src/readelf.h b/contrib/file/src/readelf.h index 732b20c..f443b29 100644 --- a/contrib/file/src/readelf.h +++ b/contrib/file/src/readelf.h @@ -54,6 +54,42 @@ typedef uint8_t Elf64_Char; #define EI_NIDENT 16 typedef struct { + Elf32_Word a_type; /* 32-bit id */ + Elf32_Word a_v; /* 32-bit id */ +} Aux32Info; + +typedef struct { + Elf64_Xword a_type; /* 64-bit id */ + Elf64_Xword a_v; /* 64-bit id */ +} Aux64Info; + +#define AT_NULL 0 /* end of vector */ +#define AT_IGNORE 1 /* entry should be ignored */ +#define AT_EXECFD 2 /* file descriptor of program */ +#define AT_PHDR 3 /* program headers for program */ +#define AT_PHENT 4 /* size of program header entry */ +#define AT_PHNUM 5 /* number of program headers */ +#define AT_PAGESZ 6 /* system page size */ +#define AT_BASE 7 /* base address of interpreter */ +#define AT_FLAGS 8 /* flags */ +#define AT_ENTRY 9 /* entry point of program */ +#define AT_LINUX_NOTELF 10 /* program is not ELF */ +#define AT_LINUX_UID 11 /* real uid */ +#define AT_LINUX_EUID 12 /* effective uid */ +#define AT_LINUX_GID 13 /* real gid */ +#define AT_LINUX_EGID 14 /* effective gid */ +#define AT_LINUX_PLATFORM 15 /* string identifying CPU for optimizations */ +#define AT_LINUX_HWCAP 16 /* arch dependent hints at CPU capabilities */ +#define AT_LINUX_CLKTCK 17 /* frequency at which times() increments */ +/* AT_* values 18 through 22 are reserved */ +#define AT_LINUX_SECURE 23 /* secure mode boolean */ +#define AT_LINUX_BASE_PLATFORM 24 /* string identifying real platform, may + * differ from AT_PLATFORM. */ +#define AT_LINUX_RANDOM 25 /* address of 16 random bytes */ +#define AT_LINUX_HWCAP2 26 /* extension of AT_HWCAP */ +#define AT_LINUX_EXECFN 31 /* filename of program */ + +typedef struct { Elf32_Char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; diff --git a/contrib/file/src/softmagic.c b/contrib/file/src/softmagic.c index 84a8932..29533b5 100644 --- a/contrib/file/src/softmagic.c +++ b/contrib/file/src/softmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.218 2015/09/11 17:24:09 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.229 2016/03/21 23:04:40 christos Exp $") #endif /* lint */ #include "magic.h" @@ -41,26 +41,27 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.218 2015/09/11 17:24:09 christos Exp $") #include <ctype.h> #include <stdlib.h> #include <time.h> +#include "der.h" private int match(struct magic_set *, struct magic *, uint32_t, - const unsigned char *, size_t, size_t, int, int, int, uint16_t, + const unsigned char *, size_t, size_t, int, int, int, uint16_t *, uint16_t *, int *, int *, int *); private int mget(struct magic_set *, const unsigned char *, - struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t, + struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t *, uint16_t *, int *, int *, int *); private int magiccheck(struct magic_set *, struct magic *); private int32_t mprint(struct magic_set *, struct magic *); -private int32_t moffset(struct magic_set *, struct magic *); +private int moffset(struct magic_set *, struct magic *, size_t, int32_t *); private void mdebug(uint32_t, const char *, size_t); private int mcopy(struct magic_set *, union VALUETYPE *, int, int, const unsigned char *, uint32_t, size_t, struct magic *); private int mconvert(struct magic_set *, struct magic *, int); private int print_sep(struct magic_set *, int); private int handle_annotation(struct magic_set *, struct magic *); -private void cvt_8(union VALUETYPE *, const struct magic *); -private void cvt_16(union VALUETYPE *, const struct magic *); -private void cvt_32(union VALUETYPE *, const struct magic *); -private void cvt_64(union VALUETYPE *, const struct magic *); +private int cvt_8(union VALUETYPE *, const struct magic *); +private int cvt_16(union VALUETYPE *, const struct magic *); +private int cvt_32(union VALUETYPE *, const struct magic *); +private int cvt_64(union VALUETYPE *, const struct magic *); #define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o))) #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \ @@ -87,20 +88,24 @@ private void cvt_64(union VALUETYPE *, const struct magic *); /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ protected int file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, - uint16_t indir_level, uint16_t *name_count, int mode, int text) + uint16_t *indir_count, uint16_t *name_count, int mode, int text) { struct mlist *ml; int rv, printed_something = 0, need_separator = 0; - uint16_t nc; + uint16_t nc, ic; if (name_count == NULL) { nc = 0; name_count = &nc; } + if (indir_count == NULL) { + ic = 0; + indir_count = ⁣ + } for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode, - text, 0, indir_level, name_count, + text, 0, indir_count, name_count, &printed_something, &need_separator, NULL)) != 0) return rv; @@ -156,7 +161,7 @@ file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def, private int match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, const unsigned char *s, size_t nbytes, size_t offset, int mode, int text, - int flip, uint16_t indir_level, uint16_t *name_count, + int flip, uint16_t *indir_count, uint16_t *name_count, int *printed_something, int *need_separator, int *returnval) { uint32_t magindex = 0; @@ -194,7 +199,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, /* if main entry matches, print it... */ switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text, - flip, indir_level, name_count, + flip, indir_count, name_count, printed_something, need_separator, returnval)) { case -1: return -1; @@ -234,6 +239,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, *returnval = 1; return e; } + /* * If we are going to print something, we'll need to print * a blank before we print something else. @@ -249,7 +255,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (print && mprint(ms, m) == -1) return -1; - ms->c.li[cont_level].off = moffset(ms, m); + if (moffset(ms, m, nbytes, &ms->c.li[cont_level].off) == -1) + return -1; /* and any continuations that match */ if (file_check_mem(ms, ++cont_level) == -1) @@ -283,7 +290,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, } #endif switch (mget(ms, s, m, nbytes, offset, cont_level, mode, - text, flip, indir_level, name_count, + text, flip, indir_count, name_count, printed_something, need_separator, returnval)) { case -1: return -1; @@ -318,6 +325,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, break; } else ms->c.li[cont_level].got_match = 1; + if ((e = handle_annotation(ms, m)) != 0) { *need_separator = 1; *printed_something = 1; @@ -354,7 +362,9 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (print && mprint(ms, m) == -1) return -1; - ms->c.li[cont_level].off = moffset(ms, m); + if (moffset(ms, m, nbytes, + &ms->c.li[cont_level].off) == -1) + return -1; if (*m->desc) *need_separator = 1; @@ -682,7 +692,12 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_NAME: t = ms->offset; break; - + case FILE_DER: + if (file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1) + return -1; + t = ms->offset; + break; default: file_magerror(ms, "invalid m->type (%d) in mprint()", m->type); return -1; @@ -690,100 +705,144 @@ mprint(struct magic_set *ms, struct magic *m) return (int32_t)t; } -private int32_t -moffset(struct magic_set *ms, struct magic *m) +private int +moffset(struct magic_set *ms, struct magic *m, size_t nbytes, int32_t *op) { + int32_t o; + switch (m->type) { case FILE_BYTE: - return CAST(int32_t, (ms->offset + sizeof(char))); + o = CAST(int32_t, (ms->offset + sizeof(char))); + break; case FILE_SHORT: case FILE_BESHORT: case FILE_LESHORT: - return CAST(int32_t, (ms->offset + sizeof(short))); + o = CAST(int32_t, (ms->offset + sizeof(short))); + break; case FILE_LONG: case FILE_BELONG: case FILE_LELONG: case FILE_MELONG: - return CAST(int32_t, (ms->offset + sizeof(int32_t))); + o = CAST(int32_t, (ms->offset + sizeof(int32_t))); + break; case FILE_QUAD: case FILE_BEQUAD: case FILE_LEQUAD: - return CAST(int32_t, (ms->offset + sizeof(int64_t))); + o = CAST(int32_t, (ms->offset + sizeof(int64_t))); + break; case FILE_STRING: case FILE_PSTRING: case FILE_BESTRING16: case FILE_LESTRING16: - if (m->reln == '=' || m->reln == '!') - return ms->offset + m->vallen; - else { + if (m->reln == '=' || m->reln == '!') { + o = ms->offset + m->vallen; + } else { union VALUETYPE *p = &ms->ms_value; - uint32_t t; if (*m->value.s == '\0') p->s[strcspn(p->s, "\r\n")] = '\0'; - t = CAST(uint32_t, (ms->offset + strlen(p->s))); + o = CAST(uint32_t, (ms->offset + strlen(p->s))); if (m->type == FILE_PSTRING) - t += (uint32_t)file_pstring_length_size(m); - return t; + o += (uint32_t)file_pstring_length_size(m); } + break; case FILE_DATE: case FILE_BEDATE: case FILE_LEDATE: case FILE_MEDATE: - return CAST(int32_t, (ms->offset + sizeof(uint32_t))); + o = CAST(int32_t, (ms->offset + sizeof(uint32_t))); + break; case FILE_LDATE: case FILE_BELDATE: case FILE_LELDATE: case FILE_MELDATE: - return CAST(int32_t, (ms->offset + sizeof(uint32_t))); + o = CAST(int32_t, (ms->offset + sizeof(uint32_t))); + break; case FILE_QDATE: case FILE_BEQDATE: case FILE_LEQDATE: - return CAST(int32_t, (ms->offset + sizeof(uint64_t))); + o = CAST(int32_t, (ms->offset + sizeof(uint64_t))); + break; case FILE_QLDATE: case FILE_BEQLDATE: case FILE_LEQLDATE: - return CAST(int32_t, (ms->offset + sizeof(uint64_t))); + o = CAST(int32_t, (ms->offset + sizeof(uint64_t))); + break; case FILE_FLOAT: case FILE_BEFLOAT: case FILE_LEFLOAT: - return CAST(int32_t, (ms->offset + sizeof(float))); + o = CAST(int32_t, (ms->offset + sizeof(float))); + break; case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: - return CAST(int32_t, (ms->offset + sizeof(double))); + o = CAST(int32_t, (ms->offset + sizeof(double))); + break; case FILE_REGEX: if ((m->str_flags & REGEX_OFFSET_START) != 0) - return CAST(int32_t, ms->search.offset); + o = CAST(int32_t, ms->search.offset); else - return CAST(int32_t, (ms->search.offset + - ms->search.rm_len)); + o = CAST(int32_t, + (ms->search.offset + ms->search.rm_len)); + break; case FILE_SEARCH: if ((m->str_flags & REGEX_OFFSET_START) != 0) - return CAST(int32_t, ms->search.offset); + o = CAST(int32_t, ms->search.offset); else - return CAST(int32_t, (ms->search.offset + m->vallen)); + o = CAST(int32_t, (ms->search.offset + m->vallen)); + break; case FILE_CLEAR: case FILE_DEFAULT: case FILE_INDIRECT: - return ms->offset; + o = ms->offset; + break; + + case FILE_DER: + { + o = der_offs(ms, m, nbytes); + if (o == -1) { + file_error(ms, 0, "EOF computing DER offset"); + return -1; + } + break; + } default: - return 0; + o = 0; + break; + } + + if ((size_t)o >= nbytes) { + file_error(ms, 0, "Offset out of range"); + return -1; } + *op = o; + return 0; +} + +private uint32_t +cvt_id3(struct magic_set *ms, uint32_t v) +{ + v = ((((v >> 0) & 0x7f) << 0) | + (((v >> 8) & 0x7f) << 7) | + (((v >> 16) & 0x7f) << 14) | + (((v >> 24) & 0x7f) << 21)); + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "id3 offs=%u\n", v); + return v; } private int @@ -858,37 +917,45 @@ cvt_flip(int type, int flip) p->fld *= cast m->num_mask; \ break; \ case FILE_OPDIVIDE: \ + if (cast m->num_mask == 0) \ + return -1; \ p->fld /= cast m->num_mask; \ break; \ case FILE_OPMODULO: \ + if (cast m->num_mask == 0) \ + return -1; \ p->fld %= cast m->num_mask; \ break; \ } \ if (m->mask_op & FILE_OPINVERSE) \ p->fld = ~p->fld \ -private void +private int cvt_8(union VALUETYPE *p, const struct magic *m) { DO_CVT(b, (uint8_t)); + return 0; } -private void +private int cvt_16(union VALUETYPE *p, const struct magic *m) { DO_CVT(h, (uint16_t)); + return 0; } -private void +private int cvt_32(union VALUETYPE *p, const struct magic *m) { DO_CVT(l, (uint32_t)); + return 0; } -private void +private int cvt_64(union VALUETYPE *p, const struct magic *m) { DO_CVT(q, (uint64_t)); + return 0; } #define DO_CVT2(fld, cast) \ @@ -904,20 +971,24 @@ cvt_64(union VALUETYPE *p, const struct magic *m) p->fld *= cast m->num_mask; \ break; \ case FILE_OPDIVIDE: \ + if (cast m->num_mask == 0) \ + return -1; \ p->fld /= cast m->num_mask; \ break; \ } \ -private void +private int cvt_float(union VALUETYPE *p, const struct magic *m) { DO_CVT2(f, (float)); + return 0; } -private void +private int cvt_double(union VALUETYPE *p, const struct magic *m) { DO_CVT2(d, (double)); + return 0; } /* @@ -933,21 +1004,25 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) switch (type = cvt_flip(m->type, flip)) { case FILE_BYTE: - cvt_8(p, m); + if (cvt_8(p, m) == -1) + goto out; return 1; case FILE_SHORT: - cvt_16(p, m); + if (cvt_16(p, m) == -1) + goto out; return 1; case FILE_LONG: case FILE_DATE: case FILE_LDATE: - cvt_32(p, m); + if (cvt_32(p, m) == -1) + goto out; return 1; case FILE_QUAD: case FILE_QDATE: case FILE_QLDATE: case FILE_QWDATE: - cvt_64(p, m); + if (cvt_64(p, m) == -1) + goto out; return 1; case FILE_STRING: case FILE_BESTRING16: @@ -979,65 +1054,78 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) } case FILE_BESHORT: p->h = (short)BE16(p); - cvt_16(p, m); + if (cvt_16(p, m) == -1) + goto out; return 1; case FILE_BELONG: case FILE_BEDATE: case FILE_BELDATE: p->l = (int32_t)BE32(p); - cvt_32(p, m); + if (cvt_32(p, m) == -1) + goto out; return 1; case FILE_BEQUAD: case FILE_BEQDATE: case FILE_BEQLDATE: case FILE_BEQWDATE: p->q = (uint64_t)BE64(p); - cvt_64(p, m); + if (cvt_64(p, m) == -1) + goto out; return 1; case FILE_LESHORT: p->h = (short)LE16(p); - cvt_16(p, m); + if (cvt_16(p, m) == -1) + goto out; return 1; case FILE_LELONG: case FILE_LEDATE: case FILE_LELDATE: p->l = (int32_t)LE32(p); - cvt_32(p, m); + if (cvt_32(p, m) == -1) + goto out; return 1; case FILE_LEQUAD: case FILE_LEQDATE: case FILE_LEQLDATE: case FILE_LEQWDATE: p->q = (uint64_t)LE64(p); - cvt_64(p, m); + if (cvt_64(p, m) == -1) + goto out; return 1; case FILE_MELONG: case FILE_MEDATE: case FILE_MELDATE: p->l = (int32_t)ME32(p); - cvt_32(p, m); + if (cvt_32(p, m) == -1) + goto out; return 1; case FILE_FLOAT: - cvt_float(p, m); + if (cvt_float(p, m) == -1) + goto out; return 1; case FILE_BEFLOAT: p->l = BE32(p); - cvt_float(p, m); + if (cvt_float(p, m) == -1) + goto out; return 1; case FILE_LEFLOAT: p->l = LE32(p); - cvt_float(p, m); + if (cvt_float(p, m) == -1) + goto out; return 1; case FILE_DOUBLE: - cvt_double(p, m); + if (cvt_double(p, m) == -1) + goto out; return 1; case FILE_BEDOUBLE: p->q = BE64(p); - cvt_double(p, m); + if (cvt_double(p, m) == -1) + goto out; return 1; case FILE_LEDOUBLE: p->q = LE64(p); - cvt_double(p, m); + if (cvt_double(p, m) == -1) + goto out; return 1; case FILE_REGEX: case FILE_SEARCH: @@ -1045,11 +1133,15 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_CLEAR: case FILE_NAME: case FILE_USE: + case FILE_DER: return 1; default: file_magerror(ms, "invalid type %d in mconvert()", m->type); return 0; } +out: + file_magerror(ms, "zerodivide in mconvert()"); + return 0; } @@ -1072,6 +1164,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, */ if (indir == 0) { switch (type) { + case FILE_DER: case FILE_SEARCH: ms->search.s = RCAST(const char *, s) + offset; ms->search.s_len = nbytes - offset; @@ -1186,7 +1279,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, private int mget(struct magic_set *ms, const unsigned char *s, struct magic *m, size_t nbytes, size_t o, unsigned int cont_level, int mode, int text, - int flip, uint16_t indir_level, uint16_t *name_count, + int flip, uint16_t *indir_count, uint16_t *name_count, int *printed_something, int *need_separator, int *returnval) { uint32_t offset = ms->offset; @@ -1197,9 +1290,9 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, union VALUETYPE *p = &ms->ms_value; struct mlist ml; - if (indir_level >= ms->indir_max) { - file_error(ms, 0, "indirect recursion nesting (%hu) exceeded", - indir_level); + if (*indir_count >= ms->indir_max) { + file_error(ms, 0, "indirect count (%hu) exceeded", + *indir_count); return -1; } @@ -1218,7 +1311,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT "u, il=%hu, nc=%hu)\n", m->type, m->flag, offset, o, nbytes, - indir_level, *name_count); + *indir_count, *name_count); mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE)); #ifndef COMPILE_ONLY file_mdump(m); @@ -1230,6 +1323,8 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (m->in_op & FILE_OPINDIRECT) { const union VALUETYPE *q = CAST(const union VALUETYPE *, ((const void *)(s + offset + off))); + if (OFFSET_OOB(nbytes, offset + off, sizeof(*q))) + return 0; switch (cvt_flip(m->in_type, flip)) { case FILE_BYTE: off = q->b; @@ -1410,6 +1505,8 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (OFFSET_OOB(nbytes, offset, 4)) return 0; lhs = BE32(p); + if (in_type == FILE_BEID3) + lhs = cvt_id3(ms, lhs); if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: @@ -1447,6 +1544,8 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (OFFSET_OOB(nbytes, offset, 4)) return 0; lhs = LE32(p); + if (in_type == FILE_LEID3) + lhs = cvt_id3(ms, lhs); if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: @@ -1554,20 +1653,6 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, break; } - switch (in_type) { - case FILE_LEID3: - case FILE_BEID3: - offset = ((((offset >> 0) & 0x7f) << 0) | - (((offset >> 8) & 0x7f) << 7) | - (((offset >> 16) & 0x7f) << 14) | - (((offset >> 24) & 0x7f) << 21)); - if ((ms->flags & MAGIC_DEBUG) != 0) - fprintf(stderr, "id3 offs=%u\n", offset); - break; - default: - break; - } - if (m->flag & INDIROFFADD) { offset += ms->c.li[cont_level-1].off; if (offset == 0) { @@ -1656,8 +1741,9 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if ((pb = file_push_buffer(ms)) == NULL) return -1; + (*indir_count)++; rv = file_softmagic(ms, s + offset, nbytes - offset, - indir_level + 1, name_count, BINTEST, text); + indir_count, name_count, BINTEST, text); if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); @@ -1697,7 +1783,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (m->flag & NOSPACE) *need_separator = 0; rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o, - mode, text, flip, indir_level, name_count, + mode, text, flip, indir_count, name_count, printed_something, need_separator, returnval); if (rv != 1) *need_separator = oneed_separator; @@ -1709,6 +1795,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (file_printf(ms, "%s", m->desc) == -1) return -1; return 1; + case FILE_DER: case FILE_DEFAULT: /* nothing to check */ case FILE_CLEAR: default: @@ -1969,10 +2056,8 @@ magiccheck(struct magic_set *ms, struct magic *m) file_regerror(&rx, rc, ms); v = (uint64_t)-1; } else { - regmatch_t pmatch[1]; + regmatch_t pmatch; size_t slen = ms->search.s_len; -#ifndef REG_STARTEND -#define REG_STARTEND 0 char *copy; if (slen != 0) { copy = malloc(slen); @@ -1989,22 +2074,15 @@ magiccheck(struct magic_set *ms, struct magic *m) search = ms->search.s; copy = NULL; } -#else - search = ms->search.s; - pmatch[0].rm_so = 0; - pmatch[0].rm_eo = slen; -#endif rc = file_regexec(&rx, (const char *)search, - 1, pmatch, REG_STARTEND); -#if REG_STARTEND == 0 + 1, &pmatch, 0); free(copy); -#endif switch (rc) { case 0: - ms->search.s += (int)pmatch[0].rm_so; - ms->search.offset += (size_t)pmatch[0].rm_so; + ms->search.s += (int)pmatch.rm_so; + ms->search.offset += (size_t)pmatch.rm_so; ms->search.rm_len = - (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so); + (size_t)(pmatch.rm_eo - pmatch.rm_so); v = 0; break; @@ -2027,6 +2105,11 @@ magiccheck(struct magic_set *ms, struct magic *m) case FILE_USE: case FILE_NAME: return 1; + case FILE_DER: + matched = der_cmp(ms, m); + if (matched == -1) + file_error(ms, 0, "EOF comparing DER entries"); + return matched; default: file_magerror(ms, "invalid type %d in magiccheck()", m->type); return -1; @@ -2126,12 +2209,12 @@ magiccheck(struct magic_set *ms, struct magic *m) private int handle_annotation(struct magic_set *ms, struct magic *m) { - if (ms->flags & MAGIC_APPLE) { + if ((ms->flags & MAGIC_APPLE) && m->apple[0]) { if (file_printf(ms, "%.8s", m->apple) == -1) return -1; return 1; } - if (ms->flags & MAGIC_EXTENSION) { + if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) { if (file_printf(ms, "%s", m->ext) == -1) return -1; return 1; |