]> granicus.if.org Git - php/commitdiff
Fix bug #67705 (extensive backtracking in rule regular expression)
authorStanislav Malyshev <stas@php.net>
Mon, 4 Aug 2014 07:08:35 +0000 (00:08 -0700)
committerStanislav Malyshev <stas@php.net>
Mon, 4 Aug 2014 07:09:15 +0000 (00:09 -0700)
NEWS
ext/fileinfo/data_file.c
ext/fileinfo/libmagic/softmagic.c
ext/fileinfo/magicdata.patch
ext/fileinfo/tests/cve-2014-3538.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 88ebb8cd592d8c77ddcd6e0edee2f9709454ed08..8598b46d6b8816983771bd5c06a119fb3464dc2f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,10 @@ PHP                                                                        NEWS
   . Removed inconsistency regarding behaviour of array in constants at
     run-time. (Bob)
 
+- Fileinfo:
+  . Fixed bug #67705 (extensive backtracking in rule regular expression).
+    (CVE-2014-3538) (Remi)
+
 - Milter:
   . Fixed bug #67715 (php-milter does not build and crashes randomly). (Mike)
 
index 8bcd5aa0e135686de156c0616cd6dd9e5cddc00d..5b24670a729f93451fb08ff6812c3fba6b256878 100644 (file)
@@ -121057,7 +121057,7 @@ const unsigned char php_magic_database[2803888] = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x40, 0x00, 0x3D, 0x1B, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x5E, 0x5C, 0x73, 0x7B, 0x30, 0x2C, 0x31, 0x30, 0x30, 0x7D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x5C, 
 0x73, 0x7B, 0x30, 0x2C, 0x31, 0x30, 0x30, 0x7D, 0x5B, 0x7B, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
index 3dd07820a4f4ff18187841f8869ff91d81c15d3d..e000dff92e638c7affd5282c94a0f7b53c0758c3 100644 (file)
@@ -67,7 +67,7 @@ private int32_t mprint(struct magic_set *, struct magic *);
 private int32_t moffset(struct magic_set *, struct magic *);
 private void mdebug(uint32_t, const char *, size_t);
 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
-    const unsigned char *, uint32_t, size_t, size_t);
+    const unsigned char *, uint32_t, size_t, struct magic *);
 private int mconvert(struct magic_set *, struct magic *, int);
 private int print_sep(struct magic_set *, int);
 private int handle_annotation(struct magic_set *, struct magic *);
@@ -1038,7 +1038,7 @@ mdebug(uint32_t offset, const char *str, size_t len)
 
 private int
 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
-    const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
+    const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
 {
        /*
         * Note: FILE_SEARCH and FILE_REGEX do not actually copy
@@ -1058,15 +1058,24 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
                        const char *last;       /* end of search region */
                        const char *buf;        /* start of search region */
                        const char *end;
-                       size_t lines;
+                       size_t lines, linecnt, bytecnt;
 
+                       linecnt = m->str_range;
+                       bytecnt = linecnt * 80;
+
+                       if (bytecnt == 0) {
+                               bytecnt = 8192;
+                       }
+                       if (bytecnt > nbytes) {
+                               bytecnt = nbytes;
+                       }
                        if (s == NULL) {
                                ms->search.s_len = 0;
                                ms->search.s = NULL;
                                return 0;
                        }
                        buf = RCAST(const char *, s) + offset;
-                       end = last = RCAST(const char *, s) + nbytes;
+                       end = last = RCAST(const char *, s) + bytecnt;
                        /* mget() guarantees buf <= last */
                        for (lines = linecnt, b = buf; lines && b < end &&
                             ((b = CAST(const char *,
@@ -1079,7 +1088,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
                                        b++;
                        }
                        if (lines)
-                               last = RCAST(const char *, s) + nbytes;
+                               last = RCAST(const char *, s) + bytecnt;
 
                        ms->search.s = buf;
                        ms->search.s_len = last - buf;
@@ -1150,7 +1159,6 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
     int *need_separator, int *returnval)
 {
        uint32_t soffset, offset = ms->offset;
-       uint32_t count = m->str_range;
        int rv, oneed_separator, in_type;
        char *sbuf, *rbuf;
        union VALUETYPE *p = &ms->ms_value;
@@ -1162,13 +1170,12 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
        }
 
        if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
-           (uint32_t)nbytes, count) == -1)
+           (uint32_t)nbytes, m) == -1)
                return -1;
 
        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)\n", m->type, m->flag, offset, o, nbytes);
                mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
        }
 
