All of lore.kernel.org
 help / color / mirror / Atom feed
* [daisy][PATCH] file: CVE-2014-9620 and CVE-2014-9621
@ 2015-01-22  9:28 Chong Lu
  2015-01-30  1:18 ` Chong Lu
  2015-02-02 13:55 ` Saul Wold
  0 siblings, 2 replies; 5+ messages in thread
From: Chong Lu @ 2015-01-22  9:28 UTC (permalink / raw)
  To: openembedded-core

CVE-2014-9620:
Limit the number of ELF notes processed - DoS
CVE-2014-9621:
Limit string printing to 100 chars - DoS

The patch comes from:
https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67
https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6
https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33
https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba
https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9
https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7
https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f
https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4
https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c

[YOCTO #7178]

Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
---
 .../file-CVE-2014-9620-and-CVE-2014-9621.patch     | 1357 ++++++++++++++++++++
 meta/recipes-devtools/file/file_5.16.bb            |    1 +
 2 files changed, 1358 insertions(+)
 create mode 100644 meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch

diff --git a/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
new file mode 100644
index 0000000..bd5944e
--- /dev/null
+++ b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
@@ -0,0 +1,1357 @@
+file: CVE-2014-9620 and CVE-2014-9621
+
+The patch comes from:
+https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67
+https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6
+https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33
+https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba
+https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9
+https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7
+https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f
+https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4
+https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c
+
+Upstream-Status: Backport
+
+Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
+---
+ src/apprentice.c |    5 +
+ src/ascmagic.c   |    3 +-
+ src/elfclass.h   |   34 ++--
+ src/file.c       |   58 ++++++-
+ src/file.h       |   20 ++-
+ src/file_opts.h  |    6 +
+ src/funcs.c      |   42 ++++-
+ src/magic.c      |   50 ++++++
+ src/magic.h      |    9 ++
+ src/magic.h.in   |    4 +
+ src/readelf.c    |  467 +++++++++++++++++++++++++++++++++---------------------
+ src/softmagic.c  |   70 ++++----
+ 12 files changed, 541 insertions(+), 227 deletions(-)
+
+diff --git a/src/apprentice.c b/src/apprentice.c
+index 2df60d9..d906f7b 100644
+--- a/src/apprentice.c
++++ b/src/apprentice.c
+@@ -494,6 +494,11 @@ file_ms_alloc(int flags)
+ 		ms->mlist[i] = NULL;
+ 	ms->file = "unknown";
+ 	ms->line = 0;
++	ms->indir_max = FILE_INDIR_MAX;
++	ms->name_max = FILE_NAME_MAX;
++	ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
++	ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
++	ms->elf_notes_max = FILE_ELF_NOTES_MAX;
+ 	return ms;
+ free:
+ 	free(ms);
+diff --git a/src/ascmagic.c b/src/ascmagic.c
+index 28ebadc..7a22328 100644
+--- a/src/ascmagic.c
++++ b/src/ascmagic.c
+@@ -147,7 +147,8 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf,
+ 		    == NULL)
+ 			goto done;
+ 		if ((rv = file_softmagic(ms, utf8_buf,
+-		    (size_t)(utf8_end - utf8_buf), TEXTTEST, text)) == 0)
++		    (size_t)(utf8_end - utf8_buf), 0, NULL,
++		    TEXTTEST, text)) == 0)
+ 			rv = -1;
+ 	}
+ 
+diff --git a/src/elfclass.h b/src/elfclass.h
+index 010958a..5360b0b 100644
+--- a/src/elfclass.h
++++ b/src/elfclass.h
+@@ -32,39 +32,51 @@
+ 	swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
+ 
+ 	type = elf_getu16(swap, elfhdr.e_type);
++	notecount = ms->elf_notes_max;
+ 	switch (type) {
+ #ifdef ELFCORE
+ 	case ET_CORE:
++		phnum = elf_getu16(swap, elfhdr.e_phnum);
++		if (phnum > ms->elf_phnum_max)
++			return toomany(ms, "program headers", phnum);
+ 		flags |= FLAGS_IS_CORE;
+ 		if (dophn_core(ms, clazz, swap, fd,
+-		    (off_t)elf_getu(swap, elfhdr.e_phoff),
+-		    elf_getu16(swap, elfhdr.e_phnum), 
++		    (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
+ 		    (size_t)elf_getu16(swap, elfhdr.e_phentsize),
+-		    fsize, &flags) == -1)
++		    fsize, &flags, &notecount) == -1)
+ 			return -1;
+ 		break;
+ #endif
+ 	case ET_EXEC:
+ 	case ET_DYN:
++		phnum = elf_getu16(swap, elfhdr.e_phnum);
++		if (phnum > ms->elf_phnum_max)
++			return toomany(ms, "program", phnum);
++		shnum = elf_getu16(swap, elfhdr.e_shnum);
++		if (shnum > ms->elf_shnum_max)
++			return toomany(ms, "section", shnum);
+ 		if (dophn_exec(ms, clazz, swap, fd,
+-		    (off_t)elf_getu(swap, elfhdr.e_phoff),
+-		    elf_getu16(swap, elfhdr.e_phnum), 
++		    (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
+ 		    (size_t)elf_getu16(swap, elfhdr.e_phentsize),
+-		    fsize, &flags, elf_getu16(swap, elfhdr.e_shnum))
+-		    == -1)
++		    fsize, shnum, &flags, &notecount) == -1)
+ 			return -1;
+ 		/*FALLTHROUGH*/
+ 	case ET_REL:
++		shnum = elf_getu16(swap, elfhdr.e_shnum);
++		if (shnum > ms->elf_shnum_max)
++			return toomany(ms, "section headers", shnum);
+ 		if (doshn(ms, clazz, swap, fd,
+-		    (off_t)elf_getu(swap, elfhdr.e_shoff),
+-		    elf_getu16(swap, elfhdr.e_shnum),
++		    (off_t)elf_getu(swap, elfhdr.e_shoff), shnum,
+ 		    (size_t)elf_getu16(swap, elfhdr.e_shentsize),
+-		    fsize, &flags, elf_getu16(swap, elfhdr.e_machine),
+-		    (int)elf_getu16(swap, elfhdr.e_shstrndx)) == -1)
++		    fsize, elf_getu16(swap, elfhdr.e_machine),
++		    (int)elf_getu16(swap, elfhdr.e_shstrndx),
++		    &flags, &notecount) == -1)
+ 			return -1;
+ 		break;
+ 
+ 	default:
+ 		break;
+ 	}
++	if (notecount == 0)
++		return toomany(ms, "notes", ms->elf_notes_max);
+ 	return 1;
+diff --git a/src/file.c b/src/file.c
+index ac773ea..ee1edcd 100644
+--- a/src/file.c
++++ b/src/file.c
+@@ -101,7 +101,7 @@ private const struct option long_options[] = {
+ #undef OPT_LONGONLY
+     {0, 0, NULL, 0}
+ };
+-#define OPTSTRING	"bcCde:f:F:hiklLm:nNprsvz0"
++#define OPTSTRING	"bcCde:f:F:hiklLm:nNpP:rsvz0"
+ 
+ private const struct {
+ 	const char *name;
+@@ -119,6 +119,18 @@ private const struct {
+ 	{ "tokens",	MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */
+ };
+ 
++private struct {
++	const char *name;
++	int tag;
++	size_t value;
++} pm[] = {
++	{ "indir",	MAGIC_PARAM_INDIR_MAX, 0 },
++	{ "name",	MAGIC_PARAM_NAME_MAX, 0 },
++	{ "elf_phnum",	MAGIC_PARAM_ELF_PHNUM_MAX, 0 },
++	{ "elf_shnum",	MAGIC_PARAM_ELF_SHNUM_MAX, 0 },
++	{ "elf_notes",	MAGIC_PARAM_ELF_NOTES_MAX, 0 },
++};
++
+ private char *progname;		/* used throughout 		*/
+ 
+ private void usage(void);
+@@ -128,6 +140,8 @@ private void help(void);
+ private int unwrap(struct magic_set *, const char *);
+ private int process(struct magic_set *ms, const char *, int);
+ private struct magic_set *load(const char *, int);
++private void setparam(const char *);
++private void applyparam(magic_t);
+ 
+ 
+ /*
+@@ -240,6 +254,9 @@ main(int argc, char *argv[])
+ 			flags |= MAGIC_PRESERVE_ATIME;
+ 			break;
+ #endif
++		case 'P':
++			setparam(optarg);
++			break;
+ 		case 'r':
+ 			flags |= MAGIC_RAW;
+ 			break;
+@@ -295,6 +312,8 @@ main(int argc, char *argv[])
+ 			    strerror(errno));
+ 			return 1;
+ 		}
++
++
+ 		switch(action) {
+ 		case FILE_CHECK:
+ 			c = magic_check(magic, magicfile);
+@@ -318,7 +337,7 @@ main(int argc, char *argv[])
+ 		if (magic == NULL)
+ 			if ((magic = load(magicfile, flags)) == NULL)
+ 				return 1;
+-		break;
++		applyparam(magic);
+ 	}
+ 
+ 	if (optind == argc) {
+@@ -348,6 +367,41 @@ main(int argc, char *argv[])
+ 	return e;
+ }
+ 
++private void
++applyparam(magic_t magic)
++{
++	size_t i;
++
++	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);
++		}
++	}
++}
++
++private void
++setparam(const char *p)
++{
++	size_t i;
++	char *s;
++
++	if ((s = strchr(p, '=')) == NULL)
++		goto badparm;
++
++	for (i = 0; i < __arraycount(pm); i++) {
++		if (strncmp(p, pm[i].name, s - p) != 0)
++			continue;
++		pm[i].value = atoi(s + 1);
++		return;
++	}
++badparm:
++	(void)fprintf(stderr, "%s: Unknown param %s\n", progname, p);
++	exit(1);
++}
+ 
+ private struct magic_set *
+ /*ARGSUSED*/
+diff --git a/src/file.h b/src/file.h
+index e910a2b..57e7307 100644
+--- a/src/file.h
++++ b/src/file.h
+@@ -400,6 +400,16 @@ struct magic_set {
+ 	/* FIXME: Make the string dynamically allocated so that e.g.
+ 	   strings matched in files can be longer than MAXstring */
+ 	union VALUETYPE ms_value;	/* either number or string */
++	uint16_t indir_max;
++	uint16_t name_max;
++	uint16_t elf_shnum_max;
++	uint16_t elf_phnum_max;
++	uint16_t elf_notes_max;
++#define	FILE_INDIR_MAX			15
++#define	FILE_NAME_MAX			30
++#define	FILE_ELF_SHNUM_MAX		32768
++#define	FILE_ELF_PHNUM_MAX		128
++#define	FILE_ELF_NOTES_MAX		256
+ };
+ 
+ /* Type for Unicode characters */
+@@ -438,7 +448,7 @@ protected int file_encoding(struct magic_set *, const unsigned char *, size_t,
+     unichar **, size_t *, const char **, const char **, const char **);
+ protected int file_is_tar(struct magic_set *, const unsigned char *, size_t);
+ protected int file_softmagic(struct magic_set *, const unsigned char *, size_t,
+-    int, int);
++    uint16_t, uint16_t *, int, int);
+ protected int file_apprentice(struct magic_set *, const char *, int);
+ protected int file_magicfind(struct magic_set *, const char *, struct mlist *);
+ protected uint64_t file_signextend(struct magic_set *, struct magic *,
+@@ -468,6 +478,14 @@ protected int file_os2_apptype(struct magic_set *, const char *, const void *,
+ #endif /* __EMX__ */
+ 
+ 
++typedef struct {
++	char *buf;
++	uint32_t offset;
++} file_pushbuf_t;
++
++protected file_pushbuf_t *file_push_buffer(struct magic_set *);
++protected char  *file_pop_buffer(struct magic_set *, file_pushbuf_t *);
++
+ #ifndef COMPILE_ONLY
+ extern const char *file_names[];
+ extern const size_t file_nnames;
+diff --git a/src/file_opts.h b/src/file_opts.h
+index db34eb7..3286ac6 100644
+--- a/src/file_opts.h
++++ b/src/file_opts.h
+@@ -43,6 +43,12 @@ OPT('0', "print0", 0, "               terminate filenames with ASCII NUL\n")
+ #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
+ OPT('p', "preserve-date", 0, "        preserve access times on files\n")
+ #endif
++OPT('P', "parameter", 0, "            set file engine parameter limits\n"
++    "                               indir        15 recursion limit for indirection\n"
++    "                               name         30 use limit for name/use magic\n"
++    "                               elf_notes   256 max ELF notes processed\n"
++    "                               elf_phnum   128 max ELF prog sections processed\n"
++    "                               elf_shnum 32768 max ELF sections processed\n")
+ OPT('r', "raw", 0, "                  don't translate unprintable chars to \\ooo\n")
+ OPT('s', "special-files", 0, "        treat special (block/char devices) files as\n"
+     "                             ordinary ones\n")
+diff --git a/src/funcs.c b/src/funcs.c
+index b798e44..50c38e5 100644
+--- a/src/funcs.c
++++ b/src/funcs.c
+@@ -226,7 +226,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu
+ 
+ 	/* try soft magic tests */
+ 	if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
+-		if ((m = file_softmagic(ms, ubuf, nb, BINTEST,
++		if ((m = file_softmagic(ms, ubuf, nb, 0, NULL, BINTEST,
+ 		    looks_text)) != 0) {
+ 			if ((ms->flags & MAGIC_DEBUG) != 0)
+ 				(void)fprintf(stderr, "softmagic %d\n", m);
+@@ -459,3 +459,43 @@ file_replace(struct magic_set *ms, const char *pat, const char *rep)
+ 		return nm;
+ 	}
+ }
++
++protected file_pushbuf_t *
++file_push_buffer(struct magic_set *ms)
++{
++	file_pushbuf_t *pb;
++
++	if (ms->event_flags & EVENT_HAD_ERR)
++		return NULL;
++
++	if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
++		return NULL;
++
++	pb->buf = ms->o.buf;
++	pb->offset = ms->offset;
++
++	ms->o.buf = NULL;
++	ms->offset = 0;
++
++	return pb;
++}
++
++protected char *
++file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
++{
++	char *rbuf;
++
++	if (ms->event_flags & EVENT_HAD_ERR) {
++		free(pb->buf);
++		free(pb);
++		return NULL;
++	}
++
++	rbuf = ms->o.buf;
++
++	ms->o.buf = pb->buf;
++	ms->offset = pb->offset;
++
++	free(pb);
++	return rbuf;
++}
+diff --git a/src/magic.c b/src/magic.c
+index 22174b8..a89647c 100644
+--- a/src/magic.c
++++ b/src/magic.c
+@@ -490,3 +490,53 @@ magic_version(void)
+ {
+ 	return MAGIC_VERSION;
+ }
++
++public int
++magic_setparam(struct magic_set *ms, int param, const void *val)
++{
++	switch (param) {
++	case MAGIC_PARAM_INDIR_MAX:
++		ms->indir_max = *(const size_t *)val;
++		return 0;
++	case MAGIC_PARAM_NAME_MAX:
++		ms->name_max = *(const size_t *)val;
++		return 0;
++	case MAGIC_PARAM_ELF_PHNUM_MAX:
++		ms->elf_phnum_max = *(const size_t *)val;
++		return 0;
++	case MAGIC_PARAM_ELF_SHNUM_MAX:
++		ms->elf_shnum_max = *(const size_t *)val;
++		return 0;
++	case MAGIC_PARAM_ELF_NOTES_MAX:
++		ms->elf_notes_max = *(const size_t *)val;
++		return 0;
++	default:
++		errno = EINVAL;
++		return -1;
++	}
++}
++
++public int
++magic_getparam(struct magic_set *ms, int param, void *val)
++{
++	switch (param) {
++	case MAGIC_PARAM_INDIR_MAX:
++		*(size_t *)val = ms->indir_max;
++		return 0;
++	case MAGIC_PARAM_NAME_MAX:
++		*(size_t *)val = ms->name_max;
++		return 0;
++	case MAGIC_PARAM_ELF_PHNUM_MAX:
++		*(size_t *)val = ms->elf_phnum_max;
++		return 0;
++	case MAGIC_PARAM_ELF_SHNUM_MAX:
++		*(size_t *)val = ms->elf_shnum_max;
++		return 0;
++	case MAGIC_PARAM_ELF_NOTES_MAX:
++		*(size_t *)val = ms->elf_notes_max;
++		return 0;
++	default:
++		errno = EINVAL;
++		return -1;
++	}
++}
+diff --git a/src/magic.h b/src/magic.h
+index cc8ed68..2938a20 100644
+--- a/src/magic.h
++++ b/src/magic.h
+@@ -101,6 +101,15 @@ int magic_check(magic_t, const char *);
+ int magic_list(magic_t, const char *);
+ int magic_errno(magic_t);
+ 
++#define MAGIC_PARAM_INDIR_MAX		0
++#define MAGIC_PARAM_NAME_MAX		1
++#define MAGIC_PARAM_ELF_PHNUM_MAX	2
++#define MAGIC_PARAM_ELF_SHNUM_MAX	3
++#define MAGIC_PARAM_ELF_NOTES_MAX	4
++
++int magic_setparam(magic_t, int, const void *);
++int magic_getparam(magic_t, int, void *);
++
+ #ifdef __cplusplus
+ };
+ #endif
+diff --git a/src/magic.h.in b/src/magic.h.in
+index 86fc41b..a256cf0 100644
+--- a/src/magic.h.in
++++ b/src/magic.h.in
+@@ -101,6 +101,10 @@ int magic_check(magic_t, const char *);
+ int magic_list(magic_t, const char *);
+ int magic_errno(magic_t);
+ 
++#define MAGIC_PARAM_MAX_RECURSION	0
++int magic_setparam(magic_t, int, const void *);
++int magic_getparam(magic_t, int, void *);
++
+ #ifdef __cplusplus
+ };
+ #endif
+diff --git a/src/readelf.c b/src/readelf.c
+index f8b8bbc..a7b2ba4 100644
+--- a/src/readelf.c
++++ b/src/readelf.c
+@@ -43,14 +43,14 @@ FILE_RCSID("@(#)$File: readelf.c,v 1.99 2013/11/05 15:44:01 christos Exp $")
+ 
+ #ifdef	ELFCORE
+ private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
+-    off_t, int *);
++    off_t, int *, uint16_t *);
+ #endif
+ private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
+-    off_t, int *, int);
++    off_t, int, int *, uint16_t *);
+ private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
+-    off_t, int *, int, int);
++    off_t, int, int, int *, uint16_t *);
+ private size_t donote(struct magic_set *, void *, size_t, size_t, int,
+-    int, size_t, int *);
++    int, size_t, int *, uint16_t *);
+ 
+ #define	ELF_ALIGN(a)	((((a) + align - 1) / align) * align)
+ 
+@@ -60,6 +60,19 @@ private uint16_t getu16(int, uint16_t);
+ private uint32_t getu32(int, uint32_t);
+ private uint64_t getu64(int, uint64_t);
+ 
++#define MAX_PHNUM	128
++#define	MAX_SHNUM	32768
++#define SIZE_UNKNOWN	((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)
++		return -1;
++	return 0;
++}
++
+ private uint16_t
+ getu16(int swap, uint16_t value)
+ {
+@@ -280,15 +293,19 @@ private const char os_style_names[][8] = {
+ 	"NetBSD",
+ };
+ 
+-#define FLAGS_DID_CORE		0x01
+-#define FLAGS_DID_NOTE		0x02
+-#define FLAGS_DID_BUILD_ID	0x04
+-#define FLAGS_DID_CORE_STYLE	0x08
+-#define FLAGS_IS_CORE		0x10
++#define FLAGS_DID_CORE			0x001
++#define FLAGS_DID_OS_NOTE		0x002
++#define FLAGS_DID_BUILD_ID		0x004
++#define FLAGS_DID_CORE_STYLE		0x008
++#define FLAGS_DID_NETBSD_PAX		0x010
++#define FLAGS_DID_NETBSD_MARCH		0x020
++#define FLAGS_DID_NETBSD_CMODEL		0x040
++#define FLAGS_DID_NETBSD_UNKNOWN	0x080
++#define FLAGS_IS_CORE			0x100
+ 
+ private int
+ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
+-    int num, size_t size, off_t fsize, int *flags)
++    int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
+ {
+ 	Elf32_Phdr ph32;
+ 	Elf64_Phdr ph64;
+@@ -306,13 +323,13 @@ 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) == -1) {
++		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
+ 			file_badread(ms);
+ 			return -1;
+ 		}
+ 		off += size;
+ 
+-		if (xph_offset > fsize) {
++		if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
+ 			/* Perhaps warn here */
+ 			continue;
+ 		}
+@@ -334,7 +351,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
+ 			if (offset >= (size_t)bufsize)
+ 				break;
+ 			offset = donote(ms, nbuf, offset, (size_t)bufsize,
+-			    clazz, swap, 4, flags);
++			    clazz, swap, 4, flags, notecount);
+ 			if (offset == 0)
+ 				break;
+ 
+@@ -464,125 +481,127 @@ do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
+ 	}
+ }
+ 
+-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)
++private int
++do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
++    int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
++    size_t noff, size_t doff, int *flags)
+ {
+-	Elf32_Nhdr nh32;
+-	Elf64_Nhdr nh64;
+-	size_t noff, doff;
+-#ifdef ELFCORE
+-	int os_style = -1;
+-#endif
+-	uint32_t namesz, descsz;
+-	unsigned char *nbuf = CAST(unsigned char *, vbuf);
+-
+-	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
+-	offset += xnh_sizeof;
+-
+-	namesz = xnh_namesz;
+-	descsz = xnh_descsz;
+-	if ((namesz == 0) && (descsz == 0)) {
+-		/*
+-		 * We're out of note headers.
+-		 */
+-		return (offset >= size) ? offset : size;
+-	}
+-
+-	if (namesz & 0x80000000) {
+-	    (void)file_printf(ms, ", bad note name size 0x%lx",
+-		(unsigned long)namesz);
+-	    return offset;
+-	}
+-
+-	if (descsz & 0x80000000) {
+-	    (void)file_printf(ms, ", bad note description size 0x%lx",
+-		(unsigned long)descsz);
+-	    return offset;
+-	}
+-
+-
+-	noff = offset;
+-	doff = ELF_ALIGN(offset + namesz);
+-
+-	if (offset + namesz > size) {
+-		/*
+-		 * We're past the end of the buffer.
+-		 */
+-		return doff;
+-	}
+-
+-	offset = ELF_ALIGN(doff + descsz);
+-	if (doff + descsz > size) {
+-		/*
+-		 * We're past the end of the buffer.
+-		 */
+-		return (offset >= size) ? offset : size;
++	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
++	    type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
++		uint8_t desc[20];
++		uint32_t i;
++		*flags |= FLAGS_DID_BUILD_ID;
++		if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
++		    "sha1") == -1)
++			return 1;
++		(void)memcpy(desc, &nbuf[doff], descsz);
++		for (i = 0; i < descsz; i++)
++		    if (file_printf(ms, "%02x", desc[i]) == -1)
++			return 1;
++		return 1;
+ 	}
+-
+-	if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) ==
+-	    (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID))
+-		goto core;
+-
++	return 0;
++}
++	
++private int
++do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
++    int swap, uint32_t namesz, uint32_t descsz,
++    size_t noff, size_t doff, int *flags)
++{
+ 	if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
+-	    xnh_type == NT_GNU_VERSION && descsz == 2) {
++	    type == NT_GNU_VERSION && descsz == 2) {
++	    *flags |= FLAGS_DID_OS_NOTE;
+ 	    file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]);
++	    return 1;
+ 	}
++
+ 	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
+-	    xnh_type == NT_GNU_VERSION && descsz == 16) {
++	    type == NT_GNU_VERSION && descsz == 16) {
+ 		uint32_t desc[4];
+ 		(void)memcpy(desc, &nbuf[doff], sizeof(desc));
+ 
++		*flags |= FLAGS_DID_OS_NOTE;
+ 		if (file_printf(ms, ", for GNU/") == -1)
+-			return size;
++			return 1;
+ 		switch (elf_getu32(swap, desc[0])) {
+ 		case GNU_OS_LINUX:
+ 			if (file_printf(ms, "Linux") == -1)
+-				return size;
++				return 1;
+ 			break;
+ 		case GNU_OS_HURD:
+ 			if (file_printf(ms, "Hurd") == -1)
+-				return size;
++				return 1;
+ 			break;
+ 		case GNU_OS_SOLARIS:
+ 			if (file_printf(ms, "Solaris") == -1)
+-				return size;
++				return 1;
+ 			break;
+ 		case GNU_OS_KFREEBSD:
+ 			if (file_printf(ms, "kFreeBSD") == -1)
+-				return size;
++				return 1;
+ 			break;
+ 		case GNU_OS_KNETBSD:
+ 			if (file_printf(ms, "kNetBSD") == -1)
+-				return size;
++				return 1;
+ 			break;
+ 		default:
+ 			if (file_printf(ms, "<unknown>") == -1)
+-				return size; 
++				return 1;
+ 		}
+ 		if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
+ 		    elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
+-			return size;
+-		*flags |= FLAGS_DID_NOTE;
+-		return size;
++			return 1;
++		return 1;
+ 	}
+ 
+-	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
+-	    xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
+-	    uint8_t desc[20];
+-	    uint32_t i;
+-	    if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
+-		"sha1") == -1)
+-		    return size;
+-	    (void)memcpy(desc, &nbuf[doff], descsz);
+-	    for (i = 0; i < descsz; i++)
+-		if (file_printf(ms, "%02x", desc[i]) == -1)
+-		    return size;
+-	    *flags |= FLAGS_DID_BUILD_ID;
++	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
++	    	if (type == NT_NETBSD_VERSION && descsz == 4) {
++			*flags |= FLAGS_DID_OS_NOTE;
++			do_note_netbsd_version(ms, swap, &nbuf[doff]);
++			return 1;
++		}
++	}
++
++	if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
++	    	if (type == NT_FREEBSD_VERSION && descsz == 4) {
++			*flags |= FLAGS_DID_OS_NOTE;
++			do_note_freebsd_version(ms, swap, &nbuf[doff]);
++			return 1;
++		}
++	}
++
++	if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
++	    type == NT_OPENBSD_VERSION && descsz == 4) {
++		*flags |= FLAGS_DID_OS_NOTE;
++		if (file_printf(ms, ", for OpenBSD") == -1)
++			return 1;
++		/* Content of note is always 0 */
++		return 1;
++	}
++
++	if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
++	    type == NT_DRAGONFLY_VERSION && descsz == 4) {
++		uint32_t desc;
++		*flags |= FLAGS_DID_OS_NOTE;
++		if (file_printf(ms, ", for DragonFly") == -1)
++			return 1;
++		(void)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)
++			return 1;
++		return 1;
+ 	}
++	return 0;
++}
+ 
++private int
++do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
++    int swap, uint32_t namesz, uint32_t descsz,
++    size_t noff, size_t doff, int *flags)
++{
+ 	if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
+-	    xnh_type == NT_NETBSD_PAX && descsz == 4) {
++	    type == NT_NETBSD_PAX && descsz == 4) {
+ 		static const char *pax[] = {
+ 		    "+mprotect",
+ 		    "-mprotect",
+@@ -595,80 +614,32 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
+ 		size_t i;
+ 		int did = 0;
+ 
++		*flags |= FLAGS_DID_NETBSD_PAX;
+ 		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
+ 		desc = elf_getu32(swap, desc);
+ 
+ 		if (desc && file_printf(ms, ", PaX: ") == -1)
+-			return size;
++			return 1;
+ 
+ 		for (i = 0; i < __arraycount(pax); i++) {
+ 			if (((1 << i) & desc) == 0)
+ 				continue;
+ 			if (file_printf(ms, "%s%s", did++ ? "," : "",
+ 			    pax[i]) == -1)
+-				return size;
+-		}
+-	}
+-
+-	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
+-		switch (xnh_type) {
+-		case NT_NETBSD_VERSION:
+-			if (descsz == 4) {
+-				do_note_netbsd_version(ms, swap, &nbuf[doff]);
+-				*flags |= FLAGS_DID_NOTE;
+-				return size;
+-			}
+-			break;
+-		case NT_NETBSD_MARCH:
+-			if (file_printf(ms, ", compiled for: %.*s", (int)descsz,
+-			    (const char *)&nbuf[doff]) == -1)
+-				return size;
+-			break;
+-		case NT_NETBSD_CMODEL:
+-			if (file_printf(ms, ", compiler model: %.*s",
+-			    (int)descsz, (const char *)&nbuf[doff]) == -1)
+-				return size;
+-			break;
+-		default:
+-			if (file_printf(ms, ", note=%u", xnh_type) == -1)
+-				return size;
+-			break;
+-		}
+-		return size;
+-	}
+-
+-	if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
+-	    	if (xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
+-			do_note_freebsd_version(ms, swap, &nbuf[doff]);
+-			*flags |= FLAGS_DID_NOTE;
+-			return size;
++			return 1;
+ 		}
++		return 1;
+ 	}
++	return 0;
++}
+ 
+-	if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
+-	    xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
+-		if (file_printf(ms, ", for OpenBSD") == -1)
+-			return size;
+-		/* Content of note is always 0 */
+-		*flags |= FLAGS_DID_NOTE;
+-		return size;
+-	}
+-
+-	if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
+-	    xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
+-		uint32_t desc;
+-		if (file_printf(ms, ", for DragonFly") == -1)
+-			return size;
+-		(void)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)
+-			return size;
+-		*flags |= FLAGS_DID_NOTE;
+-		return size;
+-	}
+-
+-core:
++private int
++do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
++    int swap, uint32_t namesz, uint32_t descsz,
++    size_t noff, size_t doff, int *flags, size_t size, int clazz)
++{
++#ifdef ELFCORE
++	int os_style = -1;
+ 	/*
+ 	 * Sigh.  The 2.0.36 kernel in Debian 2.1, at
+ 	 * least, doesn't correctly implement name
+@@ -697,20 +668,17 @@ core:
+ 		os_style = OS_STYLE_NETBSD;
+ 	}
+ 
+-#ifdef ELFCORE
+-	if ((*flags & FLAGS_DID_CORE) != 0)
+-		return size;
+-
+ 	if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
+ 		if (file_printf(ms, ", %s-style", os_style_names[os_style])
+ 		    == -1)
+-			return size;
++			return 1;
+ 		*flags |= FLAGS_DID_CORE_STYLE;
+ 	}
+ 
+ 	switch (os_style) {
+ 	case OS_STYLE_NETBSD:
+-		if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
++		if (type == NT_NETBSD_CORE_PROCINFO) {
++			char sbuf[512];
+ 			uint32_t signo;
+ 			/*
+ 			 * Extract the program name.  It is at
+@@ -719,7 +687,7 @@ core:
+ 			 */
+ 			if (file_printf(ms, ", from '%.31s'",
+ 			    &nbuf[doff + 0x7c]) == -1)
+-				return size;
++				return 1;
+ 			
+ 			/*
+ 			 * Extract the signal number.  It is at
+@@ -736,8 +704,7 @@ core:
+ 		break;
+ 
+ 	default:
+-		if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
+-/*###709 [cc] warning: declaration of 'i' shadows previous non-variable%%%*/
++		if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
+ 			size_t i, j;
+ 			unsigned char c;
+ 			/*
+@@ -805,7 +772,7 @@ core:
+ 				 * Try next offsets, in case this match is
+ 				 * in the middle of a string.
+ 				 */
+-				for (k = i + 1 ; k < NOFFSETS ; k++) {
++				for (k = i + 1 ; k < NOFFSETS; k++) {
+ 					size_t no;
+ 					int adjust = 1;
+ 					if (prpsoffsets(k) >= prpsoffsets(i))
+@@ -830,9 +797,9 @@ core:
+ 					cp--;
+ 				if (file_printf(ms, ", from '%.*s'",
+ 				    (int)(cp - cname), cname) == -1)
+-					return size;
++					return 1;
+ 				*flags |= FLAGS_DID_CORE;
+-				return size;
++				return 1;
+ 
+ 			tryanother:
+ 				;
+@@ -841,6 +808,129 @@ core:
+ 		break;
+ 	}
+ #endif
++	return 0;
++}
++
++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)
++{
++	Elf32_Nhdr nh32;
++	Elf64_Nhdr nh64;
++	size_t noff, doff;
++	uint32_t namesz, descsz;
++	unsigned char *nbuf = CAST(unsigned char *, vbuf);
++
++	if (*notecount == 0)
++		return 0;
++	--*notecount;
++
++	if (xnh_sizeof + offset > size) {
++		/*
++		 * We're out of note headers.
++		 */
++		return xnh_sizeof + offset;
++	}
++
++	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
++	offset += xnh_sizeof;
++
++	namesz = xnh_namesz;
++	descsz = xnh_descsz;
++	if ((namesz == 0) && (descsz == 0)) {
++		/*
++		 * We're out of note headers.
++		 */
++		return (offset >= size) ? offset : size;
++	}
++
++	if (namesz & 0x80000000) {
++	    (void)file_printf(ms, ", bad note name size 0x%lx",
++		(unsigned long)namesz);
++	    return 0;
++	}
++
++	if (descsz & 0x80000000) {
++	    (void)file_printf(ms, ", bad note description size 0x%lx",
++		(unsigned long)descsz);
++	    return 0;
++	}
++
++	noff = offset;
++	doff = ELF_ALIGN(offset + namesz);
++
++	if (offset + namesz > size) {
++		/*
++		 * We're past the end of the buffer.
++		 */
++		return doff;
++	}
++
++	offset = ELF_ALIGN(doff + descsz);
++	if (doff + descsz > size) {
++		/*
++		 * We're past the end of the buffer.
++		 */
++		return (offset >= size) ? offset : size;
++	}
++
++	if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
++		if (do_os_note(ms, nbuf, xnh_type, swap,
++		    namesz, descsz, noff, doff, flags))
++			return size;
++	}
++
++	if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
++		if (do_bid_note(ms, nbuf, xnh_type, swap,
++		    namesz, descsz, noff, doff, flags))
++			return size;
++	}
++		
++	if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
++		if (do_pax_note(ms, nbuf, xnh_type, swap,
++		    namesz, descsz, noff, doff, flags))
++			return size;
++	}
++
++	if ((*flags & FLAGS_DID_CORE) == 0) {
++		if (do_core_note(ms, nbuf, xnh_type, swap,
++		    namesz, descsz, noff, doff, flags, size, clazz))
++			return size;
++	}
++
++	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
++		if (descsz > 100)
++			descsz = 100;
++		switch (xnh_type) {
++	    	case NT_NETBSD_VERSION:
++			return size;
++		case NT_NETBSD_MARCH:
++			if (*flags & FLAGS_DID_NETBSD_MARCH)
++				return size;
++			*flags |= FLAGS_DID_NETBSD_MARCH;
++			if (file_printf(ms, ", compiled for: %.*s",
++			    (int)descsz, (const char *)&nbuf[doff]) == -1)
++				return size;
++			break;
++		case NT_NETBSD_CMODEL:
++			if (*flags & FLAGS_DID_NETBSD_CMODEL)
++				return size;
++			*flags |= FLAGS_DID_NETBSD_CMODEL;
++			if (file_printf(ms, ", compiler model: %.*s",
++			    (int)descsz, (const char *)&nbuf[doff]) == -1)
++				return size;
++			break;
++		default:
++			if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
++				return size;
++			*flags |= FLAGS_DID_NETBSD_UNKNOWN;
++			if (file_printf(ms, ", note=%u", xnh_type) == -1)
++				return size;
++			break;
++		}
++		return size;
++	}
++
+ 	return offset;
+ }
+ 
+@@ -896,16 +986,19 @@ static const cap_desc_t cap_desc_386[] = {
+ 
+ private int
+ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
+-    size_t size, off_t fsize, int *flags, int mach, int strtab)
++    size_t size, off_t fsize, int mach, int strtab, int *flags,
++    uint16_t *notecount)
+ {
+ 	Elf32_Shdr sh32;
+ 	Elf64_Shdr sh64;
+ 	int stripped = 1;
++	size_t nbadcap = 0;
+ 	void *nbuf;
+ 	off_t noff, coff, name_off;
+ 	uint64_t cap_hw1 = 0;	/* SunOS 5.x hardware capabilites */
+ 	uint64_t cap_sf1 = 0;	/* SunOS 5.x software capabilites */
+ 	char name[50];
++	ssize_t namesize;
+ 
+ 	if (size != xsh_sizeof) {
+ 		if (file_printf(ms, ", corrupted section header size") == -1)
+@@ -914,7 +1007,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, off + size * strtab) == -1) {
++	if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) < (ssize_t)xsh_sizeof) {
+ 		file_badread(ms);
+ 		return -1;
+ 	}
+@@ -922,15 +1015,15 @@ 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 (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) {
++		if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
+ 			file_badread(ms);
+ 			return -1;
+ 		}
+-		name[sizeof(name) - 1] = '\0';
++		name[namesize] = '\0';
+ 		if (strcmp(name, ".debug_info") == 0)
+ 			stripped = 0;
+ 
+-		if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) {
++		if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
+ 			file_badread(ms);
+ 			return -1;
+ 		}
+@@ -945,7 +1038,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
+ 			stripped = 0;
+ 			break;
+ 		default:
+-			if (xsh_offset > fsize) {
++			if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
+ 				/* Perhaps warn here */
+ 				continue;
+ 			}
+@@ -960,7 +1053,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
+ 				    " for note");
+ 				return -1;
+ 			}
+-			if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) {
++			if (pread(fd, nbuf, xsh_size, xsh_offset) < (ssize_t)xsh_size) {
+ 				file_badread(ms);
+ 				free(nbuf);
+ 				return -1;
+@@ -971,7 +1064,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
+ 				if (noff >= (off_t)xsh_size)
+ 					break;
+ 				noff = donote(ms, nbuf, (size_t)noff,
+-				    xsh_size, clazz, swap, 4, flags);
++				    xsh_size, clazz, swap, 4, flags, notecount);
+ 				if (noff == 0)
+ 					break;
+ 			}
+@@ -989,6 +1082,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
+ 				goto skip;
+ 			}
+ 
++			if (nbadcap > 5)
++				break;
+ 			if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
+ 				file_badseek(ms);
+ 				return -1;
+@@ -1024,6 +1119,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
+ 					    (unsigned long long)xcap_tag,
+ 					    (unsigned long long)xcap_val) == -1)
+ 						return -1;
++					if (nbadcap++ > 2)
++						coff = xsh_size;
+ 					break;
+ 				}
+ 			}
+@@ -1104,7 +1201,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
+  */
+ private int
+ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
+-    int num, size_t size, off_t fsize, int *flags, int sh_num)
++    int num, size_t size, off_t fsize, int sh_num, int *flags,
++    uint16_t *notecount)
+ {
+ 	Elf32_Phdr ph32;
+ 	Elf64_Phdr ph64;
+@@ -1121,7 +1219,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
+ 	}
+ 
+   	for ( ; num; num--) {
+-		if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
++		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
+ 			file_badread(ms);
+ 			return -1;
+ 		}
+@@ -1137,7 +1235,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
+ 			shared_libraries = " (uses shared libs)";
+ 			break;
+ 		default:
+-			if (xph_offset > fsize) {
++			if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
+ 				/* Maybe warn here? */
+ 				continue;
+ 			}
+@@ -1173,7 +1271,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
+ 					break;
+ 				offset = donote(ms, nbuf, offset,
+ 				    (size_t)bufsize, clazz, swap, align,
+-				    flags);
++				    flags, notecount);
+ 				if (offset == 0)
+ 					break;
+ 			}
+@@ -1204,7 +1302,7 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
+ 	int flags = 0;
+ 	Elf32_Ehdr elf32hdr;
+ 	Elf64_Ehdr elf64hdr;
+-	uint16_t type;
++	uint16_t type, phnum, shnum, notecount;
+ 
+ 	if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
+ 		return 0;
+@@ -1230,7 +1328,10 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
+   		file_badread(ms);
+ 		return -1;
+ 	}
+-	fsize = st.st_size;
++	if (S_ISREG(st.st_mode))
++		fsize = st.st_size;
++	else
++		fsize = SIZE_UNKNOWN;
+ 
+ 	clazz = buf[EI_CLASS];
+ 
+diff --git a/src/softmagic.c b/src/softmagic.c
+index dc7928b..b1f5779 100644
+--- a/src/softmagic.c
++++ b/src/softmagic.c
+@@ -43,11 +43,11 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.168 2013/05/30 15:53:33 christos Exp $")
+ 
+ 
+ private int match(struct magic_set *, struct magic *, uint32_t,
+-    const unsigned char *, size_t, size_t, int, int, int, int, int *, int *,
+-    int *);
++    const unsigned char *, size_t, size_t, int, int, int, uint16_t,
++    uint16_t *, int *, int *, int *);
+ private int mget(struct magic_set *, const unsigned char *,
+-    struct magic *, size_t, size_t, unsigned int, int, int, int, int, int *,
+-    int *, int *);
++    struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t,
++    uint16_t *, int *, int *, int *);
+ private int magiccheck(struct magic_set *, struct magic *);
+ private int32_t mprint(struct magic_set *, struct magic *);
+ private int32_t moffset(struct magic_set *, struct magic *);
+@@ -69,14 +69,20 @@ private void cvt_64(union VALUETYPE *, const struct magic *);
+ /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
+ protected int
+ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
+-    int mode, int text)
++    uint16_t indir_level, uint16_t *name_count, int mode, int text)
+ {
+ 	struct mlist *ml;
+ 	int rv, printed_something = 0, need_separator = 0;
++	uint16_t nc;
++
++	if (name_count == NULL) {
++		nc = 0;
++		name_count = &nc;
++	}
+ 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
+ 		if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
+-		    text, 0, 0, &printed_something, &need_separator,
+-		    NULL)) != 0)
++		    text, 0, indir_level, name_count,
++		    &printed_something, &need_separator, NULL)) != 0)
+ 			return rv;
+ 
+ 	return 0;
+@@ -112,8 +118,8 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
+ private int
+ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
+     const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
+-    int flip, int recursion_level, int *printed_something, int *need_separator,
+-    int *returnval)
++    int flip, uint16_t indir_level, uint16_t *name_count,
++    int *printed_something, int *need_separator, int *returnval)
+ {
+ 	uint32_t magindex = 0;
+ 	unsigned int cont_level = 0;
+@@ -150,8 +156,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
+ 
+ 		/* if main entry matches, print it... */
+ 		switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
+-		    flip, recursion_level + 1, printed_something,
+-		    need_separator, returnval)) {
++		    flip, indir_level, name_count,
++		    printed_something, need_separator, returnval)) {
+ 		case -1:
+ 			return -1;
+ 		case 0:
+@@ -237,8 +243,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
+ 			}
+ #endif
+ 			switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
+-			    text, flip, recursion_level + 1, printed_something,
+-			    need_separator, returnval)) {
++			    text, flip, indir_level, name_count,
++			    printed_something, need_separator, returnval)) {
+ 			case -1:
+ 				return -1;
+ 			case 0:
+@@ -1120,8 +1126,8 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
+ private int
+ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
+     size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
+-    int flip, int recursion_level, int *printed_something,
+-    int *need_separator, int *returnval)
++    int flip, uint16_t indir_level, uint16_t *name_count,
++    int *printed_something, int *need_separator, int *returnval)
+ {
+ 	uint32_t soffset, offset = ms->offset;
+ 	uint32_t count = m->str_range;
+@@ -1130,8 +1136,15 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
+ 	union VALUETYPE *p = &ms->ms_value;
+ 	struct mlist ml;
+ 
+-	if (recursion_level >= 20) {
+-		file_error(ms, 0, "recursion nesting exceeded");
++	if (indir_level >= ms->indir_max) {
++		file_error(ms, 0, "indirect recursion nesting (%hu) exceeded",
++		    indir_level);
++		return -1;
++	}
++
++	if (*name_count >= ms->name_max) {
++		file_error(ms, 0, "name use count (%hu) exceeded",
++		    *name_count);
+ 		return -1;
+ 	}
+ 
+@@ -1141,8 +1154,9 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
+ 
+ 	if ((ms->flags & MAGIC_DEBUG) != 0) {
+ 		fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, "
+-		    "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o,
+-		    nbytes, count);
++		    "nbytes=%zu, il=%hu, nc=%hu)\n",
++		    m->type, m->flag, offset, o, nbytes,
++		    indir_level, *name_count);
+ 		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
+ #ifndef COMPILE_ONLY
+ 		file_mdump(m);
+@@ -1711,7 +1725,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
+ 		ms->o.buf = NULL;
+ 		ms->offset = 0;
+ 		rv = file_softmagic(ms, s + offset, nbytes - offset,
+-		    BINTEST, text);
++		    indir_level + 1, name_count, BINTEST, text);
+ 		if ((ms->flags & MAGIC_DEBUG) != 0)
+ 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
+ 		rbuf = ms->o.buf;
+@@ -1730,22 +1744,22 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
+ 	case FILE_USE:
+ 		if (nbytes < offset)
+ 			return 0;
+-		sbuf = m->value.s;
+-		if (*sbuf == '^') {
+-			sbuf++;
++		rbuf = m->value.s;
++		if (*rbuf == '^') {
++			rbuf++;
+ 			flip = !flip;
+ 		}
+-		if (file_magicfind(ms, sbuf, &ml) == -1) {
+-			file_error(ms, 0, "cannot find entry `%s'", sbuf);
++		if (file_magicfind(ms, rbuf, &ml) == -1) {
++			file_error(ms, 0, "cannot find entry `%s'", rbuf);
+ 			return -1;
+ 		}
+-
++		(*name_count)++;
+ 		oneed_separator = *need_separator;
+ 		if (m->flag & NOSPACE)
+ 			*need_separator = 0;
+ 		rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
+-		    mode, text, flip, recursion_level, printed_something,
+-		    need_separator, returnval);
++		    mode, text, flip, indir_level, name_count,
++		    printed_something, need_separator, returnval);
+ 		if (rv != 1)
+ 		    *need_separator = oneed_separator;
+ 		return rv;
+-- 
+1.7.9.5
+
diff --git a/meta/recipes-devtools/file/file_5.16.bb b/meta/recipes-devtools/file/file_5.16.bb
index a15d952..f231a55 100644
--- a/meta/recipes-devtools/file/file_5.16.bb
+++ b/meta/recipes-devtools/file/file_5.16.bb
@@ -12,6 +12,7 @@ DEPENDS = "zlib file-native"
 DEPENDS_class-native = "zlib-native"
 
 SRC_URI = "ftp://ftp.astron.com/pub/file/file-${PV}.tar.gz \
+           file://file-CVE-2014-9620-and-CVE-2014-9621.patch \
            file://dump \
            file://filesystems"
 
