Fix multiple vulnerabilities in file(1) and libmagic(3).
Security: FreeBSD-SA-14:28.file Security: CVE-2014-3710, CVE-2014-8116, CVE-2014-8117
This commit is contained in:
parent
805288c2f0
commit
2c4f16476d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=275666
@ -35,10 +35,12 @@
|
||||
switch (type) {
|
||||
#ifdef ELFCORE
|
||||
case ET_CORE:
|
||||
phnum = elf_getu16(swap, elfhdr.e_phnum);
|
||||
if (phnum > MAX_PHNUM)
|
||||
return toomany(ms, "program", 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)
|
||||
return -1;
|
||||
@ -46,18 +48,24 @@
|
||||
#endif
|
||||
case ET_EXEC:
|
||||
case ET_DYN:
|
||||
phnum = elf_getu16(swap, elfhdr.e_phnum);
|
||||
if (phnum > MAX_PHNUM)
|
||||
return toomany(ms, "program", phnum);
|
||||
shnum = elf_getu16(swap, elfhdr.e_shnum);
|
||||
if (shnum > MAX_SHNUM)
|
||||
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, &flags, shnum) == -1)
|
||||
return -1;
|
||||
/*FALLTHROUGH*/
|
||||
case ET_REL:
|
||||
shnum = elf_getu16(swap, elfhdr.e_shnum);
|
||||
if (shnum > MAX_SHNUM)
|
||||
return toomany(ms, "section", 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)
|
||||
|
@ -482,6 +482,14 @@ protected int file_regexec(file_regex_t *, const char *, size_t, regmatch_t *,
|
||||
protected void file_regfree(file_regex_t *);
|
||||
protected void file_regerror(file_regex_t *, int, struct magic_set *);
|
||||
|
||||
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;
|
||||
|
@ -491,3 +491,43 @@ file_regerror(file_regex_t *rx, int rc, struct magic_set *ms)
|
||||
file_magerror(ms, "regex error %d for `%s', (%s)", rc, rx->pat,
|
||||
errmsg);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -60,6 +60,18 @@ private uint16_t getu16(int, uint16_t);
|
||||
private uint32_t getu32(int, uint32_t);
|
||||
private uint64_t getu64(int, uint64_t);
|
||||
|
||||
#define MAX_PHNUM 256
|
||||
#define MAX_SHNUM 1024
|
||||
|
||||
private int
|
||||
toomany(struct magic_set *ms, const char *name, uint16_t num)
|
||||
{
|
||||
if (file_printf(ms, ", too many %s header sections (%u)", name, num
|
||||
) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private uint16_t
|
||||
getu16(int swap, uint16_t value)
|
||||
{
|
||||
@ -477,6 +489,13 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
|
||||
uint32_t namesz, descsz;
|
||||
unsigned char *nbuf = CAST(unsigned char *, vbuf);
|
||||
|
||||
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;
|
||||
|
||||
@ -492,13 +511,13 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
|
||||
if (namesz & 0x80000000) {
|
||||
(void)file_printf(ms, ", bad note name size 0x%lx",
|
||||
(unsigned long)namesz);
|
||||
return offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (descsz & 0x80000000) {
|
||||
(void)file_printf(ms, ", bad note description size 0x%lx",
|
||||
(unsigned long)descsz);
|
||||
return offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -900,6 +919,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
|
||||
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 */
|
||||
@ -988,6 +1008,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;
|
||||
@ -1053,6 +1075,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;
|
||||
}
|
||||
}
|
||||
@ -1233,7 +1257,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;
|
||||
|
||||
if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
|
||||
return 0;
|
||||
|
@ -67,6 +67,9 @@ private void cvt_32(union VALUETYPE *, const struct magic *);
|
||||
private void cvt_64(union VALUETYPE *, const struct magic *);
|
||||
|
||||
#define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o)))
|
||||
|
||||
#define MAX_RECURSION_LEVEL 10
|
||||
|
||||
/*
|
||||
* softmagic - lookup one file in parsed, in-memory copy of database
|
||||
* Passed the name and FILE * of one file to be typed.
|
||||
@ -1193,14 +1196,15 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
|
||||
int flip, int recursion_level, int *printed_something,
|
||||
int *need_separator, int *returnval)
|
||||
{
|
||||
uint32_t soffset, offset = ms->offset;
|
||||
uint32_t offset = ms->offset;
|
||||
uint32_t lhs;
|
||||
file_pushbuf_t *pb;
|
||||
int rv, oneed_separator, in_type;
|
||||
char *sbuf, *rbuf;
|
||||
char *rbuf;
|
||||
union VALUETYPE *p = &ms->ms_value;
|
||||
struct mlist ml;
|
||||
|
||||
if (recursion_level >= 20) {
|
||||
if (recursion_level >= MAX_RECURSION_LEVEL) {
|
||||
file_error(ms, 0, "recursion nesting exceeded");
|
||||
return -1;
|
||||
}
|
||||
@ -1644,19 +1648,23 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
|
||||
case FILE_INDIRECT:
|
||||
if (offset == 0)
|
||||
return 0;
|
||||
|
||||
if (nbytes < offset)
|
||||
return 0;
|
||||
sbuf = ms->o.buf;
|
||||
soffset = ms->offset;
|
||||
ms->o.buf = NULL;
|
||||
ms->offset = 0;
|
||||
|
||||
if ((pb = file_push_buffer(ms)) == NULL)
|
||||
return -1;
|
||||
|
||||
rv = file_softmagic(ms, s + offset, nbytes - offset,
|
||||
recursion_level, BINTEST, text);
|
||||
|
||||
if ((ms->flags & MAGIC_DEBUG) != 0)
|
||||
fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
|
||||
rbuf = ms->o.buf;
|
||||
ms->o.buf = sbuf;
|
||||
ms->offset = soffset;
|
||||
|
||||
rbuf = file_pop_buffer(ms, pb);
|
||||
if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
|
||||
return -1;
|
||||
|
||||
if (rv == 1) {
|
||||
if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
|
||||
file_printf(ms, F(ms, m, "%u"), offset) == -1) {
|
||||
@ -1674,13 +1682,13 @@ 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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user