summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2014-12-30 22:12:14 +0100
committerOndřej Surý <ondrej@sury.org>2014-12-30 22:12:14 +0100
commit463a5535508ca9e936e5deab588be225aa95d7b1 (patch)
tree04b4b4469d751eb3e8eca093bc7c2cf2fdfa81c9
parent2b07682954e500f86156a630efebc5bba329f1c3 (diff)
downloadphp-463a5535508ca9e936e5deab588be225aa95d7b1.tar.gz
[CVE-2014-8116,CVE-2014-8117]: Fix severe performance issues on pathological input
-rw-r--r--debian/patches/libmagic-security.patch262
-rw-r--r--debian/patches/series1
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