-- 
1.7.9.5



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [daisy][PATCH] file: CVE-2014-9620 and CVE-2014-9621
  2015-01-22  9:28 [daisy][PATCH] file: CVE-2014-9620 and CVE-2014-9621 Chong Lu
@ 2015-01-30  1:18 ` Chong Lu
  2015-01-30  3:57   ` Saul Wold
  2015-02-02 13:55 ` Saul Wold
  1 sibling, 1 reply; 5+ messages in thread
From: Chong Lu @ 2015-01-30  1:18 UTC (permalink / raw)
  To: openembedded-core

ping

//Chong

On 01/22/2015 05:28 PM, Chong Lu wrote:
> CVE-2014-9620:
> Limit the number of ELF notes processed - DoS
> CVE-2014-9621:
> Limit string printing to 100 chars - DoS
>
> The patch comes from:
> https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67
> https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6
> https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33
> https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba
> https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9
> https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7
> https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f
> https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4
> https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c
>
> [YOCTO #7178]
>
> Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
> ---
>   .../file-CVE-2014-9620-and-CVE-2014-9621.patch     | 1357 ++++++++++++++++++++
>   meta/recipes-devtools/file/file_5.16.bb            |    1 +
>   2 files changed, 1358 insertions(+)
>   create mode 100644 meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
>
> diff --git a/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
> new file mode 100644
> index 0000000..bd5944e
> --- /dev/null
> +++ b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
> @@ -0,0 +1,1357 @@
> +file: CVE-2014-9620 and CVE-2014-9621
> +
> +The patch comes from:
> +https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67
> +https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6
> +https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33
> +https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba
> +https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9
> +https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7
> +https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f
> +https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4
> +https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c
> +
> +Upstream-Status: Backport
> +
> +Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
> +---
> + src/apprentice.c |    5 +
> + src/ascmagic.c   |    3 +-
> + src/elfclass.h   |   34 ++--
> + src/file.c       |   58 ++++++-
> + src/file.h       |   20 ++-
> + src/file_opts.h  |    6 +
> + src/funcs.c      |   42 ++++-
> + src/magic.c      |   50 ++++++
> + src/magic.h      |    9 ++
> + src/magic.h.in   |    4 +
> + src/readelf.c    |  467 +++++++++++++++++++++++++++++++++---------------------
> + src/softmagic.c  |   70 ++++----
> + 12 files changed, 541 insertions(+), 227 deletions(-)
> +
> +diff --git a/src/apprentice.c b/src/apprentice.c
> +index 2df60d9..d906f7b 100644
> +--- a/src/apprentice.c
> ++++ b/src/apprentice.c
> +@@ -494,6 +494,11 @@ file_ms_alloc(int flags)
> + 		ms->mlist[i] = NULL;
> + 	ms->file = "unknown";
> + 	ms->line = 0;
> ++	ms->indir_max = FILE_INDIR_MAX;
> ++	ms->name_max = FILE_NAME_MAX;
> ++	ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
> ++	ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
> ++	ms->elf_notes_max = FILE_ELF_NOTES_MAX;
> + 	return ms;
> + free:
> + 	free(ms);
> +diff --git a/src/ascmagic.c b/src/ascmagic.c
> +index 28ebadc..7a22328 100644
> +--- a/src/ascmagic.c
> ++++ b/src/ascmagic.c
> +@@ -147,7 +147,8 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf,
> + 		    == NULL)
> + 			goto done;
> + 		if ((rv = file_softmagic(ms, utf8_buf,
> +-		    (size_t)(utf8_end - utf8_buf), TEXTTEST, text)) == 0)
> ++		    (size_t)(utf8_end - utf8_buf), 0, NULL,
> ++		    TEXTTEST, text)) == 0)
> + 			rv = -1;
> + 	}
> +
> +diff --git a/src/elfclass.h b/src/elfclass.h
> +index 010958a..5360b0b 100644
> +--- a/src/elfclass.h
> ++++ b/src/elfclass.h
> +@@ -32,39 +32,51 @@
> + 	swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
> +
> + 	type = elf_getu16(swap, elfhdr.e_type);
> ++	notecount = ms->elf_notes_max;
> + 	switch (type) {
> + #ifdef ELFCORE
> + 	case ET_CORE:
> ++		phnum = elf_getu16(swap, elfhdr.e_phnum);
> ++		if (phnum > ms->elf_phnum_max)
> ++			return toomany(ms, "program headers", phnum);
> + 		flags |= FLAGS_IS_CORE;
> + 		if (dophn_core(ms, clazz, swap, fd,
> +-		    (off_t)elf_getu(swap, elfhdr.e_phoff),
> +-		    elf_getu16(swap, elfhdr.e_phnum),
> ++		    (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
> + 		    (size_t)elf_getu16(swap, elfhdr.e_phentsize),
> +-		    fsize, &flags) == -1)
> ++		    fsize, &flags, &notecount) == -1)
> + 			return -1;
> + 		break;
> + #endif
> + 	case ET_EXEC:
> + 	case ET_DYN:
> ++		phnum = elf_getu16(swap, elfhdr.e_phnum);
> ++		if (phnum > ms->elf_phnum_max)
> ++			return toomany(ms, "program", phnum);
> ++		shnum = elf_getu16(swap, elfhdr.e_shnum);
> ++		if (shnum > ms->elf_shnum_max)
> ++			return toomany(ms, "section", shnum);
> + 		if (dophn_exec(ms, clazz, swap, fd,
> +-		    (off_t)elf_getu(swap, elfhdr.e_phoff),
> +-		    elf_getu16(swap, elfhdr.e_phnum),
> ++		    (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
> + 		    (size_t)elf_getu16(swap, elfhdr.e_phentsize),
> +-		    fsize, &flags, elf_getu16(swap, elfhdr.e_shnum))
> +-		    == -1)
> ++		    fsize, shnum, &flags, &notecount) == -1)
> + 			return -1;
> + 		/*FALLTHROUGH*/
> + 	case ET_REL:
> ++		shnum = elf_getu16(swap, elfhdr.e_shnum);
> ++		if (shnum > ms->elf_shnum_max)
> ++			return toomany(ms, "section headers", shnum);
> + 		if (doshn(ms, clazz, swap, fd,
> +-		    (off_t)elf_getu(swap, elfhdr.e_shoff),
> +-		    elf_getu16(swap, elfhdr.e_shnum),
> ++		    (off_t)elf_getu(swap, elfhdr.e_shoff), shnum,
> + 		    (size_t)elf_getu16(swap, elfhdr.e_shentsize),
> +-		    fsize, &flags, elf_getu16(swap, elfhdr.e_machine),
> +-		    (int)elf_getu16(swap, elfhdr.e_shstrndx)) == -1)
> ++		    fsize, elf_getu16(swap, elfhdr.e_machine),
> ++		    (int)elf_getu16(swap, elfhdr.e_shstrndx),
> ++		    &flags, &notecount) == -1)
> + 			return -1;
> + 		break;
> +
> + 	default:
> + 		break;
> + 	}
> ++	if (notecount == 0)
> ++		return toomany(ms, "notes", ms->elf_notes_max);
> + 	return 1;
> +diff --git a/src/file.c b/src/file.c
> +index ac773ea..ee1edcd 100644
> +--- a/src/file.c
> ++++ b/src/file.c
> +@@ -101,7 +101,7 @@ private const struct option long_options[] = {
> + #undef OPT_LONGONLY
> +     {0, 0, NULL, 0}
> + };
> +-#define OPTSTRING	"bcCde:f:F:hiklLm:nNprsvz0"
> ++#define OPTSTRING	"bcCde:f:F:hiklLm:nNpP:rsvz0"
> +
> + private const struct {
> + 	const char *name;
> +@@ -119,6 +119,18 @@ private const struct {
> + 	{ "tokens",	MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */
> + };
> +
> ++private struct {
> ++	const char *name;
> ++	int tag;
> ++	size_t value;
> ++} pm[] = {
> ++	{ "indir",	MAGIC_PARAM_INDIR_MAX, 0 },
> ++	{ "name",	MAGIC_PARAM_NAME_MAX, 0 },
> ++	{ "elf_phnum",	MAGIC_PARAM_ELF_PHNUM_MAX, 0 },
> ++	{ "elf_shnum",	MAGIC_PARAM_ELF_SHNUM_MAX, 0 },
> ++	{ "elf_notes",	MAGIC_PARAM_ELF_NOTES_MAX, 0 },
> ++};
> ++
> + private char *progname;		/* used throughout 		*/
> +
> + private void usage(void);
> +@@ -128,6 +140,8 @@ private void help(void);
> + private int unwrap(struct magic_set *, const char *);
> + private int process(struct magic_set *ms, const char *, int);
> + private struct magic_set *load(const char *, int);
> ++private void setparam(const char *);
> ++private void applyparam(magic_t);
> +
> +
> + /*
> +@@ -240,6 +254,9 @@ main(int argc, char *argv[])
> + 			flags |= MAGIC_PRESERVE_ATIME;
> + 			break;
> + #endif
> ++		case 'P':
> ++			setparam(optarg);
> ++			break;
> + 		case 'r':
> + 			flags |= MAGIC_RAW;
> + 			break;
> +@@ -295,6 +312,8 @@ main(int argc, char *argv[])
> + 			    strerror(errno));
> + 			return 1;
> + 		}
> ++
> ++
> + 		switch(action) {
> + 		case FILE_CHECK:
> + 			c = magic_check(magic, magicfile);
> +@@ -318,7 +337,7 @@ main(int argc, char *argv[])
> + 		if (magic == NULL)
> + 			if ((magic = load(magicfile, flags)) == NULL)
> + 				return 1;
> +-		break;
> ++		applyparam(magic);
> + 	}
> +
> + 	if (optind == argc) {
> +@@ -348,6 +367,41 @@ main(int argc, char *argv[])
> + 	return e;
> + }
> +
> ++private void
> ++applyparam(magic_t magic)
> ++{
> ++	size_t i;
> ++
> ++	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);
> ++		}
> ++	}
> ++}
> ++
> ++private void
> ++setparam(const char *p)
> ++{
> ++	size_t i;
> ++	char *s;
> ++
> ++	if ((s = strchr(p, '=')) == NULL)
> ++		goto badparm;
> ++
> ++	for (i = 0; i < __arraycount(pm); i++) {
> ++		if (strncmp(p, pm[i].name, s - p) != 0)
> ++			continue;
> ++		pm[i].value = atoi(s + 1);
> ++		return;
> ++	}
> ++badparm:
> ++	(void)fprintf(stderr, "%s: Unknown param %s\n", progname, p);
> ++	exit(1);
> ++}
> +
> + private struct magic_set *
> + /*ARGSUSED*/
> +diff --git a/src/file.h b/src/file.h
> +index e910a2b..57e7307 100644
> +--- a/src/file.h
> ++++ b/src/file.h
> +@@ -400,6 +400,16 @@ struct magic_set {
> + 	/* FIXME: Make the string dynamically allocated so that e.g.
> + 	   strings matched in files can be longer than MAXstring */
> + 	union VALUETYPE ms_value;	/* either number or string */
> ++	uint16_t indir_max;
> ++	uint16_t name_max;
> ++	uint16_t elf_shnum_max;
> ++	uint16_t elf_phnum_max;
> ++	uint16_t elf_notes_max;
> ++#define	FILE_INDIR_MAX			15
> ++#define	FILE_NAME_MAX			30
> ++#define	FILE_ELF_SHNUM_MAX		32768
> ++#define	FILE_ELF_PHNUM_MAX		128
> ++#define	FILE_ELF_NOTES_MAX		256
> + };
> +
> + /* Type for Unicode characters */
> +@@ -438,7 +448,7 @@ protected int file_encoding(struct magic_set *, const unsigned char *, size_t,
> +     unichar **, size_t *, const char **, const char **, const char **);
> + protected int file_is_tar(struct magic_set *, const unsigned char *, size_t);
> + protected int file_softmagic(struct magic_set *, const unsigned char *, size_t,
> +-    int, int);
> ++    uint16_t, uint16_t *, int, int);
> + protected int file_apprentice(struct magic_set *, const char *, int);
> + protected int file_magicfind(struct magic_set *, const char *, struct mlist *);
> + protected uint64_t file_signextend(struct magic_set *, struct magic *,
> +@@ -468,6 +478,14 @@ protected int file_os2_apptype(struct magic_set *, const char *, const void *,
> + #endif /* __EMX__ */
> +
> +
> ++typedef struct {
> ++	char *buf;
> ++	uint32_t offset;
> ++} file_pushbuf_t;
> ++
> ++protected file_pushbuf_t *file_push_buffer(struct magic_set *);
> ++protected char  *file_pop_buffer(struct magic_set *, file_pushbuf_t *);
> ++
> + #ifndef COMPILE_ONLY
> + extern const char *file_names[];
> + extern const size_t file_nnames;
> +diff --git a/src/file_opts.h b/src/file_opts.h
> +index db34eb7..3286ac6 100644
> +--- a/src/file_opts.h
> ++++ b/src/file_opts.h
> +@@ -43,6 +43,12 @@ OPT('0', "print0", 0, "               terminate filenames with ASCII NUL\n")
> + #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
> + OPT('p', "preserve-date", 0, "        preserve access times on files\n")
> + #endif
> ++OPT('P', "parameter", 0, "            set file engine parameter limits\n"
> ++    "                               indir        15 recursion limit for indirection\n"
> ++    "                               name         30 use limit for name/use magic\n"
> ++    "                               elf_notes   256 max ELF notes processed\n"
> ++    "                               elf_phnum   128 max ELF prog sections processed\n"
> ++    "                               elf_shnum 32768 max ELF sections processed\n")
> + OPT('r', "raw", 0, "                  don't translate unprintable chars to \\ooo\n")
> + OPT('s', "special-files", 0, "        treat special (block/char devices) files as\n"
> +     "                             ordinary ones\n")
> +diff --git a/src/funcs.c b/src/funcs.c
> +index b798e44..50c38e5 100644
> +--- a/src/funcs.c
> ++++ b/src/funcs.c
> +@@ -226,7 +226,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu
> +
> + 	/* try soft magic tests */
> + 	if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
> +-		if ((m = file_softmagic(ms, ubuf, nb, BINTEST,
> ++		if ((m = file_softmagic(ms, ubuf, nb, 0, NULL, BINTEST,
> + 		    looks_text)) != 0) {
> + 			if ((ms->flags & MAGIC_DEBUG) != 0)
> + 				(void)fprintf(stderr, "softmagic %d\n", m);
> +@@ -459,3 +459,43 @@ file_replace(struct magic_set *ms, const char *pat, const char *rep)
> + 		return nm;
> + 	}
> + }
> ++
> ++protected file_pushbuf_t *
> ++file_push_buffer(struct magic_set *ms)
> ++{
> ++	file_pushbuf_t *pb;
> ++
> ++	if (ms->event_flags & EVENT_HAD_ERR)
> ++		return NULL;
> ++
> ++	if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
> ++		return NULL;
> ++
> ++	pb->buf = ms->o.buf;
> ++	pb->offset = ms->offset;
> ++
> ++	ms->o.buf = NULL;
> ++	ms->offset = 0;
> ++
> ++	return pb;
> ++}
> ++
> ++protected char *
> ++file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
> ++{
> ++	char *rbuf;
> ++
> ++	if (ms->event_flags & EVENT_HAD_ERR) {
> ++		free(pb->buf);
> ++		free(pb);
> ++		return NULL;
> ++	}
> ++
> ++	rbuf = ms->o.buf;
> ++
> ++	ms->o.buf = pb->buf;
> ++	ms->offset = pb->offset;
> ++
> ++	free(pb);
> ++	return rbuf;
> ++}
> +diff --git a/src/magic.c b/src/magic.c
> +index 22174b8..a89647c 100644
> +--- a/src/magic.c
> ++++ b/src/magic.c
> +@@ -490,3 +490,53 @@ magic_version(void)
> + {
> + 	return MAGIC_VERSION;
> + }
> ++
> ++public int
> ++magic_setparam(struct magic_set *ms, int param, const void *val)
> ++{
> ++	switch (param) {
> ++	case MAGIC_PARAM_INDIR_MAX:
> ++		ms->indir_max = *(const size_t *)val;
> ++		return 0;
> ++	case MAGIC_PARAM_NAME_MAX:
> ++		ms->name_max = *(const size_t *)val;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_PHNUM_MAX:
> ++		ms->elf_phnum_max = *(const size_t *)val;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_SHNUM_MAX:
> ++		ms->elf_shnum_max = *(const size_t *)val;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_NOTES_MAX:
> ++		ms->elf_notes_max = *(const size_t *)val;
> ++		return 0;
> ++	default:
> ++		errno = EINVAL;
> ++		return -1;
> ++	}
> ++}
> ++
> ++public int
> ++magic_getparam(struct magic_set *ms, int param, void *val)
> ++{
> ++	switch (param) {
> ++	case MAGIC_PARAM_INDIR_MAX:
> ++		*(size_t *)val = ms->indir_max;
> ++		return 0;
> ++	case MAGIC_PARAM_NAME_MAX:
> ++		*(size_t *)val = ms->name_max;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_PHNUM_MAX:
> ++		*(size_t *)val = ms->elf_phnum_max;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_SHNUM_MAX:
> ++		*(size_t *)val = ms->elf_shnum_max;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_NOTES_MAX:
> ++		*(size_t *)val = ms->elf_notes_max;
> ++		return 0;
> ++	default:
> ++		errno = EINVAL;
> ++		return -1;
> ++	}
> ++}
> +diff --git a/src/magic.h b/src/magic.h
> +index cc8ed68..2938a20 100644
> +--- a/src/magic.h
> ++++ b/src/magic.h
> +@@ -101,6 +101,15 @@ int magic_check(magic_t, const char *);
> + int magic_list(magic_t, const char *);
> + int magic_errno(magic_t);
> +
> ++#define MAGIC_PARAM_INDIR_MAX		0
> ++#define MAGIC_PARAM_NAME_MAX		1
> ++#define MAGIC_PARAM_ELF_PHNUM_MAX	2
> ++#define MAGIC_PARAM_ELF_SHNUM_MAX	3
> ++#define MAGIC_PARAM_ELF_NOTES_MAX	4
> ++
> ++int magic_setparam(magic_t, int, const void *);
> ++int magic_getparam(magic_t, int, void *);
> ++
> + #ifdef __cplusplus
> + };
> + #endif
> +diff --git a/src/magic.h.in b/src/magic.h.in
> +index 86fc41b..a256cf0 100644
> +--- a/src/magic.h.in
> ++++ b/src/magic.h.in
> +@@ -101,6 +101,10 @@ int magic_check(magic_t, const char *);
> + int magic_list(magic_t, const char *);
> + int magic_errno(magic_t);
> +
> ++#define MAGIC_PARAM_MAX_RECURSION	0
> ++int magic_setparam(magic_t, int, const void *);
> ++int magic_getparam(magic_t, int, void *);
> ++
> + #ifdef __cplusplus
> + };
> + #endif
> +diff --git a/src/readelf.c b/src/readelf.c
> +index f8b8bbc..a7b2ba4 100644
> +--- a/src/readelf.c
> ++++ b/src/readelf.c
> +@@ -43,14 +43,14 @@ FILE_RCSID("@(#)$File: readelf.c,v 1.99 2013/11/05 15:44:01 christos Exp $")
> +
> + #ifdef	ELFCORE
> + private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
> +-    off_t, int *);
> ++    off_t, int *, uint16_t *);
> + #endif
> + private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
> +-    off_t, int *, int);
> ++    off_t, int, int *, uint16_t *);
> + private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
> +-    off_t, int *, int, int);
> ++    off_t, int, int, int *, uint16_t *);
> + private size_t donote(struct magic_set *, void *, size_t, size_t, int,
> +-    int, size_t, int *);
> ++    int, size_t, int *, uint16_t *);
> +
> + #define	ELF_ALIGN(a)	((((a) + align - 1) / align) * align)
> +
> +@@ -60,6 +60,19 @@ private uint16_t getu16(int, uint16_t);
> + private uint32_t getu32(int, uint32_t);
> + private uint64_t getu64(int, uint64_t);
> +
> ++#define MAX_PHNUM	128
> ++#define	MAX_SHNUM	32768
> ++#define SIZE_UNKNOWN	((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)
> ++		return -1;
> ++	return 0;
> ++}
> ++
> + private uint16_t
> + getu16(int swap, uint16_t value)
> + {
> +@@ -280,15 +293,19 @@ private const char os_style_names[][8] = {
> + 	"NetBSD",
> + };
> +
> +-#define FLAGS_DID_CORE		0x01
> +-#define FLAGS_DID_NOTE		0x02
> +-#define FLAGS_DID_BUILD_ID	0x04
> +-#define FLAGS_DID_CORE_STYLE	0x08
> +-#define FLAGS_IS_CORE		0x10
> ++#define FLAGS_DID_CORE			0x001
> ++#define FLAGS_DID_OS_NOTE		0x002
> ++#define FLAGS_DID_BUILD_ID		0x004
> ++#define FLAGS_DID_CORE_STYLE		0x008
> ++#define FLAGS_DID_NETBSD_PAX		0x010
> ++#define FLAGS_DID_NETBSD_MARCH		0x020
> ++#define FLAGS_DID_NETBSD_CMODEL		0x040
> ++#define FLAGS_DID_NETBSD_UNKNOWN	0x080
> ++#define FLAGS_IS_CORE			0x100
> +
> + private int
> + dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> +-    int num, size_t size, off_t fsize, int *flags)
> ++    int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
> + {
> + 	Elf32_Phdr ph32;
> + 	Elf64_Phdr ph64;
> +@@ -306,13 +323,13 @@ 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) == -1) {
> ++		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
> + 			file_badread(ms);
> + 			return -1;
> + 		}
> + 		off += size;
> +
> +-		if (xph_offset > fsize) {
> ++		if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
> + 			/* Perhaps warn here */
> + 			continue;
> + 		}
> +@@ -334,7 +351,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> + 			if (offset >= (size_t)bufsize)
> + 				break;
> + 			offset = donote(ms, nbuf, offset, (size_t)bufsize,
> +-			    clazz, swap, 4, flags);
> ++			    clazz, swap, 4, flags, notecount);
> + 			if (offset == 0)
> + 				break;
> +
> +@@ -464,125 +481,127 @@ do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
> + 	}
> + }
> +
> +-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)
> ++private int
> ++do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
> ++    int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
> ++    size_t noff, size_t doff, int *flags)
> + {
> +-	Elf32_Nhdr nh32;
> +-	Elf64_Nhdr nh64;
> +-	size_t noff, doff;
> +-#ifdef ELFCORE
> +-	int os_style = -1;
> +-#endif
> +-	uint32_t namesz, descsz;
> +-	unsigned char *nbuf = CAST(unsigned char *, vbuf);
> +-
> +-	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
> +-	offset += xnh_sizeof;
> +-
> +-	namesz = xnh_namesz;
> +-	descsz = xnh_descsz;
> +-	if ((namesz == 0) && (descsz == 0)) {
> +-		/*
> +-		 * We're out of note headers.
> +-		 */
> +-		return (offset >= size) ? offset : size;
> +-	}
> +-
> +-	if (namesz & 0x80000000) {
> +-	    (void)file_printf(ms, ", bad note name size 0x%lx",
> +-		(unsigned long)namesz);
> +-	    return offset;
> +-	}
> +-
> +-	if (descsz & 0x80000000) {
> +-	    (void)file_printf(ms, ", bad note description size 0x%lx",
> +-		(unsigned long)descsz);
> +-	    return offset;
> +-	}
> +-
> +-
> +-	noff = offset;
> +-	doff = ELF_ALIGN(offset + namesz);
> +-
> +-	if (offset + namesz > size) {
> +-		/*
> +-		 * We're past the end of the buffer.
> +-		 */
> +-		return doff;
> +-	}
> +-
> +-	offset = ELF_ALIGN(doff + descsz);
> +-	if (doff + descsz > size) {
> +-		/*
> +-		 * We're past the end of the buffer.
> +-		 */
> +-		return (offset >= size) ? offset : size;
> ++	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
> ++	    type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
> ++		uint8_t desc[20];
> ++		uint32_t i;
> ++		*flags |= FLAGS_DID_BUILD_ID;
> ++		if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
> ++		    "sha1") == -1)
> ++			return 1;
> ++		(void)memcpy(desc, &nbuf[doff], descsz);
> ++		for (i = 0; i < descsz; i++)
> ++		    if (file_printf(ms, "%02x", desc[i]) == -1)
> ++			return 1;
> ++		return 1;
> + 	}
> +-
> +-	if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) ==
> +-	    (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID))
> +-		goto core;
> +-
> ++	return 0;
> ++}
> ++	
> ++private int
> ++do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
> ++    int swap, uint32_t namesz, uint32_t descsz,
> ++    size_t noff, size_t doff, int *flags)
> ++{
> + 	if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
> +-	    xnh_type == NT_GNU_VERSION && descsz == 2) {
> ++	    type == NT_GNU_VERSION && descsz == 2) {
> ++	    *flags |= FLAGS_DID_OS_NOTE;
> + 	    file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]);
> ++	    return 1;
> + 	}
> ++
> + 	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
> +-	    xnh_type == NT_GNU_VERSION && descsz == 16) {
> ++	    type == NT_GNU_VERSION && descsz == 16) {
> + 		uint32_t desc[4];
> + 		(void)memcpy(desc, &nbuf[doff], sizeof(desc));
> +
> ++		*flags |= FLAGS_DID_OS_NOTE;
> + 		if (file_printf(ms, ", for GNU/") == -1)
> +-			return size;
> ++			return 1;
> + 		switch (elf_getu32(swap, desc[0])) {
> + 		case GNU_OS_LINUX:
> + 			if (file_printf(ms, "Linux") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		case GNU_OS_HURD:
> + 			if (file_printf(ms, "Hurd") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		case GNU_OS_SOLARIS:
> + 			if (file_printf(ms, "Solaris") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		case GNU_OS_KFREEBSD:
> + 			if (file_printf(ms, "kFreeBSD") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		case GNU_OS_KNETBSD:
> + 			if (file_printf(ms, "kNetBSD") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		default:
> + 			if (file_printf(ms, "<unknown>") == -1)
> +-				return size;
> ++				return 1;
> + 		}
> + 		if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
> + 		    elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
> +-			return size;
> +-		*flags |= FLAGS_DID_NOTE;
> +-		return size;
> ++			return 1;
> ++		return 1;
> + 	}
> +
> +-	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
> +-	    xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
> +-	    uint8_t desc[20];
> +-	    uint32_t i;
> +-	    if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
> +-		"sha1") == -1)
> +-		    return size;
> +-	    (void)memcpy(desc, &nbuf[doff], descsz);
> +-	    for (i = 0; i < descsz; i++)
> +-		if (file_printf(ms, "%02x", desc[i]) == -1)
> +-		    return size;
> +-	    *flags |= FLAGS_DID_BUILD_ID;
> ++	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
> ++	    	if (type == NT_NETBSD_VERSION && descsz == 4) {
> ++			*flags |= FLAGS_DID_OS_NOTE;
> ++			do_note_netbsd_version(ms, swap, &nbuf[doff]);
> ++			return 1;
> ++		}
> ++	}
> ++
> ++	if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
> ++	    	if (type == NT_FREEBSD_VERSION && descsz == 4) {
> ++			*flags |= FLAGS_DID_OS_NOTE;
> ++			do_note_freebsd_version(ms, swap, &nbuf[doff]);
> ++			return 1;
> ++		}
> ++	}
> ++
> ++	if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
> ++	    type == NT_OPENBSD_VERSION && descsz == 4) {
> ++		*flags |= FLAGS_DID_OS_NOTE;
> ++		if (file_printf(ms, ", for OpenBSD") == -1)
> ++			return 1;
> ++		/* Content of note is always 0 */
> ++		return 1;
> ++	}
> ++
> ++	if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
> ++	    type == NT_DRAGONFLY_VERSION && descsz == 4) {
> ++		uint32_t desc;
> ++		*flags |= FLAGS_DID_OS_NOTE;
> ++		if (file_printf(ms, ", for DragonFly") == -1)
> ++			return 1;
> ++		(void)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)
> ++			return 1;
> ++		return 1;
> + 	}
> ++	return 0;
> ++}
> +
> ++private int
> ++do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
> ++    int swap, uint32_t namesz, uint32_t descsz,
> ++    size_t noff, size_t doff, int *flags)
> ++{
> + 	if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
> +-	    xnh_type == NT_NETBSD_PAX && descsz == 4) {
> ++	    type == NT_NETBSD_PAX && descsz == 4) {
> + 		static const char *pax[] = {
> + 		    "+mprotect",
> + 		    "-mprotect",
> +@@ -595,80 +614,32 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
> + 		size_t i;
> + 		int did = 0;
> +
> ++		*flags |= FLAGS_DID_NETBSD_PAX;
> + 		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
> + 		desc = elf_getu32(swap, desc);
> +
> + 		if (desc && file_printf(ms, ", PaX: ") == -1)
> +-			return size;
> ++			return 1;
> +
> + 		for (i = 0; i < __arraycount(pax); i++) {
> + 			if (((1 << i) & desc) == 0)
> + 				continue;
> + 			if (file_printf(ms, "%s%s", did++ ? "," : "",
> + 			    pax[i]) == -1)
> +-				return size;
> +-		}
> +-	}
> +-
> +-	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
> +-		switch (xnh_type) {
> +-		case NT_NETBSD_VERSION:
> +-			if (descsz == 4) {
> +-				do_note_netbsd_version(ms, swap, &nbuf[doff]);
> +-				*flags |= FLAGS_DID_NOTE;
> +-				return size;
> +-			}
> +-			break;
> +-		case NT_NETBSD_MARCH:
> +-			if (file_printf(ms, ", compiled for: %.*s", (int)descsz,
> +-			    (const char *)&nbuf[doff]) == -1)
> +-				return size;
> +-			break;
> +-		case NT_NETBSD_CMODEL:
> +-			if (file_printf(ms, ", compiler model: %.*s",
> +-			    (int)descsz, (const char *)&nbuf[doff]) == -1)
> +-				return size;
> +-			break;
> +-		default:
> +-			if (file_printf(ms, ", note=%u", xnh_type) == -1)
> +-				return size;
> +-			break;
> +-		}
> +-		return size;
> +-	}
> +-
> +-	if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
> +-	    	if (xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
> +-			do_note_freebsd_version(ms, swap, &nbuf[doff]);
> +-			*flags |= FLAGS_DID_NOTE;
> +-			return size;
> ++			return 1;
> + 		}
> ++		return 1;
> + 	}
> ++	return 0;
> ++}
> +
> +-	if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
> +-	    xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
> +-		if (file_printf(ms, ", for OpenBSD") == -1)
> +-			return size;
> +-		/* Content of note is always 0 */
> +-		*flags |= FLAGS_DID_NOTE;
> +-		return size;
> +-	}
> +-
> +-	if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
> +-	    xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
> +-		uint32_t desc;
> +-		if (file_printf(ms, ", for DragonFly") == -1)
> +-			return size;
> +-		(void)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)
> +-			return size;
> +-		*flags |= FLAGS_DID_NOTE;
> +-		return size;
> +-	}
> +-
> +-core:
> ++private int
> ++do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
> ++    int swap, uint32_t namesz, uint32_t descsz,
> ++    size_t noff, size_t doff, int *flags, size_t size, int clazz)
> ++{
> ++#ifdef ELFCORE
> ++	int os_style = -1;
> + 	/*
> + 	 * Sigh.  The 2.0.36 kernel in Debian 2.1, at
> + 	 * least, doesn't correctly implement name
> +@@ -697,20 +668,17 @@ core:
> + 		os_style = OS_STYLE_NETBSD;
> + 	}
> +
> +-#ifdef ELFCORE
> +-	if ((*flags & FLAGS_DID_CORE) != 0)
> +-		return size;
> +-
> + 	if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
> + 		if (file_printf(ms, ", %s-style", os_style_names[os_style])
> + 		    == -1)
> +-			return size;
> ++			return 1;
> + 		*flags |= FLAGS_DID_CORE_STYLE;
> + 	}
> +
> + 	switch (os_style) {
> + 	case OS_STYLE_NETBSD:
> +-		if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
> ++		if (type == NT_NETBSD_CORE_PROCINFO) {
> ++			char sbuf[512];
> + 			uint32_t signo;
> + 			/*
> + 			 * Extract the program name.  It is at
> +@@ -719,7 +687,7 @@ core:
> + 			 */
> + 			if (file_printf(ms, ", from '%.31s'",
> + 			    &nbuf[doff + 0x7c]) == -1)
> +-				return size;
> ++				return 1;
> + 			
> + 			/*
> + 			 * Extract the signal number.  It is at
> +@@ -736,8 +704,7 @@ core:
> + 		break;
> +
> + 	default:
> +-		if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
> +-/*###709 [cc] warning: declaration of 'i' shadows previous non-variable%%%*/
> ++		if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
> + 			size_t i, j;
> + 			unsigned char c;
> + 			/*
> +@@ -805,7 +772,7 @@ core:
> + 				 * Try next offsets, in case this match is
> + 				 * in the middle of a string.
> + 				 */
> +-				for (k = i + 1 ; k < NOFFSETS ; k++) {
> ++				for (k = i + 1 ; k < NOFFSETS; k++) {
> + 					size_t no;
> + 					int adjust = 1;
> + 					if (prpsoffsets(k) >= prpsoffsets(i))
> +@@ -830,9 +797,9 @@ core:
> + 					cp--;
> + 				if (file_printf(ms, ", from '%.*s'",
> + 				    (int)(cp - cname), cname) == -1)
> +-					return size;
> ++					return 1;
> + 				*flags |= FLAGS_DID_CORE;
> +-				return size;
> ++				return 1;
> +
> + 			tryanother:
> + 				;
> +@@ -841,6 +808,129 @@ core:
> + 		break;
> + 	}
> + #endif
> ++	return 0;
> ++}
> ++
> ++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)
> ++{
> ++	Elf32_Nhdr nh32;
> ++	Elf64_Nhdr nh64;
> ++	size_t noff, doff;
> ++	uint32_t namesz, descsz;
> ++	unsigned char *nbuf = CAST(unsigned char *, vbuf);
> ++
> ++	if (*notecount == 0)
> ++		return 0;
> ++	--*notecount;
> ++
> ++	if (xnh_sizeof + offset > size) {
> ++		/*
> ++		 * We're out of note headers.
> ++		 */
> ++		return xnh_sizeof + offset;
> ++	}
> ++
> ++	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
> ++	offset += xnh_sizeof;
> ++
> ++	namesz = xnh_namesz;
> ++	descsz = xnh_descsz;
> ++	if ((namesz == 0) && (descsz == 0)) {
> ++		/*
> ++		 * We're out of note headers.
> ++		 */
> ++		return (offset >= size) ? offset : size;
> ++	}
> ++
> ++	if (namesz & 0x80000000) {
> ++	    (void)file_printf(ms, ", bad note name size 0x%lx",
> ++		(unsigned long)namesz);
> ++	    return 0;
> ++	}
> ++
> ++	if (descsz & 0x80000000) {
> ++	    (void)file_printf(ms, ", bad note description size 0x%lx",
> ++		(unsigned long)descsz);
> ++	    return 0;
> ++	}
> ++
> ++	noff = offset;
> ++	doff = ELF_ALIGN(offset + namesz);
> ++
> ++	if (offset + namesz > size) {
> ++		/*
> ++		 * We're past the end of the buffer.
> ++		 */
> ++		return doff;
> ++	}
> ++
> ++	offset = ELF_ALIGN(doff + descsz);
> ++	if (doff + descsz > size) {
> ++		/*
> ++		 * We're past the end of the buffer.
> ++		 */
> ++		return (offset >= size) ? offset : size;
> ++	}
> ++
> ++	if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
> ++		if (do_os_note(ms, nbuf, xnh_type, swap,
> ++		    namesz, descsz, noff, doff, flags))
> ++			return size;
> ++	}
> ++
> ++	if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
> ++		if (do_bid_note(ms, nbuf, xnh_type, swap,
> ++		    namesz, descsz, noff, doff, flags))
> ++			return size;
> ++	}
> ++		
> ++	if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
> ++		if (do_pax_note(ms, nbuf, xnh_type, swap,
> ++		    namesz, descsz, noff, doff, flags))
> ++			return size;
> ++	}
> ++
> ++	if ((*flags & FLAGS_DID_CORE) == 0) {
> ++		if (do_core_note(ms, nbuf, xnh_type, swap,
> ++		    namesz, descsz, noff, doff, flags, size, clazz))
> ++			return size;
> ++	}
> ++
> ++	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
> ++		if (descsz > 100)
> ++			descsz = 100;
> ++		switch (xnh_type) {
> ++	    	case NT_NETBSD_VERSION:
> ++			return size;
> ++		case NT_NETBSD_MARCH:
> ++			if (*flags & FLAGS_DID_NETBSD_MARCH)
> ++				return size;
> ++			*flags |= FLAGS_DID_NETBSD_MARCH;
> ++			if (file_printf(ms, ", compiled for: %.*s",
> ++			    (int)descsz, (const char *)&nbuf[doff]) == -1)
> ++				return size;
> ++			break;
> ++		case NT_NETBSD_CMODEL:
> ++			if (*flags & FLAGS_DID_NETBSD_CMODEL)
> ++				return size;
> ++			*flags |= FLAGS_DID_NETBSD_CMODEL;
> ++			if (file_printf(ms, ", compiler model: %.*s",
> ++			    (int)descsz, (const char *)&nbuf[doff]) == -1)
> ++				return size;
> ++			break;
> ++		default:
> ++			if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
> ++				return size;
> ++			*flags |= FLAGS_DID_NETBSD_UNKNOWN;
> ++			if (file_printf(ms, ", note=%u", xnh_type) == -1)
> ++				return size;
> ++			break;
> ++		}
> ++		return size;
> ++	}
> ++
> + 	return offset;
> + }
> +
> +@@ -896,16 +986,19 @@ static const cap_desc_t cap_desc_386[] = {
> +
> + private int
> + doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> +-    size_t size, off_t fsize, int *flags, int mach, int strtab)
> ++    size_t size, off_t fsize, int mach, int strtab, int *flags,
> ++    uint16_t *notecount)
> + {
> + 	Elf32_Shdr sh32;
> + 	Elf64_Shdr sh64;
> + 	int stripped = 1;
> ++	size_t nbadcap = 0;
> + 	void *nbuf;
> + 	off_t noff, coff, name_off;
> + 	uint64_t cap_hw1 = 0;	/* SunOS 5.x hardware capabilites */
> + 	uint64_t cap_sf1 = 0;	/* SunOS 5.x software capabilites */
> + 	char name[50];
> ++	ssize_t namesize;
> +
> + 	if (size != xsh_sizeof) {
> + 		if (file_printf(ms, ", corrupted section header size") == -1)
> +@@ -914,7 +1007,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, off + size * strtab) == -1) {
> ++	if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) < (ssize_t)xsh_sizeof) {
> + 		file_badread(ms);
> + 		return -1;
> + 	}
> +@@ -922,15 +1015,15 @@ 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 (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) {
> ++		if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
> + 			file_badread(ms);
> + 			return -1;
> + 		}
> +-		name[sizeof(name) - 1] = '\0';
> ++		name[namesize] = '\0';
> + 		if (strcmp(name, ".debug_info") == 0)
> + 			stripped = 0;
> +
> +-		if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) {
> ++		if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
> + 			file_badread(ms);
> + 			return -1;
> + 		}
> +@@ -945,7 +1038,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 			stripped = 0;
> + 			break;
> + 		default:
> +-			if (xsh_offset > fsize) {
> ++			if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
> + 				/* Perhaps warn here */
> + 				continue;
> + 			}
> +@@ -960,7 +1053,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 				    " for note");
> + 				return -1;
> + 			}
> +-			if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) {
> ++			if (pread(fd, nbuf, xsh_size, xsh_offset) < (ssize_t)xsh_size) {
> + 				file_badread(ms);
> + 				free(nbuf);
> + 				return -1;
> +@@ -971,7 +1064,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 				if (noff >= (off_t)xsh_size)
> + 					break;
> + 				noff = donote(ms, nbuf, (size_t)noff,
> +-				    xsh_size, clazz, swap, 4, flags);
> ++				    xsh_size, clazz, swap, 4, flags, notecount);
> + 				if (noff == 0)
> + 					break;
> + 			}
> +@@ -989,6 +1082,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 				goto skip;
> + 			}
> +
> ++			if (nbadcap > 5)
> ++				break;
> + 			if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
> + 				file_badseek(ms);
> + 				return -1;
> +@@ -1024,6 +1119,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 					    (unsigned long long)xcap_tag,
> + 					    (unsigned long long)xcap_val) == -1)
> + 						return -1;
> ++					if (nbadcap++ > 2)
> ++						coff = xsh_size;
> + 					break;
> + 				}
> + 			}
> +@@ -1104,7 +1201,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> +  */
> + private int
> + dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> +-    int num, size_t size, off_t fsize, int *flags, int sh_num)
> ++    int num, size_t size, off_t fsize, int sh_num, int *flags,
> ++    uint16_t *notecount)
> + {
> + 	Elf32_Phdr ph32;
> + 	Elf64_Phdr ph64;
> +@@ -1121,7 +1219,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> + 	}
> +
> +   	for ( ; num; num--) {
> +-		if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
> ++		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
> + 			file_badread(ms);
> + 			return -1;
> + 		}
> +@@ -1137,7 +1235,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> + 			shared_libraries = " (uses shared libs)";
> + 			break;
> + 		default:
> +-			if (xph_offset > fsize) {
> ++			if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
> + 				/* Maybe warn here? */
> + 				continue;
> + 			}
> +@@ -1173,7 +1271,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> + 					break;
> + 				offset = donote(ms, nbuf, offset,
> + 				    (size_t)bufsize, clazz, swap, align,
> +-				    flags);
> ++				    flags, notecount);
> + 				if (offset == 0)
> + 					break;
> + 			}
> +@@ -1204,7 +1302,7 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
> + 	int flags = 0;
> + 	Elf32_Ehdr elf32hdr;
> + 	Elf64_Ehdr elf64hdr;
> +-	uint16_t type;
> ++	uint16_t type, phnum, shnum, notecount;
> +
> + 	if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
> + 		return 0;
> +@@ -1230,7 +1328,10 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
> +   		file_badread(ms);
> + 		return -1;
> + 	}
> +-	fsize = st.st_size;
> ++	if (S_ISREG(st.st_mode))
> ++		fsize = st.st_size;
> ++	else
> ++		fsize = SIZE_UNKNOWN;
> +
> + 	clazz = buf[EI_CLASS];
> +
> +diff --git a/src/softmagic.c b/src/softmagic.c
> +index dc7928b..b1f5779 100644
> +--- a/src/softmagic.c
> ++++ b/src/softmagic.c
> +@@ -43,11 +43,11 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.168 2013/05/30 15:53:33 christos Exp $")
> +
> +
> + private int match(struct magic_set *, struct magic *, uint32_t,
> +-    const unsigned char *, size_t, size_t, int, int, int, int, int *, int *,
> +-    int *);
> ++    const unsigned char *, size_t, size_t, int, int, int, uint16_t,
> ++    uint16_t *, int *, int *, int *);
> + private int mget(struct magic_set *, const unsigned char *,
> +-    struct magic *, size_t, size_t, unsigned int, int, int, int, int, int *,
> +-    int *, int *);
> ++    struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t,
> ++    uint16_t *, int *, int *, int *);
> + private int magiccheck(struct magic_set *, struct magic *);
> + private int32_t mprint(struct magic_set *, struct magic *);
> + private int32_t moffset(struct magic_set *, struct magic *);
> +@@ -69,14 +69,20 @@ private void cvt_64(union VALUETYPE *, const struct magic *);
> + /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
> + protected int
> + file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
> +-    int mode, int text)
> ++    uint16_t indir_level, uint16_t *name_count, int mode, int text)
> + {
> + 	struct mlist *ml;
> + 	int rv, printed_something = 0, need_separator = 0;
> ++	uint16_t nc;
> ++
> ++	if (name_count == NULL) {
> ++		nc = 0;
> ++		name_count = &nc;
> ++	}
> + 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
> + 		if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
> +-		    text, 0, 0, &printed_something, &need_separator,
> +-		    NULL)) != 0)
> ++		    text, 0, indir_level, name_count,
> ++		    &printed_something, &need_separator, NULL)) != 0)
> + 			return rv;
> +
> + 	return 0;
> +@@ -112,8 +118,8 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
> + private int
> + match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
> +     const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
> +-    int flip, int recursion_level, int *printed_something, int *need_separator,
> +-    int *returnval)
> ++    int flip, uint16_t indir_level, uint16_t *name_count,
> ++    int *printed_something, int *need_separator, int *returnval)
> + {
> + 	uint32_t magindex = 0;
> + 	unsigned int cont_level = 0;
> +@@ -150,8 +156,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
> +
> + 		/* if main entry matches, print it... */
> + 		switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
> +-		    flip, recursion_level + 1, printed_something,
> +-		    need_separator, returnval)) {
> ++		    flip, indir_level, name_count,
> ++		    printed_something, need_separator, returnval)) {
> + 		case -1:
> + 			return -1;
> + 		case 0:
> +@@ -237,8 +243,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
> + 			}
> + #endif
> + 			switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
> +-			    text, flip, recursion_level + 1, printed_something,
> +-			    need_separator, returnval)) {
> ++			    text, flip, indir_level, name_count,
> ++			    printed_something, need_separator, returnval)) {
> + 			case -1:
> + 				return -1;
> + 			case 0:
> +@@ -1120,8 +1126,8 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
> + private int
> + mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> +     size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
> +-    int flip, int recursion_level, int *printed_something,
> +-    int *need_separator, int *returnval)
> ++    int flip, uint16_t indir_level, uint16_t *name_count,
> ++    int *printed_something, int *need_separator, int *returnval)
> + {
> + 	uint32_t soffset, offset = ms->offset;
> + 	uint32_t count = m->str_range;
> +@@ -1130,8 +1136,15 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> + 	union VALUETYPE *p = &ms->ms_value;
> + 	struct mlist ml;
> +
> +-	if (recursion_level >= 20) {
> +-		file_error(ms, 0, "recursion nesting exceeded");
> ++	if (indir_level >= ms->indir_max) {
> ++		file_error(ms, 0, "indirect recursion nesting (%hu) exceeded",
> ++		    indir_level);
> ++		return -1;
> ++	}
> ++
> ++	if (*name_count >= ms->name_max) {
> ++		file_error(ms, 0, "name use count (%hu) exceeded",
> ++		    *name_count);
> + 		return -1;
> + 	}
> +
> +@@ -1141,8 +1154,9 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> +
> + 	if ((ms->flags & MAGIC_DEBUG) != 0) {
> + 		fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, "
> +-		    "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o,
> +-		    nbytes, count);
> ++		    "nbytes=%zu, il=%hu, nc=%hu)\n",
> ++		    m->type, m->flag, offset, o, nbytes,
> ++		    indir_level, *name_count);
> + 		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
> + #ifndef COMPILE_ONLY
> + 		file_mdump(m);
> +@@ -1711,7 +1725,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> + 		ms->o.buf = NULL;
> + 		ms->offset = 0;
> + 		rv = file_softmagic(ms, s + offset, nbytes - offset,
> +-		    BINTEST, text);
> ++		    indir_level + 1, name_count, BINTEST, text);
> + 		if ((ms->flags & MAGIC_DEBUG) != 0)
> + 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
> + 		rbuf = ms->o.buf;
> +@@ -1730,22 +1744,22 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> + 	case FILE_USE:
> + 		if (nbytes < offset)
> + 			return 0;
> +-		sbuf = m->value.s;
> +-		if (*sbuf == '^') {
> +-			sbuf++;
> ++		rbuf = m->value.s;
> ++		if (*rbuf == '^') {
> ++			rbuf++;
> + 			flip = !flip;
> + 		}
> +-		if (file_magicfind(ms, sbuf, &ml) == -1) {
> +-			file_error(ms, 0, "cannot find entry `%s'", sbuf);
> ++		if (file_magicfind(ms, rbuf, &ml) == -1) {
> ++			file_error(ms, 0, "cannot find entry `%s'", rbuf);
> + 			return -1;
> + 		}
> +-
> ++		(*name_count)++;
> + 		oneed_separator = *need_separator;
> + 		if (m->flag & NOSPACE)
> + 			*need_separator = 0;
> + 		rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
> +-		    mode, text, flip, recursion_level, printed_something,
> +-		    need_separator, returnval);
> ++		    mode, text, flip, indir_level, name_count,
> ++		    printed_something, need_separator, returnval);
> + 		if (rv != 1)
> + 		    *need_separator = oneed_separator;
> + 		return rv;
> +--
> +1.7.9.5
> +
> diff --git a/meta/recipes-devtools/file/file_5.16.bb b/meta/recipes-devtools/file/file_5.16.bb
> index a15d952..f231a55 100644
> --- a/meta/recipes-devtools/file/file_5.16.bb
> +++ b/meta/recipes-devtools/file/file_5.16.bb
> @@ -12,6 +12,7 @@ DEPENDS = "zlib file-native"
>   DEPENDS_class-native = "zlib-native"
>   
>   SRC_URI = "ftp://ftp.astron.com/pub/file/file-${PV}.tar.gz \
> +           file://file-CVE-2014-9620-and-CVE-2014-9621.patch \
>              file://dump \
>              file://filesystems"
>   



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [daisy][PATCH] file: CVE-2014-9620 and CVE-2014-9621
  2015-01-30  1:18 ` Chong Lu
@ 2015-01-30  3:57   ` Saul Wold
  0 siblings, 0 replies; 5+ messages in thread
