diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.in | 86 | ||||
-rw-r--r-- | src/apprentice.c | 10 | ||||
-rw-r--r-- | src/compress.c | 23 | ||||
-rw-r--r-- | src/der.c | 4 | ||||
-rw-r--r-- | src/file.h | 7 | ||||
-rw-r--r-- | src/funcs.c | 53 | ||||
-rw-r--r-- | src/readcdf.c | 366 | ||||
-rw-r--r-- | src/readelf.c | 305 | ||||
-rw-r--r-- | src/readelf.h | 112 | ||||
-rw-r--r-- | src/seccomp.c | 21 | ||||
-rw-r--r-- | src/softmagic.c | 56 |
11 files changed, 672 insertions, 371 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index c096c71ea477..afa7bfa061eb 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2012 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -17,23 +17,61 @@ VPATH = @srcdir@ -am__make_dryrun = \ - { \ - am__dry=no; \ +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 \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ - 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;; \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ - test $$am__dry = yes; \ - } + 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;; \ + 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)) pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ @@ -53,10 +91,6 @@ 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 \ @@ -64,6 +98,7 @@ 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 = @@ -177,6 +212,10 @@ 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@ @@ -190,6 +229,7 @@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ +CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ @@ -205,6 +245,7 @@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ +HAVE_VISIBILITY = @HAVE_VISIBILITY@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -333,7 +374,6 @@ $(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*) \ @@ -386,6 +426,7 @@ 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) @@ -437,6 +478,7 @@ 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) @@ -748,6 +790,8 @@ 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 e2ce2d3ad2ff..ea8d0b222e0a 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.270 2018/02/21 21:26:48 christos Exp $") +FILE_RCSID("@(#)$File: apprentice.c,v 1.272 2018/06/22 20:39:50 christos Exp $") #endif /* lint */ #include "magic.h" @@ -1980,6 +1980,12 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, case 'I': m->in_type = FILE_BEID3; break; + case 'q': + m->in_type = FILE_LEQUAD; + break; + case 'Q': + m->in_type = FILE_BEQUAD; + break; default: if (ms->flags & MAGIC_CHECK) file_magwarn(ms, @@ -3335,7 +3341,7 @@ private void bs1(struct magic *m) { m->cont_level = swap2(m->cont_level); - m->offset = swap4((int32_t)m->offset); + m->offset = swap4((uint32_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/compress.c b/src/compress.c index 184011b92307..5d565d56089e 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.106 2017/11/02 20:25:39 christos Exp $") +FILE_RCSID("@(#)$File: compress.c,v 1.107 2018/04/28 18:48:22 christos Exp $") #endif #include "magic.h" @@ -183,6 +183,23 @@ static int makeerror(unsigned char **, size_t *, const char *, ...) __attribute__((__format__(__printf__, 3, 4))); private const char *methodname(size_t); +private int +format_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf) +{ + unsigned char *p; + int mime = ms->flags & MAGIC_MIME; + + if (!mime) + return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf); + + for (p = buf; *p; p++) + if (!isalnum(*p)) + *p = '-'; + + return file_printf(ms, "application/x-decompression-error-%s-%s", + methodname(i), buf); +} + protected int file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name) { @@ -226,11 +243,9 @@ file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name) switch (urv) { case OKDATA: case ERRDATA: - ms->flags &= ~MAGIC_COMPRESS; if (urv == ERRDATA) - prv = file_printf(ms, "%s ERROR: %s", - methodname(i), newbuf); + prv = format_decompression_error(ms, i, newbuf); else prv = file_buffer(ms, -1, name, newbuf, nsz); if (prv == -1) diff --git a/src/der.c b/src/der.c index 4e22caf41d4a..d017b63983f0 100644 --- a/src/der.c +++ b/src/der.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: der.c,v 1.12 2017/02/10 18:14:01 christos Exp $") +FILE_RCSID("@(#)$File: der.c,v 1.13 2018/06/23 15:15:26 christos Exp $") #endif #endif @@ -199,7 +199,7 @@ getlength(const uint8_t *c, size_t *p, size_t l) for (i = 0; i < digits; i++) len = (len << 8) | c[(*p)++]; - if (*p + len >= l) + if (len > UINT32_MAX - *p || *p + len >= l) return DER_BAD; return CAST(uint32_t, len); } diff --git a/src/file.h b/src/file.h index 66598bc6bb30..57a84a80c0d5 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.191 2018/02/21 21:26:00 christos Exp $ + * @(#)$File: file.h,v 1.193 2018/05/24 18:09:17 christos Exp $ */ #ifndef __file_h__ @@ -413,6 +413,7 @@ struct magic_set { #define EVENT_HAD_ERR 0x01 const char *file; size_t line; /* current magic line number */ + mode_t mode; /* copy of current stat mode */ /* data for searches */ struct { @@ -618,9 +619,9 @@ int enable_sandbox_full(void); protected const char *file_getprogname(void); protected void file_setprogname(const char *); protected void file_err(int, const char *, ...) - __attribute__((__format__(__printf__, 2, 3))); + __attribute__((__format__(__printf__, 2, 3), __noreturn__)); protected void file_errx(int, const char *, ...) - __attribute__((__format__(__printf__, 2, 3))); + __attribute__((__format__(__printf__, 2, 3), __noreturn__)); protected void file_warn(const char *, ...) __attribute__((__format__(__printf__, 1, 2))); protected void file_warnx(const char *, ...) diff --git a/src/funcs.c b/src/funcs.c index f59f4a1b97dc..0bf92fe1c250 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.94 2017/11/02 20:25:39 christos Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.95 2018/05/24 18:09:17 christos Exp $") #endif /* lint */ #include "magic.h" @@ -183,9 +183,11 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u const char *type = "application/octet-stream"; const char *def = "data"; const char *ftype = NULL; + char *rbuf = NULL; struct buffer b; buffer_init(&b, fd, buf, nb); + ms->mode = b.st.st_mode; if (nb == 0) { def = "empty"; @@ -248,31 +250,43 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u goto done; } } +#ifdef BUILTIN_ELF + if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && nb > 5 && fd != -1) { + file_pushbuf_t *pb; + /* + * We matched something in the file, so this + * *might* be an ELF file, and the file is at + * least 5 bytes long, so if it's an ELF file + * it has at least one byte past the ELF magic + * number - try extracting information from the + * ELF headers that cannot easily be extracted + * with rules in the magic file. We we don't + * print the information yet. + */ + if ((pb = file_push_buffer(ms)) == NULL) + return -1; + + rv = file_tryelf(ms, &b); + rbuf = file_pop_buffer(ms, pb); + if (rv != 1) { + free(rbuf); + rbuf = NULL; + } + if ((ms->flags & MAGIC_DEBUG) != 0) + (void)fprintf(stderr, "[try elf %d]\n", m); + } +#endif /* try soft magic tests */ if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) { 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 == 1 && rbuf) { + if (file_printf(ms, "%s", rbuf) == -1) + goto done; + } if (m) { -#ifdef BUILTIN_ELF - if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 && - nb > 5 && fd != -1) { - /* - * We matched something in the file, so this - * *might* be an ELF file, and the file is at - * least 5 bytes long, so if it's an ELF file - * it has at least one byte past the ELF magic - * number - try extracting information from the - * ELF headers that cannot easily * be - * extracted with rules in the magic file. - */ - m = file_tryelf(ms, &b); - if ((ms->flags & MAGIC_DEBUG) != 0) - (void)fprintf(stderr, "[try elf %d]\n", - m); - } -#endif if (checkdone(ms, &rv)) goto done; } @@ -318,6 +332,7 @@ simple: #if HAVE_FORK done_encoding: #endif + free(rbuf); buffer_fini(&b); if (rv) return rv; diff --git a/src/readcdf.c b/src/readcdf.c index 51b862cf168a..4b86e6fed08d 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.66 2017/11/02 20:25:39 christos Exp $") +FILE_RCSID("@(#)$File: readcdf.c,v 1.67 2018/04/15 19:57:07 christos Exp $") #endif #include <assert.h> @@ -147,118 +147,118 @@ private int cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, size_t count, const cdf_directory_t *root_storage) { - size_t i; - cdf_timestamp_t tp; - struct timespec ts; - char buf[64]; - const char *str = NULL; - const char *s, *e; - int len; - - if (!NOTMIME(ms) && root_storage) + size_t i; + cdf_timestamp_t tp; + struct timespec ts; + char buf[64]; + const char *str = NULL; + const char *s, *e; + int len; + + if (!NOTMIME(ms) && root_storage) str = cdf_clsid_to_mime(root_storage->d_storage_uuid, clsid2mime); - for (i = 0; i < count; i++) { - cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); - switch (info[i].pi_type) { - case CDF_NULL: - break; - case CDF_SIGNED16: - if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, - info[i].pi_s16) == -1) - return -1; - break; - case CDF_SIGNED32: - if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, - info[i].pi_s32) == -1) - return -1; - break; - case CDF_UNSIGNED32: - if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, - info[i].pi_u32) == -1) - return -1; - break; - case CDF_FLOAT: - if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, - info[i].pi_f) == -1) - return -1; - break; - case CDF_DOUBLE: - if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, - info[i].pi_d) == -1) - return -1; - break; - case CDF_LENGTH32_STRING: - case CDF_LENGTH32_WSTRING: - len = info[i].pi_str.s_len; - if (len > 1) { - char vbuf[1024]; - size_t j, k = 1; - - if (info[i].pi_type == CDF_LENGTH32_WSTRING) - k++; - s = info[i].pi_str.s_buf; + for (i = 0; i < count; i++) { + cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); + switch (info[i].pi_type) { + case CDF_NULL: + break; + case CDF_SIGNED16: + if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, + info[i].pi_s16) == -1) + return -1; + break; + case CDF_SIGNED32: + if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, + info[i].pi_s32) == -1) + return -1; + break; + case CDF_UNSIGNED32: + if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, + info[i].pi_u32) == -1) + return -1; + break; + case CDF_FLOAT: + if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, + info[i].pi_f) == -1) + return -1; + break; + case CDF_DOUBLE: + if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, + info[i].pi_d) == -1) + return -1; + break; + case CDF_LENGTH32_STRING: + case CDF_LENGTH32_WSTRING: + len = info[i].pi_str.s_len; + if (len > 1) { + char vbuf[1024]; + size_t j, k = 1; + + if (info[i].pi_type == CDF_LENGTH32_WSTRING) + k++; + s = info[i].pi_str.s_buf; e = info[i].pi_str.s_buf + len; - for (j = 0; s < e && j < sizeof(vbuf) + for (j = 0; s < e && j < sizeof(vbuf) && len--; s += k) { - if (*s == '\0') - break; - if (isprint((unsigned char)*s)) - vbuf[j++] = *s; - } - if (j == sizeof(vbuf)) - --j; - vbuf[j] = '\0'; - if (NOTMIME(ms)) { - if (vbuf[0]) { - if (file_printf(ms, ", %s: %s", - buf, vbuf) == -1) - return -1; - } - } else if (str == NULL && info[i].pi_id == + if (*s == '\0') + break; + if (isprint((unsigned char)*s)) + vbuf[j++] = *s; + } + if (j == sizeof(vbuf)) + --j; + vbuf[j] = '\0'; + if (NOTMIME(ms)) { + if (vbuf[0]) { + if (file_printf(ms, ", %s: %s", + buf, vbuf) == -1) + return -1; + } + } else if (str == NULL && info[i].pi_id == CDF_PROPERTY_NAME_OF_APPLICATION) { str = cdf_app_to_mime(vbuf, app2mime); } } - break; - case CDF_FILETIME: - tp = info[i].pi_tp; - if (tp != 0) { + break; + case CDF_FILETIME: + tp = info[i].pi_tp; + if (tp != 0) { char tbuf[64]; - if (tp < 1000000000000000LL) { - cdf_print_elapsed_time(tbuf, - sizeof(tbuf), tp); - if (NOTMIME(ms) && file_printf(ms, - ", %s: %s", buf, tbuf) == -1) - return -1; - } else { - char *c, *ec; - cdf_timestamp_to_timespec(&ts, tp); - c = cdf_ctime(&ts.tv_sec, tbuf); - if (c != NULL && + if (tp < 1000000000000000LL) { + cdf_print_elapsed_time(tbuf, + sizeof(tbuf), tp); + if (NOTMIME(ms) && file_printf(ms, + ", %s: %s", buf, tbuf) == -1) + return -1; + } else { + char *c, *ec; + cdf_timestamp_to_timespec(&ts, tp); + c = cdf_ctime(&ts.tv_sec, tbuf); + if (c != NULL && (ec = strchr(c, '\n')) != NULL) *ec = '\0'; - if (NOTMIME(ms) && file_printf(ms, - ", %s: %s", buf, c) == -1) - return -1; - } - } - break; - case CDF_CLIPBOARD: - break; - default: - return -1; - } - } - if (!NOTMIME(ms)) { + if (NOTMIME(ms) && file_printf(ms, + ", %s: %s", buf, c) == -1) + return -1; + } + } + break; + case CDF_CLIPBOARD: + break; + default: + return -1; + } + } + if (!NOTMIME(ms)) { if (str == NULL) return 0; - if (file_printf(ms, "application/%s", str) == -1) - return -1; - } - return 1; + if (file_printf(ms, "application/%s", str) == -1) + return -1; + } + return 1; } private int @@ -270,7 +270,7 @@ cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h, char buf[256]; cdf_catalog_entry_t *ce; - if (NOTMIME(ms)) { + if (NOTMIME(ms)) { if (file_printf(ms, "Microsoft Thumbs.db [") == -1) return -1; if (cdf_unpack_catalog(h, sst, &cat) == -1) @@ -296,44 +296,44 @@ private int cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, const cdf_stream_t *sst, const cdf_directory_t *root_storage) { - cdf_summary_info_header_t si; - cdf_property_info_t *info; - size_t count; - int m; + cdf_summary_info_header_t si; + cdf_property_info_t *info; + size_t count; + int m; - if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1) - return -1; + if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1) + return -1; - if (NOTMIME(ms)) { + if (NOTMIME(ms)) { const char *str; - if (file_printf(ms, "Composite Document File V2 Document") + if (file_printf(ms, "Composite Document File V2 Document") == -1) - return -1; - - if (file_printf(ms, ", %s Endian", - si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) - return -2; - switch (si.si_os) { - case 2: - if (file_printf(ms, ", Os: Windows, Version %d.%d", - si.si_os_version & 0xff, - (uint32_t)si.si_os_version >> 8) == -1) - return -2; - break; - case 1: - if (file_printf(ms, ", Os: MacOS, Version %d.%d", - (uint32_t)si.si_os_version >> 8, - si.si_os_version & 0xff) == -1) - return -2; - break; - default: - if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, - si.si_os_version & 0xff, - (uint32_t)si.si_os_version >> 8) == -1) - return -2; - break; - } + return -1; + + if (file_printf(ms, ", %s Endian", + si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) + return -2; + switch (si.si_os) { + case 2: + if (file_printf(ms, ", Os: Windows, Version %d.%d", + si.si_os_version & 0xff, + (uint32_t)si.si_os_version >> 8) == -1) + return -2; + break; + case 1: + if (file_printf(ms, ", Os: MacOS, Version %d.%d", + (uint32_t)si.si_os_version >> 8, + si.si_os_version & 0xff) == -1) + return -2; + break; + default: + if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, + si.si_os_version & 0xff, + (uint32_t)si.si_os_version >> 8) == -1) + return -2; + break; + } if (root_storage) { str = cdf_clsid_to_mime(root_storage->d_storage_uuid, clsid2desc); @@ -344,10 +344,10 @@ cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, } } - m = cdf_file_property_info(ms, info, count, root_storage); - free(info); + m = cdf_file_property_info(ms, info, count, root_storage); + free(info); - return m == -1 ? -2 : m; + return m == -1 ? -2 : m; } #ifdef notdef @@ -395,10 +395,10 @@ cdf_check_summary_info(struct magic_set *ms, const cdf_info_t *info, size_t j, k; #ifdef CDF_DEBUG - cdf_dump_summary_info(h, scn); + cdf_dump_summary_info(h, scn); #endif - if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) { - *expn = "Can't expand summary_info"; + if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) { + *expn = "Can't expand summary_info"; return i; } if (i == 1) @@ -542,55 +542,55 @@ 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; - cdf_stream_t sst, scn; - cdf_dir_t dir; - int i; - const char *expn = ""; - const cdf_directory_t *root_storage; - - scn.sst_tab = NULL; - info.i_fd = fd; - info.i_buf = buf; - info.i_len = nbytes; - if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) - return 0; - if (cdf_read_header(&info, &h) == -1) - return 0; + cdf_info_t info; + cdf_header_t h; + cdf_sat_t sat, ssat; + cdf_stream_t sst, scn; + cdf_dir_t dir; + int i; + const char *expn = ""; + const cdf_directory_t *root_storage; + + scn.sst_tab = NULL; + info.i_fd = fd; + info.i_buf = buf; + info.i_len = nbytes; + if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) + return 0; + if (cdf_read_header(&info, &h) == -1) + return 0; #ifdef CDF_DEBUG - cdf_dump_header(&h); + cdf_dump_header(&h); #endif - if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { - expn = "Can't read SAT"; - goto out0; - } + if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { + expn = "Can't read SAT"; + goto out0; + } #ifdef CDF_DEBUG - cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); + cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); #endif - if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { - expn = "Can't read SSAT"; - goto out1; - } + if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { + expn = "Can't read SSAT"; + goto out1; + } #ifdef CDF_DEBUG - cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); + cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); #endif - if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { - expn = "Can't read directory"; - goto out2; - } + if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { + expn = "Can't read directory"; + goto out2; + } - if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst, + if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root_storage)) == -1) { - expn = "Cannot read short stream"; - goto out3; - } + expn = "Cannot read short stream"; + goto out3; + } #ifdef CDF_DEBUG - cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); + cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); #endif #ifdef notdef if (root_storage) { @@ -625,10 +625,10 @@ file_trycdf(struct magic_set *ms, const struct buffer *b) } } - if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, - &scn)) == -1) { - if (errno != ESRCH) { - expn = "Cannot read summary info"; + if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, + &scn)) == -1) { + if (errno != ESRCH) { + expn = "Cannot read summary info"; } } else { i = cdf_check_summary_info(ms, &info, &h, @@ -655,11 +655,11 @@ out5: cdf_zero_stream(&scn); cdf_zero_stream(&sst); out3: - free(dir.dir_tab); + free(dir.dir_tab); out2: - free(ssat.sat_tab); + free(ssat.sat_tab); out1: - free(sat.sat_tab); + free(sat.sat_tab); out0: if (i == -1) { if (NOTMIME(ms)) { @@ -675,5 +675,5 @@ out0: } i = 1; } - return i; + return i; } diff --git a/src/readelf.c b/src/readelf.c index 3df0836d7029..db0b35a506a7 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.141 2018/04/12 16:50:52 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.144 2018/07/08 23:37:33 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -62,13 +62,12 @@ private uint64_t getu64(int, uint64_t); #define MAX_PHNUM 128 #define MAX_SHNUM 32768 -#define SIZE_UNKNOWN ((off_t)-1) +#define SIZE_UNKNOWN CAST(off_t, -1) private int toomany(struct magic_set *ms, const char *name, uint16_t num) { - if (file_printf(ms, ", too many %s (%u)", name, num - ) == -1) + if (file_printf(ms, ", too many %s (%u)", name, num) == -1) return -1; return 0; } @@ -143,54 +142,55 @@ getu64(int swap, uint64_t value) #define elf_getu64(swap, value) getu64(swap, value) #define xsh_addr (clazz == ELFCLASS32 \ - ? (void *)&sh32 \ - : (void *)&sh64) + ? CAST(void *, &sh32) \ + : CAST(void *, &sh64)) #define xsh_sizeof (clazz == ELFCLASS32 \ ? sizeof(sh32) \ : sizeof(sh64)) -#define xsh_size (size_t)(clazz == ELFCLASS32 \ +#define xsh_size CAST(size_t, (clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_size) \ - : elf_getu64(swap, sh64.sh_size)) -#define xsh_offset (off_t)(clazz == ELFCLASS32 \ + : elf_getu64(swap, sh64.sh_size))) +#define xsh_offset CAST(off_t, (clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_offset) \ - : elf_getu64(swap, sh64.sh_offset)) + : elf_getu64(swap, sh64.sh_offset))) #define xsh_type (clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_type) \ : elf_getu32(swap, sh64.sh_type)) #define xsh_name (clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_name) \ : elf_getu32(swap, sh64.sh_name)) + #define xph_addr (clazz == ELFCLASS32 \ - ? (void *) &ph32 \ - : (void *) &ph64) + ? CAST(void *, &ph32) \ + : CAST(void *, &ph64)) #define xph_sizeof (clazz == ELFCLASS32 \ ? sizeof(ph32) \ : sizeof(ph64)) #define xph_type (clazz == ELFCLASS32 \ ? elf_getu32(swap, ph32.p_type) \ : elf_getu32(swap, ph64.p_type)) -#define xph_offset (off_t)(clazz == ELFCLASS32 \ +#define xph_offset CAST(off_t, (clazz == ELFCLASS32 \ ? elf_getu32(swap, ph32.p_offset) \ - : elf_getu64(swap, ph64.p_offset)) -#define xph_align (size_t)((clazz == ELFCLASS32 \ - ? (off_t) (ph32.p_align ? \ - 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_getu64(swap, ph64.p_offset))) +#define xph_align CAST(size_t, (clazz == ELFCLASS32 \ + ? CAST(off_t, (ph32.p_align ? \ + elf_getu32(swap, ph32.p_align) : 4))\ + : CAST(off_t, (ph64.p_align ? \ + elf_getu64(swap, ph64.p_align) : 4)))) +#define xph_vaddr CAST(size_t, (clazz == ELFCLASS32 \ + ? CAST(off_t, (ph32.p_vaddr ? \ + elf_getu32(swap, ph32.p_vaddr) : 4))\ + : CAST(off_t, (ph64.p_vaddr ? \ + elf_getu64(swap, ph64.p_vaddr) : 4)))) +#define xph_filesz CAST(size_t, (clazz == ELFCLASS32 \ ? elf_getu32(swap, ph32.p_filesz) \ : elf_getu64(swap, ph64.p_filesz))) -#define xnh_addr (clazz == ELFCLASS32 \ - ? (void *)&nh32 \ - : (void *)&nh64) -#define xph_memsz (size_t)((clazz == ELFCLASS32 \ +#define xph_memsz CAST(size_t, ((clazz == ELFCLASS32 \ ? elf_getu32(swap, ph32.p_memsz) \ - : elf_getu64(swap, ph64.p_memsz))) + : elf_getu64(swap, ph64.p_memsz)))) +#define xnh_addr (clazz == ELFCLASS32 \ + ? CAST(void *, &nh32) \ + : CAST(void *, &nh64)) #define xnh_sizeof (clazz == ELFCLASS32 \ ? sizeof(nh32) \ : sizeof(nh64)) @@ -203,24 +203,36 @@ getu64(int swap, uint64_t value) #define xnh_descsz (clazz == ELFCLASS32 \ ? elf_getu32(swap, nh32.n_descsz) \ : elf_getu32(swap, nh64.n_descsz)) -#define prpsoffsets(i) (clazz == ELFCLASS32 \ - ? prpsoffsets32[i] \ - : prpsoffsets64[i]) + +#define xdh_addr (clazz == ELFCLASS32 \ + ? CAST(void *, &dh32) \ + : CAST(void *, &dh64)) +#define xdh_sizeof (clazz == ELFCLASS32 \ + ? sizeof(dh32) \ + : sizeof(dh64)) +#define xdh_tag (clazz == ELFCLASS32 \ + ? elf_getu32(swap, dh32.d_tag) \ + : elf_getu64(swap, dh64.d_tag)) +#define xdh_val (clazz == ELFCLASS32 \ + ? elf_getu32(swap, dh32.d_un.d_val) \ + : elf_getu64(swap, dh64.d_un.d_val)) + #define xcap_addr (clazz == ELFCLASS32 \ - ? (void *)&cap32 \ - : (void *)&cap64) + ? CAST(void *, &cap32) \ + : CAST(void *, &cap64)) #define xcap_sizeof (clazz == ELFCLASS32 \ - ? sizeof cap32 \ - : sizeof cap64) + ? sizeof(cap32) \ + : sizeof(cap64)) #define xcap_tag (clazz == ELFCLASS32 \ ? elf_getu32(swap, cap32.c_tag) \ : elf_getu64(swap, cap64.c_tag)) #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) + ? CAST(void *, &auxv32) \ + : CAST(void *, &auxv64)) #define xauxv_sizeof (clazz == ELFCLASS32 \ ? sizeof(auxv32) \ : sizeof(auxv64)) @@ -231,6 +243,10 @@ getu64(int swap, uint64_t value) ? elf_getu32(swap, auxv32.a_v) \ : elf_getu64(swap, auxv64.a_v)) +#define prpsoffsets(i) (clazz == ELFCLASS32 \ + ? prpsoffsets32[i] \ + : prpsoffsets64[i]) + #ifdef ELFCORE /* * Try larger offsets first to avoid false matches @@ -266,8 +282,8 @@ static const size_t prpsoffsets64[] = { 16, /* FreeBSD, 64-bit */ }; -#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) -#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) +#define NOFFSETS32 (sizeof(prpsoffsets32) / sizeof(prpsoffsets32[0])) +#define NOFFSETS64 (sizeof(prpsoffsets64) / sizeof(prpsoffsets64[0])) #define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) @@ -346,7 +362,8 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, * Loop through all the program headers. */ for ( ; num; num--) { - if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { + if (pread(fd, xph_addr, xph_sizeof, off) < + CAST(ssize_t, xph_sizeof)) { file_badread(ms); return -1; } @@ -389,7 +406,7 @@ static void do_note_netbsd_version(struct magic_set *ms, int swap, void *v) { uint32_t desc; - (void)memcpy(&desc, v, sizeof(desc)); + memcpy(&desc, v, sizeof(desc)); desc = elf_getu32(swap, desc); if (file_printf(ms, ", for NetBSD") == -1) @@ -435,7 +452,7 @@ do_note_freebsd_version(struct magic_set *ms, int swap, void *v) { uint32_t desc; - (void)memcpy(&desc, v, sizeof(desc)); + memcpy(&desc, v, sizeof(desc)); desc = elf_getu32(swap, desc); if (file_printf(ms, ", for FreeBSD") == -1) return; @@ -533,12 +550,19 @@ do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, } if (file_printf(ms, ", BuildID[%s]=", btype) == -1) return 1; - (void)memcpy(desc, &nbuf[doff], descsz); + memcpy(desc, &nbuf[doff], descsz); for (i = 0; i < descsz; i++) if (file_printf(ms, "%02x", desc[i]) == -1) return 1; return 1; } + if (namesz == 4 && strcmp((char *)&nbuf[noff], "Go") == 0 && + type == NT_GO_BUILD_ID && descsz < 128) { + if (file_printf(ms, ", Go BuildID=%s", + (char *)&nbuf[doff]) == -1) + return 1; + return 1; + } return 0; } @@ -557,7 +581,7 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && type == NT_GNU_VERSION && descsz == 16) { uint32_t desc[4]; - (void)memcpy(desc, &nbuf[doff], sizeof(desc)); + memcpy(desc, &nbuf[doff], sizeof(desc)); *flags |= FLAGS_DID_OS_NOTE; if (file_printf(ms, ", for GNU/") == -1) @@ -624,7 +648,7 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, *flags |= FLAGS_DID_OS_NOTE; if (file_printf(ms, ", for DragonFly") == -1) return 1; - (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); + memcpy(&desc, &nbuf[doff], sizeof(desc)); desc = elf_getu32(swap, desc); if (file_printf(ms, " %d.%d.%d", desc / 100000, desc / 10000 % 10, desc % 10000) == -1) @@ -654,7 +678,7 @@ do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, int did = 0; *flags |= FLAGS_DID_NETBSD_PAX; - (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); + memcpy(&desc, &nbuf[doff], sizeof(desc)); desc = elf_getu32(swap, desc); if (desc && file_printf(ms, ", PaX: ") == -1) @@ -825,7 +849,8 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, cname = (unsigned char *) &nbuf[doff + prpsoffsets(i)]; - for (cp = cname; *cp && isprint(*cp); cp++) + for (cp = cname; cp < nbuf + size && *cp + && isprint(*cp); cp++) continue; /* * Linux apparently appends a space at the end @@ -953,7 +978,7 @@ do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, nval = 0; for (size_t off = 0; off + elsize <= descsz; off += elsize) { - (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof); + 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"); @@ -1018,6 +1043,38 @@ do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, } private size_t +dodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size, + int clazz, int swap) +{ + Elf32_Dyn dh32; + Elf64_Dyn dh64; + unsigned char *dbuf = CAST(unsigned char *, vbuf); + + if (xdh_sizeof + offset > size) { + /* + * We're out of note headers. + */ + return xdh_sizeof + offset; + } + + memcpy(xdh_addr, &dbuf[offset], xdh_sizeof); + offset += xdh_sizeof; + + switch (xdh_tag) { + case DT_FLAGS_1: + if (xdh_val == DF_1_PIE) + ms->mode |= 0111; + else + ms->mode &= ~0111; + break; + default: + break; + } + return offset; +} + + +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 fd, off_t ph_off, int ph_num, off_t fsize) @@ -1039,7 +1096,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, return xnh_sizeof + offset; } - (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); + memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); offset += xnh_sizeof; namesz = xnh_namesz; @@ -1053,14 +1110,14 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, } if (namesz & 0x80000000) { - (void)file_printf(ms, ", bad note name size %#lx", - (unsigned long)namesz); + file_printf(ms, ", bad note name size %#lx", + CAST(unsigned long, namesz)); return 0; } if (descsz & 0x80000000) { - (void)file_printf(ms, ", bad note description size %#lx", - (unsigned long)descsz); + file_printf(ms, ", bad note description size %#lx", + CAST(unsigned long, descsz)); return 0; } @@ -1114,35 +1171,25 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, return offset; } - if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { + if (namesz == 7 && strcmp(CAST(char *, &nbuf[noff]), "NetBSD") == 0) { + int descw, flag; + const char *str, *tag; if (descsz > 100) descsz = 100; switch (xnh_type) { case NT_NETBSD_VERSION: return offset; case NT_NETBSD_MARCH: - if (*flags & FLAGS_DID_NETBSD_MARCH) - return offset; - *flags |= FLAGS_DID_NETBSD_MARCH; - if (file_printf(ms, ", compiled for: %.*s", - (int)descsz, (const char *)&nbuf[doff]) == -1) - return offset; + flag = FLAGS_DID_NETBSD_MARCH; + tag = "compiled for"; break; case NT_NETBSD_CMODEL: - if (*flags & FLAGS_DID_NETBSD_CMODEL) - return offset; - *flags |= FLAGS_DID_NETBSD_CMODEL; - if (file_printf(ms, ", compiler model: %.*s", - (int)descsz, (const char *)&nbuf[doff]) == -1) - return offset; + flag = FLAGS_DID_NETBSD_CMODEL; + tag = "compiler model"; 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; + flag = FLAGS_DID_NETBSD_EMULATION; + tag = "emulation:"; break; default: if (*flags & FLAGS_DID_NETBSD_UNKNOWN) @@ -1150,8 +1197,15 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, *flags |= FLAGS_DID_NETBSD_UNKNOWN; if (file_printf(ms, ", note=%u", xnh_type) == -1) return offset; - break; + return offset; } + + if (*flags & flag) + return offset; + str = CAST(const char *, &nbuf[doff]); + descw = CAST(int, descsz); + *flags |= flag; + file_printf(ms, ", %s: %.*s", tag, descw, str); return offset; } @@ -1232,7 +1286,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, /* Read offset of name section to be able to read section names later */ if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab))) - < (ssize_t)xsh_sizeof) { + < CAST(ssize_t, xsh_sizeof)) { if (file_printf(ms, ", missing section headers") == -1) return -1; return 0; @@ -1241,7 +1295,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, for ( ; num; num--) { /* Read the name of this section. */ - if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) { + if ((namesize = pread(fd, name, sizeof(name) - 1, + name_off + xsh_name)) == -1) { file_badread(ms); return -1; } @@ -1251,7 +1306,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, stripped = 0; } - if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) { + if (pread(fd, xsh_addr, xsh_sizeof, off) < + CAST(ssize_t, xsh_sizeof)) { file_badread(ms); return -1; } @@ -1277,14 +1333,15 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, /* Things we can determine when we seek */ switch (xsh_type) { case SHT_NOTE: - if ((uintmax_t)(xsh_size + xsh_offset) > - (uintmax_t)fsize) { + if (CAST(uintmax_t, (xsh_size + xsh_offset)) > + CAST(uintmax_t, fsize)) { if (file_printf(ms, ", note offset/size %#" INTMAX_T_FORMAT "x+%#" INTMAX_T_FORMAT "x exceeds" " file size %#" INTMAX_T_FORMAT "x", - (uintmax_t)xsh_offset, (uintmax_t)xsh_size, - (uintmax_t)fsize) == -1) + CAST(uintmax_t, xsh_offset), + CAST(uintmax_t, xsh_size), + CAST(uintmax_t, fsize)) == -1) return -1; return 0; } @@ -1294,7 +1351,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, return -1; } if (pread(fd, nbuf, xsh_size, xsh_offset) < - (ssize_t)xsh_size) { + CAST(ssize_t, xsh_size)) { file_badread(ms); free(nbuf); return -1; @@ -1302,9 +1359,9 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, noff = 0; for (;;) { - if (noff >= (off_t)xsh_size) + if (noff >= CAST(off_t, xsh_size)) break; - noff = donote(ms, nbuf, (size_t)noff, + noff = donote(ms, nbuf, CAST(size_t, noff), xsh_size, clazz, swap, 4, flags, notecount, fd, 0, 0, 0); if (noff == 0) @@ -1326,7 +1383,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, if (nbadcap > 5) break; - if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) { + if (lseek(fd, xsh_offset, SEEK_SET) + == CAST(off_t, -1)) { file_badseek(ms); return -1; } @@ -1335,11 +1393,12 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, Elf32_Cap cap32; Elf64_Cap cap64; char cbuf[/*CONSTCOND*/ - MAX(sizeof cap32, sizeof cap64)]; - if ((coff += xcap_sizeof) > (off_t)xsh_size) + MAX(sizeof(cap32), sizeof(cap64))]; + if ((coff += xcap_sizeof) > + CAST(off_t, xsh_size)) break; - if (read(fd, cbuf, (size_t)xcap_sizeof) != - (ssize_t)xcap_sizeof) { + if (read(fd, cbuf, CAST(size_t, xcap_sizeof)) != + CAST(ssize_t, xcap_sizeof)) { file_badread(ms); return -1; } @@ -1373,7 +1432,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, #endif break; } - (void)memcpy(xcap_addr, cbuf, xcap_sizeof); + memcpy(xcap_addr, cbuf, xcap_sizeof); switch (xcap_tag) { case CA_SUNW_NULL: break; @@ -1388,8 +1447,9 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, ", with unknown capability " "%#" INT64_T_FORMAT "x = %#" INT64_T_FORMAT "x", - (unsigned long long)xcap_tag, - (unsigned long long)xcap_val) == -1) + CAST(unsigned long long, xcap_tag), + CAST(unsigned long long, xcap_val)) + == -1) return -1; if (nbadcap++ > 2) coff = xsh_size; @@ -1442,12 +1502,12 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, if (file_printf(ms, " unknown hardware capability %#" INT64_T_FORMAT "x", - (unsigned long long)cap_hw1) == -1) + CAST(unsigned long long, cap_hw1)) == -1) return -1; } else { if (file_printf(ms, " hardware capability %#" INT64_T_FORMAT "x", - (unsigned long long)cap_hw1) == -1) + CAST(unsigned long long, cap_hw1)) == -1) return -1; } } @@ -1464,7 +1524,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, if (file_printf(ms, ", with unknown software capability %#" INT64_T_FORMAT "x", - (unsigned long long)cap_sf1) == -1) + CAST(unsigned long long, cap_sf1)) == -1) return -1; } return 0; @@ -1483,9 +1543,9 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, Elf32_Phdr ph32; Elf64_Phdr ph64; const char *linking_style = "statically"; - const char *interp = ""; unsigned char nbuf[BUFSIZ]; char ibuf[BUFSIZ]; + char interp[BUFSIZ]; ssize_t bufsize; size_t offset, align, len; @@ -1495,8 +1555,11 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, return 0; } + interp[0] = '\0'; for ( ; num; num--) { - if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { + int doread; + if (pread(fd, xph_addr, xph_sizeof, off) < + CAST(ssize_t, xph_sizeof)) { file_badread(ms); return -1; } @@ -1509,6 +1572,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, switch (xph_type) { case PT_DYNAMIC: linking_style = "dynamically"; + doread = 1; break; case PT_NOTE: if (sh_num) /* Did this through section headers */ @@ -1517,21 +1581,16 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, align < 4) { if (file_printf(ms, ", invalid note alignment %#lx", - (unsigned long)align) == -1) + CAST(unsigned long, align)) == -1) return -1; align = 4; } /*FALLTHROUGH*/ case PT_INTERP: - len = xph_filesz < sizeof(nbuf) ? xph_filesz - : sizeof(nbuf); - bufsize = pread(fd, nbuf, len, xph_offset); - if (bufsize == -1) { - file_badread(ms); - return -1; - } + doread = 1; break; default: + doread = 0; if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { /* Maybe warn here? */ continue; @@ -1539,14 +1598,37 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, break; } + if (doread) { + len = xph_filesz < sizeof(nbuf) ? xph_filesz + : sizeof(nbuf); + bufsize = pread(fd, nbuf, len, xph_offset); + if (bufsize == -1) { + file_badread(ms); + return -1; + } + } else + len = 0; + /* Things we can determine when we seek */ switch (xph_type) { + case PT_DYNAMIC: + offset = 0; + for (;;) { + if (offset >= (size_t)bufsize) + break; + offset = dodynamic(ms, nbuf, offset, + CAST(size_t, bufsize), clazz, swap); + if (offset == 0) + break; + } + break; + case PT_INTERP: if (bufsize && nbuf[0]) { nbuf[bufsize - 1] = '\0'; - interp = (const char *)nbuf; + memcpy(interp, nbuf, bufsize); } else - interp = "*empty*"; + strlcpy(interp, "*empty*", sizeof(interp)); break; case PT_NOTE: /* @@ -1558,7 +1640,7 @@ dophn_exec(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, align, + CAST(size_t, bufsize), clazz, swap, align, flags, notecount, fd, 0, 0, 0); if (offset == 0) break; @@ -1587,7 +1669,7 @@ file_tryelf(struct magic_set *ms, const struct buffer *b) size_t nbytes = b->flen; union { int32_t l; - char c[sizeof (int32_t)]; + char c[sizeof(int32_t)]; } u; int clazz; int swap; @@ -1615,7 +1697,8 @@ file_tryelf(struct magic_set *ms, const struct buffer *b) /* * If we cannot seek, it must be a pipe, socket or fifo. */ - if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) + if((lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) + && (errno == ESPIPE)) fd = file_pipe2file(ms, fd, buf, nbytes); if (fstat(fd, &st) == -1) { diff --git a/src/readelf.h b/src/readelf.h index ef880b9cbe22..6ae63f2d950d 100644 --- a/src/readelf.h +++ b/src/readelf.h @@ -356,6 +356,15 @@ typedef struct { #define NT_NETBSD_CMODEL 6 /* + * Golang-specific note type + * name: Go\0\0 + * namesz: 4 + * desc: base-64 build id. + * descsz: < 128 + */ +#define NT_GO_BUILD_ID 4 + +/* * FreeBSD specific notes */ #define NT_FREEBSD_PROCSTAT_AUXV 16 @@ -430,4 +439,107 @@ typedef struct { #define AV_386_SSE4_1 0x00800000 #define AV_386_SSE4_2 0x01000000 +/* + * Dynamic Section structure array + */ +typedef struct { + Elf32_Word d_tag; /* entry tag value */ + union { + Elf32_Addr d_ptr; + Elf32_Word d_val; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Xword d_tag; /* entry tag value */ + union { + Elf64_Addr d_ptr; + Elf64_Xword d_val; + } d_un; +} Elf64_Dyn; + +/* d_tag */ +#define DT_NULL 0 /* Marks end of dynamic array */ +#define DT_NEEDED 1 /* Name of needed library (DT_STRTAB offset) */ +#define DT_PLTRELSZ 2 /* Size, in bytes, of relocations in PLT */ +#define DT_PLTGOT 3 /* Address of PLT and/or GOT */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocation table */ +#define DT_RELASZ 8 /* Size, in bytes, of DT_RELA table */ +#define DT_RELAENT 9 /* Size, in bytes, of one DT_RELA entry */ +#define DT_STRSZ 10 /* Size, in bytes, of DT_STRTAB table */ +#define DT_SYMENT 11 /* Size, in bytes, of one DT_SYMTAB entry */ +#define DT_INIT 12 /* Address of initialization function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Shared object name (DT_STRTAB offset) */ +#define DT_RPATH 15 /* Library search path (DT_STRTAB offset) */ +#define DT_SYMBOLIC 16 /* Start symbol search within local object */ +#define DT_REL 17 /* Address of Rel relocation table */ +#define DT_RELSZ 18 /* Size, in bytes, of DT_REL table */ +#define DT_RELENT 19 /* Size, in bytes, of one DT_REL entry */ +#define DT_PLTREL 20 /* Type of PLT relocation entries */ +#define DT_DEBUG 21 /* Used for debugging; unspecified */ +#define DT_TEXTREL 22 /* Relocations might modify non-writable seg */ +#define DT_JMPREL 23 /* Address of relocations associated with PLT */ +#define DT_BIND_NOW 24 /* Process all relocations at load-time */ +#define DT_INIT_ARRAY 25 /* Address of initialization function array */ +#define DT_FINI_ARRAY 26 /* Size, in bytes, of DT_INIT_ARRAY array */ +#define DT_INIT_ARRAYSZ 27 /* Address of termination function array */ +#define DT_FINI_ARRAYSZ 28 /* Size, in bytes, of DT_FINI_ARRAY array*/ +#define DT_RUNPATH 29 /* overrides DT_RPATH */ +#define DT_FLAGS 30 /* Encodes ORIGIN, SYMBOLIC, TEXTREL, BIND_NOW, STATIC_TLS */ +#define DT_ENCODING 31 /* ??? */ +#define DT_PREINIT_ARRAY 32 /* Address of pre-init function array */ +#define DT_PREINIT_ARRAYSZ 33 /* Size, in bytes, of DT_PREINIT_ARRAY array */ +#define DT_NUM 34 + +#define DT_LOOS 0x60000000 /* Operating system specific range */ +#define DT_VERSYM 0x6ffffff0 /* Symbol versions */ +#define DT_FLAGS_1 0x6ffffffb /* ELF dynamic flags */ +#define DT_VERDEF 0x6ffffffc /* Versions defined by file */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of versions defined by file */ +#define DT_VERNEED 0x6ffffffe /* Versions needed by file */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of versions needed by file */ +#define DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 /* Processor-specific range */ +#define DT_HIPROC 0x7fffffff + +/* Flag values for DT_FLAGS */ +#define DF_ORIGIN 0x00000001 /* uses $ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* */ +#define DF_TEXTREL 0x00000004 /* */ +#define DF_BIND_NOW 0x00000008 /* */ +#define DF_STATIC_TLS 0x00000010 /* */ + +/* Flag values for DT_FLAGS_1 */ +#define DF_1_NOW 0x00000001 /* Same as DF_BIND_NOW */ +#define DF_1_GLOBAL 0x00000002 /* Unused */ +#define DF_1_GROUP 0x00000004 /* Is member of group */ +#define DF_1_NODELETE 0x00000008 /* Cannot be deleted from process */ +#define DF_1_LOADFLTR 0x00000010 /* Immediate loading of filters */ +#define DF_1_INITFIRST 0x00000020 /* init/fini takes priority */ +#define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */ +#define DF_1_ORIGIN 0x00000080 /* Require $ORIGIN processing */ +#define DF_1_DIRECT 0x00000100 /* Enable direct bindings */ +#define DF_1_INTERPOSE 0x00000400 /* Is an interposer */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default library search path */ +#define DF_1_NODUMP 0x00001000 /* Cannot be dumped with dldump(3C) */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative */ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee ends filter's search */ +#define DF_1_DISPRELDNE 0x00008000 /* Did displacement relocation */ +#define DF_1_DISPRELPND 0x00010000 /* Pending displacement relocation */ +#define DF_1_NODIRECT 0x00020000 /* Has non-direct bindings */ +#define DF_1_IGNMULDEF 0x00040000 /* Used internally */ +#define DF_1_NOKSYMS 0x00080000 /* Used internally */ +#define DF_1_NOHDR 0x00100000 /* Used internally */ +#define DF_1_EDITED 0x00200000 /* Has been modified since build */ +#define DF_1_NORELOC 0x00400000 /* Used internally */ +#define DF_1_SYMINTPOSE 0x00800000 /* Has individual symbol interposers */ +#define DF_1_GLOBAUDIT 0x01000000 /* Require global auditing */ +#define DF_1_SINGLETON 0x02000000 /* Has singleton symbols */ +#define DF_1_STUB 0x04000000 /* Stub */ +#define DF_1_PIE 0x08000000 /* Position Independent Executable */ + #endif diff --git a/src/seccomp.c b/src/seccomp.c index 7c8a31443b43..a5abb4a159f9 100644 --- a/src/seccomp.c +++ b/src/seccomp.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: seccomp.c,v 1.2 2017/11/04 01:14:25 christos Exp $") +FILE_RCSID("@(#)$File: seccomp.c,v 1.6 2018/06/26 20:29:29 christos Exp $") #endif /* lint */ #if HAVE_LIBSECCOMP @@ -59,12 +59,7 @@ 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) + if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) return -1; // initialize the filter @@ -169,15 +164,26 @@ enable_sandbox_full(void) ALLOW_RULE(exit); ALLOW_RULE(exit_group); ALLOW_RULE(fcntl); + ALLOW_RULE(fcntl64); ALLOW_RULE(fstat); + ALLOW_RULE(fstat64); ALLOW_RULE(getdents); +#ifdef __NR_getdents64 + ALLOW_RULE(getdents64); +#endif ALLOW_RULE(ioctl); ALLOW_RULE(lseek); + ALLOW_RULE(_llseek); ALLOW_RULE(lstat); + ALLOW_RULE(lstat64); ALLOW_RULE(mmap); + ALLOW_RULE(mmap2); ALLOW_RULE(mprotect); ALLOW_RULE(mremap); ALLOW_RULE(munmap); +#ifdef __NR_newfstatat + ALLOW_RULE(newfstatat); +#endif ALLOW_RULE(open); ALLOW_RULE(openat); ALLOW_RULE(pread64); @@ -188,6 +194,7 @@ enable_sandbox_full(void) ALLOW_RULE(rt_sigreturn); ALLOW_RULE(select); ALLOW_RULE(stat); + ALLOW_RULE(stat64); ALLOW_RULE(sysinfo); ALLOW_RULE(unlink); ALLOW_RULE(write); diff --git a/src/softmagic.c b/src/softmagic.c index 00d5aac6000f..9a5db9d3e2b3 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.259 2018/03/11 01:23:52 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.262 2018/06/22 20:39:50 christos Exp $") #endif /* lint */ #include "magic.h" @@ -53,8 +53,7 @@ private int mget(struct magic_set *, struct magic *, const struct buffer *, 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 *, - const struct buffer *); +private int32_t mprint(struct magic_set *, struct magic *); private int moffset(struct magic_set *, struct magic *, const struct buffer *, int32_t *); private void mdebug(uint32_t, const char *, size_t); @@ -62,8 +61,7 @@ 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 *, - const struct buffer *, int); +private int handle_annotation(struct magic_set *, struct magic *, 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 *); @@ -240,7 +238,7 @@ flush: goto flush; } - if ((e = handle_annotation(ms, m, b, firstline)) != 0) { + if ((e = handle_annotation(ms, m, firstline)) != 0) { *need_separator = 1; *printed_something = 1; *returnval = 1; @@ -258,7 +256,7 @@ flush: return -1; } - if (print && mprint(ms, m, b) == -1) + if (print && mprint(ms, m) == -1) return -1; switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) { @@ -339,7 +337,7 @@ flush: } else ms->c.li[cont_level].got_match = 1; - if ((e = handle_annotation(ms, m, b, firstline)) + if ((e = handle_annotation(ms, m, firstline)) != 0) { *need_separator = 1; *printed_something = 1; @@ -373,7 +371,7 @@ flush: return -1; *need_separator = 0; } - if (print && mprint(ms, m, b) == -1) + if (print && mprint(ms, m) == -1) return -1; switch (moffset(ms, m, &bb, @@ -433,8 +431,11 @@ check_fmt(struct magic_set *ms, const char *fmt) return rv; } -#ifndef HAVE_STRNDUP -char * strndup(const char *, size_t); +#if !defined(HAVE_STRNDUP) || defined(__aiws__) +# ifdef __aiws__ +# define strndup aix_strndup /* aix is broken */ +# endif +char *strndup(const char *, size_t); char * strndup(const char *str, size_t n) @@ -453,7 +454,7 @@ 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) +varexpand(struct magic_set *ms, char *buf, size_t len, const char *str) { const char *ptr, *sptr, *e, *t, *ee, *et; size_t l; @@ -478,7 +479,7 @@ varexpand(char *buf, size_t len, const struct buffer *b, const char *str) return -1; switch (*ptr) { case 'x': - if (b->st.st_mode & 0111) { + if (ms->mode & 0111) { ptr = t; l = et - t; } else { @@ -508,7 +509,7 @@ varexpand(char *buf, size_t len, const struct buffer *b, const char *str) private int32_t -mprint(struct magic_set *ms, struct magic *m, const struct buffer *b) +mprint(struct magic_set *ms, struct magic *m) { uint64_t v; float vf; @@ -518,7 +519,7 @@ mprint(struct magic_set *ms, struct magic *m, const struct buffer *b) const char *desc; union VALUETYPE *p = &ms->ms_value; - if (varexpand(ebuf, sizeof(ebuf), b, m->desc) == -1) + if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1) desc = m->desc; else desc = ebuf; @@ -1534,6 +1535,14 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, case FILE_MELONG: off = SEXT(sgn,32,ME32(q)); break; + case FILE_BEQUAD: + off = SEXT(sgn,64,BE64(q)); + break; + case FILE_LEQUAD: + off = SEXT(sgn,64,LE64(q)); + break; + default: + abort(); } if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect offs=%jd\n", off); @@ -1587,8 +1596,18 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, return 0; offset = do_ops(m, SEXT(sgn,32,p->l), off); break; - default: + case FILE_LEQUAD: + if (OFFSET_OOB(nbytes, offset, 8)) + return 0; + offset = do_ops(m, SEXT(sgn,64,LE64(p)), off); + break; + case FILE_BEQUAD: + if (OFFSET_OOB(nbytes, offset, 8)) + return 0; + offset = do_ops(m, SEXT(sgn,64,BE64(p)), off); break; + default: + abort(); } if (m->flag & INDIROFFADD) { @@ -2159,8 +2178,7 @@ magiccheck(struct magic_set *ms, struct magic *m) } private int -handle_annotation(struct magic_set *ms, struct magic *m, const struct buffer *b, - int firstline) +handle_annotation(struct magic_set *ms, struct magic *m, int firstline) { if ((ms->flags & MAGIC_APPLE) && m->apple[0]) { if (!firstline && file_printf(ms, "\n- ") == -1) @@ -2181,7 +2199,7 @@ handle_annotation(struct magic_set *ms, struct magic *m, const struct buffer *b, const char *p; if (!firstline && file_printf(ms, "\n- ") == -1) return -1; - if (varexpand(buf, sizeof(buf), b, m->mimetype) == -1) + if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1) p = m->mimetype; else p = buf; |