@@ -1661,7 +1668,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
                        if ((ms->flags & MAGIC_DEBUG) != 0)
                                fprintf(stderr, "indirect +offs=%u\n", offset);
                }
-               if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
+               if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
                        return -1;
                ms->offset = offset;
 
@@ -2093,7 +2100,7 @@ magiccheck(struct magic_set *ms, struct magic *m)
                        zval *retval;
                        zval *subpats;
                        char *haystack;
-                       
+
                        MAKE_STD_ZVAL(retval);
                        ALLOC_INIT_ZVAL(subpats);
                        
index fb34c3c533db62cf0e1d919ef4d8876b56797c8a..524d40b56782aa0e72e70ce1b8b754f2c8176cae 100644 (file)
@@ -1,4 +1,58 @@
-Patches applied to file sources tree before generating magic.mgc
+Patches applied to file 5.17 sources tree before generating magic.mgc
 and before running create_data_file.php to create data_file.c.
 
 
+
+From 0b478f445b6b7540b58af5d1fe583fa9e48fd745 Mon Sep 17 00:00:00 2001
+From: Christos Zoulas <christos@zoulas.com>
+Date: Wed, 28 May 2014 19:52:36 +0000
+Subject: [PATCH] further optimize awk by not looking for the BEGIN regex until
+ we found the BEGIN (Jan Kaluza)
+
+---
+ magic/Magdir/commands | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/magic/Magdir/commands b/magic/Magdir/commands
+index bfffdef..26b2869 100644
+--- a/magic/Magdir/commands
++++ b/magic/Magdir/commands
+@@ -49,7 +49,8 @@
+ !:mime        text/x-awk
+ 0     string/wt       #!\ /usr/bin/awk        awk script text executable
+ !:mime        text/x-awk
+-0     regex           =^\\s{0,100}BEGIN\\s{0,100}[{]  awk script text
++0       search/16384    BEGIN
++>0    regex           =^\\s{0,100}BEGIN\\s{0,100}[{]  awk script text
+ # AT&T Bell Labs' Plan 9 shell
+ 0     string/wt       #!\ /bin/rc     Plan 9 rc shell script text executable
+-- 
+2.0.3
+
+From 71a8b6c0d758acb0f73e2e51421a711b5e9d6668 Mon Sep 17 00:00:00 2001
+From: Christos Zoulas <christos@zoulas.com>
+Date: Fri, 30 May 2014 16:48:44 +0000
+Subject: [PATCH] Limit regex search for BEGIN to the first 4K of the file.
+
+---
+ magic/Magdir/commands | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/magic/Magdir/commands b/magic/Magdir/commands
+index 26b2869..bcd0f43 100644
+--- a/magic/Magdir/commands
++++ b/magic/Magdir/commands
+@@ -49,8 +49,7 @@
+ !:mime        text/x-awk
+ 0     string/wt       #!\ /usr/bin/awk        awk script text executable
+ !:mime        text/x-awk
+-0       search/16384    BEGIN
+->0    regex           =^\\s{0,100}BEGIN\\s{0,100}[{]  awk script text
++0     regex/4096      =^\\s{0,100}BEGIN\\s{0,100}[{]  awk script text
+ # AT&T Bell Labs' Plan 9 shell
+ 0     string/wt       #!\ /bin/rc     Plan 9 rc shell script text executable
+-- 
+2.0.3
+
diff --git a/ext/fileinfo/tests/cve-2014-3538.phpt b/ext/fileinfo/tests/cve-2014-3538.phpt
new file mode 100644 (file)
index 0000000..d6bc9c6
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+Bug #66731: file: extensive backtraking
+--SKIPIF--
+<?php
+if (!class_exists('finfo'))
+       die('skip no fileinfo extension');
+--FILE--
+<?php
+$fd = __DIR__.'/cve-2014-3538.data';
+
+file_put_contents($fd,
+  'try:' .
+  str_repeat("\n", 1000000));
+
+$fi = finfo_open(FILEINFO_NONE);
+$t = microtime(true);
+var_dump(finfo_file($fi, $fd));
+$t = microtime(true) - $t;
+finfo_close($fi);
+if ($t < 1) {
+       echo "Ok\n";
+} else {
+       printf("Failed, time=%.2f\n", $t);
+}
+
+?>
+Done
+--CLEAN--
+<?php
+@unlink(__DIR__.'/cve-2014-3538.data');
+?>
+--EXPECTF--
+string(%d) "%s"
+Ok
+Done
\ No newline at end of file