From: Saul Wold @ 2015-01-30  3:57 UTC (permalink / raw)
  To: Chong Lu, openembedded-core

On 01/29/2015 05:18 PM, Chong Lu wrote:
> ping
>
Added to the sgw/daisy branch, will be tested on AB soon

Sau!

> //Chong
>
> On 01/22/2015 05:28 PM, Chong Lu wrote:
>> CVE-2014-9620:
>> Limit the number of ELF notes processed - DoS
>> CVE-2014-9621:
>> Limit string printing to 100 chars - DoS
>>
>> The patch comes from:
>> https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67
>>
>> https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6
>>
>> https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33
>>
>> https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba
>>
>> https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9
>>
>> https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7
>>
>> https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f
>>
>> https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4
>>
>> https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c
>>
>>
>> [YOCTO #7178]
>>
>> Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
>> ---
>>   .../file-CVE-2014-9620-and-CVE-2014-9621.patch     | 1357
>> ++++++++++++++++++++
>>   meta/recipes-devtools/file/file_5.16.bb            |    1 +
>>   2 files changed, 1358 insertions(+)
>>   create mode 100644
>> meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
>>
>>
>> diff --git
>> a/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
>> b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
>>
>> new file mode 100644
>> index 0000000..bd5944e
>> --- /dev/null
>> +++
>> b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
>>
>> @@ -0,0 +1,1357 @@
>> +file: CVE-2014-9620 and CVE-2014-9621
>> +
>> +The patch comes from:
>> +https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67
>>
>> +https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6
>>
>> +https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33
>>
>> +https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba
>>
>> +https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9
>>
>> +https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7
>>
>> +https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f
>>
>> +https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4
>>
>> +https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c
>>
>> +
>> +Upstream-Status: Backport
>> +
>> +Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
>> +---
>> + src/apprentice.c |    5 +
>> + src/ascmagic.c   |    3 +-
>> + src/elfclass.h   |   34 ++--
>> + src/file.c       |   58 ++++++-
>> + src/file.h       |   20 ++-
>> + src/file_opts.h  |    6 +
>> + src/funcs.c      |   42 ++++-
>> + src/magic.c      |   50 ++++++
>> + src/magic.h      |    9 ++
>> + src/magic.h.in   |    4 +
>> + src/readelf.c    |  467
>> +++++++++++++++++++++++++++++++++---------------------
>> + src/softmagic.c  |   70 ++++----
>> + 12 files changed, 541 insertions(+), 227 deletions(-)
>> +
>> +diff --git a/src/apprentice.c b/src/apprentice.c
>> +index 2df60d9..d906f7b 100644
>> +--- a/src/apprentice.c
>> ++++ b/src/apprentice.c
>> +@@ -494,6 +494,11 @@ file_ms_alloc(int flags)
>> +         ms->mlist[i] = NULL;
>> +     ms->file = "unknown";
>> +     ms->line = 0;
>> ++    ms->indir_max = FILE_INDIR_MAX;
>> ++    ms->name_max = FILE_NAME_MAX;
>> ++    ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
>> ++    ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
>> ++    ms->elf_notes_max = FILE_ELF_NOTES_MAX;
>> +     return ms;
>> + free:
>> +     free(ms);
>> +diff --git a/src/ascmagic.c b/src/ascmagic.c
>> +index 28ebadc..7a22328 100644
>> +--- a/src/ascmagic.c
>> ++++ b/src/ascmagic.c
>> +@@ -147,7 +147,8 @@ file_ascmagic_with_encoding(struct magic_set *ms,
>> const unsigned char *buf,
>> +             == NULL)
>> +             goto done;
>> +         if ((rv = file_softmagic(ms, utf8_buf,
>> +-            (size_t)(utf8_end - utf8_buf), TEXTTEST, text)) == 0)
>> ++            (size_t)(utf8_end - utf8_buf), 0, NULL,
>> ++            TEXTTEST, text)) == 0)
>> +             rv = -1;
>> +     }
>> +
>> +diff --git a/src/elfclass.h b/src/elfclass.h
>> +index 010958a..5360b0b 100644
>> +--- a/src/elfclass.h
>> ++++ b/src/elfclass.h
>> +@@ -32,39 +32,51 @@
>> +     swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
>> +
>> +     type = elf_getu16(swap, elfhdr.e_type);
>> ++    notecount = ms->elf_notes_max;
>> +     switch (type) {
>> + #ifdef ELFCORE
>> +     case ET_CORE:
>> ++        phnum = elf_getu16(swap, elfhdr.e_phnum);
>> ++        if (phnum > ms->elf_phnum_max)
>> ++            return toomany(ms, "program headers", phnum);
>> +         flags |= FLAGS_IS_CORE;
>> +         if (dophn_core(ms, clazz, swap, fd,
>> +-            (off_t)elf_getu(swap, elfhdr.e_phoff),
>> +-            elf_getu16(swap, elfhdr.e_phnum),
>> ++            (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
>> +             (size_t)elf_getu16(swap, elfhdr.e_phentsize),
>> +-            fsize, &flags) == -1)
>> ++            fsize, &flags, &notecount) == -1)
>> +             return -1;
>> +         break;
>> + #endif
>> +     case ET_EXEC:
>> +     case ET_DYN:
>> ++        phnum = elf_getu16(swap, elfhdr.e_phnum);
>> ++        if (phnum > ms->elf_phnum_max)
>> ++            return toomany(ms, "program", phnum);
>> ++        shnum = elf_getu16(swap, elfhdr.e_shnum);
>> ++        if (shnum > ms->elf_shnum_max)
>> ++            return toomany(ms, "section", shnum);
>> +         if (dophn_exec(ms, clazz, swap, fd,
>> +-            (off_t)elf_getu(swap, elfhdr.e_phoff),
>> +-            elf_getu16(swap, elfhdr.e_phnum),
>> ++            (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
>> +             (size_t)elf_getu16(swap, elfhdr.e_phentsize),
>> +-            fsize, &flags, elf_getu16(swap, elfhdr.e_shnum))
>> +-            == -1)
>> ++            fsize, shnum, &flags, &notecount) == -1)
>> +             return -1;
>> +         /*FALLTHROUGH*/
>> +     case ET_REL:
>> ++        shnum = elf_getu16(swap, elfhdr.e_shnum);
>> ++        if (shnum > ms->elf_shnum_max)
>> ++            return toomany(ms, "section headers", shnum);
>> +         if (doshn(ms, clazz, swap, fd,
>> +-            (off_t)elf_getu(swap, elfhdr.e_shoff),
>> +-            elf_getu16(swap, elfhdr.e_shnum),
>> ++            (off_t)elf_getu(swap, elfhdr.e_shoff), shnum,
>> +             (size_t)elf_getu16(swap, elfhdr.e_shentsize),
>> +-            fsize, &flags, elf_getu16(swap, elfhdr.e_machine),
>> +-            (int)elf_getu16(swap, elfhdr.e_shstrndx)) == -1)
>> ++            fsize, elf_getu16(swap, elfhdr.e_machine),
>> ++            (int)elf_getu16(swap, elfhdr.e_shstrndx),
>> ++            &flags, &notecount) == -1)
>> +             return -1;
>> +         break;
>> +
>> +     default:
>> +         break;
>> +     }
>> ++    if (notecount == 0)
>> ++        return toomany(ms, "notes", ms->elf_notes_max);
>> +     return 1;
>> +diff --git a/src/file.c b/src/file.c
>> +index ac773ea..ee1edcd 100644
>> +--- a/src/file.c
>> ++++ b/src/file.c
>> +@@ -101,7 +101,7 @@ private const struct option long_options[] = {
>> + #undef OPT_LONGONLY
>> +     {0, 0, NULL, 0}
>> + };
>> +-#define OPTSTRING    "bcCde:f:F:hiklLm:nNprsvz0"
>> ++#define OPTSTRING    "bcCde:f:F:hiklLm:nNpP:rsvz0"
>> +
>> + private const struct {
>> +     const char *name;
>> +@@ -119,6 +119,18 @@ private const struct {
>> +     { "tokens",    MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for
>> backwards compatibility */
>> + };
>> +
>> ++private struct {
>> ++    const char *name;
>> ++    int tag;
>> ++    size_t value;
>> ++} pm[] = {
>> ++    { "indir",    MAGIC_PARAM_INDIR_MAX, 0 },
>> ++    { "name",    MAGIC_PARAM_NAME_MAX, 0 },
>> ++    { "elf_phnum",    MAGIC_PARAM_ELF_PHNUM_MAX, 0 },
>> ++    { "elf_shnum",    MAGIC_PARAM_ELF_SHNUM_MAX, 0 },
>> ++    { "elf_notes",    MAGIC_PARAM_ELF_NOTES_MAX, 0 },
>> ++};
>> ++
>> + private char *progname;        /* used throughout         */
>> +
>> + private void usage(void);
>> +@@ -128,6 +140,8 @@ private void help(void);
>> + private int unwrap(struct magic_set *, const char *);
>> + private int process(struct magic_set *ms, const char *, int);
>> + private struct magic_set *load(const char *, int);
>> ++private void setparam(const char *);
>> ++private void applyparam(magic_t);
>> +
>> +
>> + /*
>> +@@ -240,6 +254,9 @@ main(int argc, char *argv[])
>> +             flags |= MAGIC_PRESERVE_ATIME;
>> +             break;
>> + #endif
>> ++        case 'P':
>> ++            setparam(optarg);
>> ++            break;
>> +         case 'r':
>> +             flags |= MAGIC_RAW;
>> +             break;
>> +@@ -295,6 +312,8 @@ main(int argc, char *argv[])
>> +                 strerror(errno));
>> +             return 1;
>> +         }
>> ++
>> ++
>> +         switch(action) {
>> +         case FILE_CHECK:
>> +             c = magic_check(magic, magicfile);
>> +@@ -318,7 +337,7 @@ main(int argc, char *argv[])
>> +         if (magic == NULL)
>> +             if ((magic = load(magicfile, flags)) == NULL)
>> +                 return 1;
>> +-        break;
>> ++        applyparam(magic);
>> +     }
>> +
>> +     if (optind == argc) {
>> +@@ -348,6 +367,41 @@ main(int argc, char *argv[])
>> +     return e;
>> + }
>> +
>> ++private void
>> ++applyparam(magic_t magic)
>> ++{
>> ++    size_t i;
>> ++
>> ++    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);
>> ++        }
>> ++    }
>> ++}
>> ++
>> ++private void
>> ++setparam(const char *p)
>> ++{
>> ++    size_t i;
>> ++    char *s;
>> ++
>> ++    if ((s = strchr(p, '=')) == NULL)
>> ++        goto badparm;
>> ++
>> ++    for (i = 0; i < __arraycount(pm); i++) {
>> ++        if (strncmp(p, pm[i].name, s - p) != 0)
>> ++            continue;
>> ++        pm[i].value = atoi(s + 1);
>> ++        return;
>> ++    }
>> ++badparm:
>> ++    (void)fprintf(stderr, "%s: Unknown param %s\n", progname, p);
>> ++    exit(1);
>> ++}
>> +
>> + private struct magic_set *
>> + /*ARGSUSED*/
>> +diff --git a/src/file.h b/src/file.h
>> +index e910a2b..57e7307 100644
>> +--- a/src/file.h
>> ++++ b/src/file.h
>> +@@ -400,6 +400,16 @@ struct magic_set {
>> +     /* FIXME: Make the string dynamically allocated so that e.g.
>> +        strings matched in files can be longer than MAXstring */
>> +     union VALUETYPE ms_value;    /* either number or string */
>> ++    uint16_t indir_max;
>> ++    uint16_t name_max;
>> ++    uint16_t elf_shnum_max;
>> ++    uint16_t elf_phnum_max;
>> ++    uint16_t elf_notes_max;
>> ++#define    FILE_INDIR_MAX            15
>> ++#define    FILE_NAME_MAX            30
>> ++#define    FILE_ELF_SHNUM_MAX        32768
>> ++#define    FILE_ELF_PHNUM_MAX        128
>> ++#define    FILE_ELF_NOTES_MAX        256
>> + };
>> +
>> + /* Type for Unicode characters */
>> +@@ -438,7 +448,7 @@ protected int file_encoding(struct magic_set *,
>> const unsigned char *, size_t,
>> +     unichar **, size_t *, const char **, const char **, const char **);
>> + protected int file_is_tar(struct magic_set *, const unsigned char *,
>> size_t);
>> + protected int file_softmagic(struct magic_set *, const unsigned char
>> *, size_t,
>> +-    int, int);
>> ++    uint16_t, uint16_t *, int, int);
>> + protected int file_apprentice(struct magic_set *, const char *, int);
>> + protected int file_magicfind(struct magic_set *, const char *,
>> struct mlist *);
>> + protected uint64_t file_signextend(struct magic_set *, struct magic *,
>> +@@ -468,6 +478,14 @@ protected int file_os2_apptype(struct magic_set
>> *, const char *, const void *,
>> + #endif /* __EMX__ */
>> +
>> +
>> ++typedef struct {
>> ++    char *buf;
>> ++    uint32_t offset;
>> ++} file_pushbuf_t;
>> ++
>> ++protected file_pushbuf_t *file_push_buffer(struct magic_set *);
>> ++protected char  *file_pop_buffer(struct magic_set *, file_pushbuf_t *);
>> ++
>> + #ifndef COMPILE_ONLY
>> + extern const char *file_names[];
>> + extern const size_t file_nnames;
>> +diff --git a/src/file_opts.h b/src/file_opts.h
>> +index db34eb7..3286ac6 100644
>> +--- a/src/file_opts.h
>> ++++ b/src/file_opts.h
>> +@@ -43,6 +43,12 @@ OPT('0', "print0", 0, "               terminate
>> filenames with ASCII NUL\n")
>> + #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
>> + OPT('p', "preserve-date", 0, "        preserve access times on
>> files\n")
>> + #endif
>> ++OPT('P', "parameter", 0, "            set file engine parameter
>> limits\n"
>> ++    "                               indir        15 recursion limit
>> for indirection\n"
>> ++    "                               name         30 use limit for
>> name/use magic\n"
>> ++    "                               elf_notes   256 max ELF notes
>> processed\n"
>> ++    "                               elf_phnum   128 max ELF prog
>> sections processed\n"
>> ++    "                               elf_shnum 32768 max ELF sections
>> processed\n")
>> + OPT('r', "raw", 0, "                  don't translate unprintable
>> chars to \\ooo\n")
>> + OPT('s', "special-files", 0, "        treat special (block/char
>> devices) files as\n"
>> +     "                             ordinary ones\n")
>> +diff --git a/src/funcs.c b/src/funcs.c
>> +index b798e44..50c38e5 100644
>> +--- a/src/funcs.c
>> ++++ b/src/funcs.c
>> +@@ -226,7 +226,7 @@ file_buffer(struct magic_set *ms, int fd, const
>> char *inname __attribute__ ((unu
>> +
>> +     /* try soft magic tests */
>> +     if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
>> +-        if ((m = file_softmagic(ms, ubuf, nb, BINTEST,
>> ++        if ((m = file_softmagic(ms, ubuf, nb, 0, NULL, BINTEST,
>> +             looks_text)) != 0) {
>> +             if ((ms->flags & MAGIC_DEBUG) != 0)
>> +                 (void)fprintf(stderr, "softmagic %d\n", m);
>> +@@ -459,3 +459,43 @@ file_replace(struct magic_set *ms, const char
>> *pat, const char *rep)
>> +         return nm;
>> +     }
>> + }
>> ++
>> ++protected file_pushbuf_t *
>> ++file_push_buffer(struct magic_set *ms)
>> ++{
>> ++    file_pushbuf_t *pb;
>> ++
>> ++    if (ms->event_flags & EVENT_HAD_ERR)
>> ++        return NULL;
>> ++
>> ++    if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
>> ++        return NULL;
>> ++
>> ++    pb->buf = ms->o.buf;
>> ++    pb->offset = ms->offset;
>> ++
>> ++    ms->o.buf = NULL;
>> ++    ms->offset = 0;
>> ++
>> ++    return pb;
>> ++}
>> ++
>> ++protected char *
>> ++file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
>> ++{
>> ++    char *rbuf;
>> ++
>> ++    if (ms->event_flags & EVENT_HAD_ERR) {
>> ++        free(pb->buf);
>> ++        free(pb);
>> ++        return NULL;
>> ++    }
>> ++
>> ++    rbuf = ms->o.buf;
>> ++
>> ++    ms->o.buf = pb->buf;
>> ++    ms->offset = pb->offset;
>> ++
>> ++    free(pb);
>> ++    return rbuf;
>> ++}
>> +diff --git a/src/magic.c b/src/magic.c
>> +index 22174b8..a89647c 100644
>> +--- a/src/magic.c
>> ++++ b/src/magic.c
>> +@@ -490,3 +490,53 @@ magic_version(void)
>> + {
>> +     return MAGIC_VERSION;
>> + }
>> ++
>> ++public int
>> ++magic_setparam(struct magic_set *ms, int param, const void *val)
>> ++{
>> ++    switch (param) {
>> ++    case MAGIC_PARAM_INDIR_MAX:
>> ++        ms->indir_max = *(const size_t *)val;
>> ++        return 0;
>> ++    case MAGIC_PARAM_NAME_MAX:
>> ++        ms->name_max = *(const size_t *)val;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_PHNUM_MAX:
>> ++        ms->elf_phnum_max = *(const size_t *)val;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_SHNUM_MAX:
>> ++        ms->elf_shnum_max = *(const size_t *)val;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_NOTES_MAX:
>> ++        ms->elf_notes_max = *(const size_t *)val;
>> ++        return 0;
>> ++    default:
>> ++        errno = EINVAL;
>> ++        return -1;
>> ++    }
>> ++}
>> ++
>> ++public int
>> ++magic_getparam(struct magic_set *ms, int param, void *val)
>> ++{
>> ++    switch (param) {
>> ++    case MAGIC_PARAM_INDIR_MAX:
>> ++        *(size_t *)val = ms->indir_max;
>> ++        return 0;
>> ++    case MAGIC_PARAM_NAME_MAX:
>> ++        *(size_t *)val = ms->name_max;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_PHNUM_MAX:
>> ++        *(size_t *)val = ms->elf_phnum_max;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_SHNUM_MAX:
>> ++        *(size_t *)val = ms->elf_shnum_max;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_NOTES_MAX:
>> ++        *(size_t *)val = ms->elf_notes_max;
>> ++        return 0;
>> ++    default:
>> ++        errno = EINVAL;
>> ++        return -1;
>> ++    }
>> ++}
>> +diff --git a/src/magic.h b/src/magic.h
>> +index cc8ed68..2938a20 100644
>> +--- a/src/magic.h
>> ++++ b/src/magic.h
>> +@@ -101,6 +101,15 @@ int magic_check(magic_t, const char *);
>> + int magic_list(magic_t, const char *);
>> + int magic_errno(magic_t);
>> +
>> ++#define MAGIC_PARAM_INDIR_MAX        0
>> ++#define MAGIC_PARAM_NAME_MAX        1
>> ++#define MAGIC_PARAM_ELF_PHNUM_MAX    2
>> ++#define MAGIC_PARAM_ELF_SHNUM_MAX    3
>> ++#define MAGIC_PARAM_ELF_NOTES_MAX    4
>> ++
>> ++int magic_setparam(magic_t, int, const void *);
>> ++int magic_getparam(magic_t, int, void *);
>> ++
>> + #ifdef __cplusplus
>> + };
>> + #endif
>> +diff --git a/src/magic.h.in b/src/magic.h.in
>> +index 86fc41b..a256cf0 100644
>> +--- a/src/magic.h.in
>> ++++ b/src/magic.h.in
>> +@@ -101,6 +101,10 @@ int magic_check(magic_t, const char *);
>> + int magic_list(magic_t, const char *);
>> + int magic_errno(magic_t);
>> +
>> ++#define MAGIC_PARAM_MAX_RECURSION    0
>> ++int magic_setparam(magic_t, int, const void *);
>> ++int magic_getparam(magic_t, int, void *);
>> ++
>> + #ifdef __cplusplus
>> + };
>> + #endif
>> +diff --git a/src/readelf.c b/src/readelf.c
>> +index f8b8bbc..a7b2ba4 100644
>> +--- a/src/readelf.c
>> ++++ b/src/readelf.c
>> +@@ -43,14 +43,14 @@ FILE_RCSID("@(#)$File: readelf.c,v 1.99
>> 2013/11/05 15:44:01 christos Exp $")
>> +
>> + #ifdef    ELFCORE
>> + private int dophn_core(struct magic_set *, int, int, int, off_t,
>> int, size_t,
>> +-    off_t, int *);
>> ++    off_t, int *, uint16_t *);
>> + #endif
>> + private int dophn_exec(struct magic_set *, int, int, int, off_t,
>> int, size_t,
>> +-    off_t, int *, int);
>> ++    off_t, int, int *, uint16_t *);
>> + private int doshn(struct magic_set *, int, int, int, off_t, int,
>> size_t,
>> +-    off_t, int *, int, int);
>> ++    off_t, int, int, int *, uint16_t *);
>> + private size_t donote(struct magic_set *, void *, size_t, size_t, int,
>> +-    int, size_t, int *);
>> ++    int, size_t, int *, uint16_t *);
>> +
>> + #define    ELF_ALIGN(a)    ((((a) + align - 1) / align) * align)
>> +
>> +@@ -60,6 +60,19 @@ private uint16_t getu16(int, uint16_t);
>> + private uint32_t getu32(int, uint32_t);
>> + private uint64_t getu64(int, uint64_t);
>> +
>> ++#define MAX_PHNUM    128
>> ++#define    MAX_SHNUM    32768
>> ++#define SIZE_UNKNOWN    ((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)
>> ++        return -1;
>> ++    return 0;
>> ++}
>> ++
>> + private uint16_t
>> + getu16(int swap, uint16_t value)
>> + {
>> +@@ -280,15 +293,19 @@ private const char os_style_names[][8] = {
>> +     "NetBSD",
>> + };
>> +
>> +-#define FLAGS_DID_CORE        0x01
>> +-#define FLAGS_DID_NOTE        0x02
>> +-#define FLAGS_DID_BUILD_ID    0x04
>> +-#define FLAGS_DID_CORE_STYLE    0x08
>> +-#define FLAGS_IS_CORE        0x10
>> ++#define FLAGS_DID_CORE            0x001
>> ++#define FLAGS_DID_OS_NOTE        0x002
>> ++#define FLAGS_DID_BUILD_ID        0x004
>> ++#define FLAGS_DID_CORE_STYLE        0x008
>> ++#define FLAGS_DID_NETBSD_PAX        0x010
>> ++#define FLAGS_DID_NETBSD_MARCH        0x020
>> ++#define FLAGS_DID_NETBSD_CMODEL        0x040
>> ++#define FLAGS_DID_NETBSD_UNKNOWN    0x080
>> ++#define FLAGS_IS_CORE            0x100
>> +
>> + private int
>> + dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t
>> off,
>> +-    int num, size_t size, off_t fsize, int *flags)
>> ++    int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
>> + {
>> +     Elf32_Phdr ph32;
>> +     Elf64_Phdr ph64;
>> +@@ -306,13 +323,13 @@ 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) == -1) {
>> ++        if (pread(fd, xph_addr, xph_sizeof, off) <
>> (ssize_t)xph_sizeof) {
>> +             file_badread(ms);
>> +             return -1;
>> +         }
>> +         off += size;
>> +
>> +-        if (xph_offset > fsize) {
>> ++        if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
>> +             /* Perhaps warn here */
>> +             continue;
>> +         }
>> +@@ -334,7 +351,7 @@ dophn_core(struct magic_set *ms, int clazz, int
>> swap, int fd, off_t off,
>> +             if (offset >= (size_t)bufsize)
>> +                 break;
>> +             offset = donote(ms, nbuf, offset, (size_t)bufsize,
>> +-                clazz, swap, 4, flags);
>> ++                clazz, swap, 4, flags, notecount);
>> +             if (offset == 0)
>> +                 break;
>> +
>> +@@ -464,125 +481,127 @@ do_note_freebsd_version(struct magic_set *ms,
>> int swap, void *v)
>> +     }
>> + }
>> +
>> +-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)
>> ++private int
>> ++do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
>> ++    int swap __attribute__((__unused__)), uint32_t namesz, uint32_t
>> descsz,
>> ++    size_t noff, size_t doff, int *flags)
>> + {
>> +-    Elf32_Nhdr nh32;
>> +-    Elf64_Nhdr nh64;
>> +-    size_t noff, doff;
>> +-#ifdef ELFCORE
>> +-    int os_style = -1;
>> +-#endif
>> +-    uint32_t namesz, descsz;
>> +-    unsigned char *nbuf = CAST(unsigned char *, vbuf);
>> +-
>> +-    (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
>> +-    offset += xnh_sizeof;
>> +-
>> +-    namesz = xnh_namesz;
>> +-    descsz = xnh_descsz;
>> +-    if ((namesz == 0) && (descsz == 0)) {
>> +-        /*
>> +-         * We're out of note headers.
>> +-         */
>> +-        return (offset >= size) ? offset : size;
>> +-    }
>> +-
>> +-    if (namesz & 0x80000000) {
>> +-        (void)file_printf(ms, ", bad note name size 0x%lx",
>> +-        (unsigned long)namesz);
>> +-        return offset;
>> +-    }
>> +-
>> +-    if (descsz & 0x80000000) {
>> +-        (void)file_printf(ms, ", bad note description size 0x%lx",
>> +-        (unsigned long)descsz);
>> +-        return offset;
>> +-    }
>> +-
>> +-
>> +-    noff = offset;
>> +-    doff = ELF_ALIGN(offset + namesz);
>> +-
>> +-    if (offset + namesz > size) {
>> +-        /*
>> +-         * We're past the end of the buffer.
>> +-         */
>> +-        return doff;
>> +-    }
>> +-
>> +-    offset = ELF_ALIGN(doff + descsz);
>> +-    if (doff + descsz > size) {
>> +-        /*
>> +-         * We're past the end of the buffer.
>> +-         */
>> +-        return (offset >= size) ? offset : size;
>> ++    if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
>> ++        type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
>> ++        uint8_t desc[20];
>> ++        uint32_t i;
>> ++        *flags |= FLAGS_DID_BUILD_ID;
>> ++        if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ?
>> "md5/uuid" :
>> ++            "sha1") == -1)
>> ++            return 1;
>> ++        (void)memcpy(desc, &nbuf[doff], descsz);
>> ++        for (i = 0; i < descsz; i++)
>> ++            if (file_printf(ms, "%02x", desc[i]) == -1)
>> ++            return 1;
>> ++        return 1;
>> +     }
>> +-
>> +-    if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) ==
>> +-        (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID))
>> +-        goto core;
>> +-
>> ++    return 0;
>> ++}
>> ++
>> ++private int
>> ++do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
>> ++    int swap, uint32_t namesz, uint32_t descsz,
>> ++    size_t noff, size_t doff, int *flags)
>> ++{
>> +     if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
>> +-        xnh_type == NT_GNU_VERSION && descsz == 2) {
>> ++        type == NT_GNU_VERSION && descsz == 2) {
>> ++        *flags |= FLAGS_DID_OS_NOTE;
>> +         file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff +
>> 1]);
>> ++        return 1;
>> +     }
>> ++
>> +     if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
>> +-        xnh_type == NT_GNU_VERSION && descsz == 16) {
>> ++        type == NT_GNU_VERSION && descsz == 16) {
>> +         uint32_t desc[4];
>> +         (void)memcpy(desc, &nbuf[doff], sizeof(desc));
>> +
>> ++        *flags |= FLAGS_DID_OS_NOTE;
>> +         if (file_printf(ms, ", for GNU/") == -1)
>> +-            return size;
>> ++            return 1;
>> +         switch (elf_getu32(swap, desc[0])) {
>> +         case GNU_OS_LINUX:
>> +             if (file_printf(ms, "Linux") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         case GNU_OS_HURD:
>> +             if (file_printf(ms, "Hurd") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         case GNU_OS_SOLARIS:
>> +             if (file_printf(ms, "Solaris") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         case GNU_OS_KFREEBSD:
>> +             if (file_printf(ms, "kFreeBSD") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         case GNU_OS_KNETBSD:
>> +             if (file_printf(ms, "kNetBSD") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         default:
>> +             if (file_printf(ms, "<unknown>") == -1)
>> +-                return size;
>> ++                return 1;
>> +         }
>> +         if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
>> +             elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) ==
>> -1)
>> +-            return size;
>> +-        *flags |= FLAGS_DID_NOTE;
>> +-        return size;
>> ++            return 1;
>> ++        return 1;
>> +     }
>> +
>> +-    if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
>> +-        xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz ==
>> 20)) {
>> +-        uint8_t desc[20];
>> +-        uint32_t i;
>> +-        if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ?
>> "md5/uuid" :
>> +-        "sha1") == -1)
>> +-            return size;
>> +-        (void)memcpy(desc, &nbuf[doff], descsz);
>> +-        for (i = 0; i < descsz; i++)
>> +-        if (file_printf(ms, "%02x", desc[i]) == -1)
>> +-            return size;
>> +-        *flags |= FLAGS_DID_BUILD_ID;
>> ++    if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
>> ++            if (type == NT_NETBSD_VERSION && descsz == 4) {
>> ++            *flags |= FLAGS_DID_OS_NOTE;
>> ++            do_note_netbsd_version(ms, swap, &nbuf[doff]);
>> ++            return 1;
>> ++        }
>> ++    }
>> ++
>> ++    if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
>> ++            if (type == NT_FREEBSD_VERSION && descsz == 4) {
>> ++            *flags |= FLAGS_DID_OS_NOTE;
>> ++            do_note_freebsd_version(ms, swap, &nbuf[doff]);
>> ++            return 1;
>> ++        }
>> ++    }
>> ++
>> ++    if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
>> ++        type == NT_OPENBSD_VERSION && descsz == 4) {
>> ++        *flags |= FLAGS_DID_OS_NOTE;
>> ++        if (file_printf(ms, ", for OpenBSD") == -1)
>> ++            return 1;
>> ++        /* Content of note is always 0 */
>> ++        return 1;
>> ++    }
>> ++
>> ++    if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") ==
>> 0 &&
>> ++        type == NT_DRAGONFLY_VERSION && descsz == 4) {
>> ++        uint32_t desc;
>> ++        *flags |= FLAGS_DID_OS_NOTE;
>> ++        if (file_printf(ms, ", for DragonFly") == -1)
>> ++            return 1;
>> ++        (void)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)
>> ++            return 1;
>> ++        return 1;
>> +     }
>> ++    return 0;
>> ++}
>> +
>> ++private int
>> ++do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
>> ++    int swap, uint32_t namesz, uint32_t descsz,
>> ++    size_t noff, size_t doff, int *flags)
>> ++{
>> +     if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
>> +-        xnh_type == NT_NETBSD_PAX && descsz == 4) {
>> ++        type == NT_NETBSD_PAX && descsz == 4) {
>> +         static const char *pax[] = {
>> +             "+mprotect",
>> +             "-mprotect",
>> +@@ -595,80 +614,32 @@ donote(struct magic_set *ms, void *vbuf, size_t
>> offset, size_t size,
>> +         size_t i;
>> +         int did = 0;
>> +
>> ++        *flags |= FLAGS_DID_NETBSD_PAX;
>> +         (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
>> +         desc = elf_getu32(swap, desc);
>> +
>> +         if (desc && file_printf(ms, ", PaX: ") == -1)
>> +-            return size;
>> ++            return 1;
>> +
>> +         for (i = 0; i < __arraycount(pax); i++) {
>> +             if (((1 << i) & desc) == 0)
>> +                 continue;
>> +             if (file_printf(ms, "%s%s", did++ ? "," : "",
>> +                 pax[i]) == -1)
>> +-                return size;
>> +-        }
>> +-    }
>> +-
>> +-    if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
>> +-        switch (xnh_type) {
>> +-        case NT_NETBSD_VERSION:
>> +-            if (descsz == 4) {
>> +-                do_note_netbsd_version(ms, swap, &nbuf[doff]);
>> +-                *flags |= FLAGS_DID_NOTE;
>> +-                return size;
>> +-            }
>> +-            break;
>> +-        case NT_NETBSD_MARCH:
>> +-            if (file_printf(ms, ", compiled for: %.*s", (int)descsz,
>> +-                (const char *)&nbuf[doff]) == -1)
>> +-                return size;
>> +-            break;
>> +-        case NT_NETBSD_CMODEL:
>> +-            if (file_printf(ms, ", compiler model: %.*s",
>> +-                (int)descsz, (const char *)&nbuf[doff]) == -1)
>> +-                return size;
>> +-            break;
>> +-        default:
>> +-            if (file_printf(ms, ", note=%u", xnh_type) == -1)
>> +-                return size;
>> +-            break;
>> +-        }
>> +-        return size;
>> +-    }
>> +-
>> +-    if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
>> +-            if (xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
>> +-            do_note_freebsd_version(ms, swap, &nbuf[doff]);
>> +-            *flags |= FLAGS_DID_NOTE;
>> +-            return size;
>> ++            return 1;
>> +         }
>> ++        return 1;
>> +     }
>> ++    return 0;
>> ++}
>> +
>> +-    if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
>> +-        xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
>> +-        if (file_printf(ms, ", for OpenBSD") == -1)
>> +-            return size;
>> +-        /* Content of note is always 0 */
>> +-        *flags |= FLAGS_DID_NOTE;
>> +-        return size;
>> +-    }
>> +-
>> +-    if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") ==
>> 0 &&
>> +-        xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
>> +-        uint32_t desc;
>> +-        if (file_printf(ms, ", for DragonFly") == -1)
>> +-            return size;
>> +-        (void)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)
>> +-            return size;
>> +-        *flags |= FLAGS_DID_NOTE;
>> +-        return size;
>> +-    }
>> +-
>> +-core:
>> ++private int
>> ++do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
>> ++    int swap, uint32_t namesz, uint32_t descsz,
>> ++    size_t noff, size_t doff, int *flags, size_t size, int clazz)
>> ++{
>> ++#ifdef ELFCORE
>> ++    int os_style = -1;
>> +     /*
>> +      * Sigh.  The 2.0.36 kernel in Debian 2.1, at
>> +      * least, doesn't correctly implement name
>> +@@ -697,20 +668,17 @@ core:
>> +         os_style = OS_STYLE_NETBSD;
>> +     }
>> +
>> +-#ifdef ELFCORE
>> +-    if ((*flags & FLAGS_DID_CORE) != 0)
>> +-        return size;
>> +-
>> +     if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
>> +         if (file_printf(ms, ", %s-style", os_style_names[os_style])
>> +             == -1)
>> +-            return size;
>> ++            return 1;
>> +         *flags |= FLAGS_DID_CORE_STYLE;
>> +     }
>> +
>> +     switch (os_style) {
>> +     case OS_STYLE_NETBSD:
>> +-        if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
>> ++        if (type == NT_NETBSD_CORE_PROCINFO) {
>> ++            char sbuf[512];
>> +             uint32_t signo;
>> +             /*
>> +              * Extract the program name.  It is at
>> +@@ -719,7 +687,7 @@ core:
>> +              */
>> +             if (file_printf(ms, ", from '%.31s'",
>> +                 &nbuf[doff + 0x7c]) == -1)
>> +-                return size;
>> ++                return 1;
>> +
>> +             /*
>> +              * Extract the signal number.  It is at
>> +@@ -736,8 +704,7 @@ core:
>> +         break;
>> +
>> +     default:
>> +-        if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
>> +-/*###709 [cc] warning: declaration of 'i' shadows previous
>> non-variable%%%*/
>> ++        if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
>> +             size_t i, j;
>> +             unsigned char c;
>> +             /*
>> +@@ -805,7 +772,7 @@ core:
>> +                  * Try next offsets, in case this match is
>> +                  * in the middle of a string.
>> +                  */
>> +-                for (k = i + 1 ; k < NOFFSETS ; k++) {
>> ++                for (k = i + 1 ; k < NOFFSETS; k++) {
>> +                     size_t no;
>> +                     int adjust = 1;
>> +                     if (prpsoffsets(k) >= prpsoffsets(i))
>> +@@ -830,9 +797,9 @@ core:
>> +                     cp--;
>> +                 if (file_printf(ms, ", from '%.*s'",
>> +                     (int)(cp - cname), cname) == -1)
>> +-                    return size;
>> ++                    return 1;
>> +                 *flags |= FLAGS_DID_CORE;
>> +-                return size;
>> ++                return 1;
>> +
>> +             tryanother:
>> +                 ;
>> +@@ -841,6 +808,129 @@ core:
>> +         break;
>> +     }
>> + #endif
>> ++    return 0;
>> ++}
>> ++
>> ++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)
>> ++{
>> ++    Elf32_Nhdr nh32;
>> ++    Elf64_Nhdr nh64;
>> ++    size_t noff, doff;
>> ++    uint32_t namesz, descsz;
>> ++    unsigned char *nbuf = CAST(unsigned char *, vbuf);
>> ++
>> ++    if (*notecount == 0)
>> ++        return 0;
>> ++    --*notecount;
>> ++
>> ++    if (xnh_sizeof + offset > size) {
>> ++        /*
>> ++         * We're out of note headers.
>> ++         */
>> ++        return xnh_sizeof + offset;
>> ++    }
>> ++
>> ++    (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
>> ++    offset += xnh_sizeof;
>> ++
>> ++    namesz = xnh_namesz;
>> ++    descsz = xnh_descsz;
>> ++    if ((namesz == 0) && (descsz == 0)) {
>> ++        /*
>> ++         * We're out of note headers.
>> ++         */
>> ++        return (offset >= size) ? offset : size;
>> ++    }
>> ++
>> ++    if (namesz & 0x80000000) {
>> ++        (void)file_printf(ms, ", bad note name size 0x%lx",
>> ++        (unsigned long)namesz);
>> ++        return 0;
>> ++    }
>> ++
>> ++    if (descsz & 0x80000000) {
>> ++        (void)file_printf(ms, ", bad note description size 0x%lx",
>> ++        (unsigned long)descsz);
>> ++        return 0;
>> ++    }
>> ++
>> ++    noff = offset;
>> ++    doff = ELF_ALIGN(offset + namesz);
>> ++
>> ++    if (offset + namesz > size) {
>> ++        /*
>> ++         * We're past the end of the buffer.
>> ++         */
>> ++        return doff;
>> ++    }
>> ++
>> ++    offset = ELF_ALIGN(doff + descsz);
>> ++    if (doff + descsz > size) {
>> ++        /*
>> ++         * We're past the end of the buffer.
>> ++         */
>> ++        return (offset >= size) ? offset : size;
>> ++    }
>> ++
>> ++    if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
>> ++        if (do_os_note(ms, nbuf, xnh_type, swap,
>> ++            namesz, descsz, noff, doff, flags))
>> ++            return size;
>> ++    }
>> ++
>> ++    if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
>> ++        if (do_bid_note(ms, nbuf, xnh_type, swap,
>> ++            namesz, descsz, noff, doff, flags))
>> ++            return size;
>> ++    }
>> ++
>> ++    if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
>> ++        if (do_pax_note(ms, nbuf, xnh_type, swap,
>> ++            namesz, descsz, noff, doff, flags))
>> ++            return size;
>> ++    }
>> ++
>> ++    if ((*flags & FLAGS_DID_CORE) == 0) {
>> ++        if (do_core_note(ms, nbuf, xnh_type, swap,
>> ++            namesz, descsz, noff, doff, flags, size, clazz))
>> ++            return size;
>> ++    }
>> ++
>> ++    if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
>> ++        if (descsz > 100)
>> ++            descsz = 100;
>> ++        switch (xnh_type) {
>> ++            case NT_NETBSD_VERSION:
>> ++            return size;
>> ++        case NT_NETBSD_MARCH:
>> ++            if (*flags & FLAGS_DID_NETBSD_MARCH)
>> ++                return size;
>> ++            *flags |= FLAGS_DID_NETBSD_MARCH;
>> ++            if (file_printf(ms, ", compiled for: %.*s",
>> ++                (int)descsz, (const char *)&nbuf[doff]) == -1)
>> ++                return size;
>> ++            break;
>> ++        case NT_NETBSD_CMODEL:
>> ++            if (*flags & FLAGS_DID_NETBSD_CMODEL)
>> ++                return size;
>> ++            *flags |= FLAGS_DID_NETBSD_CMODEL;
>> ++            if (file_printf(ms, ", compiler model: %.*s",
>> ++                (int)descsz, (const char *)&nbuf[doff]) == -1)
>> ++                return size;
>> ++            break;
>> ++        default:
>> ++            if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
>> ++                return size;
>> ++            *flags |= FLAGS_DID_NETBSD_UNKNOWN;
>> ++            if (file_printf(ms, ", note=%u", xnh_type) == -1)
>> ++                return size;
>> ++            break;
>> ++        }
>> ++        return size;
>> ++    }
>> ++
>> +     return offset;
>> + }
>> +
>> +@@ -896,16 +986,19 @@ static const cap_desc_t cap_desc_386[] = {
>> +
>> + private int
>> + doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
>> int num,
>> +-    size_t size, off_t fsize, int *flags, int mach, int strtab)
>> ++    size_t size, off_t fsize, int mach, int strtab, int *flags,
>> ++    uint16_t *notecount)
>> + {
>> +     Elf32_Shdr sh32;
>> +     Elf64_Shdr sh64;
>> +     int stripped = 1;
>> ++    size_t nbadcap = 0;
>> +     void *nbuf;
>> +     off_t noff, coff, name_off;
>> +     uint64_t cap_hw1 = 0;    /* SunOS 5.x hardware capabilites */
>> +     uint64_t cap_sf1 = 0;    /* SunOS 5.x software capabilites */
>> +     char name[50];
>> ++    ssize_t namesize;
>> +
>> +     if (size != xsh_sizeof) {
>> +         if (file_printf(ms, ", corrupted section header size") == -1)
>> +@@ -914,7 +1007,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, off + size * strtab) == -1) {
>> ++    if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) <
>> (ssize_t)xsh_sizeof) {
>> +         file_badread(ms);
>> +         return -1;
>> +     }
>> +@@ -922,15 +1015,15 @@ 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 (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) {
>> ++        if ((namesize = pread(fd, name, sizeof(name) - 1, name_off +
>> xsh_name)) == -1) {
>> +             file_badread(ms);
>> +             return -1;
>> +         }
>> +-        name[sizeof(name) - 1] = '\0';
>> ++        name[namesize] = '\0';
>> +         if (strcmp(name, ".debug_info") == 0)
>> +             stripped = 0;
>> +
>> +-        if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) {
>> ++        if (pread(fd, xsh_addr, xsh_sizeof, off) <
>> (ssize_t)xsh_sizeof) {
>> +             file_badread(ms);
>> +             return -1;
>> +         }
>> +@@ -945,7 +1038,7 @@ doshn(struct magic_set *ms, int clazz, int swap,
>> int fd, off_t off, int num,
>> +             stripped = 0;
>> +             break;
>> +         default:
>> +-            if (xsh_offset > fsize) {
>> ++            if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
>> +                 /* Perhaps warn here */
>> +                 continue;
>> +             }
>> +@@ -960,7 +1053,7 @@ doshn(struct magic_set *ms, int clazz, int swap,
>> int fd, off_t off, int num,
>> +                     " for note");
>> +                 return -1;
>> +             }
>> +-            if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) {
>> ++            if (pread(fd, nbuf, xsh_size, xsh_offset) <
>> (ssize_t)xsh_size) {
>> +                 file_badread(ms);
>> +                 free(nbuf);
>> +                 return -1;
>> +@@ -971,7 +1064,7 @@ doshn(struct magic_set *ms, int clazz, int swap,
>> int fd, off_t off, int num,
>> +                 if (noff >= (off_t)xsh_size)
>> +                     break;
>> +                 noff = donote(ms, nbuf, (size_t)noff,
>> +-                    xsh_size, clazz, swap, 4, flags);
>> ++                    xsh_size, clazz, swap, 4, flags, notecount);
>> +                 if (noff == 0)
>> +                     break;
>> +             }
>> +@@ -989,6 +1082,8 @@ doshn(struct magic_set *ms, int clazz, int swap,
>> int fd, off_t off, int num,
>> +                 goto skip;
>> +             }
>> +
>> ++            if (nbadcap > 5)
>> ++                break;
>> +             if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
>> +                 file_badseek(ms);
>> +                 return -1;
>> +@@ -1024,6 +1119,8 @@ doshn(struct magic_set *ms, int clazz, int
>> swap, int fd, off_t off, int num,
>> +                         (unsigned long long)xcap_tag,
>> +                         (unsigned long long)xcap_val) == -1)
>> +                         return -1;
>> ++                    if (nbadcap++ > 2)
>> ++                        coff = xsh_size;
>> +                     break;
>> +                 }
>> +             }
>> +@@ -1104,7 +1201,8 @@ doshn(struct magic_set *ms, int clazz, int
>> swap, int fd, off_t off, int num,
>> +  */
>> + private int
>> + dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t
>> off,
>> +-    int num, size_t size, off_t fsize, int *flags, int sh_num)
>> ++    int num, size_t size, off_t fsize, int sh_num, int *flags,
>> ++    uint16_t *notecount)
>> + {
>> +     Elf32_Phdr ph32;
>> +     Elf64_Phdr ph64;
>> +@@ -1121,7 +1219,7 @@ dophn_exec(struct magic_set *ms, int clazz, int
>> swap, int fd, off_t off,
>> +     }
>> +
>> +       for ( ; num; num--) {
>> +-        if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
>> ++        if (pread(fd, xph_addr, xph_sizeof, off) <
>> (ssize_t)xph_sizeof) {
>> +             file_badread(ms);
>> +             return -1;
>> +         }
>> +@@ -1137,7 +1235,7 @@ dophn_exec(struct magic_set *ms, int clazz, int
>> swap, int fd, off_t off,
>> +             shared_libraries = " (uses shared libs)";
>> +             break;
>> +         default:
>> +-            if (xph_offset > fsize) {
>> ++            if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
>> +                 /* Maybe warn here? */
>> +                 continue;
>> +             }
>> +@@ -1173,7 +1271,7 @@ dophn_exec(struct magic_set *ms, int clazz, int
>> swap, int fd, off_t off,
>> +                     break;
>> +                 offset = donote(ms, nbuf, offset,
>> +                     (size_t)bufsize, clazz, swap, align,
>> +-                    flags);
>> ++                    flags, notecount);
>> +                 if (offset == 0)
>> +                     break;
>> +             }
>> +@@ -1204,7 +1302,7 @@ file_tryelf(struct magic_set *ms, int fd, const
>> unsigned char *buf,
>> +     int flags = 0;
>> +     Elf32_Ehdr elf32hdr;
>> +     Elf64_Ehdr elf64hdr;
>> +-    uint16_t type;
>> ++    uint16_t type, phnum, shnum, notecount;
>> +
>> +     if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
>> +         return 0;
>> +@@ -1230,7 +1328,10 @@ file_tryelf(struct magic_set *ms, int fd,
>> const unsigned char *buf,
>> +           file_badread(ms);
>> +         return -1;
>> +     }
>> +-    fsize = st.st_size;
>> ++    if (S_ISREG(st.st_mode))
>> ++        fsize = st.st_size;
>> ++    else
>> ++        fsize = SIZE_UNKNOWN;
>> +
>> +     clazz = buf[EI_CLASS];
>> +
>> +diff --git a/src/softmagic.c b/src/softmagic.c
>> +index dc7928b..b1f5779 100644
>> +--- a/src/softmagic.c
>> ++++ b/src/softmagic.c
>> +@@ -43,11 +43,11 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.168
>> 2013/05/30 15:53:33 christos Exp $")
>> +
>> +
>> + private int match(struct magic_set *, struct magic *, uint32_t,
>> +-    const unsigned char *, size_t, size_t, int, int, int, int, int
>> *, int *,
>> +-    int *);
>> ++    const unsigned char *, size_t, size_t, int, int, int, uint16_t,
>> ++    uint16_t *, int *, int *, int *);
>> + private int mget(struct magic_set *, const unsigned char *,
>> +-    struct magic *, size_t, size_t, unsigned int, int, int, int,
>> int, int *,
>> +-    int *, int *);
>> ++    struct magic *, size_t, size_t, unsigned int, int, int, int,
>> uint16_t,
>> ++    uint16_t *, int *, int *, int *);
>> + private int magiccheck(struct magic_set *, struct magic *);
>> + private int32_t mprint(struct magic_set *, struct magic *);
>> + private int32_t moffset(struct magic_set *, struct magic *);
>> +@@ -69,14 +69,20 @@ private void cvt_64(union VALUETYPE *, const
>> struct magic *);
>> + /*ARGSUSED1*/        /* nbytes passed for regularity, maybe need
>> later */
>> + protected int
>> + file_softmagic(struct magic_set *ms, const unsigned char *buf,
>> size_t nbytes,
>> +-    int mode, int text)
>> ++    uint16_t indir_level, uint16_t *name_count, int mode, int text)
>> + {
>> +     struct mlist *ml;
>> +     int rv, printed_something = 0, need_separator = 0;
>> ++    uint16_t nc;
>> ++
>> ++    if (name_count == NULL) {
>> ++        nc = 0;
>> ++        name_count = &nc;
>> ++    }
>> +     for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
>> +         if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0,
>> mode,
>> +-            text, 0, 0, &printed_something, &need_separator,
>> +-            NULL)) != 0)
>> ++            text, 0, indir_level, name_count,
>> ++            &printed_something, &need_separator, NULL)) != 0)
>> +             return rv;
>> +
>> +     return 0;
>> +@@ -112,8 +118,8 @@ file_softmagic(struct magic_set *ms, const
>> unsigned char *buf, size_t nbytes,
>> + private int
>> + match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
>> +     const unsigned char *s, size_t nbytes, size_t offset, int mode,
>> int text,
>> +-    int flip, int recursion_level, int *printed_something, int
>> *need_separator,
>> +-    int *returnval)
>> ++    int flip, uint16_t indir_level, uint16_t *name_count,
>> ++    int *printed_something, int *need_separator, int *returnval)
>> + {
>> +     uint32_t magindex = 0;
>> +     unsigned int cont_level = 0;
>> +@@ -150,8 +156,8 @@ match(struct magic_set *ms, struct magic *magic,
>> uint32_t nmagic,
>> +
>> +         /* if main entry matches, print it... */
>> +         switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
>> +-            flip, recursion_level + 1, printed_something,
>> +-            need_separator, returnval)) {
>> ++            flip, indir_level, name_count,
>> ++            printed_something, need_separator, returnval)) {
>> +         case -1:
>> +             return -1;
>> +         case 0:
>> +@@ -237,8 +243,8 @@ match(struct magic_set *ms, struct magic *magic,
>> uint32_t nmagic,
>> +             }
>> + #endif
>> +             switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
>> +-                text, flip, recursion_level + 1, printed_something,
>> +-                need_separator, returnval)) {
>> ++                text, flip, indir_level, name_count,
>> ++                printed_something, need_separator, returnval)) {
>> +             case -1:
>> +                 return -1;
>> +             case 0:
>> +@@ -1120,8 +1126,8 @@ mcopy(struct magic_set *ms, union VALUETYPE *p,
>> int type, int indir,
>> + private int
>> + mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
>> +     size_t nbytes, size_t o, unsigned int cont_level, int mode, int
>> text,
>> +-    int flip, int recursion_level, int *printed_something,
>> +-    int *need_separator, int *returnval)
>> ++    int flip, uint16_t indir_level, uint16_t *name_count,
>> ++    int *printed_something, int *need_separator, int *returnval)
>> + {
>> +     uint32_t soffset, offset = ms->offset;
>> +     uint32_t count = m->str_range;
>> +@@ -1130,8 +1136,15 @@ mget(struct magic_set *ms, const unsigned char
>> *s, struct magic *m,
>> +     union VALUETYPE *p = &ms->ms_value;
>> +     struct mlist ml;
>> +
>> +-    if (recursion_level >= 20) {
>> +-        file_error(ms, 0, "recursion nesting exceeded");
>> ++    if (indir_level >= ms->indir_max) {
>> ++        file_error(ms, 0, "indirect recursion nesting (%hu) exceeded",
>> ++            indir_level);
>> ++        return -1;
>> ++    }
>> ++
>> ++    if (*name_count >= ms->name_max) {
>> ++        file_error(ms, 0, "name use count (%hu) exceeded",
>> ++            *name_count);
>> +         return -1;
>> +     }
>> +
>> +@@ -1141,8 +1154,9 @@ mget(struct magic_set *ms, const unsigned char
>> *s, struct magic *m,
>> +
>> +     if ((ms->flags & MAGIC_DEBUG) != 0) {
>> +         fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, "
>> +-            "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o,
>> +-            nbytes, count);
>> ++            "nbytes=%zu, il=%hu, nc=%hu)\n",
>> ++            m->type, m->flag, offset, o, nbytes,
>> ++            indir_level, *name_count);
>> +         mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
>> + #ifndef COMPILE_ONLY
>> +         file_mdump(m);
>> +@@ -1711,7 +1725,7 @@ mget(struct magic_set *ms, const unsigned char
>> *s, struct magic *m,
>> +         ms->o.buf = NULL;
>> +         ms->offset = 0;
>> +         rv = file_softmagic(ms, s + offset, nbytes - offset,
>> +-            BINTEST, text);
>> ++            indir_level + 1, name_count, BINTEST, text);
>> +         if ((ms->flags & MAGIC_DEBUG) != 0)
>> +             fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
>> +         rbuf = ms->o.buf;
>> +@@ -1730,22 +1744,22 @@ mget(struct magic_set *ms, const unsigned
>> char *s, struct magic *m,
>> +     case FILE_USE:
>> +         if (nbytes < offset)
>> +             return 0;
>> +-        sbuf = m->value.s;
>> +-        if (*sbuf == '^') {
>> +-            sbuf++;
>> ++        rbuf = m->value.s;
>> ++        if (*rbuf == '^') {
>> ++            rbuf++;
>> +             flip = !flip;
>> +         }
>> +-        if (file_magicfind(ms, sbuf, &ml) == -1) {
>> +-            file_error(ms, 0, "cannot find entry `%s'", sbuf);
>> ++        if (file_magicfind(ms, rbuf, &ml) == -1) {
>> ++            file_error(ms, 0, "cannot find entry `%s'", rbuf);
>> +             return -1;
>> +         }
>> +-
>> ++        (*name_count)++;
>> +         oneed_separator = *need_separator;
>> +         if (m->flag & NOSPACE)
>> +             *need_separator = 0;
>> +         rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
>> +-            mode, text, flip, recursion_level, printed_something,
>> +-            need_separator, returnval);
>> ++            mode, text, flip, indir_level, name_count,
>> ++            printed_something, need_separator, returnval);
>> +         if (rv != 1)
>> +             *need_separator = oneed_separator;
>> +         return rv;
>> +--
>> +1.7.9.5
>> +
>> diff --git a/meta/recipes-devtools/file/file_5.16.bb
>> b/meta/recipes-devtools/file/file_5.16.bb
>> index a15d952..f231a55 100644
>> --- a/meta/recipes-devtools/file/file_5.16.bb
>> +++ b/meta/recipes-devtools/file/file_5.16.bb
>> @@ -12,6 +12,7 @@ DEPENDS = "zlib file-native"
>>   DEPENDS_class-native = "zlib-native"
>>   SRC_URI = "ftp://ftp.astron.com/pub/file/file-${PV}.tar.gz \
>> +           file://file-CVE-2014-9620-and-CVE-2014-9621.patch \
>>              file://dump \
>>              file://filesystems"
>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [daisy][PATCH] file: CVE-2014-9620 and CVE-2014-9621
  2015-01-22  9:28 [daisy][PATCH] file: CVE-2014-9620 and CVE-2014-9621 Chong Lu
  2015-01-30  1:18 ` Chong Lu
@ 2015-02-02 13:55 ` Saul Wold
  2015-02-03  1:23   ` Chong Lu
  1 sibling, 1 reply; 5+ messages in thread
From: Saul Wold @ 2015-02-02 13:55 UTC (permalink / raw)
  To: Chong Lu, openembedded-core


I had some issues with this patch on the Autobuilder, it failed in some 
cases for nativesdk-file on some, but not all machines of the autobuilder.

See: 
https://autobuilder.yoctoproject.org/main/builders/nightly-arm/builds/178/steps/Building%20Toolchain%20Images/logs/stdio

That's one example of the failure.

Sau!



On 01/22/2015 01:28 AM, Chong Lu wrote:
> CVE-2014-9620:
> Limit the number of ELF notes processed - DoS
> CVE-2014-9621:
> Limit string printing to 100 chars - DoS
>
> The patch comes from:
> https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67
> https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6
> https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33
> https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba
> https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9
> https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7
> https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f
> https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4
> https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c
>
> [YOCTO #7178]
>
> Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
> ---
>   .../file-CVE-2014-9620-and-CVE-2014-9621.patch     | 1357 ++++++++++++++++++++
>   meta/recipes-devtools/file/file_5.16.bb            |    1 +
>   2 files changed, 1358 insertions(+)
>   create mode 100644 meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
>
> diff --git a/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
> new file mode 100644
> index 0000000..bd5944e
> --- /dev/null
> +++ b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
> @@ -0,0 +1,1357 @@
> +file: CVE-2014-9620 and CVE-2014-9621
> +
> +The patch comes from:
> +https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67
> +https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6
> +https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33
> +https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba
> +https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9
> +https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7
> +https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f
> +https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4
> +https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c
> +
> +Upstream-Status: Backport
> +
> +Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
> +---
> + src/apprentice.c |    5 +
> + src/ascmagic.c   |    3 +-
> + src/elfclass.h   |   34 ++--
> + src/file.c       |   58 ++++++-
> + src/file.h       |   20 ++-
> + src/file_opts.h  |    6 +
> + src/funcs.c      |   42 ++++-
> + src/magic.c      |   50 ++++++
> + src/magic.h      |    9 ++
> + src/magic.h.in   |    4 +
> + src/readelf.c    |  467 +++++++++++++++++++++++++++++++++---------------------
> + src/softmagic.c  |   70 ++++----
> + 12 files changed, 541 insertions(+), 227 deletions(-)
> +
> +diff --git a/src/apprentice.c b/src/apprentice.c
> +index 2df60d9..d906f7b 100644
> +--- a/src/apprentice.c
> ++++ b/src/apprentice.c
> +@@ -494,6 +494,11 @@ file_ms_alloc(int flags)
> + 		ms->mlist[i] = NULL;
> + 	ms->file = "unknown";
> + 	ms->line = 0;
> ++	ms->indir_max = FILE_INDIR_MAX;
> ++	ms->name_max = FILE_NAME_MAX;
> ++	ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
> ++	ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
> ++	ms->elf_notes_max = FILE_ELF_NOTES_MAX;
> + 	return ms;
> + free:
> + 	free(ms);
> +diff --git a/src/ascmagic.c b/src/ascmagic.c
> +index 28ebadc..7a22328 100644
> +--- a/src/ascmagic.c
> ++++ b/src/ascmagic.c
> +@@ -147,7 +147,8 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf,
> + 		    == NULL)
> + 			goto done;
> + 		if ((rv = file_softmagic(ms, utf8_buf,
> +-		    (size_t)(utf8_end - utf8_buf), TEXTTEST, text)) == 0)
> ++		    (size_t)(utf8_end - utf8_buf), 0, NULL,
> ++		    TEXTTEST, text)) == 0)
> + 			rv = -1;
> + 	}
> +
> +diff --git a/src/elfclass.h b/src/elfclass.h
> +index 010958a..5360b0b 100644
> +--- a/src/elfclass.h
> ++++ b/src/elfclass.h
> +@@ -32,39 +32,51 @@
> + 	swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
> +
> + 	type = elf_getu16(swap, elfhdr.e_type);
> ++	notecount = ms->elf_notes_max;
> + 	switch (type) {
> + #ifdef ELFCORE
> + 	case ET_CORE:
> ++		phnum = elf_getu16(swap, elfhdr.e_phnum);
> ++		if (phnum > ms->elf_phnum_max)
> ++			return toomany(ms, "program headers", phnum);
> + 		flags |= FLAGS_IS_CORE;
> + 		if (dophn_core(ms, clazz, swap, fd,
> +-		    (off_t)elf_getu(swap, elfhdr.e_phoff),
> +-		    elf_getu16(swap, elfhdr.e_phnum),
> ++		    (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
> + 		    (size_t)elf_getu16(swap, elfhdr.e_phentsize),
> +-		    fsize, &flags) == -1)
> ++		    fsize, &flags, &notecount) == -1)
> + 			return -1;
> + 		break;
> + #endif
> + 	case ET_EXEC:
> + 	case ET_DYN:
> ++		phnum = elf_getu16(swap, elfhdr.e_phnum);
> ++		if (phnum > ms->elf_phnum_max)
> ++			return toomany(ms, "program", phnum);
> ++		shnum = elf_getu16(swap, elfhdr.e_shnum);
> ++		if (shnum > ms->elf_shnum_max)
> ++			return toomany(ms, "section", shnum);
> + 		if (dophn_exec(ms, clazz, swap, fd,
> +-		    (off_t)elf_getu(swap, elfhdr.e_phoff),
> +-		    elf_getu16(swap, elfhdr.e_phnum),
> ++		    (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
> + 		    (size_t)elf_getu16(swap, elfhdr.e_phentsize),
> +-		    fsize, &flags, elf_getu16(swap, elfhdr.e_shnum))
> +-		    == -1)
> ++		    fsize, shnum, &flags, &notecount) == -1)
> + 			return -1;
> + 		/*FALLTHROUGH*/
> + 	case ET_REL:
> ++		shnum = elf_getu16(swap, elfhdr.e_shnum);
> ++		if (shnum > ms->elf_shnum_max)
> ++			return toomany(ms, "section headers", shnum);
> + 		if (doshn(ms, clazz, swap, fd,
> +-		    (off_t)elf_getu(swap, elfhdr.e_shoff),
> +-		    elf_getu16(swap, elfhdr.e_shnum),
> ++		    (off_t)elf_getu(swap, elfhdr.e_shoff), shnum,
> + 		    (size_t)elf_getu16(swap, elfhdr.e_shentsize),
> +-		    fsize, &flags, elf_getu16(swap, elfhdr.e_machine),
> +-		    (int)elf_getu16(swap, elfhdr.e_shstrndx)) == -1)
> ++		    fsize, elf_getu16(swap, elfhdr.e_machine),
> ++		    (int)elf_getu16(swap, elfhdr.e_shstrndx),
> ++		    &flags, &notecount) == -1)
> + 			return -1;
> + 		break;
> +
> + 	default:
> + 		break;
> + 	}
> ++	if (notecount == 0)
> ++		return toomany(ms, "notes", ms->elf_notes_max);
> + 	return 1;
> +diff --git a/src/file.c b/src/file.c
> +index ac773ea..ee1edcd 100644
> +--- a/src/file.c
> ++++ b/src/file.c
> +@@ -101,7 +101,7 @@ private const struct option long_options[] = {
> + #undef OPT_LONGONLY
> +     {0, 0, NULL, 0}
> + };
> +-#define OPTSTRING	"bcCde:f:F:hiklLm:nNprsvz0"
> ++#define OPTSTRING	"bcCde:f:F:hiklLm:nNpP:rsvz0"
> +
> + private const struct {
> + 	const char *name;
> +@@ -119,6 +119,18 @@ private const struct {
> + 	{ "tokens",	MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */
> + };
> +
> ++private struct {
> ++	const char *name;
> ++	int tag;
> ++	size_t value;
> ++} pm[] = {
> ++	{ "indir",	MAGIC_PARAM_INDIR_MAX, 0 },
> ++	{ "name",	MAGIC_PARAM_NAME_MAX, 0 },
> ++	{ "elf_phnum",	MAGIC_PARAM_ELF_PHNUM_MAX, 0 },
> ++	{ "elf_shnum",	MAGIC_PARAM_ELF_SHNUM_MAX, 0 },
> ++	{ "elf_notes",	MAGIC_PARAM_ELF_NOTES_MAX, 0 },
> ++};
> ++
> + private char *progname;		/* used throughout 		*/
> +
> + private void usage(void);
> +@@ -128,6 +140,8 @@ private void help(void);
> + private int unwrap(struct magic_set *, const char *);
> + private int process(struct magic_set *ms, const char *, int);
> + private struct magic_set *load(const char *, int);
> ++private void setparam(const char *);
> ++private void applyparam(magic_t);
> +
> +
> + /*
> +@@ -240,6 +254,9 @@ main(int argc, char *argv[])
> + 			flags |= MAGIC_PRESERVE_ATIME;
> + 			break;
> + #endif
> ++		case 'P':
> ++			setparam(optarg);
> ++			break;
> + 		case 'r':
> + 			flags |= MAGIC_RAW;
> + 			break;
> +@@ -295,6 +312,8 @@ main(int argc, char *argv[])
> + 			    strerror(errno));
> + 			return 1;
> + 		}
> ++
> ++
> + 		switch(action) {
> + 		case FILE_CHECK:
> + 			c = magic_check(magic, magicfile);
> +@@ -318,7 +337,7 @@ main(int argc, char *argv[])
> + 		if (magic == NULL)
> + 			if ((magic = load(magicfile, flags)) == NULL)
> + 				return 1;
> +-		break;
> ++		applyparam(magic);
> + 	}
> +
> + 	if (optind == argc) {
> +@@ -348,6 +367,41 @@ main(int argc, char *argv[])
> + 	return e;
> + }
> +
> ++private void
> ++applyparam(magic_t magic)
> ++{
> ++	size_t i;
> ++
> ++	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);
> ++		}
> ++	}
> ++}
> ++
> ++private void
> ++setparam(const char *p)
> ++{
> ++	size_t i;
> ++	char *s;
> ++
> ++	if ((s = strchr(p, '=')) == NULL)
> ++		goto badparm;
> ++
> ++	for (i = 0; i < __arraycount(pm); i++) {
> ++		if (strncmp(p, pm[i].name, s - p) != 0)
> ++			continue;
> ++		pm[i].value = atoi(s + 1);
> ++		return;
> ++	}
> ++badparm:
> ++	(void)fprintf(stderr, "%s: Unknown param %s\n", progname, p);
> ++	exit(1);
> ++}
> +
> + private struct magic_set *
> + /*ARGSUSED*/
> +diff --git a/src/file.h b/src/file.h
> +index e910a2b..57e7307 100644
> +--- a/src/file.h
> ++++ b/src/file.h
> +@@ -400,6 +400,16 @@ struct magic_set {
> + 	/* FIXME: Make the string dynamically allocated so that e.g.
> + 	   strings matched in files can be longer than MAXstring */
> + 	union VALUETYPE ms_value;	/* either number or string */
> ++	uint16_t indir_max;
> ++	uint16_t name_max;
> ++	uint16_t elf_shnum_max;
> ++	uint16_t elf_phnum_max;
> ++	uint16_t elf_notes_max;
> ++#define	FILE_INDIR_MAX			15
> ++#define	FILE_NAME_MAX			30
> ++#define	FILE_ELF_SHNUM_MAX		32768
> ++#define	FILE_ELF_PHNUM_MAX		128
> ++#define	FILE_ELF_NOTES_MAX		256
> + };
> +
> + /* Type for Unicode characters */
> +@@ -438,7 +448,7 @@ protected int file_encoding(struct magic_set *, const unsigned char *, size_t,
> +     unichar **, size_t *, const char **, const char **, const char **);
> + protected int file_is_tar(struct magic_set *, const unsigned char *, size_t);
> + protected int file_softmagic(struct magic_set *, const unsigned char *, size_t,
> +-    int, int);
> ++    uint16_t, uint16_t *, int, int);
> + protected int file_apprentice(struct magic_set *, const char *, int);
> + protected int file_magicfind(struct magic_set *, const char *, struct mlist *);
> + protected uint64_t file_signextend(struct magic_set *, struct magic *,
> +@@ -468,6 +478,14 @@ protected int file_os2_apptype(struct magic_set *, const char *, const void *,
> + #endif /* __EMX__ */
> +
> +
> ++typedef struct {
> ++	char *buf;
> ++	uint32_t offset;
> ++} file_pushbuf_t;
> ++
> ++protected file_pushbuf_t *file_push_buffer(struct magic_set *);
> ++protected char  *file_pop_buffer(struct magic_set *, file_pushbuf_t *);
> ++
> + #ifndef COMPILE_ONLY
> + extern const char *file_names[];
> + extern const size_t file_nnames;
> +diff --git a/src/file_opts.h b/src/file_opts.h
> +index db34eb7..3286ac6 100644
> +--- a/src/file_opts.h
> ++++ b/src/file_opts.h
> +@@ -43,6 +43,12 @@ OPT('0', "print0", 0, "               terminate filenames with ASCII NUL\n")
> + #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
> + OPT('p', "preserve-date", 0, "        preserve access times on files\n")
> + #endif
> ++OPT('P', "parameter", 0, "            set file engine parameter limits\n"
> ++    "                               indir        15 recursion limit for indirection\n"
> ++    "                               name         30 use limit for name/use magic\n"
> ++    "                               elf_notes   256 max ELF notes processed\n"
> ++    "                               elf_phnum   128 max ELF prog sections processed\n"
> ++    "                               elf_shnum 32768 max ELF sections processed\n")
> + OPT('r', "raw", 0, "                  don't translate unprintable chars to \\ooo\n")
> + OPT('s', "special-files", 0, "        treat special (block/char devices) files as\n"
> +     "                             ordinary ones\n")
> +diff --git a/src/funcs.c b/src/funcs.c
> +index b798e44..50c38e5 100644
> +--- a/src/funcs.c
> ++++ b/src/funcs.c
> +@@ -226,7 +226,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu
> +
> + 	/* try soft magic tests */
> + 	if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
> +-		if ((m = file_softmagic(ms, ubuf, nb, BINTEST,
> ++		if ((m = file_softmagic(ms, ubuf, nb, 0, NULL, BINTEST,
> + 		    looks_text)) != 0) {
> + 			if ((ms->flags & MAGIC_DEBUG) != 0)
> + 				(void)fprintf(stderr, "softmagic %d\n", m);
> +@@ -459,3 +459,43 @@ file_replace(struct magic_set *ms, const char *pat, const char *rep)
> + 		return nm;
> + 	}
> + }
> ++
> ++protected file_pushbuf_t *
> ++file_push_buffer(struct magic_set *ms)
> ++{
> ++	file_pushbuf_t *pb;
> ++
> ++	if (ms->event_flags & EVENT_HAD_ERR)
> ++		return NULL;
> ++
> ++	if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
> ++		return NULL;
> ++
> ++	pb->buf = ms->o.buf;
> ++	pb->offset = ms->offset;
> ++
> ++	ms->o.buf = NULL;
> ++	ms->offset = 0;
> ++
> ++	return pb;
> ++}
> ++
> ++protected char *
> ++file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
> ++{
> ++	char *rbuf;
> ++
> ++	if (ms->event_flags & EVENT_HAD_ERR) {
> ++		free(pb->buf);
> ++		free(pb);
> ++		return NULL;
> ++	}
> ++
> ++	rbuf = ms->o.buf;
> ++
> ++	ms->o.buf = pb->buf;
> ++	ms->offset = pb->offset;
> ++
> ++	free(pb);
> ++	return rbuf;
> ++}
> +diff --git a/src/magic.c b/src/magic.c
> +index 22174b8..a89647c 100644
> +--- a/src/magic.c
> ++++ b/src/magic.c
> +@@ -490,3 +490,53 @@ magic_version(void)
> + {
> + 	return MAGIC_VERSION;
> + }
> ++
> ++public int
> ++magic_setparam(struct magic_set *ms, int param, const void *val)
> ++{
> ++	switch (param) {
> ++	case MAGIC_PARAM_INDIR_MAX:
> ++		ms->indir_max = *(const size_t *)val;
> ++		return 0;
> ++	case MAGIC_PARAM_NAME_MAX:
> ++		ms->name_max = *(const size_t *)val;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_PHNUM_MAX:
> ++		ms->elf_phnum_max = *(const size_t *)val;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_SHNUM_MAX:
> ++		ms->elf_shnum_max = *(const size_t *)val;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_NOTES_MAX:
> ++		ms->elf_notes_max = *(const size_t *)val;
> ++		return 0;
> ++	default:
> ++		errno = EINVAL;
> ++		return -1;
> ++	}
> ++}
> ++
> ++public int
> ++magic_getparam(struct magic_set *ms, int param, void *val)
> ++{
> ++	switch (param) {
> ++	case MAGIC_PARAM_INDIR_MAX:
> ++		*(size_t *)val = ms->indir_max;
> ++		return 0;
> ++	case MAGIC_PARAM_NAME_MAX:
> ++		*(size_t *)val = ms->name_max;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_PHNUM_MAX:
> ++		*(size_t *)val = ms->elf_phnum_max;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_SHNUM_MAX:
> ++		*(size_t *)val = ms->elf_shnum_max;
> ++		return 0;
> ++	case MAGIC_PARAM_ELF_NOTES_MAX:
> ++		*(size_t *)val = ms->elf_notes_max;
> ++		return 0;
> ++	default:
> ++		errno = EINVAL;
> ++		return -1;
> ++	}
> ++}
> +diff --git a/src/magic.h b/src/magic.h
> +index cc8ed68..2938a20 100644
> +--- a/src/magic.h
> ++++ b/src/magic.h
> +@@ -101,6 +101,15 @@ int magic_check(magic_t, const char *);
> + int magic_list(magic_t, const char *);
> + int magic_errno(magic_t);
> +
> ++#define MAGIC_PARAM_INDIR_MAX		0
> ++#define MAGIC_PARAM_NAME_MAX		1
> ++#define MAGIC_PARAM_ELF_PHNUM_MAX	2
> ++#define MAGIC_PARAM_ELF_SHNUM_MAX	3
> ++#define MAGIC_PARAM_ELF_NOTES_MAX	4
> ++
> ++int magic_setparam(magic_t, int, const void *);
> ++int magic_getparam(magic_t, int, void *);
> ++
> + #ifdef __cplusplus
> + };
> + #endif
> +diff --git a/src/magic.h.in b/src/magic.h.in
> +index 86fc41b..a256cf0 100644
> +--- a/src/magic.h.in
> ++++ b/src/magic.h.in
> +@@ -101,6 +101,10 @@ int magic_check(magic_t, const char *);
> + int magic_list(magic_t, const char *);
> + int magic_errno(magic_t);
> +
> ++#define MAGIC_PARAM_MAX_RECURSION	0
> ++int magic_setparam(magic_t, int, const void *);
> ++int magic_getparam(magic_t, int, void *);
> ++
> + #ifdef __cplusplus
> + };
> + #endif
> +diff --git a/src/readelf.c b/src/readelf.c
> +index f8b8bbc..a7b2ba4 100644
> +--- a/src/readelf.c
> ++++ b/src/readelf.c
> +@@ -43,14 +43,14 @@ FILE_RCSID("@(#)$File: readelf.c,v 1.99 2013/11/05 15:44:01 christos Exp $")
> +
> + #ifdef	ELFCORE
> + private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
> +-    off_t, int *);
> ++    off_t, int *, uint16_t *);
> + #endif
> + private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
> +-    off_t, int *, int);
> ++    off_t, int, int *, uint16_t *);
> + private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
> +-    off_t, int *, int, int);
> ++    off_t, int, int, int *, uint16_t *);
> + private size_t donote(struct magic_set *, void *, size_t, size_t, int,
> +-    int, size_t, int *);
> ++    int, size_t, int *, uint16_t *);
> +
> + #define	ELF_ALIGN(a)	((((a) + align - 1) / align) * align)
> +
> +@@ -60,6 +60,19 @@ private uint16_t getu16(int, uint16_t);
> + private uint32_t getu32(int, uint32_t);
> + private uint64_t getu64(int, uint64_t);
> +
> ++#define MAX_PHNUM	128
> ++#define	MAX_SHNUM	32768
> ++#define SIZE_UNKNOWN	((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)
> ++		return -1;
> ++	return 0;
> ++}
> ++
> + private uint16_t
> + getu16(int swap, uint16_t value)
> + {
> +@@ -280,15 +293,19 @@ private const char os_style_names[][8] = {
> + 	"NetBSD",
> + };
> +
> +-#define FLAGS_DID_CORE		0x01
> +-#define FLAGS_DID_NOTE		0x02
> +-#define FLAGS_DID_BUILD_ID	0x04
> +-#define FLAGS_DID_CORE_STYLE	0x08
> +-#define FLAGS_IS_CORE		0x10
> ++#define FLAGS_DID_CORE			0x001
> ++#define FLAGS_DID_OS_NOTE		0x002
> ++#define FLAGS_DID_BUILD_ID		0x004
> ++#define FLAGS_DID_CORE_STYLE		0x008
> ++#define FLAGS_DID_NETBSD_PAX		0x010
> ++#define FLAGS_DID_NETBSD_MARCH		0x020
> ++#define FLAGS_DID_NETBSD_CMODEL		0x040
> ++#define FLAGS_DID_NETBSD_UNKNOWN	0x080
> ++#define FLAGS_IS_CORE			0x100
> +
> + private int
> + dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> +-    int num, size_t size, off_t fsize, int *flags)
> ++    int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
> + {
> + 	Elf32_Phdr ph32;
> + 	Elf64_Phdr ph64;
> +@@ -306,13 +323,13 @@ 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) == -1) {
> ++		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
> + 			file_badread(ms);
> + 			return -1;
> + 		}
> + 		off += size;
> +
> +-		if (xph_offset > fsize) {
> ++		if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
> + 			/* Perhaps warn here */
> + 			continue;
> + 		}
> +@@ -334,7 +351,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> + 			if (offset >= (size_t)bufsize)
> + 				break;
> + 			offset = donote(ms, nbuf, offset, (size_t)bufsize,
> +-			    clazz, swap, 4, flags);
> ++			    clazz, swap, 4, flags, notecount);
> + 			if (offset == 0)
> + 				break;
> +
> +@@ -464,125 +481,127 @@ do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
> + 	}
> + }
> +
> +-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)
> ++private int
> ++do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
> ++    int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
> ++    size_t noff, size_t doff, int *flags)
> + {
> +-	Elf32_Nhdr nh32;
> +-	Elf64_Nhdr nh64;
> +-	size_t noff, doff;
> +-#ifdef ELFCORE
> +-	int os_style = -1;
> +-#endif
> +-	uint32_t namesz, descsz;
> +-	unsigned char *nbuf = CAST(unsigned char *, vbuf);
> +-
> +-	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
> +-	offset += xnh_sizeof;
> +-
> +-	namesz = xnh_namesz;
> +-	descsz = xnh_descsz;
> +-	if ((namesz == 0) && (descsz == 0)) {
> +-		/*
> +-		 * We're out of note headers.
> +-		 */
> +-		return (offset >= size) ? offset : size;
> +-	}
> +-
> +-	if (namesz & 0x80000000) {
> +-	    (void)file_printf(ms, ", bad note name size 0x%lx",
> +-		(unsigned long)namesz);
> +-	    return offset;
> +-	}
> +-
> +-	if (descsz & 0x80000000) {
> +-	    (void)file_printf(ms, ", bad note description size 0x%lx",
> +-		(unsigned long)descsz);
> +-	    return offset;
> +-	}
> +-
> +-
> +-	noff = offset;
> +-	doff = ELF_ALIGN(offset + namesz);
> +-
> +-	if (offset + namesz > size) {
> +-		/*
> +-		 * We're past the end of the buffer.
> +-		 */
> +-		return doff;
> +-	}
> +-
> +-	offset = ELF_ALIGN(doff + descsz);
> +-	if (doff + descsz > size) {
> +-		/*
> +-		 * We're past the end of the buffer.
> +-		 */
> +-		return (offset >= size) ? offset : size;
> ++	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
> ++	    type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
> ++		uint8_t desc[20];
> ++		uint32_t i;
> ++		*flags |= FLAGS_DID_BUILD_ID;
> ++		if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
> ++		    "sha1") == -1)
> ++			return 1;
> ++		(void)memcpy(desc, &nbuf[doff], descsz);
> ++		for (i = 0; i < descsz; i++)
> ++		    if (file_printf(ms, "%02x", desc[i]) == -1)
> ++			return 1;
> ++		return 1;
> + 	}
> +-
> +-	if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) ==
> +-	    (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID))
> +-		goto core;
> +-
> ++	return 0;
> ++}
> ++	
> ++private int
> ++do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
> ++    int swap, uint32_t namesz, uint32_t descsz,
> ++    size_t noff, size_t doff, int *flags)
> ++{
> + 	if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
> +-	    xnh_type == NT_GNU_VERSION && descsz == 2) {
> ++	    type == NT_GNU_VERSION && descsz == 2) {
> ++	    *flags |= FLAGS_DID_OS_NOTE;
> + 	    file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]);
> ++	    return 1;
> + 	}
> ++
> + 	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
> +-	    xnh_type == NT_GNU_VERSION && descsz == 16) {
> ++	    type == NT_GNU_VERSION && descsz == 16) {
> + 		uint32_t desc[4];
> + 		(void)memcpy(desc, &nbuf[doff], sizeof(desc));
> +
> ++		*flags |= FLAGS_DID_OS_NOTE;
> + 		if (file_printf(ms, ", for GNU/") == -1)
> +-			return size;
> ++			return 1;
> + 		switch (elf_getu32(swap, desc[0])) {
> + 		case GNU_OS_LINUX:
> + 			if (file_printf(ms, "Linux") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		case GNU_OS_HURD:
> + 			if (file_printf(ms, "Hurd") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		case GNU_OS_SOLARIS:
> + 			if (file_printf(ms, "Solaris") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		case GNU_OS_KFREEBSD:
> + 			if (file_printf(ms, "kFreeBSD") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		case GNU_OS_KNETBSD:
> + 			if (file_printf(ms, "kNetBSD") == -1)
> +-				return size;
> ++				return 1;
> + 			break;
> + 		default:
> + 			if (file_printf(ms, "<unknown>") == -1)
> +-				return size;
> ++				return 1;
> + 		}
> + 		if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
> + 		    elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
> +-			return size;
> +-		*flags |= FLAGS_DID_NOTE;
> +-		return size;
> ++			return 1;
> ++		return 1;
> + 	}
> +
> +-	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
> +-	    xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
> +-	    uint8_t desc[20];
> +-	    uint32_t i;
> +-	    if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" :
> +-		"sha1") == -1)
> +-		    return size;
> +-	    (void)memcpy(desc, &nbuf[doff], descsz);
> +-	    for (i = 0; i < descsz; i++)
> +-		if (file_printf(ms, "%02x", desc[i]) == -1)
> +-		    return size;
> +-	    *flags |= FLAGS_DID_BUILD_ID;
> ++	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
> ++	    	if (type == NT_NETBSD_VERSION && descsz == 4) {
> ++			*flags |= FLAGS_DID_OS_NOTE;
> ++			do_note_netbsd_version(ms, swap, &nbuf[doff]);
> ++			return 1;
> ++		}
> ++	}
> ++
> ++	if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
> ++	    	if (type == NT_FREEBSD_VERSION && descsz == 4) {
> ++			*flags |= FLAGS_DID_OS_NOTE;
> ++			do_note_freebsd_version(ms, swap, &nbuf[doff]);
> ++			return 1;
> ++		}
> ++	}
> ++
> ++	if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
> ++	    type == NT_OPENBSD_VERSION && descsz == 4) {
> ++		*flags |= FLAGS_DID_OS_NOTE;
> ++		if (file_printf(ms, ", for OpenBSD") == -1)
> ++			return 1;
> ++		/* Content of note is always 0 */
> ++		return 1;
> ++	}
> ++
> ++	if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
> ++	    type == NT_DRAGONFLY_VERSION && descsz == 4) {
> ++		uint32_t desc;
> ++		*flags |= FLAGS_DID_OS_NOTE;
> ++		if (file_printf(ms, ", for DragonFly") == -1)
> ++			return 1;
> ++		(void)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)
> ++			return 1;
> ++		return 1;
> + 	}
> ++	return 0;
> ++}
> +
> ++private int
> ++do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
> ++    int swap, uint32_t namesz, uint32_t descsz,
> ++    size_t noff, size_t doff, int *flags)
> ++{
> + 	if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
> +-	    xnh_type == NT_NETBSD_PAX && descsz == 4) {
> ++	    type == NT_NETBSD_PAX && descsz == 4) {
> + 		static const char *pax[] = {
> + 		    "+mprotect",
> + 		    "-mprotect",
> +@@ -595,80 +614,32 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
> + 		size_t i;
> + 		int did = 0;
> +
> ++		*flags |= FLAGS_DID_NETBSD_PAX;
> + 		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
> + 		desc = elf_getu32(swap, desc);
> +
> + 		if (desc && file_printf(ms, ", PaX: ") == -1)
> +-			return size;
> ++			return 1;
> +
> + 		for (i = 0; i < __arraycount(pax); i++) {
> + 			if (((1 << i) & desc) == 0)
> + 				continue;
> + 			if (file_printf(ms, "%s%s", did++ ? "," : "",
> + 			    pax[i]) == -1)
> +-				return size;
> +-		}
> +-	}
> +-
> +-	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
> +-		switch (xnh_type) {
> +-		case NT_NETBSD_VERSION:
> +-			if (descsz == 4) {
> +-				do_note_netbsd_version(ms, swap, &nbuf[doff]);
> +-				*flags |= FLAGS_DID_NOTE;
> +-				return size;
> +-			}
> +-			break;
> +-		case NT_NETBSD_MARCH:
> +-			if (file_printf(ms, ", compiled for: %.*s", (int)descsz,
> +-			    (const char *)&nbuf[doff]) == -1)
> +-				return size;
> +-			break;
> +-		case NT_NETBSD_CMODEL:
> +-			if (file_printf(ms, ", compiler model: %.*s",
> +-			    (int)descsz, (const char *)&nbuf[doff]) == -1)
> +-				return size;
> +-			break;
> +-		default:
> +-			if (file_printf(ms, ", note=%u", xnh_type) == -1)
> +-				return size;
> +-			break;
> +-		}
> +-		return size;
> +-	}
> +-
> +-	if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
> +-	    	if (xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
> +-			do_note_freebsd_version(ms, swap, &nbuf[doff]);
> +-			*flags |= FLAGS_DID_NOTE;
> +-			return size;
> ++			return 1;
> + 		}
> ++		return 1;
> + 	}
> ++	return 0;
> ++}
> +
> +-	if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
> +-	    xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
> +-		if (file_printf(ms, ", for OpenBSD") == -1)
> +-			return size;
> +-		/* Content of note is always 0 */
> +-		*flags |= FLAGS_DID_NOTE;
> +-		return size;
> +-	}
> +-
> +-	if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
> +-	    xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
> +-		uint32_t desc;
> +-		if (file_printf(ms, ", for DragonFly") == -1)
> +-			return size;
> +-		(void)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)
> +-			return size;
> +-		*flags |= FLAGS_DID_NOTE;
> +-		return size;
> +-	}
> +-
> +-core:
> ++private int
> ++do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
> ++    int swap, uint32_t namesz, uint32_t descsz,
> ++    size_t noff, size_t doff, int *flags, size_t size, int clazz)
> ++{
> ++#ifdef ELFCORE
> ++	int os_style = -1;
> + 	/*
> + 	 * Sigh.  The 2.0.36 kernel in Debian 2.1, at
> + 	 * least, doesn't correctly implement name
> +@@ -697,20 +668,17 @@ core:
> + 		os_style = OS_STYLE_NETBSD;
> + 	}
> +
> +-#ifdef ELFCORE
> +-	if ((*flags & FLAGS_DID_CORE) != 0)
> +-		return size;
> +-
> + 	if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
> + 		if (file_printf(ms, ", %s-style", os_style_names[os_style])
> + 		    == -1)
> +-			return size;
> ++			return 1;
> + 		*flags |= FLAGS_DID_CORE_STYLE;
> + 	}
> +
> + 	switch (os_style) {
> + 	case OS_STYLE_NETBSD:
> +-		if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
> ++		if (type == NT_NETBSD_CORE_PROCINFO) {
> ++			char sbuf[512];
> + 			uint32_t signo;
> + 			/*
> + 			 * Extract the program name.  It is at
> +@@ -719,7 +687,7 @@ core:
> + 			 */
> + 			if (file_printf(ms, ", from '%.31s'",
> + 			    &nbuf[doff + 0x7c]) == -1)
> +-				return size;
> ++				return 1;
> + 			
> + 			/*
> + 			 * Extract the signal number.  It is at
> +@@ -736,8 +704,7 @@ core:
> + 		break;
> +
> + 	default:
> +-		if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
> +-/*###709 [cc] warning: declaration of 'i' shadows previous non-variable%%%*/
> ++		if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
> + 			size_t i, j;
> + 			unsigned char c;
> + 			/*
> +@@ -805,7 +772,7 @@ core:
> + 				 * Try next offsets, in case this match is
> + 				 * in the middle of a string.
> + 				 */
> +-				for (k = i + 1 ; k < NOFFSETS ; k++) {
> ++				for (k = i + 1 ; k < NOFFSETS; k++) {
> + 					size_t no;
> + 					int adjust = 1;
> + 					if (prpsoffsets(k) >= prpsoffsets(i))
> +@@ -830,9 +797,9 @@ core:
> + 					cp--;
> + 				if (file_printf(ms, ", from '%.*s'",
> + 				    (int)(cp - cname), cname) == -1)
> +-					return size;
> ++					return 1;
> + 				*flags |= FLAGS_DID_CORE;
> +-				return size;
> ++				return 1;
> +
> + 			tryanother:
> + 				;
> +@@ -841,6 +808,129 @@ core:
> + 		break;
> + 	}
> + #endif
> ++	return 0;
> ++}
> ++
> ++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)
> ++{
> ++	Elf32_Nhdr nh32;
> ++	Elf64_Nhdr nh64;
> ++	size_t noff, doff;
> ++	uint32_t namesz, descsz;
> ++	unsigned char *nbuf = CAST(unsigned char *, vbuf);
> ++
> ++	if (*notecount == 0)
> ++		return 0;
> ++	--*notecount;
> ++
> ++	if (xnh_sizeof + offset > size) {
> ++		/*
> ++		 * We're out of note headers.
> ++		 */
> ++		return xnh_sizeof + offset;
> ++	}
> ++
> ++	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
> ++	offset += xnh_sizeof;
> ++
> ++	namesz = xnh_namesz;
> ++	descsz = xnh_descsz;
> ++	if ((namesz == 0) && (descsz == 0)) {
> ++		/*
> ++		 * We're out of note headers.
> ++		 */
> ++		return (offset >= size) ? offset : size;
> ++	}
> ++
> ++	if (namesz & 0x80000000) {
> ++	    (void)file_printf(ms, ", bad note name size 0x%lx",
> ++		(unsigned long)namesz);
> ++	    return 0;
> ++	}
> ++
> ++	if (descsz & 0x80000000) {
> ++	    (void)file_printf(ms, ", bad note description size 0x%lx",
> ++		(unsigned long)descsz);
> ++	    return 0;
> ++	}
> ++
> ++	noff = offset;
> ++	doff = ELF_ALIGN(offset + namesz);
> ++
> ++	if (offset + namesz > size) {
> ++		/*
> ++		 * We're past the end of the buffer.
> ++		 */
> ++		return doff;
> ++	}
> ++
> ++	offset = ELF_ALIGN(doff + descsz);
> ++	if (doff + descsz > size) {
> ++		/*
> ++		 * We're past the end of the buffer.
> ++		 */
> ++		return (offset >= size) ? offset : size;
> ++	}
> ++
> ++	if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
> ++		if (do_os_note(ms, nbuf, xnh_type, swap,
> ++		    namesz, descsz, noff, doff, flags))
> ++			return size;
> ++	}
> ++
> ++	if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
> ++		if (do_bid_note(ms, nbuf, xnh_type, swap,
> ++		    namesz, descsz, noff, doff, flags))
> ++			return size;
> ++	}
> ++		
> ++	if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
> ++		if (do_pax_note(ms, nbuf, xnh_type, swap,
> ++		    namesz, descsz, noff, doff, flags))
> ++			return size;
> ++	}
> ++
> ++	if ((*flags & FLAGS_DID_CORE) == 0) {
> ++		if (do_core_note(ms, nbuf, xnh_type, swap,
> ++		    namesz, descsz, noff, doff, flags, size, clazz))
> ++			return size;
> ++	}
> ++
> ++	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
> ++		if (descsz > 100)
> ++			descsz = 100;
> ++		switch (xnh_type) {
> ++	    	case NT_NETBSD_VERSION:
> ++			return size;
> ++		case NT_NETBSD_MARCH:
> ++			if (*flags & FLAGS_DID_NETBSD_MARCH)
> ++				return size;
> ++			*flags |= FLAGS_DID_NETBSD_MARCH;
> ++			if (file_printf(ms, ", compiled for: %.*s",
> ++			    (int)descsz, (const char *)&nbuf[doff]) == -1)
> ++				return size;
> ++			break;
> ++		case NT_NETBSD_CMODEL:
> ++			if (*flags & FLAGS_DID_NETBSD_CMODEL)
> ++				return size;
> ++			*flags |= FLAGS_DID_NETBSD_CMODEL;
> ++			if (file_printf(ms, ", compiler model: %.*s",
> ++			    (int)descsz, (const char *)&nbuf[doff]) == -1)
> ++				return size;
> ++			break;
> ++		default:
> ++			if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
> ++				return size;
> ++			*flags |= FLAGS_DID_NETBSD_UNKNOWN;
> ++			if (file_printf(ms, ", note=%u", xnh_type) == -1)
> ++				return size;
> ++			break;
> ++		}
> ++		return size;
> ++	}
> ++
> + 	return offset;
> + }
> +
> +@@ -896,16 +986,19 @@ static const cap_desc_t cap_desc_386[] = {
> +
> + private int
> + doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> +-    size_t size, off_t fsize, int *flags, int mach, int strtab)
> ++    size_t size, off_t fsize, int mach, int strtab, int *flags,
> ++    uint16_t *notecount)
> + {
> + 	Elf32_Shdr sh32;
> + 	Elf64_Shdr sh64;
> + 	int stripped = 1;
> ++	size_t nbadcap = 0;
> + 	void *nbuf;
> + 	off_t noff, coff, name_off;
> + 	uint64_t cap_hw1 = 0;	/* SunOS 5.x hardware capabilites */
> + 	uint64_t cap_sf1 = 0;	/* SunOS 5.x software capabilites */
> + 	char name[50];
> ++	ssize_t namesize;
> +
> + 	if (size != xsh_sizeof) {
> + 		if (file_printf(ms, ", corrupted section header size") == -1)
> +@@ -914,7 +1007,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, off + size * strtab) == -1) {
> ++	if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) < (ssize_t)xsh_sizeof) {
> + 		file_badread(ms);
> + 		return -1;
> + 	}
> +@@ -922,15 +1015,15 @@ 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 (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) {
> ++		if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
> + 			file_badread(ms);
> + 			return -1;
> + 		}
> +-		name[sizeof(name) - 1] = '\0';
> ++		name[namesize] = '\0';
> + 		if (strcmp(name, ".debug_info") == 0)
> + 			stripped = 0;
> +
> +-		if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) {
> ++		if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
> + 			file_badread(ms);
> + 			return -1;
> + 		}
> +@@ -945,7 +1038,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 			stripped = 0;
> + 			break;
> + 		default:
> +-			if (xsh_offset > fsize) {
> ++			if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
> + 				/* Perhaps warn here */
> + 				continue;
> + 			}
> +@@ -960,7 +1053,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 				    " for note");
> + 				return -1;
> + 			}
> +-			if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) {
> ++			if (pread(fd, nbuf, xsh_size, xsh_offset) < (ssize_t)xsh_size) {
> + 				file_badread(ms);
> + 				free(nbuf);
> + 				return -1;
> +@@ -971,7 +1064,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 				if (noff >= (off_t)xsh_size)
> + 					break;
> + 				noff = donote(ms, nbuf, (size_t)noff,
> +-				    xsh_size, clazz, swap, 4, flags);
> ++				    xsh_size, clazz, swap, 4, flags, notecount);
> + 				if (noff == 0)
> + 					break;
> + 			}
> +@@ -989,6 +1082,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 				goto skip;
> + 			}
> +
> ++			if (nbadcap > 5)
> ++				break;
> + 			if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
> + 				file_badseek(ms);
> + 				return -1;
> +@@ -1024,6 +1119,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> + 					    (unsigned long long)xcap_tag,
> + 					    (unsigned long long)xcap_val) == -1)
> + 						return -1;
> ++					if (nbadcap++ > 2)
> ++						coff = xsh_size;
> + 					break;
> + 				}
> + 			}
> +@@ -1104,7 +1201,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
> +  */
> + private int
> + dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> +-    int num, size_t size, off_t fsize, int *flags, int sh_num)
> ++    int num, size_t size, off_t fsize, int sh_num, int *flags,
> ++    uint16_t *notecount)
> + {
> + 	Elf32_Phdr ph32;
> + 	Elf64_Phdr ph64;
> +@@ -1121,7 +1219,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> + 	}
> +
> +   	for ( ; num; num--) {
> +-		if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
> ++		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
> + 			file_badread(ms);
> + 			return -1;
> + 		}
> +@@ -1137,7 +1235,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> + 			shared_libraries = " (uses shared libs)";
> + 			break;
> + 		default:
> +-			if (xph_offset > fsize) {
> ++			if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
> + 				/* Maybe warn here? */
> + 				continue;
> + 			}
> +@@ -1173,7 +1271,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
> + 					break;
> + 				offset = donote(ms, nbuf, offset,
> + 				    (size_t)bufsize, clazz, swap, align,
> +-				    flags);
> ++				    flags, notecount);
> + 				if (offset == 0)
> + 					break;
> + 			}
> +@@ -1204,7 +1302,7 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
> + 	int flags = 0;
> + 	Elf32_Ehdr elf32hdr;
> + 	Elf64_Ehdr elf64hdr;
> +-	uint16_t type;
> ++	uint16_t type, phnum, shnum, notecount;
> +
> + 	if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
> + 		return 0;
> +@@ -1230,7 +1328,10 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
> +   		file_badread(ms);
> + 		return -1;
> + 	}
> +-	fsize = st.st_size;
> ++	if (S_ISREG(st.st_mode))
> ++		fsize = st.st_size;
> ++	else
> ++		fsize = SIZE_UNKNOWN;
> +
> + 	clazz = buf[EI_CLASS];
> +
> +diff --git a/src/softmagic.c b/src/softmagic.c
> +index dc7928b..b1f5779 100644
> +--- a/src/softmagic.c
> ++++ b/src/softmagic.c
> +@@ -43,11 +43,11 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.168 2013/05/30 15:53:33 christos Exp $")
> +
> +
> + private int match(struct magic_set *, struct magic *, uint32_t,
> +-    const unsigned char *, size_t, size_t, int, int, int, int, int *, int *,
> +-    int *);
> ++    const unsigned char *, size_t, size_t, int, int, int, uint16_t,
> ++    uint16_t *, int *, int *, int *);
> + private int mget(struct magic_set *, const unsigned char *,
> +-    struct magic *, size_t, size_t, unsigned int, int, int, int, int, int *,
> +-    int *, int *);
> ++    struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t,
> ++    uint16_t *, int *, int *, int *);
> + private int magiccheck(struct magic_set *, struct magic *);
> + private int32_t mprint(struct magic_set *, struct magic *);
> + private int32_t moffset(struct magic_set *, struct magic *);
> +@@ -69,14 +69,20 @@ private void cvt_64(union VALUETYPE *, const struct magic *);
> + /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
> + protected int
> + file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
> +-    int mode, int text)
> ++    uint16_t indir_level, uint16_t *name_count, int mode, int text)
> + {
> + 	struct mlist *ml;
> + 	int rv, printed_something = 0, need_separator = 0;
> ++	uint16_t nc;
> ++
> ++	if (name_count == NULL) {
> ++		nc = 0;
> ++		name_count = &nc;
> ++	}
> + 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
> + 		if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
> +-		    text, 0, 0, &printed_something, &need_separator,
> +-		    NULL)) != 0)
> ++		    text, 0, indir_level, name_count,
> ++		    &printed_something, &need_separator, NULL)) != 0)
> + 			return rv;
> +
> + 	return 0;
> +@@ -112,8 +118,8 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
> + private int
> + match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
> +     const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
> +-    int flip, int recursion_level, int *printed_something, int *need_separator,
> +-    int *returnval)
> ++    int flip, uint16_t indir_level, uint16_t *name_count,
> ++    int *printed_something, int *need_separator, int *returnval)
> + {
> + 	uint32_t magindex = 0;
> + 	unsigned int cont_level = 0;
> +@@ -150,8 +156,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
> +
> + 		/* if main entry matches, print it... */
> + 		switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
> +-		    flip, recursion_level + 1, printed_something,
> +-		    need_separator, returnval)) {
> ++		    flip, indir_level, name_count,
> ++		    printed_something, need_separator, returnval)) {
> + 		case -1:
> + 			return -1;
> + 		case 0:
> +@@ -237,8 +243,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
> + 			}
> + #endif
> + 			switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
> +-			    text, flip, recursion_level + 1, printed_something,
> +-			    need_separator, returnval)) {
> ++			    text, flip, indir_level, name_count,
> ++			    printed_something, need_separator, returnval)) {
> + 			case -1:
> + 				return -1;
> + 			case 0:
> +@@ -1120,8 +1126,8 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
> + private int
> + mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> +     size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
> +-    int flip, int recursion_level, int *printed_something,
> +-    int *need_separator, int *returnval)
> ++    int flip, uint16_t indir_level, uint16_t *name_count,
> ++    int *printed_something, int *need_separator, int *returnval)
> + {
> + 	uint32_t soffset, offset = ms->offset;
> + 	uint32_t count = m->str_range;
> +@@ -1130,8 +1136,15 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> + 	union VALUETYPE *p = &ms->ms_value;
> + 	struct mlist ml;
> +
> +-	if (recursion_level >= 20) {
> +-		file_error(ms, 0, "recursion nesting exceeded");
> ++	if (indir_level >= ms->indir_max) {
> ++		file_error(ms, 0, "indirect recursion nesting (%hu) exceeded",
> ++		    indir_level);
> ++		return -1;
> ++	}
> ++
> ++	if (*name_count >= ms->name_max) {
> ++		file_error(ms, 0, "name use count (%hu) exceeded",
> ++		    *name_count);
> + 		return -1;
> + 	}
> +
> +@@ -1141,8 +1154,9 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> +
> + 	if ((ms->flags & MAGIC_DEBUG) != 0) {
> + 		fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, "
> +-		    "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o,
> +-		    nbytes, count);
> ++		    "nbytes=%zu, il=%hu, nc=%hu)\n",
> ++		    m->type, m->flag, offset, o, nbytes,
> ++		    indir_level, *name_count);
> + 		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
> + #ifndef COMPILE_ONLY
> + 		file_mdump(m);
> +@@ -1711,7 +1725,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> + 		ms->o.buf = NULL;
> + 		ms->offset = 0;
> + 		rv = file_softmagic(ms, s + offset, nbytes - offset,
> +-		    BINTEST, text);
> ++		    indir_level + 1, name_count, BINTEST, text);
> + 		if ((ms->flags & MAGIC_DEBUG) != 0)
> + 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
> + 		rbuf = ms->o.buf;
> +@@ -1730,22 +1744,22 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
> + 	case FILE_USE:
> + 		if (nbytes < offset)
> + 			return 0;
> +-		sbuf = m->value.s;
> +-		if (*sbuf == '^') {
> +-			sbuf++;
> ++		rbuf = m->value.s;
> ++		if (*rbuf == '^') {
> ++			rbuf++;
> + 			flip = !flip;
> + 		}
> +-		if (file_magicfind(ms, sbuf, &ml) == -1) {
> +-			file_error(ms, 0, "cannot find entry `%s'", sbuf);
> ++		if (file_magicfind(ms, rbuf, &ml) == -1) {
> ++			file_error(ms, 0, "cannot find entry `%s'", rbuf);
> + 			return -1;
> + 		}
> +-
> ++		(*name_count)++;
> + 		oneed_separator = *need_separator;
> + 		if (m->flag & NOSPACE)
> + 			*need_separator = 0;
> + 		rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
> +-		    mode, text, flip, recursion_level, printed_something,
> +-		    need_separator, returnval);
> ++		    mode, text, flip, indir_level, name_count,
> ++		    printed_something, need_separator, returnval);
> + 		if (rv != 1)
> + 		    *need_separator = oneed_separator;
> + 		return rv;
> +--
> +1.7.9.5
> +
> diff --git a/meta/recipes-devtools/file/file_5.16.bb b/meta/recipes-devtools/file/file_5.16.bb
> index a15d952..f231a55 100644
> --- a/meta/recipes-devtools/file/file_5.16.bb
> +++ b/meta/recipes-devtools/file/file_5.16.bb
> @@ -12,6 +12,7 @@ DEPENDS = "zlib file-native"
>   DEPENDS_class-native = "zlib-native"
>
>   SRC_URI = "ftp://ftp.astron.com/pub/file/file-${PV}.tar.gz \
> +           file://file-CVE-2014-9620-and-CVE-2014-9621.patch \
>              file://dump \
>              file://filesystems"
>
>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [daisy][PATCH] file: CVE-2014-9620 and CVE-2014-9621
  2015-02-02 13:55 ` Saul Wold
@ 2015-02-03  1:23   ` Chong Lu
  0 siblings, 0 replies; 5+ messages in thread
From: Chong Lu @ 2015-02-03  1:23 UTC (permalink / raw)
  To: Saul Wold, openembedded-core


On 02/02/2015 09:55 PM, Saul Wold wrote:
>
> I had some issues with this patch on the Autobuilder, it failed in 
> some cases for nativesdk-file on some, but not all machines of the 
> autobuilder.
>
> See: 
> https://autobuilder.yoctoproject.org/main/builders/nightly-arm/builds/178/steps/Building%20Toolchain%20Images/logs/stdio
>
> That's one example of the failure.

OK. I will fix and resend one.

Best Regards
Chong

>
> Sau!
>
>
>
> On 01/22/2015 01:28 AM, Chong Lu wrote:
>> CVE-2014-9620:
>> Limit the number of ELF notes processed - DoS
>> CVE-2014-9621:
>> Limit string printing to 100 chars - DoS
>>
>> The patch comes from:
>> https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67 
>>
>> https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6 
>>
>> https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33 
>>
>> https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba 
>>
>> https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9 
>>
>> https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7 
>>
>> https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f 
>>
>> https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4 
>>
>> https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c 
>>
>>
>> [YOCTO #7178]
>>
>> Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
>> ---
>>   .../file-CVE-2014-9620-and-CVE-2014-9621.patch     | 1357 
>> ++++++++++++++++++++
>>   meta/recipes-devtools/file/file_5.16.bb            |    1 +
>>   2 files changed, 1358 insertions(+)
>>   create mode 100644 
>> meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
>>
>> diff --git 
>> a/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch 
>> b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch 
>>
>> new file mode 100644
>> index 0000000..bd5944e
>> --- /dev/null
>> +++ 
>> b/meta/recipes-devtools/file/file/file-CVE-2014-9620-and-CVE-2014-9621.patch
>> @@ -0,0 +1,1357 @@
>> +file: CVE-2014-9620 and CVE-2014-9621
>> +
>> +The patch comes from:
>> +https://github.com/file/file/commit/6ce24f35cd4a43c4bdd249e8e0c4952c1f8eac67 
>>
>> +https://github.com/file/file/commit/0056ec32255de1de973574b0300161a1568767d6 
>>
>> +https://github.com/file/file/commit/09e41625c999a2e5b51e1092f0ef2432a99b5c33 
>>
>> +https://github.com/file/file/commit/af444af0738468393f40f9d2261b1ea10fc4b2ba 
>>
>> +https://github.com/file/file/commit/68bd8433c7e11a8dbe100deefdfac69138ee7cd9 
>>
>> +https://github.com/file/file/commit/dddd3cdb95210a765dd90f7d722cb8b5534daee7 
>>
>> +https://github.com/file/file/commit/445c8fb0ebff85195be94cd9f7e1df89cade5c7f 
>>
>> +https://github.com/file/file/commit/ce90e05774dd77d86cfc8dfa6da57b32816841c4 
>>
>> +https://github.com/file/file/commit/65437cee25199dbd385fb35901bc0011e164276c 
>>
>> +
>> +Upstream-Status: Backport
>> +
>> +Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
>> +---
>> + src/apprentice.c |    5 +
>> + src/ascmagic.c   |    3 +-
>> + src/elfclass.h   |   34 ++--
>> + src/file.c       |   58 ++++++-
>> + src/file.h       |   20 ++-
>> + src/file_opts.h  |    6 +
>> + src/funcs.c      |   42 ++++-
>> + src/magic.c      |   50 ++++++
>> + src/magic.h      |    9 ++
>> + src/magic.h.in   |    4 +
>> + src/readelf.c    |  467 
>> +++++++++++++++++++++++++++++++++---------------------
>> + src/softmagic.c  |   70 ++++----
>> + 12 files changed, 541 insertions(+), 227 deletions(-)
>> +
>> +diff --git a/src/apprentice.c b/src/apprentice.c
>> +index 2df60d9..d906f7b 100644
>> +--- a/src/apprentice.c
>> ++++ b/src/apprentice.c
>> +@@ -494,6 +494,11 @@ file_ms_alloc(int flags)
>> +         ms->mlist[i] = NULL;
>> +     ms->file = "unknown";
>> +     ms->line = 0;
>> ++    ms->indir_max = FILE_INDIR_MAX;
>> ++    ms->name_max = FILE_NAME_MAX;
>> ++    ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
>> ++    ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
>> ++    ms->elf_notes_max = FILE_ELF_NOTES_MAX;
>> +     return ms;
>> + free:
>> +     free(ms);
>> +diff --git a/src/ascmagic.c b/src/ascmagic.c
>> +index 28ebadc..7a22328 100644
>> +--- a/src/ascmagic.c
>> ++++ b/src/ascmagic.c
>> +@@ -147,7 +147,8 @@ file_ascmagic_with_encoding(struct magic_set 
>> *ms, const unsigned char *buf,
>> +             == NULL)
>> +             goto done;
>> +         if ((rv = file_softmagic(ms, utf8_buf,
>> +-            (size_t)(utf8_end - utf8_buf), TEXTTEST, text)) == 0)
>> ++            (size_t)(utf8_end - utf8_buf), 0, NULL,
>> ++            TEXTTEST, text)) == 0)
>> +             rv = -1;
>> +     }
>> +
>> +diff --git a/src/elfclass.h b/src/elfclass.h
>> +index 010958a..5360b0b 100644
>> +--- a/src/elfclass.h
>> ++++ b/src/elfclass.h
>> +@@ -32,39 +32,51 @@
>> +     swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
>> +
>> +     type = elf_getu16(swap, elfhdr.e_type);
>> ++    notecount = ms->elf_notes_max;
>> +     switch (type) {
>> + #ifdef ELFCORE
>> +     case ET_CORE:
>> ++        phnum = elf_getu16(swap, elfhdr.e_phnum);
>> ++        if (phnum > ms->elf_phnum_max)
>> ++            return toomany(ms, "program headers", phnum);
>> +         flags |= FLAGS_IS_CORE;
>> +         if (dophn_core(ms, clazz, swap, fd,
>> +-            (off_t)elf_getu(swap, elfhdr.e_phoff),
>> +-            elf_getu16(swap, elfhdr.e_phnum),
>> ++            (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
>> +             (size_t)elf_getu16(swap, elfhdr.e_phentsize),
>> +-            fsize, &flags) == -1)
>> ++            fsize, &flags, &notecount) == -1)
>> +             return -1;
>> +         break;
>> + #endif
>> +     case ET_EXEC:
>> +     case ET_DYN:
>> ++        phnum = elf_getu16(swap, elfhdr.e_phnum);
>> ++        if (phnum > ms->elf_phnum_max)
>> ++            return toomany(ms, "program", phnum);
>> ++        shnum = elf_getu16(swap, elfhdr.e_shnum);
>> ++        if (shnum > ms->elf_shnum_max)
>> ++            return toomany(ms, "section", shnum);
>> +         if (dophn_exec(ms, clazz, swap, fd,
>> +-            (off_t)elf_getu(swap, elfhdr.e_phoff),
>> +-            elf_getu16(swap, elfhdr.e_phnum),
>> ++            (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
>> +             (size_t)elf_getu16(swap, elfhdr.e_phentsize),
>> +-            fsize, &flags, elf_getu16(swap, elfhdr.e_shnum))
>> +-            == -1)
>> ++            fsize, shnum, &flags, &notecount) == -1)
>> +             return -1;
>> +         /*FALLTHROUGH*/
>> +     case ET_REL:
>> ++        shnum = elf_getu16(swap, elfhdr.e_shnum);
>> ++        if (shnum > ms->elf_shnum_max)
>> ++            return toomany(ms, "section headers", shnum);
>> +         if (doshn(ms, clazz, swap, fd,
>> +-            (off_t)elf_getu(swap, elfhdr.e_shoff),
>> +-            elf_getu16(swap, elfhdr.e_shnum),
>> ++            (off_t)elf_getu(swap, elfhdr.e_shoff), shnum,
>> +             (size_t)elf_getu16(swap, elfhdr.e_shentsize),
>> +-            fsize, &flags, elf_getu16(swap, elfhdr.e_machine),
>> +-            (int)elf_getu16(swap, elfhdr.e_shstrndx)) == -1)
>> ++            fsize, elf_getu16(swap, elfhdr.e_machine),
>> ++            (int)elf_getu16(swap, elfhdr.e_shstrndx),
>> ++            &flags, &notecount) == -1)
>> +             return -1;
>> +         break;
>> +
>> +     default:
>> +         break;
>> +     }
>> ++    if (notecount == 0)
>> ++        return toomany(ms, "notes", ms->elf_notes_max);
>> +     return 1;
>> +diff --git a/src/file.c b/src/file.c
>> +index ac773ea..ee1edcd 100644
>> +--- a/src/file.c
>> ++++ b/src/file.c
>> +@@ -101,7 +101,7 @@ private const struct option long_options[] = {
>> + #undef OPT_LONGONLY
>> +     {0, 0, NULL, 0}
>> + };
>> +-#define OPTSTRING    "bcCde:f:F:hiklLm:nNprsvz0"
>> ++#define OPTSTRING    "bcCde:f:F:hiklLm:nNpP:rsvz0"
>> +
>> + private const struct {
>> +     const char *name;
>> +@@ -119,6 +119,18 @@ private const struct {
>> +     { "tokens",    MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored 
>> for backwards compatibility */
>> + };
>> +
>> ++private struct {
>> ++    const char *name;
>> ++    int tag;
>> ++    size_t value;
>> ++} pm[] = {
>> ++    { "indir",    MAGIC_PARAM_INDIR_MAX, 0 },
>> ++    { "name",    MAGIC_PARAM_NAME_MAX, 0 },
>> ++    { "elf_phnum",    MAGIC_PARAM_ELF_PHNUM_MAX, 0 },
>> ++    { "elf_shnum",    MAGIC_PARAM_ELF_SHNUM_MAX, 0 },
>> ++    { "elf_notes",    MAGIC_PARAM_ELF_NOTES_MAX, 0 },
>> ++};
>> ++
>> + private char *progname;        /* used throughout         */
>> +
>> + private void usage(void);
>> +@@ -128,6 +140,8 @@ private void help(void);
>> + private int unwrap(struct magic_set *, const char *);
>> + private int process(struct magic_set *ms, const char *, int);
>> + private struct magic_set *load(const char *, int);
>> ++private void setparam(const char *);
>> ++private void applyparam(magic_t);
>> +
>> +
>> + /*
>> +@@ -240,6 +254,9 @@ main(int argc, char *argv[])
>> +             flags |= MAGIC_PRESERVE_ATIME;
>> +             break;
>> + #endif
>> ++        case 'P':
>> ++            setparam(optarg);
>> ++            break;
>> +         case 'r':
>> +             flags |= MAGIC_RAW;
>> +             break;
>> +@@ -295,6 +312,8 @@ main(int argc, char *argv[])
>> +                 strerror(errno));
>> +             return 1;
>> +         }
>> ++
>> ++
>> +         switch(action) {
>> +         case FILE_CHECK:
>> +             c = magic_check(magic, magicfile);
>> +@@ -318,7 +337,7 @@ main(int argc, char *argv[])
>> +         if (magic == NULL)
>> +             if ((magic = load(magicfile, flags)) == NULL)
>> +                 return 1;
>> +-        break;
>> ++        applyparam(magic);
>> +     }
>> +
>> +     if (optind == argc) {
>> +@@ -348,6 +367,41 @@ main(int argc, char *argv[])
>> +     return e;
>> + }
>> +
>> ++private void
>> ++applyparam(magic_t magic)
>> ++{
>> ++    size_t i;
>> ++
>> ++    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);
>> ++        }
>> ++    }
>> ++}
>> ++
>> ++private void
>> ++setparam(const char *p)
>> ++{
>> ++    size_t i;
>> ++    char *s;
>> ++
>> ++    if ((s = strchr(p, '=')) == NULL)
>> ++        goto badparm;
>> ++
>> ++    for (i = 0; i < __arraycount(pm); i++) {
>> ++        if (strncmp(p, pm[i].name, s - p) != 0)
>> ++            continue;
>> ++        pm[i].value = atoi(s + 1);
>> ++        return;
>> ++    }
>> ++badparm:
>> ++    (void)fprintf(stderr, "%s: Unknown param %s\n", progname, p);
>> ++    exit(1);
>> ++}
>> +
>> + private struct magic_set *
>> + /*ARGSUSED*/
>> +diff --git a/src/file.h b/src/file.h
>> +index e910a2b..57e7307 100644
>> +--- a/src/file.h
>> ++++ b/src/file.h
>> +@@ -400,6 +400,16 @@ struct magic_set {
>> +     /* FIXME: Make the string dynamically allocated so that e.g.
>> +        strings matched in files can be longer than MAXstring */
>> +     union VALUETYPE ms_value;    /* either number or string */
>> ++    uint16_t indir_max;
>> ++    uint16_t name_max;
>> ++    uint16_t elf_shnum_max;
>> ++    uint16_t elf_phnum_max;
>> ++    uint16_t elf_notes_max;
>> ++#define    FILE_INDIR_MAX            15
>> ++#define    FILE_NAME_MAX            30
>> ++#define    FILE_ELF_SHNUM_MAX        32768
>> ++#define    FILE_ELF_PHNUM_MAX        128
>> ++#define    FILE_ELF_NOTES_MAX        256
>> + };
>> +
>> + /* Type for Unicode characters */
>> +@@ -438,7 +448,7 @@ protected int file_encoding(struct magic_set *, 
>> const unsigned char *, size_t,
>> +     unichar **, size_t *, const char **, const char **, const char 
>> **);
>> + protected int file_is_tar(struct magic_set *, const unsigned char 
>> *, size_t);
>> + protected int file_softmagic(struct magic_set *, const unsigned 
>> char *, size_t,
>> +-    int, int);
>> ++    uint16_t, uint16_t *, int, int);
>> + protected int file_apprentice(struct magic_set *, const char *, int);
>> + protected int file_magicfind(struct magic_set *, const char *, 
>> struct mlist *);
>> + protected uint64_t file_signextend(struct magic_set *, struct magic *,
>> +@@ -468,6 +478,14 @@ protected int file_os2_apptype(struct magic_set 
>> *, const char *, const void *,
>> + #endif /* __EMX__ */
>> +
>> +
>> ++typedef struct {
>> ++    char *buf;
>> ++    uint32_t offset;
>> ++} file_pushbuf_t;
>> ++
>> ++protected file_pushbuf_t *file_push_buffer(struct magic_set *);
>> ++protected char  *file_pop_buffer(struct magic_set *, file_pushbuf_t 
>> *);
>> ++
>> + #ifndef COMPILE_ONLY
>> + extern const char *file_names[];
>> + extern const size_t file_nnames;
>> +diff --git a/src/file_opts.h b/src/file_opts.h
>> +index db34eb7..3286ac6 100644
>> +--- a/src/file_opts.h
>> ++++ b/src/file_opts.h
>> +@@ -43,6 +43,12 @@ OPT('0', "print0", 0, " terminate filenames with 
>> ASCII NUL\n")
>> + #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
>> + OPT('p', "preserve-date", 0, "        preserve access times on 
>> files\n")
>> + #endif
>> ++OPT('P', "parameter", 0, "            set file engine parameter 
>> limits\n"
>> ++    "                               indir        15 recursion limit 
>> for indirection\n"
>> ++    "                               name         30 use limit for 
>> name/use magic\n"
>> ++    "                               elf_notes   256 max ELF notes 
>> processed\n"
>> ++    "                               elf_phnum   128 max ELF prog 
>> sections processed\n"
>> ++    "                               elf_shnum 32768 max ELF 
>> sections processed\n")
>> + OPT('r', "raw", 0, "                  don't translate unprintable 
>> chars to \\ooo\n")
>> + OPT('s', "special-files", 0, "        treat special (block/char 
>> devices) files as\n"
>> +     "                             ordinary ones\n")
>> +diff --git a/src/funcs.c b/src/funcs.c
>> +index b798e44..50c38e5 100644
>> +--- a/src/funcs.c
>> ++++ b/src/funcs.c
>> +@@ -226,7 +226,7 @@ file_buffer(struct magic_set *ms, int fd, const 
>> char *inname __attribute__ ((unu
>> +
>> +     /* try soft magic tests */
>> +     if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
>> +-        if ((m = file_softmagic(ms, ubuf, nb, BINTEST,
>> ++        if ((m = file_softmagic(ms, ubuf, nb, 0, NULL, BINTEST,
>> +             looks_text)) != 0) {
>> +             if ((ms->flags & MAGIC_DEBUG) != 0)
>> +                 (void)fprintf(stderr, "softmagic %d\n", m);
>> +@@ -459,3 +459,43 @@ file_replace(struct magic_set *ms, const char 
>> *pat, const char *rep)
>> +         return nm;
>> +     }
>> + }
>> ++
>> ++protected file_pushbuf_t *
>> ++file_push_buffer(struct magic_set *ms)
>> ++{
>> ++    file_pushbuf_t *pb;
>> ++
>> ++    if (ms->event_flags & EVENT_HAD_ERR)
>> ++        return NULL;
>> ++
>> ++    if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
>> ++        return NULL;
>> ++
>> ++    pb->buf = ms->o.buf;
>> ++    pb->offset = ms->offset;
>> ++
>> ++    ms->o.buf = NULL;
>> ++    ms->offset = 0;
>> ++
>> ++    return pb;
>> ++}
>> ++
>> ++protected char *
>> ++file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
>> ++{
>> ++    char *rbuf;
>> ++
>> ++    if (ms->event_flags & EVENT_HAD_ERR) {
>> ++        free(pb->buf);
>> ++        free(pb);
>> ++        return NULL;
>> ++    }
>> ++
>> ++    rbuf = ms->o.buf;
>> ++
>> ++    ms->o.buf = pb->buf;
>> ++    ms->offset = pb->offset;
>> ++
>> ++    free(pb);
>> ++    return rbuf;
>> ++}
>> +diff --git a/src/magic.c b/src/magic.c
>> +index 22174b8..a89647c 100644
>> +--- a/src/magic.c
>> ++++ b/src/magic.c
>> +@@ -490,3 +490,53 @@ magic_version(void)
>> + {
>> +     return MAGIC_VERSION;
>> + }
>> ++
>> ++public int
>> ++magic_setparam(struct magic_set *ms, int param, const void *val)
>> ++{
>> ++    switch (param) {
>> ++    case MAGIC_PARAM_INDIR_MAX:
>> ++        ms->indir_max = *(const size_t *)val;
>> ++        return 0;
>> ++    case MAGIC_PARAM_NAME_MAX:
>> ++        ms->name_max = *(const size_t *)val;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_PHNUM_MAX:
>> ++        ms->elf_phnum_max = *(const size_t *)val;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_SHNUM_MAX:
>> ++        ms->elf_shnum_max = *(const size_t *)val;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_NOTES_MAX:
>> ++        ms->elf_notes_max = *(const size_t *)val;
>> ++        return 0;
>> ++    default:
>> ++        errno = EINVAL;
>> ++        return -1;
>> ++    }
>> ++}
>> ++
>> ++public int
>> ++magic_getparam(struct magic_set *ms, int param, void *val)
>> ++{
>> ++    switch (param) {
>> ++    case MAGIC_PARAM_INDIR_MAX:
>> ++        *(size_t *)val = ms->indir_max;
>> ++        return 0;
>> ++    case MAGIC_PARAM_NAME_MAX:
>> ++        *(size_t *)val = ms->name_max;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_PHNUM_MAX:
>> ++        *(size_t *)val = ms->elf_phnum_max;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_SHNUM_MAX:
>> ++        *(size_t *)val = ms->elf_shnum_max;
>> ++        return 0;
>> ++    case MAGIC_PARAM_ELF_NOTES_MAX:
>> ++        *(size_t *)val = ms->elf_notes_max;
>> ++        return 0;
>> ++    default:
>> ++        errno = EINVAL;
>> ++        return -1;
>> ++    }
>> ++}
>> +diff --git a/src/magic.h b/src/magic.h
>> +index cc8ed68..2938a20 100644
>> +--- a/src/magic.h
>> ++++ b/src/magic.h
>> +@@ -101,6 +101,15 @@ int magic_check(magic_t, const char *);
>> + int magic_list(magic_t, const char *);
>> + int magic_errno(magic_t);
>> +
>> ++#define MAGIC_PARAM_INDIR_MAX        0
>> ++#define MAGIC_PARAM_NAME_MAX        1
>> ++#define MAGIC_PARAM_ELF_PHNUM_MAX    2
>> ++#define MAGIC_PARAM_ELF_SHNUM_MAX    3
>> ++#define MAGIC_PARAM_ELF_NOTES_MAX    4
>> ++
>> ++int magic_setparam(magic_t, int, const void *);
>> ++int magic_getparam(magic_t, int, void *);
>> ++
>> + #ifdef __cplusplus
>> + };
>> + #endif
>> +diff --git a/src/magic.h.in b/src/magic.h.in
>> +index 86fc41b..a256cf0 100644
>> +--- a/src/magic.h.in
>> ++++ b/src/magic.h.in
>> +@@ -101,6 +101,10 @@ int magic_check(magic_t, const char *);
>> + int magic_list(magic_t, const char *);
>> + int magic_errno(magic_t);
>> +
>> ++#define MAGIC_PARAM_MAX_RECURSION    0
>> ++int magic_setparam(magic_t, int, const void *);
>> ++int magic_getparam(magic_t, int, void *);
>> ++
>> + #ifdef __cplusplus
>> + };
>> + #endif
>> +diff --git a/src/readelf.c b/src/readelf.c
>> +index f8b8bbc..a7b2ba4 100644
>> +--- a/src/readelf.c
>> ++++ b/src/readelf.c
>> +@@ -43,14 +43,14 @@ FILE_RCSID("@(#)$File: readelf.c,v 1.99 
>> 2013/11/05 15:44:01 christos Exp $")
>> +
>> + #ifdef    ELFCORE
>> + private int dophn_core(struct magic_set *, int, int, int, off_t, 
>> int, size_t,
>> +-    off_t, int *);
>> ++    off_t, int *, uint16_t *);
>> + #endif
>> + private int dophn_exec(struct magic_set *, int, int, int, off_t, 
>> int, size_t,
>> +-    off_t, int *, int);
>> ++    off_t, int, int *, uint16_t *);
>> + private int doshn(struct magic_set *, int, int, int, off_t, int, 
>> size_t,
>> +-    off_t, int *, int, int);
>> ++    off_t, int, int, int *, uint16_t *);
>> + private size_t donote(struct magic_set *, void *, size_t, size_t, int,
>> +-    int, size_t, int *);
>> ++    int, size_t, int *, uint16_t *);
>> +
>> + #define    ELF_ALIGN(a)    ((((a) + align - 1) / align) * align)
>> +
>> +@@ -60,6 +60,19 @@ private uint16_t getu16(int, uint16_t);
>> + private uint32_t getu32(int, uint32_t);
>> + private uint64_t getu64(int, uint64_t);
>> +
>> ++#define MAX_PHNUM    128
>> ++#define    MAX_SHNUM    32768
>> ++#define SIZE_UNKNOWN    ((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)
>> ++        return -1;
>> ++    return 0;
>> ++}
>> ++
>> + private uint16_t
>> + getu16(int swap, uint16_t value)
>> + {
>> +@@ -280,15 +293,19 @@ private const char os_style_names[][8] = {
>> +     "NetBSD",
>> + };
>> +
>> +-#define FLAGS_DID_CORE        0x01
>> +-#define FLAGS_DID_NOTE        0x02
>> +-#define FLAGS_DID_BUILD_ID    0x04
>> +-#define FLAGS_DID_CORE_STYLE    0x08
>> +-#define FLAGS_IS_CORE        0x10
>> ++#define FLAGS_DID_CORE            0x001
>> ++#define FLAGS_DID_OS_NOTE        0x002
>> ++#define FLAGS_DID_BUILD_ID        0x004
>> ++#define FLAGS_DID_CORE_STYLE        0x008
>> ++#define FLAGS_DID_NETBSD_PAX        0x010
>> ++#define FLAGS_DID_NETBSD_MARCH        0x020
>> ++#define FLAGS_DID_NETBSD_CMODEL        0x040
>> ++#define FLAGS_DID_NETBSD_UNKNOWN    0x080
>> ++#define FLAGS_IS_CORE            0x100
>> +
>> + private int
>> + dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t 
>> off,
>> +-    int num, size_t size, off_t fsize, int *flags)
>> ++    int num, size_t size, off_t fsize, int *flags, uint16_t 
>> *notecount)
>> + {
>> +     Elf32_Phdr ph32;
>> +     Elf64_Phdr ph64;
>> +@@ -306,13 +323,13 @@ 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) == -1) {
>> ++        if (pread(fd, xph_addr, xph_sizeof, off) < 
>> (ssize_t)xph_sizeof) {
>> +             file_badread(ms);
>> +             return -1;
>> +         }
>> +         off += size;
>> +
>> +-        if (xph_offset > fsize) {
>> ++        if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
>> +             /* Perhaps warn here */
>> +             continue;
>> +         }
>> +@@ -334,7 +351,7 @@ dophn_core(struct magic_set *ms, int clazz, int 
>> swap, int fd, off_t off,
>> +             if (offset >= (size_t)bufsize)
>> +                 break;
>> +             offset = donote(ms, nbuf, offset, (size_t)bufsize,
>> +-                clazz, swap, 4, flags);
>> ++                clazz, swap, 4, flags, notecount);
>> +             if (offset == 0)
>> +                 break;
>> +
>> +@@ -464,125 +481,127 @@ do_note_freebsd_version(struct magic_set 
>> *ms, int swap, void *v)
>> +     }
>> + }
>> +
>> +-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)
>> ++private int
>> ++do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
>> ++    int swap __attribute__((__unused__)), uint32_t namesz, uint32_t 
>> descsz,
>> ++    size_t noff, size_t doff, int *flags)
>> + {
>> +-    Elf32_Nhdr nh32;
>> +-    Elf64_Nhdr nh64;
>> +-    size_t noff, doff;
>> +-#ifdef ELFCORE
>> +-    int os_style = -1;
>> +-#endif
>> +-    uint32_t namesz, descsz;
>> +-    unsigned char *nbuf = CAST(unsigned char *, vbuf);
>> +-
>> +-    (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
>> +-    offset += xnh_sizeof;
>> +-
>> +-    namesz = xnh_namesz;
>> +-    descsz = xnh_descsz;
>> +-    if ((namesz == 0) && (descsz == 0)) {
>> +-        /*
>> +-         * We're out of note headers.
>> +-         */
>> +-        return (offset >= size) ? offset : size;
>> +-    }
>> +-
>> +-    if (namesz & 0x80000000) {
>> +-        (void)file_printf(ms, ", bad note name size 0x%lx",
>> +-        (unsigned long)namesz);
>> +-        return offset;
>> +-    }
>> +-
>> +-    if (descsz & 0x80000000) {
>> +-        (void)file_printf(ms, ", bad note description size 0x%lx",
>> +-        (unsigned long)descsz);
>> +-        return offset;
>> +-    }
>> +-
>> +-
>> +-    noff = offset;
>> +-    doff = ELF_ALIGN(offset + namesz);
>> +-
>> +-    if (offset + namesz > size) {
>> +-        /*
>> +-         * We're past the end of the buffer.
>> +-         */
>> +-        return doff;
>> +-    }
>> +-
>> +-    offset = ELF_ALIGN(doff + descsz);
>> +-    if (doff + descsz > size) {
>> +-        /*
>> +-         * We're past the end of the buffer.
>> +-         */
>> +-        return (offset >= size) ? offset : size;
>> ++    if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
>> ++        type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
>> ++        uint8_t desc[20];
>> ++        uint32_t i;
>> ++        *flags |= FLAGS_DID_BUILD_ID;
>> ++        if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? 
>> "md5/uuid" :
>> ++            "sha1") == -1)
>> ++            return 1;
>> ++        (void)memcpy(desc, &nbuf[doff], descsz);
>> ++        for (i = 0; i < descsz; i++)
>> ++            if (file_printf(ms, "%02x", desc[i]) == -1)
>> ++            return 1;
>> ++        return 1;
>> +     }
>> +-
>> +-    if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) ==
>> +-        (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID))
>> +-        goto core;
>> +-
>> ++    return 0;
>> ++}
>> ++
>> ++private int
>> ++do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
>> ++    int swap, uint32_t namesz, uint32_t descsz,
>> ++    size_t noff, size_t doff, int *flags)
>> ++{
>> +     if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
>> +-        xnh_type == NT_GNU_VERSION && descsz == 2) {
>> ++        type == NT_GNU_VERSION && descsz == 2) {
>> ++        *flags |= FLAGS_DID_OS_NOTE;
>> +         file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 
>> 1]);
>> ++        return 1;
>> +     }
>> ++
>> +     if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
>> +-        xnh_type == NT_GNU_VERSION && descsz == 16) {
>> ++        type == NT_GNU_VERSION && descsz == 16) {
>> +         uint32_t desc[4];
>> +         (void)memcpy(desc, &nbuf[doff], sizeof(desc));
>> +
>> ++        *flags |= FLAGS_DID_OS_NOTE;
>> +         if (file_printf(ms, ", for GNU/") == -1)
>> +-            return size;
>> ++            return 1;
>> +         switch (elf_getu32(swap, desc[0])) {
>> +         case GNU_OS_LINUX:
>> +             if (file_printf(ms, "Linux") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         case GNU_OS_HURD:
>> +             if (file_printf(ms, "Hurd") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         case GNU_OS_SOLARIS:
>> +             if (file_printf(ms, "Solaris") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         case GNU_OS_KFREEBSD:
>> +             if (file_printf(ms, "kFreeBSD") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         case GNU_OS_KNETBSD:
>> +             if (file_printf(ms, "kNetBSD") == -1)
>> +-                return size;
>> ++                return 1;
>> +             break;
>> +         default:
>> +             if (file_printf(ms, "<unknown>") == -1)
>> +-                return size;
>> ++                return 1;
>> +         }
>> +         if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
>> +             elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) 
>> == -1)
>> +-            return size;
>> +-        *flags |= FLAGS_DID_NOTE;
>> +-        return size;
>> ++            return 1;
>> ++        return 1;
>> +     }
>> +
>> +-    if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
>> +-        xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 
>> 20)) {
>> +-        uint8_t desc[20];
>> +-        uint32_t i;
>> +-        if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? 
>> "md5/uuid" :
>> +-        "sha1") == -1)
>> +-            return size;
>> +-        (void)memcpy(desc, &nbuf[doff], descsz);
>> +-        for (i = 0; i < descsz; i++)
>> +-        if (file_printf(ms, "%02x", desc[i]) == -1)
>> +-            return size;
>> +-        *flags |= FLAGS_DID_BUILD_ID;
>> ++    if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
>> ++            if (type == NT_NETBSD_VERSION && descsz == 4) {
>> ++            *flags |= FLAGS_DID_OS_NOTE;
>> ++            do_note_netbsd_version(ms, swap, &nbuf[doff]);
>> ++            return 1;
>> ++        }
>> ++    }
>> ++
>> ++    if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
>> ++            if (type == NT_FREEBSD_VERSION && descsz == 4) {
>> ++            *flags |= FLAGS_DID_OS_NOTE;
>> ++            do_note_freebsd_version(ms, swap, &nbuf[doff]);
>> ++            return 1;
>> ++        }
>> ++    }
>> ++
>> ++    if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
>> ++        type == NT_OPENBSD_VERSION && descsz == 4) {
>> ++        *flags |= FLAGS_DID_OS_NOTE;
>> ++        if (file_printf(ms, ", for OpenBSD") == -1)
>> ++            return 1;
>> ++        /* Content of note is always 0 */
>> ++        return 1;
>> ++    }
>> ++
>> ++    if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 
>> 0 &&
>> ++        type == NT_DRAGONFLY_VERSION && descsz == 4) {
>> ++        uint32_t desc;
>> ++        *flags |= FLAGS_DID_OS_NOTE;
>> ++        if (file_printf(ms, ", for DragonFly") == -1)
>> ++            return 1;
>> ++        (void)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)
>> ++            return 1;
>> ++        return 1;
>> +     }
>> ++    return 0;
>> ++}
>> +
>> ++private int
>> ++do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
>> ++    int swap, uint32_t namesz, uint32_t descsz,
>> ++    size_t noff, size_t doff, int *flags)
>> ++{
>> +     if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
>> +-        xnh_type == NT_NETBSD_PAX && descsz == 4) {
>> ++        type == NT_NETBSD_PAX && descsz == 4) {
>> +         static const char *pax[] = {
>> +             "+mprotect",
>> +             "-mprotect",
>> +@@ -595,80 +614,32 @@ donote(struct magic_set *ms, void *vbuf, 
>> size_t offset, size_t size,
>> +         size_t i;
>> +         int did = 0;
>> +
>> ++        *flags |= FLAGS_DID_NETBSD_PAX;
>> +         (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
>> +         desc = elf_getu32(swap, desc);
>> +
>> +         if (desc && file_printf(ms, ", PaX: ") == -1)
>> +-            return size;
>> ++            return 1;
>> +
>> +         for (i = 0; i < __arraycount(pax); i++) {
>> +             if (((1 << i) & desc) == 0)
>> +                 continue;
>> +             if (file_printf(ms, "%s%s", did++ ? "," : "",
>> +                 pax[i]) == -1)
>> +-                return size;
>> +-        }
>> +-    }
>> +-
>> +-    if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
>> +-        switch (xnh_type) {
>> +-        case NT_NETBSD_VERSION:
>> +-            if (descsz == 4) {
>> +-                do_note_netbsd_version(ms, swap, &nbuf[doff]);
>> +-                *flags |= FLAGS_DID_NOTE;
>> +-                return size;
>> +-            }
>> +-            break;
>> +-        case NT_NETBSD_MARCH:
>> +-            if (file_printf(ms, ", compiled for: %.*s", (int)descsz,
>> +-                (const char *)&nbuf[doff]) == -1)
>> +-                return size;
>> +-            break;
>> +-        case NT_NETBSD_CMODEL:
>> +-            if (file_printf(ms, ", compiler model: %.*s",
>> +-                (int)descsz, (const char *)&nbuf[doff]) == -1)
>> +-                return size;
>> +-            break;
>> +-        default:
>> +-            if (file_printf(ms, ", note=%u", xnh_type) == -1)
>> +-                return size;
>> +-            break;
>> +-        }
>> +-        return size;
>> +-    }
>> +-
>> +-    if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
>> +-            if (xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
>> +-            do_note_freebsd_version(ms, swap, &nbuf[doff]);
>> +-            *flags |= FLAGS_DID_NOTE;
>> +-            return size;
>> ++            return 1;
>> +         }
>> ++        return 1;
>> +     }
>> ++    return 0;
>> ++}
>> +
>> +-    if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
>> +-        xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
>> +-        if (file_printf(ms, ", for OpenBSD") == -1)
>> +-            return size;
>> +-        /* Content of note is always 0 */
>> +-        *flags |= FLAGS_DID_NOTE;
>> +-        return size;
>> +-    }
>> +-
>> +-    if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 
>> 0 &&
>> +-        xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
>> +-        uint32_t desc;
>> +-        if (file_printf(ms, ", for DragonFly") == -1)
>> +-            return size;
>> +-        (void)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)
>> +-            return size;
>> +-        *flags |= FLAGS_DID_NOTE;
>> +-        return size;
>> +-    }
>> +-
>> +-core:
>> ++private int
>> ++do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
>> ++    int swap, uint32_t namesz, uint32_t descsz,
>> ++    size_t noff, size_t doff, int *flags, size_t size, int clazz)
>> ++{
>> ++#ifdef ELFCORE
>> ++    int os_style = -1;
>> +     /*
>> +      * Sigh.  The 2.0.36 kernel in Debian 2.1, at
>> +      * least, doesn't correctly implement name
>> +@@ -697,20 +668,17 @@ core:
>> +         os_style = OS_STYLE_NETBSD;
>> +     }
>> +
>> +-#ifdef ELFCORE
>> +-    if ((*flags & FLAGS_DID_CORE) != 0)
>> +-        return size;
>> +-
>> +     if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
>> +         if (file_printf(ms, ", %s-style", os_style_names[os_style])
>> +             == -1)
>> +-            return size;
>> ++            return 1;
>> +         *flags |= FLAGS_DID_CORE_STYLE;
>> +     }
>> +
>> +     switch (os_style) {
>> +     case OS_STYLE_NETBSD:
>> +-        if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
>> ++        if (type == NT_NETBSD_CORE_PROCINFO) {
>> ++            char sbuf[512];
>> +             uint32_t signo;
>> +             /*
>> +              * Extract the program name.  It is at
>> +@@ -719,7 +687,7 @@ core:
>> +              */
>> +             if (file_printf(ms, ", from '%.31s'",
>> +                 &nbuf[doff + 0x7c]) == -1)
>> +-                return size;
>> ++                return 1;
>> +
>> +             /*
>> +              * Extract the signal number.  It is at
>> +@@ -736,8 +704,7 @@ core:
>> +         break;
>> +
>> +     default:
>> +-        if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
>> +-/*###709 [cc] warning: declaration of 'i' shadows previous 
>> non-variable%%%*/
>> ++        if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
>> +             size_t i, j;
>> +             unsigned char c;
>> +             /*
>> +@@ -805,7 +772,7 @@ core:
>> +                  * Try next offsets, in case this match is
>> +                  * in the middle of a string.
>> +                  */
>> +-                for (k = i + 1 ; k < NOFFSETS ; k++) {
>> ++                for (k = i + 1 ; k < NOFFSETS; k++) {
>> +                     size_t no;
>> +                     int adjust = 1;
>> +                     if (prpsoffsets(k) >= prpsoffsets(i))
>> +@@ -830,9 +797,9 @@ core:
>> +                     cp--;
>> +                 if (file_printf(ms, ", from '%.*s'",
>> +                     (int)(cp - cname), cname) == -1)
>> +-                    return size;
>> ++                    return 1;
>> +                 *flags |= FLAGS_DID_CORE;
>> +-                return size;
>> ++                return 1;
>> +
>> +             tryanother:
>> +                 ;
>> +@@ -841,6 +808,129 @@ core:
>> +         break;
>> +     }
>> + #endif
>> ++    return 0;
>> ++}
>> ++
>> ++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)
>> ++{
>> ++    Elf32_Nhdr nh32;
>> ++    Elf64_Nhdr nh64;
>> ++    size_t noff, doff;
>> ++    uint32_t namesz, descsz;
>> ++    unsigned char *nbuf = CAST(unsigned char *, vbuf);
>> ++
>> ++    if (*notecount == 0)
>> ++        return 0;
>> ++    --*notecount;
>> ++
>> ++    if (xnh_sizeof + offset > size) {
>> ++        /*
>> ++         * We're out of note headers.
>> ++         */
>> ++        return xnh_sizeof + offset;
>> ++    }
>> ++
>> ++    (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
>> ++    offset += xnh_sizeof;
>> ++
>> ++    namesz = xnh_namesz;
>> ++    descsz = xnh_descsz;
>> ++    if ((namesz == 0) && (descsz == 0)) {
>> ++        /*
>> ++         * We're out of note headers.
>> ++         */
>> ++        return (offset >= size) ? offset : size;
>> ++    }
>> ++
>> ++    if (namesz & 0x80000000) {
>> ++        (void)file_printf(ms, ", bad note name size 0x%lx",
>> ++        (unsigned long)namesz);
>> ++        return 0;
>> ++    }
>> ++
>> ++    if (descsz & 0x80000000) {
>> ++        (void)file_printf(ms, ", bad note description size 0x%lx",
>> ++        (unsigned long)descsz);
>> ++        return 0;
>> ++    }
>> ++
>> ++    noff = offset;
>> ++    doff = ELF_ALIGN(offset + namesz);
>> ++
>> ++    if (offset + namesz > size) {
>> ++        /*
>> ++         * We're past the end of the buffer.
>> ++         */
>> ++        return doff;
>> ++    }
>> ++
>> ++    offset = ELF_ALIGN(doff + descsz);
>> ++    if (doff + descsz > size) {
>> ++        /*
>> ++         * We're past the end of the buffer.
>> ++         */
>> ++        return (offset >= size) ? offset : size;
>> ++    }
>> ++
>> ++    if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
>> ++        if (do_os_note(ms, nbuf, xnh_type, swap,
>> ++            namesz, descsz, noff, doff, flags))
>> ++            return size;
>> ++    }
>> ++
>> ++    if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
>> ++        if (do_bid_note(ms, nbuf, xnh_type, swap,
>> ++            namesz, descsz, noff, doff, flags))
>> ++            return size;
>> ++    }
>> ++
>> ++    if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
>> ++        if (do_pax_note(ms, nbuf, xnh_type, swap,
>> ++            namesz, descsz, noff, doff, flags))
>> ++            return size;
>> ++    }
>> ++
>> ++    if ((*flags & FLAGS_DID_CORE) == 0) {
>> ++        if (do_core_note(ms, nbuf, xnh_type, swap,
>> ++            namesz, descsz, noff, doff, flags, size, clazz))
>> ++            return size;
>> ++    }
>> ++
>> ++    if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
>> ++        if (descsz > 100)
>> ++            descsz = 100;
>> ++        switch (xnh_type) {
>> ++            case NT_NETBSD_VERSION:
>> ++            return size;
>> ++        case NT_NETBSD_MARCH:
>> ++            if (*flags & FLAGS_DID_NETBSD_MARCH)
>> ++                return size;
>> ++            *flags |= FLAGS_DID_NETBSD_MARCH;
>> ++            if (file_printf(ms, ", compiled for: %.*s",
>> ++                (int)descsz, (const char *)&nbuf[doff]) == -1)
>> ++                return size;
>> ++            break;
>> ++        case NT_NETBSD_CMODEL:
>> ++            if (*flags & FLAGS_DID_NETBSD_CMODEL)
>> ++                return size;
>> ++            *flags |= FLAGS_DID_NETBSD_CMODEL;
>> ++            if (file_printf(ms, ", compiler model: %.*s",
>> ++                (int)descsz, (const char *)&nbuf[doff]) == -1)
>> ++                return size;
>> ++            break;
>> ++        default:
>> ++            if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
>> ++                return size;
>> ++            *flags |= FLAGS_DID_NETBSD_UNKNOWN;
>> ++            if (file_printf(ms, ", note=%u", xnh_type) == -1)
>> ++                return size;
>> ++            break;
>> ++        }
>> ++        return size;
>> ++    }
>> ++
>> +     return offset;
>> + }
>> +
>> +@@ -896,16 +986,19 @@ static const cap_desc_t cap_desc_386[] = {
>> +
>> + private int
>> + doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 
>> int num,
>> +-    size_t size, off_t fsize, int *flags, int mach, int strtab)
>> ++    size_t size, off_t fsize, int mach, int strtab, int *flags,
>> ++    uint16_t *notecount)
>> + {
>> +     Elf32_Shdr sh32;
>> +     Elf64_Shdr sh64;
>> +     int stripped = 1;
>> ++    size_t nbadcap = 0;
>> +     void *nbuf;
>> +     off_t noff, coff, name_off;
>> +     uint64_t cap_hw1 = 0;    /* SunOS 5.x hardware capabilites */
>> +     uint64_t cap_sf1 = 0;    /* SunOS 5.x software capabilites */
>> +     char name[50];
>> ++    ssize_t namesize;
>> +
>> +     if (size != xsh_sizeof) {
>> +         if (file_printf(ms, ", corrupted section header size") == -1)
>> +@@ -914,7 +1007,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, off + size * strtab) == -1) {
>> ++    if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) < 
>> (ssize_t)xsh_sizeof) {
>> +         file_badread(ms);
>> +         return -1;
>> +     }
>> +@@ -922,15 +1015,15 @@ 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 (pread(fd, name, sizeof(name), name_off + xsh_name) == 
>> -1) {
>> ++        if ((namesize = pread(fd, name, sizeof(name) - 1, name_off 
>> + xsh_name)) == -1) {
>> +             file_badread(ms);
>> +             return -1;
>> +         }
>> +-        name[sizeof(name) - 1] = '\0';
>> ++        name[namesize] = '\0';
>> +         if (strcmp(name, ".debug_info") == 0)
>> +             stripped = 0;
>> +
>> +-        if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) {
>> ++        if (pread(fd, xsh_addr, xsh_sizeof, off) < 
>> (ssize_t)xsh_sizeof) {
>> +             file_badread(ms);
>> +             return -1;
>> +         }
>> +@@ -945,7 +1038,7 @@ doshn(struct magic_set *ms, int clazz, int 
>> swap, int fd, off_t off, int num,
>> +             stripped = 0;
>> +             break;
>> +         default:
>> +-            if (xsh_offset > fsize) {
>> ++            if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
>> +                 /* Perhaps warn here */
>> +                 continue;
>> +             }
>> +@@ -960,7 +1053,7 @@ doshn(struct magic_set *ms, int clazz, int 
>> swap, int fd, off_t off, int num,
>> +                     " for note");
>> +                 return -1;
>> +             }
>> +-            if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) {
>> ++            if (pread(fd, nbuf, xsh_size, xsh_offset) < 
>> (ssize_t)xsh_size) {
>> +                 file_badread(ms);
>> +                 free(nbuf);
>> +                 return -1;
>> +@@ -971,7 +1064,7 @@ doshn(struct magic_set *ms, int clazz, int 
>> swap, int fd, off_t off, int num,
>> +                 if (noff >= (off_t)xsh_size)
>> +                     break;
>> +                 noff = donote(ms, nbuf, (size_t)noff,
>> +-                    xsh_size, clazz, swap, 4, flags);
>> ++                    xsh_size, clazz, swap, 4, flags, notecount);
>> +                 if (noff == 0)
>> +                     break;
>> +             }
>> +@@ -989,6 +1082,8 @@ doshn(struct magic_set *ms, int clazz, int 
>> swap, int fd, off_t off, int num,
>> +                 goto skip;
>> +             }
>> +
>> ++            if (nbadcap > 5)
>> ++                break;
>> +             if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
>> +                 file_badseek(ms);
>> +                 return -1;
>> +@@ -1024,6 +1119,8 @@ doshn(struct magic_set *ms, int clazz, int 
>> swap, int fd, off_t off, int num,
>> +                         (unsigned long long)xcap_tag,
>> +                         (unsigned long long)xcap_val) == -1)
>> +                         return -1;
>> ++                    if (nbadcap++ > 2)
>> ++                        coff = xsh_size;
>> +                     break;
>> +                 }
>> +             }
>> +@@ -1104,7 +1201,8 @@ doshn(struct magic_set *ms, int clazz, int 
>> swap, int fd, off_t off, int num,
>> +  */
>> + private int
>> + dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t 
>> off,
>> +-    int num, size_t size, off_t fsize, int *flags, int sh_num)
>> ++    int num, size_t size, off_t fsize, int sh_num, int *flags,
>> ++    uint16_t *notecount)
>> + {
>> +     Elf32_Phdr ph32;
>> +     Elf64_Phdr ph64;
>> +@@ -1121,7 +1219,7 @@ dophn_exec(struct magic_set *ms, int clazz, 
>> int swap, int fd, off_t off,
>> +     }
>> +
>> +       for ( ; num; num--) {
>> +-        if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
>> ++        if (pread(fd, xph_addr, xph_sizeof, off) < 
>> (ssize_t)xph_sizeof) {
>> +             file_badread(ms);
>> +             return -1;
>> +         }
>> +@@ -1137,7 +1235,7 @@ dophn_exec(struct magic_set *ms, int clazz, 
>> int swap, int fd, off_t off,
>> +             shared_libraries = " (uses shared libs)";
>> +             break;
>> +         default:
>> +-            if (xph_offset > fsize) {
>> ++            if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
>> +                 /* Maybe warn here? */
>> +                 continue;
>> +             }
>> +@@ -1173,7 +1271,7 @@ dophn_exec(struct magic_set *ms, int clazz, 
>> int swap, int fd, off_t off,
>> +                     break;
>> +                 offset = donote(ms, nbuf, offset,
>> +                     (size_t)bufsize, clazz, swap, align,
>> +-                    flags);
>> ++                    flags, notecount);
>> +                 if (offset == 0)
>> +                     break;
>> +             }
>> +@@ -1204,7 +1302,7 @@ file_tryelf(struct magic_set *ms, int fd, 
>> const unsigned char *buf,
>> +     int flags = 0;
>> +     Elf32_Ehdr elf32hdr;
>> +     Elf64_Ehdr elf64hdr;
>> +-    uint16_t type;
>> ++    uint16_t type, phnum, shnum, notecount;
>> +
>> +     if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
>> +         return 0;
>> +@@ -1230,7 +1328,10 @@ file_tryelf(struct magic_set *ms, int fd, 
>> const unsigned char *buf,
>> +           file_badread(ms);
>> +         return -1;
>> +     }
>> +-    fsize = st.st_size;
>> ++    if (S_ISREG(st.st_mode))
>> ++        fsize = st.st_size;
>> ++    else
>> ++        fsize = SIZE_UNKNOWN;
>> +
>> +     clazz = buf[EI_CLASS];
>> +
>> +diff --git a/src/softmagic.c b/src/softmagic.c
>> +index dc7928b..b1f5779 100644
>> +--- a/src/softmagic.c
>> ++++ b/src/softmagic.c
>> +@@ -43,11 +43,11 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.168 
>> 2013/05/30 15:53:33 christos Exp $")
>> +
>> +
>> + private int match(struct magic_set *, struct magic *, uint32_t,
>> +-    const unsigned char *, size_t, size_t, int, int, int, int, int 
>> *, int *,
>> +-    int *);
>> ++    const unsigned char *, size_t, size_t, int, int, int, uint16_t,
>> ++    uint16_t *, int *, int *, int *);
>> + private int mget(struct magic_set *, const unsigned char *,
>> +-    struct magic *, size_t, size_t, unsigned int, int, int, int, 
>> int, int *,
>> +-    int *, int *);
>> ++    struct magic *, size_t, size_t, unsigned int, int, int, int, 
>> uint16_t,
>> ++    uint16_t *, int *, int *, int *);
>> + private int magiccheck(struct magic_set *, struct magic *);
>> + private int32_t mprint(struct magic_set *, struct magic *);
>> + private int32_t moffset(struct magic_set *, struct magic *);
>> +@@ -69,14 +69,20 @@ private void cvt_64(union VALUETYPE *, const 
>> struct magic *);
>> + /*ARGSUSED1*/        /* nbytes passed for regularity, maybe need 
>> later */
>> + protected int
>> + file_softmagic(struct magic_set *ms, const unsigned char *buf, 
>> size_t nbytes,
>> +-    int mode, int text)
>> ++    uint16_t indir_level, uint16_t *name_count, int mode, int text)
>> + {
>> +     struct mlist *ml;
>> +     int rv, printed_something = 0, need_separator = 0;
>> ++    uint16_t nc;
>> ++
>> ++    if (name_count == NULL) {
>> ++        nc = 0;
>> ++        name_count = &nc;
>> ++    }
>> +     for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
>> +         if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, 
>> mode,
>> +-            text, 0, 0, &printed_something, &need_separator,
>> +-            NULL)) != 0)
>> ++            text, 0, indir_level, name_count,
>> ++            &printed_something, &need_separator, NULL)) != 0)
>> +             return rv;
>> +
>> +     return 0;
>> +@@ -112,8 +118,8 @@ file_softmagic(struct magic_set *ms, const 
>> unsigned char *buf, size_t nbytes,
>> + private int
>> + match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
>> +     const unsigned char *s, size_t nbytes, size_t offset, int mode, 
>> int text,
>> +-    int flip, int recursion_level, int *printed_something, int 
>> *need_separator,
>> +-    int *returnval)
>> ++    int flip, uint16_t indir_level, uint16_t *name_count,
>> ++    int *printed_something, int *need_separator, int *returnval)
>> + {
>> +     uint32_t magindex = 0;
>> +     unsigned int cont_level = 0;
>> +@@ -150,8 +156,8 @@ match(struct magic_set *ms, struct magic *magic, 
>> uint32_t nmagic,
>> +
>> +         /* if main entry matches, print it... */
>> +         switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
>> +-            flip, recursion_level + 1, printed_something,
>> +-            need_separator, returnval)) {
>> ++            flip, indir_level, name_count,
>> ++            printed_something, need_separator, returnval)) {
>> +         case -1:
>> +             return -1;
>> +         case 0:
>> +@@ -237,8 +243,8 @@ match(struct magic_set *ms, struct magic *magic, 
>> uint32_t nmagic,
>> +             }
>> + #endif
>> +             switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
>> +-                text, flip, recursion_level + 1, printed_something,
>> +-                need_separator, returnval)) {
>> ++                text, flip, indir_level, name_count,
>> ++                printed_something, need_separator, returnval)) {
>> +             case -1:
>> +                 return -1;
>> +             case 0:
>> +@@ -1120,8 +1126,8 @@ mcopy(struct magic_set *ms, union VALUETYPE 
>> *p, int type, int indir,
>> + private int
>> + mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
>> +     size_t nbytes, size_t o, unsigned int cont_level, int mode, int 
>> text,
>> +-    int flip, int recursion_level, int *printed_something,
>> +-    int *need_separator, int *returnval)
>> ++    int flip, uint16_t indir_level, uint16_t *name_count,
>> ++    int *printed_something, int *need_separator, int *returnval)
>> + {
>> +     uint32_t soffset, offset = ms->offset;
>> +     uint32_t count = m->str_range;
>> +@@ -1130,8 +1136,15 @@ mget(struct magic_set *ms, const unsigned 
>> char *s, struct magic *m,
>> +     union VALUETYPE *p = &ms->ms_value;
>> +     struct mlist ml;
>> +
>> +-    if (recursion_level >= 20) {
>> +-        file_error(ms, 0, "recursion nesting exceeded");
>> ++    if (indir_level >= ms->indir_max) {
>> ++        file_error(ms, 0, "indirect recursion nesting (%hu) exceeded",
>> ++            indir_level);
>> ++        return -1;
>> ++    }
>> ++
>> ++    if (*name_count >= ms->name_max) {
>> ++        file_error(ms, 0, "name use count (%hu) exceeded",
>> ++            *name_count);
>> +         return -1;
>> +     }
>> +
>> +@@ -1141,8 +1154,9 @@ mget(struct magic_set *ms, const unsigned char 
>> *s, struct magic *m,
>> +
>> +     if ((ms->flags & MAGIC_DEBUG) != 0) {
>> +         fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, "
>> +-            "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o,
>> +-            nbytes, count);
>> ++            "nbytes=%zu, il=%hu, nc=%hu)\n",
>> ++            m->type, m->flag, offset, o, nbytes,
>> ++            indir_level, *name_count);
>> +         mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
>> + #ifndef COMPILE_ONLY
>> +         file_mdump(m);
>> +@@ -1711,7 +1725,7 @@ mget(struct magic_set *ms, const unsigned char 
>> *s, struct magic *m,
>> +         ms->o.buf = NULL;
>> +         ms->offset = 0;
>> +         rv = file_softmagic(ms, s + offset, nbytes - offset,
>> +-            BINTEST, text);
>> ++            indir_level + 1, name_count, BINTEST, text);
>> +         if ((ms->flags & MAGIC_DEBUG) != 0)
>> +             fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
>> +         rbuf = ms->o.buf;
>> +@@ -1730,22 +1744,22 @@ mget(struct magic_set *ms, const unsigned 
>> char *s, struct magic *m,
>> +     case FILE_USE:
>> +         if (nbytes < offset)
>> +             return 0;
>> +-        sbuf = m->value.s;
>> +-        if (*sbuf == '^') {
>> +-            sbuf++;
>> ++        rbuf = m->value.s;
>> ++        if (*rbuf == '^') {
>> ++            rbuf++;
>> +             flip = !flip;
>> +         }
>> +-        if (file_magicfind(ms, sbuf, &ml) == -1) {
>> +-            file_error(ms, 0, "cannot find entry `%s'", sbuf);
>> ++        if (file_magicfind(ms, rbuf, &ml) == -1) {
>> ++            file_error(ms, 0, "cannot find entry `%s'", rbuf);
>> +             return -1;
>> +         }
>> +-
>> ++        (*name_count)++;
>> +         oneed_separator = *need_separator;
>> +         if (m->flag & NOSPACE)
>> +             *need_separator = 0;
>> +         rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
>> +-            mode, text, flip, recursion_level, printed_something,
>> +-            need_separator, returnval);
>> ++            mode, text, flip, indir_level, name_count,
>> ++            printed_something, need_separator, returnval);
>> +         if (rv != 1)
>> +             *need_separator = oneed_separator;
>> +         return rv;
>> +--
>> +1.7.9.5
>> +
>> diff --git a/meta/recipes-devtools/file/file_5.16.bb 
>> b/meta/recipes-devtools/file/file_5.16.bb
>> index a15d952..f231a55 100644
>> --- a/meta/recipes-devtools/file/file_5.16.bb
>> +++ b/meta/recipes-devtools/file/file_5.16.bb
>> @@ -12,6 +12,7 @@ DEPENDS = "zlib file-native"
>>   DEPENDS_class-native = "zlib-native"
>>
>>   SRC_URI = "ftp://ftp.astron.com/pub/file/file-${PV}.tar.gz \
>> +           file://file-CVE-2014-9620-and-CVE-2014-9621.patch \
>>              file://dump \
>>              file://filesystems"
>>
>>
>
>



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-02-03  1:23 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-22  9:28 [daisy][PATCH] file: CVE-2014-9620 and CVE-2014-9621 Chong Lu
2015-01-30  1:18 ` Chong Lu
2015-01-30  3:57   ` Saul Wold
2015-02-02 13:55 ` Saul Wold
2015-02-03  1:23   ` Chong Lu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.