diff options
author | Ondřej Surý <ondrej@sury.org> | 2014-12-30 22:12:14 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2014-12-30 22:12:14 +0100 |
commit | 463a5535508ca9e936e5deab588be225aa95d7b1 (patch) | |
tree | 04b4b4469d751eb3e8eca093bc7c2cf2fdfa81c9 | |
parent | 2b07682954e500f86156a630efebc5bba329f1c3 (diff) | |
download | php-463a5535508ca9e936e5deab588be225aa95d7b1.tar.gz |
[CVE-2014-8116,CVE-2014-8117]: Fix severe performance issues on pathological input
-rw-r--r-- | debian/patches/libmagic-security.patch | 262 | ||||
-rw-r--r-- | debian/patches/series | 1 |
2 files changed, 263 insertions, 0 deletions
diff --git a/debian/patches/libmagic-security.patch b/debian/patches/libmagic-security.patch new file mode 100644 index 000000000..8948dcb82 --- /dev/null +++ b/debian/patches/libmagic-security.patch @@ -0,0 +1,262 @@ +--- php5.orig/ext/fileinfo/libmagic/elfclass.h ++++ php5/ext/fileinfo/libmagic/elfclass.h +@@ -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) +--- php5.orig/ext/fileinfo/libmagic/file.h ++++ php5/ext/fileinfo/libmagic/file.h +@@ -464,6 +464,14 @@ protected int file_os2_apptype(struct ma + size_t); + #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 *); ++ + extern const char *file_names[]; + extern const size_t file_nnames; + +--- php5.orig/ext/fileinfo/libmagic/funcs.c ++++ php5/ext/fileinfo/libmagic/funcs.c +@@ -484,3 +484,43 @@ out: + (void)setlocale(LC_CTYPE, ""); + return rep_cnt; + } ++ ++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; ++} +--- php5.orig/ext/fileinfo/libmagic/readelf.c ++++ php5/ext/fileinfo/libmagic/readelf.c +@@ -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) + { +@@ -514,13 +526,13 @@ donote(struct magic_set *ms, void *vbuf, + 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; + } + + +@@ -923,6 +935,7 @@ doshn(struct magic_set *ms, int clazz, i + 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 */ +@@ -992,6 +1005,8 @@ doshn(struct magic_set *ms, int clazz, i + efree(nbuf); + break; + case SHT_SUNW_cap: ++ if (nbadcap > 5) ++ break; + if (FINFO_LSEEK_FUNC(fd, (off_t)xsh_offset, SEEK_SET) == + (off_t)-1) { + file_badseek(ms); +@@ -1028,6 +1043,8 @@ doshn(struct magic_set *ms, int clazz, i + (unsigned long long)xcap_tag, + (unsigned long long)xcap_val) == -1) + return -1; ++ if (nbadcap++ > 2) ++ coff = xsh_size; + break; + } + } +@@ -1215,7 +1232,7 @@ file_tryelf(struct magic_set *ms, int fd + 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; +--- php5.orig/ext/fileinfo/libmagic/softmagic.c ++++ php5/ext/fileinfo/libmagic/softmagic.c +@@ -78,6 +78,8 @@ private void cvt_64(union VALUETYPE *, c + + #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. +@@ -1158,13 +1160,14 @@ mget(struct magic_set *ms, const unsigne + int flip, int recursion_level, int *printed_something, + int *need_separator, int *returnval) + { +- uint32_t soffset, offset = ms->offset; ++ uint32_t offset = ms->offset; ++ 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; + } +@@ -1733,19 +1736,23 @@ mget(struct magic_set *ms, const unsigne + case FILE_INDIRECT: + if (offset == 0) + return 0; ++ + if (OFFSET_OOB(nbytes, offset, 0)) + 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) ++ return -1; ++ + if (rv == 1) { + if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 && + file_printf(ms, m->desc, offset) == -1) { +@@ -1769,13 +1776,13 @@ mget(struct magic_set *ms, const unsigne + case FILE_USE: + if (OFFSET_OOB(nbytes, offset, 0)) + 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; + } + diff --git a/debian/patches/series b/debian/patches/series index 3b94cb46a..11185d225 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -45,3 +45,4 @@ php-5.6.0-oldpcre.patch hack-phpdbg-to-explicitly-link-with-libedit.patch php-fpm-getallheaders.patch 0001-Fix-ZEND_MM_ALIGNMENT-on-m64k.patch +libmagic-security.patch |