diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/Makefile.in | 96 | ||||
-rw-r--r-- | src/apprentice.c | 154 | ||||
-rw-r--r-- | src/ascmagic.c | 29 | ||||
-rw-r--r-- | src/buffer.c | 84 | ||||
-rw-r--r-- | src/cdf.c | 23 | ||||
-rw-r--r-- | src/compress.c | 8 | ||||
-rw-r--r-- | src/encoding.c | 16 | ||||
-rw-r--r-- | src/file.c | 174 | ||||
-rw-r--r-- | src/file.h | 66 | ||||
-rw-r--r-- | src/file_opts.h | 3 | ||||
-rw-r--r-- | src/funcs.c | 27 | ||||
-rw-r--r-- | src/is_tar.c | 12 | ||||
-rw-r--r-- | src/readcdf.c | 8 | ||||
-rw-r--r-- | src/readelf.c | 44 | ||||
-rw-r--r-- | src/seccomp.c | 246 | ||||
-rw-r--r-- | src/softmagic.c | 273 |
17 files changed, 936 insertions, 331 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 155aec44ee67..bbd3f5016d5c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ bin_PROGRAMS = file AM_CPPFLAGS = -DMAGIC='"$(MAGIC)"' AM_CFLAGS = $(CFLAG_VISIBILITY) @WARNINGS@ -libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \ +libmagic_la_SOURCES = buffer.c 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 der.c der.h \ file_opts.h elfclass.h mygetopt.h cdf.c cdf_time.c readcdf.c cdf.h @@ -19,7 +19,7 @@ MINGWLIBS = endif libmagic_la_LIBADD = $(LTLIBOBJS) $(MINGWLIBS) -file_SOURCES = file.c +file_SOURCES = file.c seccomp.c file_LDADD = libmagic.la CLEANFILES = magic.h EXTRA_DIST = magic.h.in diff --git a/src/Makefile.in b/src/Makefile.in index b6eeb20096bc..c096c71ea477 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. +# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2014 Free Software Foundation, Inc. +# Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -17,61 +17,23 @@ VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ +am__make_dryrun = \ + { \ + am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) + test $$am__dry = yes; \ + } pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ @@ -91,6 +53,10 @@ build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = file$(EXEEXT) subdir = src +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am asprintf.c \ + getopt_long.c localtime_r.c ctime_r.c getline.c pread.c \ + strcasestr.c dprintf.c fmtcheck.c strlcpy.c asctime_r.c \ + gmtime_r.c strlcat.c vasprintf.c $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ @@ -98,7 +64,6 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -135,7 +100,7 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libmagic_la_DEPENDENCIES = $(LTLIBOBJS) $(am__DEPENDENCIES_1) -am_libmagic_la_OBJECTS = magic.lo apprentice.lo softmagic.lo \ +am_libmagic_la_OBJECTS = buffer.lo 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 der.lo cdf.lo \ cdf_time.lo readcdf.lo @@ -148,7 +113,7 @@ libmagic_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libmagic_la_LDFLAGS) $(LDFLAGS) -o $@ PROGRAMS = $(bin_PROGRAMS) -am_file_OBJECTS = file.$(OBJEXT) +am_file_OBJECTS = file.$(OBJEXT) seccomp.$(OBJEXT) file_OBJECTS = $(am_file_OBJECTS) file_DEPENDENCIES = libmagic.la AM_V_P = $(am__v_P_@AM_V@) @@ -212,10 +177,6 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ - 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@ @@ -229,7 +190,6 @@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ -CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ @@ -245,7 +205,6 @@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ -HAVE_VISIBILITY = @HAVE_VISIBILITY@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -342,7 +301,7 @@ lib_LTLIBRARIES = libmagic.la nodist_include_HEADERS = magic.h AM_CPPFLAGS = -DMAGIC='"$(MAGIC)"' AM_CFLAGS = $(CFLAG_VISIBILITY) @WARNINGS@ -libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \ +libmagic_la_SOURCES = buffer.c 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 der.c der.h \ file_opts.h elfclass.h mygetopt.h cdf.c cdf_time.c readcdf.c cdf.h @@ -351,7 +310,7 @@ libmagic_la_LDFLAGS = -no-undefined -version-info 1:0:0 @MINGW_FALSE@MINGWLIBS = @MINGW_TRUE@MINGWLIBS = -lgnurx -lshlwapi libmagic_la_LIBADD = $(LTLIBOBJS) $(MINGWLIBS) -file_SOURCES = file.c +file_SOURCES = file.c seccomp.c file_LDADD = libmagic.la CLEANFILES = magic.h EXTRA_DIST = magic.h.in @@ -374,6 +333,7 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -426,7 +386,6 @@ clean-libLTLIBRARIES: echo rm -f $${locs}; \ rm -f $${locs}; \ } - libmagic.la: $(libmagic_la_OBJECTS) $(libmagic_la_DEPENDENCIES) $(EXTRA_libmagic_la_DEPENDENCIES) $(AM_V_CCLD)$(libmagic_la_LINK) -rpath $(libdir) $(libmagic_la_OBJECTS) $(libmagic_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @@ -478,7 +437,6 @@ clean-binPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list - file$(EXEEXT): $(file_OBJECTS) $(file_DEPENDENCIES) $(EXTRA_file_DEPENDENCIES) @rm -f file$(EXEEXT) $(AM_V_CCLD)$(LINK) $(file_OBJECTS) $(file_LDADD) $(LIBS) @@ -506,6 +464,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apprentice.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apptype.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ascmagic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ @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@ @@ -519,6 +478,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readcdf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readelf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seccomp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/softmagic.Plo@am__quote@ .c.o: @@ -788,8 +748,6 @@ uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-libLTLIBRARIES uninstall-nodist_includeHEADERS -.PRECIOUS: Makefile - magic.h: ${HDR} sed -e "s/X.YY/$$(echo @VERSION@ | tr -d .)/" < ${HDR} > $@ diff --git a/src/apprentice.c b/src/apprentice.c index a7b4dd8f9115..e2ce2d3ad2ff 100644 --- a/src/apprentice.c +++ b/src/apprentice.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: apprentice.c,v 1.262 2017/08/28 13:39:18 christos Exp $") +FILE_RCSID("@(#)$File: apprentice.c,v 1.270 2018/02/21 21:26:48 christos Exp $") #endif /* lint */ #include "magic.h" @@ -652,7 +652,7 @@ protected int file_apprentice(struct magic_set *ms, const char *fn, int action) { char *p, *mfn; - int file_err, errs = -1; + int fileerr, errs = -1; size_t i; (void)file_reset(ms, 0); @@ -687,8 +687,8 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) *p++ = '\0'; if (*fn == '\0') break; - file_err = apprentice_1(ms, fn, action); - errs = MAX(errs, file_err); + fileerr = apprentice_1(ms, fn, action); + errs = MAX(errs, fileerr); fn = p; } @@ -1910,12 +1910,23 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, } /* get offset, then skip over it */ - m->offset = (uint32_t)strtoul(l, &t, 0); + m->offset = (int32_t)strtol(l, &t, 0); if (l == t) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "offset `%s' invalid", l); return -1; } +#if 0 + if (m->offset < 0 && cont_level != 0 && + (m->flag & (OFFADD | INDIROFFADD)) == 0) { + if (ms->flags & MAGIC_CHECK) { + file_magwarn(ms, + "negative direct offset `%s' at level %u", + l, cont_level); + } + return -1; + } +#endif l = t; if (m->flag & INDIR) { @@ -2337,7 +2348,7 @@ parse_ext(struct magic_set *ms, struct magic_entry *me, const char *line) return parse_extra(ms, me, line, CAST(off_t, offsetof(struct magic, ext)), - sizeof(m->ext), "EXTENSION", ",!+-/@", 0); + sizeof(m->ext), "EXTENSION", ",!+-/@?_$", 0); } /* @@ -2351,7 +2362,7 @@ parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line) return parse_extra(ms, me, line, CAST(off_t, offsetof(struct magic, mimetype)), - sizeof(m->mimetype), "MIME", "+-/.", 1); + sizeof(m->mimetype), "MIME", "+-/.$?:{}", 1); } private int @@ -2608,6 +2619,9 @@ check_format(struct magic_set *ms, struct magic *m) private int getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) { + char *ep; + uint64_t ull; + switch (m->type) { case FILE_BESTRING16: case FILE_LESTRING16: @@ -2636,79 +2650,78 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) return rc ? -1 : 0; } return 0; + default: + if (m->reln == 'x') + return 0; + break; + } + + switch (m->type) { case FILE_FLOAT: case FILE_BEFLOAT: case FILE_LEFLOAT: - if (m->reln != 'x') { - char *ep; - errno = 0; + errno = 0; #ifdef HAVE_STRTOF - m->value.f = strtof(*p, &ep); + m->value.f = strtof(*p, &ep); #else - m->value.f = (float)strtod(*p, &ep); + m->value.f = (float)strtod(*p, &ep); #endif - if (errno == 0) - *p = ep; - } + if (errno == 0) + *p = ep; return 0; case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: - if (m->reln != 'x') { - char *ep; - errno = 0; - m->value.d = strtod(*p, &ep); - if (errno == 0) - *p = ep; - } + errno = 0; + m->value.d = strtod(*p, &ep); + if (errno == 0) + *p = ep; return 0; default: - if (m->reln != 'x') { - char *ep; - uint64_t ull; - errno = 0; - ull = (uint64_t)strtoull(*p, &ep, 0); - m->value.q = file_signextend(ms, m, ull); - if (*p == ep) { - file_magwarn(ms, "Unparseable number `%s'", *p); - } else { - size_t ts = typesize(m->type); - uint64_t x; - const char *q; - - if (ts == (size_t)~0) { - file_magwarn(ms, "Expected numeric type got `%s'", - type_tbl[m->type].name); - } - for (q = *p; isspace((unsigned char)*q); q++) - continue; - if (*q == '-') - ull = -(int64_t)ull; - switch (ts) { - case 1: - x = ull & ~0xffULL; - break; - case 2: - x = ull & ~0xffffULL; - break; - case 4: - x = ull & ~0xffffffffULL; - break; - case 8: - x = 0; - break; - default: - abort(); - } - if (x) { - file_magwarn(ms, "Overflow for numeric type `%s' value %#" PRIx64, - type_tbl[m->type].name, ull); - } + errno = 0; + ull = (uint64_t)strtoull(*p, &ep, 0); + m->value.q = file_signextend(ms, m, ull); + if (*p == ep) { + file_magwarn(ms, "Unparseable number `%s'", *p); + } else { + size_t ts = typesize(m->type); + uint64_t x; + const char *q; + + if (ts == (size_t)~0) { + file_magwarn(ms, + "Expected numeric type got `%s'", + type_tbl[m->type].name); } - if (errno == 0) { - *p = ep; - eatsize(p); + for (q = *p; isspace((unsigned char)*q); q++) + continue; + if (*q == '-') + ull = -(int64_t)ull; + switch (ts) { + case 1: + x = (uint64_t)(ull & ~0xffULL); + break; + case 2: + x = (uint64_t)(ull & ~0xffffULL); + break; + case 4: + x = (uint64_t)(ull & ~0xffffffffULL); + break; + case 8: + x = 0; + break; + default: + abort(); } + if (x) { + file_magwarn(ms, "Overflow for numeric" + " type `%s' value %#" PRIx64, + type_tbl[m->type].name, ull); + } + } + if (errno == 0) { + *p = ep; + eatsize(p); } return 0; } @@ -3175,20 +3188,21 @@ apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) if (write(fd, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) { file_error(ms, errno, "error writing `%s'", dbname); - goto out; + goto out2; } for (i = 0; i < MAGIC_SETS; i++) { len = m * map->nmagic[i]; if (write(fd, map->magic[i], len) != (ssize_t)len) { file_error(ms, errno, "error writing `%s'", dbname); - goto out; + goto out2; } } + rv = 0; +out2: if (fd != -1) (void)close(fd); - rv = 0; out: apprentice_unmap(map); free(dbname); @@ -3321,7 +3335,7 @@ private void bs1(struct magic *m) { m->cont_level = swap2(m->cont_level); - m->offset = swap4((uint32_t)m->offset); + m->offset = swap4((int32_t)m->offset); m->in_offset = swap4((uint32_t)m->in_offset); m->lineno = swap4((uint32_t)m->lineno); if (IS_STRING(m->type)) { diff --git a/src/ascmagic.c b/src/ascmagic.c index 85a973e4fe2e..2d1abe543e60 100644 --- a/src/ascmagic.c +++ b/src/ascmagic.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: ascmagic.c,v 1.97 2016/06/27 20:56:25 christos Exp $") +FILE_RCSID("@(#)$File: ascmagic.c,v 1.98 2017/11/02 20:25:39 christos Exp $") #endif /* lint */ #include "magic.h" @@ -68,26 +68,27 @@ trim_nuls(const unsigned char *buf, size_t nbytes) } protected int -file_ascmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, - int text) +file_ascmagic(struct magic_set *ms, const struct buffer *b, int text) { unichar *ubuf = NULL; size_t ulen = 0; int rv = 1; + struct buffer bb; const char *code = NULL; const char *code_mime = NULL; const char *type = NULL; - nbytes = trim_nuls(buf, nbytes); + bb = *b; + bb.flen = trim_nuls(b->fbuf, b->flen); /* If file doesn't look like any sort of text, give up. */ - if (file_encoding(ms, buf, nbytes, &ubuf, &ulen, &code, &code_mime, + if (file_encoding(ms, &bb, &ubuf, &ulen, &code, &code_mime, &type) == 0) rv = 0; else - rv = file_ascmagic_with_encoding(ms, buf, nbytes, ubuf, ulen, code, - type, text); + rv = file_ascmagic_with_encoding(ms, &bb, + ubuf, ulen, code, type, text); free(ubuf); @@ -95,10 +96,13 @@ file_ascmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, } protected int -file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf, - size_t nbytes, unichar *ubuf, size_t ulen, const char *code, +file_ascmagic_with_encoding(struct magic_set *ms, + const struct buffer *b, unichar *ubuf, size_t ulen, const char *code, const char *type, int text) { + struct buffer bb; + const unsigned char *buf = b->fbuf; + size_t nbytes = b->flen; unsigned char *utf8_buf = NULL, *utf8_end; size_t mlen, i; int rv = -1; @@ -140,10 +144,13 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf, if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen)) == NULL) goto done; - if ((rv = file_softmagic(ms, utf8_buf, - (size_t)(utf8_end - utf8_buf), NULL, NULL, + buffer_init(&bb, b->fd, utf8_buf, + (size_t)(utf8_end - utf8_buf)); + + if ((rv = file_softmagic(ms, &bb, NULL, NULL, TEXTTEST, text)) == 0) rv = -1; + buffer_fini(&bb); if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))) { rv = rv == -1 ? 0 : 1; goto done; diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 000000000000..5f76b80d282c --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) Christos Zoulas 2017. + * 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 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: buffer.c,v 1.4 2018/02/21 21:26:00 christos Exp $") +#endif /* lint */ + +#include "magic.h" +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> + +void +buffer_init(struct buffer *b, int fd, const void *data, size_t len) +{ + b->fd = fd; + if (b->fd == -1 || fstat(b->fd, &b->st) == -1) + memset(&b->st, 0, sizeof(b->st)); + b->fbuf = data; + b->flen = len; + b->eoff = 0; + b->ebuf = NULL; + b->elen = 0; +} + +void +buffer_fini(struct buffer *b) +{ + free(b->ebuf); +} + +int +buffer_fill(const struct buffer *bb) +{ + struct buffer *b = CCAST(struct buffer *, bb); + + if (b->elen != 0) + return b->elen == (size_t)~0 ? -1 : 0; + + if (!S_ISREG(b->st.st_mode)) + goto out; + + b->elen = (size_t)b->st.st_size < b->flen ? + (size_t)b->st.st_size : b->flen; + if ((b->ebuf = malloc(b->elen)) == NULL) + goto out; + + b->eoff = b->st.st_size - b->elen; + if (pread(b->fd, b->ebuf, b->elen, b->eoff) == -1) { + free(b->ebuf); + goto out; + } + + return 0; +out: + b->elen = (size_t)~0; + return -1; +} diff --git a/src/cdf.c b/src/cdf.c index accfb325b999..aad68cd0a33c 100644 --- a/src/cdf.c +++ b/src/cdf.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: cdf.c,v 1.106 2017/04/30 17:05:02 christos Exp $") +FILE_RCSID("@(#)$File: cdf.c,v 1.110 2017/12/19 00:21:21 christos Exp $") #endif #include <assert.h> @@ -85,6 +85,7 @@ static union { #define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u)) +/*ARGSUSED*/ static void * cdf_malloc(const char *file __attribute__((__unused__)), size_t line __attribute__((__unused__)), size_t n) @@ -93,6 +94,7 @@ cdf_malloc(const char *file __attribute__((__unused__)), return malloc(n); } +/*ARGSUSED*/ static void * cdf_realloc(const char *file __attribute__((__unused__)), size_t line __attribute__((__unused__)), void *p, size_t n) @@ -101,6 +103,7 @@ cdf_realloc(const char *file __attribute__((__unused__)), return realloc(p, n); } +/*ARGSUSED*/ static void * cdf_calloc(const char *file __attribute__((__unused__)), size_t line __attribute__((__unused__)), size_t n, size_t u) @@ -436,7 +439,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat) if (h->h_master_sat[i] == CDF_SECID_FREE) break; -#define CDF_SEC_LIMIT (UINT32_MAX / (8 * ss)) +#define CDF_SEC_LIMIT (UINT32_MAX / (64 * ss)) if ((nsatpersec > 0 && h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec) || i > CDF_SEC_LIMIT) { @@ -846,8 +849,8 @@ cdf_find_stream(const cdf_dir_t *dir, const char *name, int type) return 0; } -#define CDF_SHLEN_LIMIT (UINT32_MAX / 8) -#define CDF_PROP_LIMIT (UINT32_MAX / (8 * sizeof(cdf_property_info_t))) +#define CDF_SHLEN_LIMIT (UINT32_MAX / 64) +#define CDF_PROP_LIMIT (UINT32_MAX / (64 * sizeof(cdf_property_info_t))) static const void * cdf_offset(const void *p, size_t l) @@ -1570,32 +1573,32 @@ main(int argc, char *argv[]) info.i_len = 0; for (i = 1; i < argc; i++) { if ((info.i_fd = open(argv[1], O_RDONLY)) == -1) - err(1, "Cannot open `%s'", argv[1]); + err(EXIT_FAILURE, "Cannot open `%s'", argv[1]); if (cdf_read_header(&info, &h) == -1) - err(1, "Cannot read header"); + err(EXIT_FAILURE, "Cannot read header"); #ifdef CDF_DEBUG cdf_dump_header(&h); #endif if (cdf_read_sat(&info, &h, &sat) == -1) - err(1, "Cannot read sat"); + err(EXIT_FAILURE, "Cannot read sat"); #ifdef CDF_DEBUG cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); #endif if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1) - err(1, "Cannot read ssat"); + err(EXIT_FAILURE, "Cannot read ssat"); #ifdef CDF_DEBUG cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); #endif if (cdf_read_dir(&info, &h, &sat, &dir) == -1) - err(1, "Cannot read dir"); + err(EXIT_FAILURE, "Cannot read dir"); if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root) == -1) - err(1, "Cannot read short stream"); + err(EXIT_FAILURE, "Cannot read short stream"); #ifdef CDF_DEBUG cdf_dump_stream(&sst); #endif diff --git a/src/compress.c b/src/compress.c index 2f789cd2bc44..184011b92307 100644 --- a/src/compress.c +++ b/src/compress.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: compress.c,v 1.105 2017/05/25 00:13:03 christos Exp $") +FILE_RCSID("@(#)$File: compress.c,v 1.106 2017/11/02 20:25:39 christos Exp $") #endif #include "magic.h" @@ -184,8 +184,7 @@ static int makeerror(unsigned char **, size_t *, const char *, ...) private const char *methodname(size_t); protected int -file_zmagic(struct magic_set *ms, int fd, const char *name, - const unsigned char *buf, size_t nbytes) +file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name) { unsigned char *newbuf = NULL; size_t i, nsz; @@ -193,6 +192,9 @@ file_zmagic(struct magic_set *ms, int fd, const char *name, file_pushbuf_t *pb; int urv, prv, rv = 0; int mime = ms->flags & MAGIC_MIME; + int fd = b->fd; + const unsigned char *buf = b->fbuf; + size_t nbytes = b->flen; #ifdef HAVE_SIGNAL_H sig_t osigpipe; #endif diff --git a/src/encoding.c b/src/encoding.c index 3c116cd74f17..3e7b9e584b08 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: encoding.c,v 1.13 2015/06/04 19:16:28 christos Exp $") +FILE_RCSID("@(#)$File: encoding.c,v 1.14 2017/11/02 20:25:39 christos Exp $") #endif /* lint */ #include "magic.h" @@ -66,11 +66,21 @@ private void from_ebcdic(const unsigned char *, size_t, unsigned char *); * ubuf, and the number of characters converted in ulen. */ protected int -file_encoding(struct magic_set *ms, const unsigned char *buf, size_t nbytes, unichar **ubuf, size_t *ulen, const char **code, const char **code_mime, const char **type) +file_encoding(struct magic_set *ms, const struct buffer *b, unichar **ubuf, + size_t *ulen, const char **code, const char **code_mime, const char **type) { + const unsigned char *buf = b->fbuf; + size_t nbytes = b->flen; size_t mlen; int rv = 1, ucs_type; unsigned char *nbuf = NULL; + unichar *udefbuf; + size_t udeflen; + + if (ubuf == NULL) + ubuf = &udefbuf; + if (ulen == NULL) + ulen = &udeflen; *type = "text"; *ulen = 0; @@ -144,6 +154,8 @@ file_encoding(struct magic_set *ms, const unsigned char *buf, size_t nbytes, uni done: free(nbuf); + if (ubuf == &udefbuf) + free(udefbuf); return rv; } diff --git a/src/file.c b/src/file.c index fad3160d15fe..87dd1bb60f4c 100644 --- a/src/file.c +++ b/src/file.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: file.c,v 1.172 2016/10/24 15:21:07 christos Exp $") +FILE_RCSID("@(#)$File: file.c,v 1.175 2018/03/02 16:11:37 christos Exp $") #endif /* lint */ #include "magic.h" @@ -59,26 +59,38 @@ FILE_RCSID("@(#)$File: file.c,v 1.172 2016/10/24 15:21:07 christos Exp $") #endif #if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION) -#include <getopt.h> -#ifndef HAVE_GETOPT_LONG -int getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex); +# include <getopt.h> +# ifndef HAVE_GETOPT_LONG +int getopt_long(int, char * const *, const char *, + const struct option *, int *); +# endif +# else +# include "mygetopt.h" #endif + +#ifdef S_IFLNK +# define IFLNK_h "h" +# define IFLNK_L "L" #else -#include "mygetopt.h" +# define IFLNK_h "" +# define IFLNK_L "" #endif -#ifdef S_IFLNK -#define FILE_FLAGS "-bcEhikLlNnprsvzZ0" +#ifdef HAVE_LIBSECCOMP +# define SECCOMP_S "S" #else -#define FILE_FLAGS "-bcEiklNnprsvzZ0" +# define SECCOMP_S "" #endif +#define FILE_FLAGS "bcCdE" IFLNK_h "ik" IFLNK_L "lNnprs" SECCOMP_S "vzZ0" +#define OPTSTRING "bcCde:Ef:F:hiklLm:nNpP:rsSvzZ0" + # define USAGE \ - "Usage: %s [" FILE_FLAGS \ - "] [--apple] [--extension] [--mime-encoding] [--mime-type]\n" \ - " [-e testname] [-F separator] [-f namefile] [-m magicfiles] " \ - "file ...\n" \ - " %s -C [-m magicfiles]\n" \ + "Usage: %s [-" FILE_FLAGS "] [--apple] [--extension] [--mime-encoding]\n" \ + " [--mime-type] [-e <testname>] [-F <separator>] " \ + " [-f <namefile>]\n" \ + " [-m <magicfiles>] [-P <parameter=value>] <file> ...\n" \ + " %s -C [-m <magicfiles>]\n" \ " %s [--help]\n" private int /* Global command-line options */ @@ -102,8 +114,7 @@ private const struct option long_options[] = { #undef OPT #undef OPT_LONGONLY {0, 0, NULL, 0} -}; -#define OPTSTRING "bcCde:Ef:F:hiklLm:nNpP:rsvzZ0" + }; private const struct { const char *name; @@ -135,7 +146,6 @@ private struct { { "bytes", MAGIC_PARAM_BYTES_MAX, 0 }, }; -private char *progname; /* used throughout */ private int posixly; #ifdef __dead @@ -165,9 +175,13 @@ main(int argc, char *argv[]) size_t i; int action = 0, didsomefiles = 0, errflg = 0; int flags = 0, e = 0; +#ifdef HAVE_LIBSECCOMP + int sandbox = 1; +#endif struct magic_set *magic = NULL; int longindex; const char *magicfile = NULL; /* where the magic is */ + char *progname; /* makes islower etc work for other langs */ #ifdef HAVE_SETLOCALE @@ -184,6 +198,9 @@ main(int argc, char *argv[]) else progname = argv[0]; + file_setprogname(progname); + + #ifdef S_IFLNK posixly = getenv("POSIXLY_CORRECT") != NULL; flags |= posixly ? MAGIC_SYMLINK : 0; @@ -280,12 +297,18 @@ main(int argc, char *argv[]) case 's': flags |= MAGIC_DEVICES; break; +#ifdef HAVE_LIBSECCOMP + case 'S': + sandbox = 0; + break; +#endif case 'v': if (magicfile == NULL) magicfile = magic_getpath(magicfile, action); - (void)fprintf(stdout, "%s-%s\n", progname, VERSION); + (void)fprintf(stdout, "%s-%s\n", file_getprogname(), + VERSION); (void)fprintf(stdout, "magic file from %s\n", - magicfile); + magicfile); return 0; case 'z': flags |= MAGIC_COMPRESS; @@ -314,10 +337,19 @@ main(int argc, char *argv[]) if (e) return e; +#ifdef HAVE_LIBSECCOMP +#if 0 + if (sandbox && enable_sandbox_basic() == -1) +#else + if (sandbox && enable_sandbox_full() == -1) +#endif + file_err(EXIT_FAILURE, "SECCOMP initialisation failed"); +#endif /* HAVE_LIBSECCOMP */ + if (MAGIC_VERSION != magic_version()) - (void)fprintf(stderr, "%s: compiled magic version [%d] " + file_warnx("Compiled magic version [%d] " "does not match with shared library magic version [%d]\n", - progname, MAGIC_VERSION, magic_version()); + MAGIC_VERSION, magic_version()); switch(action) { case FILE_CHECK: @@ -329,8 +361,7 @@ main(int argc, char *argv[]) */ magic = magic_open(flags|MAGIC_CHECK); if (magic == NULL) { - (void)fprintf(stderr, "%s: %s\n", progname, - strerror(errno)); + file_warn("Can't create magic"); return 1; } @@ -349,8 +380,7 @@ main(int argc, char *argv[]) abort(); } if (c == -1) { - (void)fprintf(stderr, "%s: %s\n", progname, - magic_error(magic)); + file_warnx("%s", magic_error(magic)); e = 1; goto out; } @@ -398,11 +428,8 @@ applyparam(magic_t magic) for (i = 0; i < __arraycount(pm); i++) { if (pm[i].value == 0) continue; - if (magic_setparam(magic, pm[i].tag, &pm[i].value) == -1) { - (void)fprintf(stderr, "%s: Can't set %s %s\n", progname, - pm[i].name, strerror(errno)); - exit(1); - } + if (magic_setparam(magic, pm[i].tag, &pm[i].value) == -1) + file_err(EXIT_FAILURE, "Can't set %s", pm[i].name); } } @@ -422,8 +449,7 @@ setparam(const char *p) return; } badparm: - (void)fprintf(stderr, "%s: Unknown param %s\n", progname, p); - exit(1); + file_errx(EXIT_FAILURE, "Unknown param %s", p); } private struct magic_set * @@ -434,17 +460,16 @@ load(const char *magicfile, int flags) const char *e; if (magic == NULL) { - (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); + file_warn("Can't create magic"); return NULL; } if (magic_load(magic, magicfile) == -1) { - (void)fprintf(stderr, "%s: %s\n", - progname, magic_error(magic)); + file_warn("%s", magic_error(magic)); magic_close(magic); return NULL; } if ((e = magic_error(magic)) != NULL) - (void)fprintf(stderr, "%s: Warning: %s\n", progname, e); + file_warn("%s", e); return magic; } @@ -466,8 +491,7 @@ unwrap(struct magic_set *ms, const char *fn) wid = 1; } else { if ((f = fopen(fn, "r")) == NULL) { - (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", - progname, fn, strerror(errno)); + file_warn("Cannot open `%s'", fn); return 1; } @@ -567,8 +591,9 @@ file_mbswidth(const char *s) private void usage(void) { - (void)fprintf(stderr, USAGE, progname, progname, progname); - exit(1); + const char *pn = file_getprogname(); + (void)fprintf(stderr, USAGE, pn, pn, pn); + exit(EXIT_FAILURE); } private void @@ -629,5 +654,74 @@ help(void) #undef OPT #undef OPT_LONGONLY fprintf(stdout, "\nReport bugs to http://bugs.gw.com/\n"); - exit(0); + exit(EXIT_SUCCESS); +} + +private const char *file_progname; + +protected void +file_setprogname(const char *progname) +{ + file_progname = progname; +} + +protected const char * +file_getprogname(void) +{ + return file_progname; +} + +protected void +file_err(int e, const char *fmt, ...) +{ + va_list ap; + int se = errno; + + va_start(ap, fmt); + fprintf(stderr, "%s: ", file_progname); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, " (%s)\n", strerror(se)); + exit(e); +} + +protected void +file_errx(int e, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%s: ", file_progname); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(e); +} + +protected void +file_warn(const char *fmt, ...) +{ + va_list ap; + int se = errno; + + va_start(ap, fmt); + fprintf(stderr, "%s: ", file_progname); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, " (%s)\n", strerror(se)); + errno = se; +} + +protected void +file_warnx(const char *fmt, ...) +{ + va_list ap; + int se = errno; + + va_start(ap, fmt); + fprintf(stderr, "%s: ", file_progname); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + errno = se; } diff --git a/src/file.h b/src/file.h index eb9c05421db6..66598bc6bb30 100644 --- a/src/file.h +++ b/src/file.h @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.183 2017/08/28 13:39:18 christos Exp $ + * @(#)$File: file.h,v 1.191 2018/02/21 21:26:00 christos Exp $ */ #ifndef __file_h__ @@ -145,6 +145,16 @@ #define FILE_COMPILE 2 #define FILE_LIST 3 +struct buffer { + int fd; + struct stat st; + const void *fbuf; + size_t flen; + off_t eoff; + void *ebuf; + size_t elen; +}; + union VALUETYPE { uint8_t b; uint16_t h; @@ -287,7 +297,7 @@ struct magic { #endif /* ENABLE_CONDITIONALS */ /* Word 4 */ - uint32_t offset; /* offset to magic number */ + int32_t offset; /* offset to magic number */ /* Word 5 */ int32_t in_offset; /* offset from indirection */ /* Word 6 */ @@ -394,7 +404,9 @@ struct magic_set { char *buf; /* Accumulation buffer */ char *pbuf; /* Printable buffer */ } o; - uint32_t offset; + uint32_t offset; /* a copy of m->offset while we */ + /* are working on the magic entry */ + uint32_t eoffset; /* offset from end of file */ int error; int flags; /* Control magic tests. */ int event_flags; /* Note things that happened. */ @@ -448,23 +460,20 @@ protected int file_replace(struct magic_set *, const char *, const char *); protected int file_printf(struct magic_set *, const char *, ...) __attribute__((__format__(__printf__, 2, 3))); protected int file_reset(struct magic_set *, int); -protected int file_tryelf(struct magic_set *, int, const unsigned char *, - size_t); -protected int file_trycdf(struct magic_set *, int, const unsigned char *, - size_t); +protected int file_tryelf(struct magic_set *, const struct buffer *); +protected int file_trycdf(struct magic_set *, const struct buffer *); #if HAVE_FORK -protected int file_zmagic(struct magic_set *, int, const char *, - const unsigned char *, size_t); +protected int file_zmagic(struct magic_set *, const struct buffer *, + const char *); #endif -protected int file_ascmagic(struct magic_set *, const unsigned char *, size_t, +protected int file_ascmagic(struct magic_set *, const struct buffer *, int); protected int file_ascmagic_with_encoding(struct magic_set *, - const unsigned char *, size_t, unichar *, size_t, const char *, - const char *, int); -protected int file_encoding(struct magic_set *, const unsigned char *, size_t, + const struct buffer *, unichar *, size_t, const char *, const char *, int); +protected int file_encoding(struct magic_set *, const struct buffer *, 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, +protected int file_is_tar(struct magic_set *, const struct buffer *); +protected int file_softmagic(struct magic_set *, const struct buffer *, 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 **, @@ -497,6 +506,10 @@ protected int file_os2_apptype(struct magic_set *, const char *, const void *, size_t); #endif /* __EMX__ */ +protected void buffer_init(struct buffer *, int, const void *, size_t); +protected void buffer_fini(struct buffer *); +protected int buffer_fill(const struct buffer *); + #if defined(HAVE_LOCALE_H) #include <locale.h> #endif @@ -590,6 +603,29 @@ const char *fmtcheck(const char *, const char *) __attribute__((__format_arg__(2))); #endif +#ifdef HAVE_LIBSECCOMP +// basic filter +// this mode should not interfere with normal operations +// only some dangerous syscalls are blacklisted +int enable_sandbox_basic(void); + +// enhanced filter +// this mode allows only the necessary syscalls used during normal operation +// extensive testing required !!! +int enable_sandbox_full(void); +#endif + +protected const char *file_getprogname(void); +protected void file_setprogname(const char *); +protected void file_err(int, const char *, ...) + __attribute__((__format__(__printf__, 2, 3))); +protected void file_errx(int, const char *, ...) + __attribute__((__format__(__printf__, 2, 3))); +protected void file_warn(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); +protected void file_warnx(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); + #if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H) && !defined(QUICK) #define QUICK #endif diff --git a/src/file_opts.h b/src/file_opts.h index 52ace1893630..02611ccb8a85 100644 --- a/src/file_opts.h +++ b/src/file_opts.h @@ -54,5 +54,8 @@ OPT('P', "parameter", 1, 0, " set file engine parameter limits\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") +#ifdef HAVE_LIBSECCOMP +OPT('S', "no-sandbox", 0, 0, " disable system call sandboxing\n") +#endif OPT('C', "compile", 0, 0, " compile file specified by -m\n") OPT('d', "debug", 0, 0, " print debugging messages\n") diff --git a/src/funcs.c b/src/funcs.c index d7a18f451a7e..f59f4a1b97dc 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: funcs.c,v 1.93 2017/08/28 13:39:18 christos Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.94 2017/11/02 20:25:39 christos Exp $") #endif /* lint */ #include "magic.h" @@ -178,14 +178,14 @@ 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; - const unsigned char *ubuf = CAST(const unsigned char *, buf); - unichar *u8buf = NULL; - size_t ulen; const char *code = NULL; const char *code_mime = "binary"; const char *type = "application/octet-stream"; const char *def = "data"; const char *ftype = NULL; + struct buffer b; + + buffer_init(&b, fd, buf, nb); if (nb == 0) { def = "empty"; @@ -197,13 +197,13 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u } if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) { - looks_text = file_encoding(ms, ubuf, nb, &u8buf, &ulen, + looks_text = file_encoding(ms, &b, NULL, 0, &code, &code_mime, &ftype); } #ifdef __EMX__ if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) { - m = file_os2_apptype(ms, inname, buf, nb); + m = file_os2_apptype(ms, inname, &b); if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "[try os2_apptype %d]\n", m); switch (m) { @@ -219,7 +219,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u #if HAVE_FORK /* try compression stuff */ if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) { - m = file_zmagic(ms, fd, inname, ubuf, nb); + m = file_zmagic(ms, &b, inname); if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "[try zmagic %d]\n", m); if (m) { @@ -229,7 +229,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u #endif /* Check if we have a tar file */ if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0) { - m = file_is_tar(ms, ubuf, nb); + m = file_is_tar(ms, &b); if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "[try tar %d]\n", m); if (m) { @@ -240,7 +240,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u /* Check if we have a CDF file */ if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) { - m = file_trycdf(ms, fd, ubuf, nb); + m = file_trycdf(ms, &b); if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "[try cdf %d]\n", m); if (m) { @@ -251,8 +251,7 @@ 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, NULL, NULL, BINTEST, - looks_text); + m = file_softmagic(ms, &b, NULL, NULL, BINTEST, looks_text); if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "[try softmagic %d]\n", m); if (m) { @@ -268,7 +267,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u * ELF headers that cannot easily * be * extracted with rules in the magic file. */ - m = file_tryelf(ms, fd, ubuf, nb); + m = file_tryelf(ms, &b); if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "[try elf %d]\n", m); @@ -282,7 +281,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u /* try text properties */ if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) { - m = file_ascmagic(ms, ubuf, nb, looks_text); + m = file_ascmagic(ms, &b, looks_text); if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "[try ascmagic %d]\n", m); if (m) { @@ -319,7 +318,7 @@ simple: #if HAVE_FORK done_encoding: #endif - free(u8buf); + buffer_fini(&b); if (rv) return rv; diff --git a/src/is_tar.c b/src/is_tar.c index 1953a7fc102e..7110604f9e81 100644 --- a/src/is_tar.c +++ b/src/is_tar.c @@ -40,7 +40,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: is_tar.c,v 1.39 2017/03/17 20:45:01 christos Exp $") +FILE_RCSID("@(#)$File: is_tar.c,v 1.41 2017/11/02 20:25:39 christos Exp $") #endif #include "magic.h" @@ -53,15 +53,17 @@ FILE_RCSID("@(#)$File: is_tar.c,v 1.39 2017/03/17 20:45:01 christos Exp $") private int is_tar(const unsigned char *, size_t); private int from_oct(const char *, size_t); /* Decode octal number */ -static const char tartype[][32] = { - "tar archive", +static const char tartype[][32] = { /* should be equal to messages */ + "tar archive", /* found in ../magic/Magdir/archive */ "POSIX tar archive", - "POSIX tar archive (GNU)", + "POSIX tar archive (GNU)", /* */ }; protected int -file_is_tar(struct magic_set *ms, const unsigned char *buf, size_t nbytes) +file_is_tar(struct magic_set *ms, const struct buffer *b) { + const unsigned char *buf = b->fbuf; + size_t nbytes = b->flen; /* * Do the tar test first, because if the first file in the tar * archive starts with a dot, we can confuse it with an nroff file. diff --git a/src/readcdf.c b/src/readcdf.c index 80c8d26e3fec..51b862cf168a 100644 --- a/src/readcdf.c +++ b/src/readcdf.c @@ -26,7 +26,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readcdf.c,v 1.65 2017/04/08 20:58:03 christos Exp $") +FILE_RCSID("@(#)$File: readcdf.c,v 1.66 2017/11/02 20:25:39 christos Exp $") #endif #include <assert.h> @@ -537,9 +537,11 @@ cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir) } protected int -file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, - size_t nbytes) +file_trycdf(struct magic_set *ms, const struct buffer *b) { + int fd = b->fd; + const unsigned char *buf = b->fbuf; + size_t nbytes = b->flen; cdf_info_t info; cdf_header_t h; cdf_sat_t sat, ssat; diff --git a/src/readelf.c b/src/readelf.c index 5f425c974e76..3df0836d7029 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readelf.c,v 1.138 2017/08/27 07:55:02 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.141 2018/04/12 16:50:52 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -310,18 +310,19 @@ private const char os_style_names[][8] = { "NetBSD", }; -#define FLAGS_CORE_STYLE 0x003 +#define FLAGS_CORE_STYLE 0x0003 -#define FLAGS_DID_CORE 0x004 -#define FLAGS_DID_OS_NOTE 0x008 -#define FLAGS_DID_BUILD_ID 0x010 -#define FLAGS_DID_CORE_STYLE 0x020 -#define FLAGS_DID_NETBSD_PAX 0x040 -#define FLAGS_DID_NETBSD_MARCH 0x080 -#define FLAGS_DID_NETBSD_CMODEL 0x100 -#define FLAGS_DID_NETBSD_UNKNOWN 0x200 -#define FLAGS_IS_CORE 0x400 -#define FLAGS_DID_AUXV 0x800 +#define FLAGS_DID_CORE 0x0004 +#define FLAGS_DID_OS_NOTE 0x0008 +#define FLAGS_DID_BUILD_ID 0x0010 +#define FLAGS_DID_CORE_STYLE 0x0020 +#define FLAGS_DID_NETBSD_PAX 0x0040 +#define FLAGS_DID_NETBSD_MARCH 0x0080 +#define FLAGS_DID_NETBSD_CMODEL 0x0100 +#define FLAGS_DID_NETBSD_EMULATION 0x0200 +#define FLAGS_DID_NETBSD_UNKNOWN 0x0400 +#define FLAGS_IS_CORE 0x0800 +#define FLAGS_DID_AUXV 0x1000 private int dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, @@ -726,11 +727,11 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)", file_printable(sbuf, sizeof(sbuf), CAST(char *, pi.cpi_name)), - elf_getu32(swap, pi.cpi_pid), + elf_getu32(swap, (uint32_t)pi.cpi_pid), elf_getu32(swap, pi.cpi_euid), elf_getu32(swap, pi.cpi_egid), elf_getu32(swap, pi.cpi_nlwps), - elf_getu32(swap, pi.cpi_siglwp), + elf_getu32(swap, (uint32_t)pi.cpi_siglwp), elf_getu32(swap, pi.cpi_signo), elf_getu32(swap, pi.cpi_sigcode)) == -1) return 1; @@ -908,6 +909,7 @@ get_string_on_virtaddr(struct magic_set *ms, } +/*ARGSUSED*/ private int do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, int swap, uint32_t namesz __attribute__((__unused__)), @@ -1134,6 +1136,14 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, (int)descsz, (const char *)&nbuf[doff]) == -1) return offset; break; + case NT_NETBSD_EMULATION: + if (*flags & FLAGS_DID_NETBSD_EMULATION) + return offset; + *flags |= FLAGS_DID_NETBSD_EMULATION; + if (file_printf(ms, ", emulation: %.*s", + (int)descsz, (const char *)&nbuf[doff]) == -1) + return offset; + break; default: if (*flags & FLAGS_DID_NETBSD_UNKNOWN) return offset; @@ -1570,9 +1580,11 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, protected int -file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, - size_t nbytes) +file_tryelf(struct magic_set *ms, const struct buffer *b) { + int fd = b->fd; + const unsigned char *buf = b->fbuf; + size_t nbytes = b->flen; union { int32_t l; char c[sizeof (int32_t)]; diff --git a/src/seccomp.c b/src/seccomp.c new file mode 100644 index 000000000000..7c8a31443b43 --- /dev/null +++ b/src/seccomp.c @@ -0,0 +1,246 @@ +/* + * 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. + */ +/* + * libseccomp hooks. + */ +#include "file.h" + +#ifndef lint +FILE_RCSID("@(#)$File: seccomp.c,v 1.2 2017/11/04 01:14:25 christos Exp $") +#endif /* lint */ + +#if HAVE_LIBSECCOMP +#include <seccomp.h> /* libseccomp */ +#include <sys/prctl.h> /* prctl */ +#include <sys/socket.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> + +#define DENY_RULE(call) \ + do \ + if (seccomp_rule_add (ctx, SCMP_ACT_KILL, SCMP_SYS(call), 0) == -1) \ + goto out; \ + while (/*CONSTCOND*/0) +#define ALLOW_RULE(call) \ + do \ + if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(call), 0) == -1) \ + goto out; \ + while (/*CONSTCOND*/0) + +static scmp_filter_ctx ctx; + + +int +enable_sandbox_basic(void) +{ + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) + return -1; + +#if 0 + // prevent escape via ptrace + prctl(PR_SET_DUMPABLE, 0); +#endif + + if (prctl (PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) + return -1; + + // initialize the filter + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return 1; + + DENY_RULE(_sysctl); + DENY_RULE(acct); + DENY_RULE(add_key); + DENY_RULE(adjtimex); + DENY_RULE(chroot); + DENY_RULE(clock_adjtime); + DENY_RULE(create_module); + DENY_RULE(delete_module); + DENY_RULE(fanotify_init); + DENY_RULE(finit_module); + DENY_RULE(get_kernel_syms); + DENY_RULE(get_mempolicy); + DENY_RULE(init_module); + DENY_RULE(io_cancel); + DENY_RULE(io_destroy); + DENY_RULE(io_getevents); + DENY_RULE(io_setup); + DENY_RULE(io_submit); + DENY_RULE(ioperm); + DENY_RULE(iopl); + DENY_RULE(ioprio_set); + DENY_RULE(kcmp); +#ifdef __NR_kexec_file_load + DENY_RULE(kexec_file_load); +#endif + DENY_RULE(kexec_load); + DENY_RULE(keyctl); + DENY_RULE(lookup_dcookie); + DENY_RULE(mbind); + DENY_RULE(nfsservctl); + DENY_RULE(migrate_pages); + DENY_RULE(modify_ldt); + DENY_RULE(mount); + DENY_RULE(move_pages); + DENY_RULE(name_to_handle_at); + DENY_RULE(open_by_handle_at); + DENY_RULE(perf_event_open); + DENY_RULE(pivot_root); + DENY_RULE(process_vm_readv); + DENY_RULE(process_vm_writev); + DENY_RULE(ptrace); + DENY_RULE(reboot); + DENY_RULE(remap_file_pages); + DENY_RULE(request_key); + DENY_RULE(set_mempolicy); + DENY_RULE(swapoff); + DENY_RULE(swapon); + DENY_RULE(sysfs); + DENY_RULE(syslog); + DENY_RULE(tuxcall); + DENY_RULE(umount2); + DENY_RULE(uselib); + DENY_RULE(vmsplice); + + // blocking dangerous syscalls that file should not need + DENY_RULE (execve); + DENY_RULE (socket); + // ... + + + // applying filter... + if (seccomp_load (ctx) == -1) + goto out; + // free ctx after the filter has been loaded into the kernel + seccomp_release(ctx); + return 0; + +out: + seccomp_release(ctx); + return -1; +} + + +int +enable_sandbox_full(void) +{ + + // prevent child processes from getting more priv e.g. via setuid, + // capabilities, ... + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) + return -1; + + if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) + return -1; + + // initialize the filter + ctx = seccomp_init(SCMP_ACT_KILL); + if (ctx == NULL) + return -1; + + ALLOW_RULE(access); + ALLOW_RULE(brk); + ALLOW_RULE(close); + ALLOW_RULE(dup2); + ALLOW_RULE(exit); + ALLOW_RULE(exit_group); + ALLOW_RULE(fcntl); + ALLOW_RULE(fstat); + ALLOW_RULE(getdents); + ALLOW_RULE(ioctl); + ALLOW_RULE(lseek); + ALLOW_RULE(lstat); + ALLOW_RULE(mmap); + ALLOW_RULE(mprotect); + ALLOW_RULE(mremap); + ALLOW_RULE(munmap); + ALLOW_RULE(open); + ALLOW_RULE(openat); + ALLOW_RULE(pread64); + ALLOW_RULE(read); + ALLOW_RULE(readlink); + ALLOW_RULE(rt_sigaction); + ALLOW_RULE(rt_sigprocmask); + ALLOW_RULE(rt_sigreturn); + ALLOW_RULE(select); + ALLOW_RULE(stat); + ALLOW_RULE(sysinfo); + ALLOW_RULE(unlink); + ALLOW_RULE(write); + + +#if 0 + // needed by valgrind + ALLOW_RULE(gettid); + ALLOW_RULE(getpid); + ALLOW_RULE(rt_sigtimedwait); +#endif + +#if 0 + /* special restrictions for socket, only allow AF_UNIX/AF_LOCAL */ + if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1, + SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) == -1) + goto out; + + if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1, + SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) == -1) + goto out; + + + /* special restrictions for open, prevent opening files for writing */ + if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1, + SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) == -1) + goto out; + + if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1, + SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) == -1) + goto out; + + if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1, + SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) == -1) + goto out; + + + /* allow stderr */ + if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, + SCMP_CMP(0, SCMP_CMP_EQ, 2)) == -1) + goto out; +#endif + + // applying filter... + if (seccomp_load(ctx) == -1) + goto out; + // free ctx after the filter has been loaded into the kernel + seccomp_release(ctx); + return 0; + +out: + // something went wrong + seccomp_release(ctx); + return -1; +} +#endif diff --git a/src/softmagic.c b/src/softmagic.c index b9e975374b40..00d5aac6000f 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.249 2017/06/19 18:30:25 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.259 2018/03/11 01:23:52 christos Exp $") #endif /* lint */ #include "magic.h" @@ -44,20 +44,26 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.249 2017/06/19 18:30:25 christos Exp $") #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 struct buffer *, 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 *, +private int mget(struct magic_set *, struct magic *, const struct buffer *, + const unsigned char *, size_t, + size_t, unsigned int, int, int, int, uint16_t *, uint16_t *, int *, int *, int *); +private int msetoffset(struct magic_set *, struct magic *, struct buffer *, + const struct buffer *, size_t, unsigned int); private int magiccheck(struct magic_set *, struct magic *); -private int32_t mprint(struct magic_set *, struct magic *); -private int moffset(struct magic_set *, struct magic *, size_t, int32_t *); +private int32_t mprint(struct magic_set *, struct magic *, + const struct buffer *); +private int moffset(struct magic_set *, struct magic *, const struct buffer *, + 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 *, int); +private int handle_annotation(struct magic_set *, struct magic *, + const struct buffer *, int); 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 *); @@ -88,7 +94,7 @@ private int 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, +file_softmagic(struct magic_set *ms, const struct buffer *b, uint16_t *indir_count, uint16_t *name_count, int mode, int text) { struct mlist *ml; @@ -105,7 +111,7 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, } 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, + if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode, text, 0, indir_count, name_count, &printed_something, &need_separator, NULL)) != 0) return rv; @@ -118,18 +124,18 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) private const char * __attribute__((__format_arg__(3))) -file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def, +file_fmtcheck(struct magic_set *ms, const char *desc, const char *def, const char *file, size_t line) { - const char *ptr = fmtcheck(m->desc, def); + const char *ptr = fmtcheck(desc, def); if (ptr == def) file_magerror(ms, "%s, %" SIZE_T_FORMAT "u: format `%s' does not match" - " with `%s'", file, line, m->desc, def); + " with `%s'", file, line, desc, def); return ptr; } #else -#define F(a, b, c) fmtcheck((b)->desc, (c)) +#define F(a, b, c) fmtcheck((b), (c)) #endif /* @@ -161,7 +167,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, + const struct buffer *b, size_t offset, int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count, int *printed_something, int *need_separator, int *returnval) { @@ -169,6 +175,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, unsigned int cont_level = 0; int returnvalv = 0, e; /* if a match is found it is set to 1*/ int firstline = 1; /* a flag to print X\n X\n- X */ + struct buffer bb; int print = (ms->flags & MAGIC_NODESC) == 0; if (returnval == NULL) @@ -196,12 +203,13 @@ flush: continue; /* Skip to next top-level test*/ } - ms->offset = m->offset; + if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) + goto flush; ms->line = m->lineno; /* if main entry matches, print it... */ - switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text, - flip, indir_count, name_count, + switch (mget(ms, m, b, bb.fbuf, bb.flen, offset, cont_level, + mode, text, flip, indir_count, name_count, printed_something, need_separator, returnval)) { case -1: return -1; @@ -232,7 +240,7 @@ flush: goto flush; } - if ((e = handle_annotation(ms, m, firstline)) != 0) { + if ((e = handle_annotation(ms, m, b, firstline)) != 0) { *need_separator = 1; *printed_something = 1; *returnval = 1; @@ -250,11 +258,10 @@ flush: return -1; } - - if (print && mprint(ms, m) == -1) + if (print && mprint(ms, m, b) == -1) return -1; - switch (moffset(ms, m, nbytes, &ms->c.li[cont_level].off)) { + switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) { case -1: case 0: goto flush; @@ -280,7 +287,8 @@ flush: */ cont_level = m->cont_level; } - ms->offset = m->offset; + if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) + goto flush; if (m->flag & OFFADD) { ms->offset += ms->c.li[cont_level - 1].off; @@ -293,9 +301,10 @@ flush: continue; } #endif - switch (mget(ms, s, m, nbytes, offset, cont_level, mode, - text, flip, indir_count, name_count, - printed_something, need_separator, returnval)) { + switch (mget(ms, m, b, bb.fbuf, bb.flen, offset, + cont_level, mode, text, flip, indir_count, + name_count, printed_something, need_separator, + returnval)) { case -1: return -1; case 0: @@ -330,7 +339,8 @@ flush: } else ms->c.li[cont_level].got_match = 1; - if ((e = handle_annotation(ms, m, firstline)) != 0) { + if ((e = handle_annotation(ms, m, b, firstline)) + != 0) { *need_separator = 1; *printed_something = 1; *returnval = 1; @@ -363,10 +373,10 @@ flush: return -1; *need_separator = 0; } - if (print && mprint(ms, m) == -1) + if (print && mprint(ms, m, b) == -1) return -1; - switch (moffset(ms, m, nbytes, + switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) { case -1: case 0: @@ -404,19 +414,19 @@ flush: } private int -check_fmt(struct magic_set *ms, struct magic *m) +check_fmt(struct magic_set *ms, const char *fmt) { file_regex_t rx; int rc, rv = -1; - if (strchr(m->desc, '%') == NULL) + if (strchr(fmt, '%') == NULL) return 0; rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); if (rc) { file_regerror(&rx, rc, ms); } else { - rc = file_regexec(&rx, m->desc, 0, 0, 0); + rc = file_regexec(&rx, fmt, 0, 0, 0); rv = !rc; } file_regfree(&rx); @@ -442,30 +452,91 @@ strndup(const char *str, size_t n) } #endif /* HAVE_STRNDUP */ +static int +varexpand(char *buf, size_t len, const struct buffer *b, const char *str) +{ + const char *ptr, *sptr, *e, *t, *ee, *et; + size_t l; + + for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) { + l = (size_t)(ptr - sptr); + if (l >= len) + return -1; + memcpy(buf, sptr, l); + buf += l; + len -= l; + ptr += 2; + if (!*ptr || ptr[1] != '?') + return -1; + for (et = t = ptr + 2; *et && *et != ':'; et++) + continue; + if (*et != ':') + return -1; + for (ee = e = et + 1; *ee && *ee != '}'; ee++) + continue; + if (*ee != '}') + return -1; + switch (*ptr) { + case 'x': + if (b->st.st_mode & 0111) { + ptr = t; + l = et - t; + } else { + ptr = e; + l = ee - e; + } + break; + default: + return -1; + } + if (l >= len) + return -1; + memcpy(buf, ptr, l); + buf += l; + len -= l; + sptr = ee + 1; + } + + l = strlen(sptr); + if (l >= len) + return -1; + + memcpy(buf, sptr, l); + buf[l] = '\0'; + return 0; +} + + private int32_t -mprint(struct magic_set *ms, struct magic *m) +mprint(struct magic_set *ms, struct magic *m, const struct buffer *b) { uint64_t v; float vf; double vd; int64_t t = 0; - char buf[128], tbuf[26], sbuf[512]; + char buf[128], tbuf[26], sbuf[512], ebuf[512]; + const char *desc; union VALUETYPE *p = &ms->ms_value; + if (varexpand(ebuf, sizeof(ebuf), b, m->desc) == -1) + desc = m->desc; + else + desc = ebuf; + switch (m->type) { case FILE_BYTE: v = file_signextend(ms, m, (uint64_t)p->b); - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%d", (unsigned char)v); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%d"), + if (file_printf(ms, F(ms, desc, "%d"), (unsigned char) v) == -1) return -1; break; @@ -477,17 +548,17 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BESHORT: case FILE_LESHORT: v = file_signextend(ms, m, (uint64_t)p->h); - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%u", (unsigned short)v); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%u"), + if (file_printf(ms, F(ms, desc, "%u"), (unsigned short) v) == -1) return -1; break; @@ -500,16 +571,16 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_LELONG: case FILE_MELONG: v = file_signextend(ms, m, (uint64_t)p->l); - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1) + if (file_printf(ms, F(ms, desc, "%u"), (uint32_t) v) == -1) return -1; break; } @@ -520,17 +591,17 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEQUAD: case FILE_LEQUAD: v = file_signextend(ms, m, p->q); - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u", (unsigned long long)v); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"), + if (file_printf(ms, F(ms, desc, "%" INT64_T_FORMAT "u"), (unsigned long long) v) == -1) return -1; break; @@ -543,7 +614,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BESTRING16: case FILE_LESTRING16: if (m->reln == '=' || m->reln == '!') { - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_printable(sbuf, sizeof(sbuf), m->value.s)) == -1) return -1; @@ -571,7 +642,7 @@ mprint(struct magic_set *ms, struct magic *m) *++last = '\0'; } - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_printable(sbuf, sizeof(sbuf), str)) == -1) return -1; @@ -584,7 +655,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEDATE: case FILE_LEDATE: case FILE_MEDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->l, 0, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint32_t); @@ -594,7 +665,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BELDATE: case FILE_LELDATE: case FILE_MELDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint32_t); @@ -603,7 +674,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QDATE: case FILE_BEQDATE: case FILE_LEQDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->q, 0, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); @@ -612,7 +683,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QLDATE: case FILE_BEQLDATE: case FILE_LEQLDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); @@ -621,7 +692,7 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QWDATE: case FILE_BEQWDATE: case FILE_LEQWDATE: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); @@ -631,16 +702,16 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEFLOAT: case FILE_LEFLOAT: vf = p->f; - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%g", vf); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%g"), vf) == -1) + if (file_printf(ms, F(ms, desc, "%g"), vf) == -1) return -1; break; } @@ -651,16 +722,16 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEDOUBLE: case FILE_LEDOUBLE: vd = p->d; - switch (check_fmt(ms, m)) { + switch (check_fmt(ms, desc)) { case -1: return -1; case 1: (void)snprintf(buf, sizeof(buf), "%g", vd); - if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, F(ms, m, "%g"), vd) == -1) + if (file_printf(ms, F(ms, desc, "%g"), vd) == -1) return -1; break; } @@ -677,7 +748,7 @@ mprint(struct magic_set *ms, struct magic *m) file_oomem(ms, ms->search.rm_len); return -1; } - rval = file_printf(ms, F(ms, m, "%s"), + rval = file_printf(ms, F(ms, desc, "%s"), file_printable(sbuf, sizeof(sbuf), cp)); free(cp); @@ -704,7 +775,7 @@ mprint(struct magic_set *ms, struct magic *m) t = ms->offset; break; case FILE_DER: - if (file_printf(ms, F(ms, m, "%s"), + if (file_printf(ms, F(ms, desc, "%s"), file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1) return -1; t = ms->offset; @@ -717,8 +788,10 @@ mprint(struct magic_set *ms, struct magic *m) } private int -moffset(struct magic_set *ms, struct magic *m, size_t nbytes, int32_t *op) +moffset(struct magic_set *ms, struct magic *m, const struct buffer *b, + int32_t *op) { + size_t nbytes = b->flen; int32_t o; switch (m->type) { @@ -1232,7 +1305,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, b++; } if (lines) - last = RCAST(const char *, s) + bytecnt; + last = end; ms->search.s = buf; ms->search.s_len = last - buf; @@ -1337,12 +1410,58 @@ do_ops(struct magic *m, intmax_t lhs, intmax_t off) } 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_count, uint16_t *name_count, +msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb, + const struct buffer *b, size_t o, unsigned int cont_level) +{ + if (m->offset < 0) { + if (cont_level > 0) { + if (m->flag & (OFFADD|INDIROFFADD)) + goto normal; +#if 0 + file_error(ms, 0, "negative offset %d at continuation" + "level %u", m->offset, cont_level); + return -1; +#endif + } + if (buffer_fill(b) == -1) + return -1; + if (o != 0) { + // Not yet! + file_magerror(ms, "non zero offset %zu at" + " level %u", o, cont_level); + return -1; + } + if ((size_t)-m->offset > b->elen) + return -1; + buffer_init(bb, -1, b->ebuf, b->elen); + ms->eoffset = ms->offset = b->elen + m->offset; + } else { + if (cont_level == 0) { +normal: + // XXX: Pass real fd, then who frees bb? + buffer_init(bb, -1, b->fbuf, b->flen); + ms->offset = m->offset; + ms->eoffset = 0; + } else { + ms->offset = ms->eoffset + m->offset; + } + } + if ((ms->flags & MAGIC_DEBUG) != 0) { + fprintf(stderr, "bb=[%p,%zu], %d [b=%p,%zu], [o=%#x, c=%d]\n", + bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen, + m->offset, cont_level); + } + return 0; +} + +private int +mget(struct magic_set *ms, struct magic *m, const struct buffer *b, + const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level, + int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count, int *printed_something, int *need_separator, int *returnval) { uint32_t offset = ms->offset; + struct buffer bb; intmax_t lhs; file_pushbuf_t *pb; int rv, oneed_separator, in_type; @@ -1362,6 +1481,8 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return -1; } + + if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o), (uint32_t)nbytes, m) == -1) return -1; @@ -1559,7 +1680,10 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return -1; (*indir_count)++; - rv = file_softmagic(ms, s + offset, nbytes - offset, + bb = *b; + bb.fbuf = s + offset; + bb.flen = nbytes - offset; + rv = file_softmagic(ms, &bb, indir_count, name_count, BINTEST, text); if ((ms->flags & MAGIC_DEBUG) != 0) @@ -1571,7 +1695,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (rv == 1) { if ((ms->flags & MAGIC_NODESC) == 0 && - file_printf(ms, F(ms, m, "%u"), offset) == -1) { + file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) { free(rbuf); return -1; } @@ -1599,12 +1723,12 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, oneed_separator = *need_separator; if (m->flag & NOSPACE) *need_separator = 0; - rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o, + rv = match(ms, ml.magic, ml.nmagic, b, offset + o, mode, text, flip, indir_count, name_count, printed_something, need_separator, returnval); if (rv != 1) *need_separator = oneed_separator; - return 1; + return rv; case FILE_NAME: if (ms->flags & MAGIC_NODESC) @@ -2035,7 +2159,8 @@ magiccheck(struct magic_set *ms, struct magic *m) } private int -handle_annotation(struct magic_set *ms, struct magic *m, int firstline) +handle_annotation(struct magic_set *ms, struct magic *m, const struct buffer *b, + int firstline) { if ((ms->flags & MAGIC_APPLE) && m->apple[0]) { if (!firstline && file_printf(ms, "\n- ") == -1) @@ -2052,9 +2177,15 @@ handle_annotation(struct magic_set *ms, struct magic *m, int firstline) return 1; } if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) { + char buf[1024]; + const char *p; if (!firstline && file_printf(ms, "\n- ") == -1) return -1; - if (file_printf(ms, "%s", m->mimetype) == -1) + if (varexpand(buf, sizeof(buf), b, m->mimetype) == -1) + p = m->mimetype; + else + p = buf; + if (file_printf(ms, "%s", p) == -1) return -1; return 1; } |