af9dc8
From eeaec70758bfc0c0e2c0f8944c8dbeae02866206 Mon Sep 17 00:00:00 2001
af9dc8
From: Stanislav Malyshev <stas@php.net>
af9dc8
Date: Mon, 4 Aug 2014 00:01:57 -0700
af9dc8
Subject: [PATCH] Fix bug #67705 (extensive backtracking in rule regular
af9dc8
 expression)
af9dc8
af9dc8
---
af9dc8
 NEWS                              |  4 +++
af9dc8
 ext/fileinfo/data_file.c          |  2 +-
af9dc8
 ext/fileinfo/libmagic/softmagic.c | 29 +++++++++++-------
af9dc8
 ext/fileinfo/magicdata.patch      | 62 +++++++++++++++++++++++++++++++++------
af9dc8
 4 files changed, 76 insertions(+), 21 deletions(-)
af9dc8
af9dc8
diff --git a/ext/fileinfo/data_file.c b/ext/fileinfo/data_file.c
af9dc8
index fba4edd..15e0fa6 100644
af9dc8
--- a/ext/fileinfo/data_file.c
af9dc8
+++ b/ext/fileinfo/data_file.c
af9dc8
@@ -115198,7 +115198,7 @@ const unsigned char php_magic_database[2606480] = {
af9dc8
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
af9dc8
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
af9dc8
 0x00, 0x00, 0x40, 0x00, 0x3D, 0x1B, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
af9dc8
-0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
af9dc8
+0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
af9dc8
 0x5E, 0x5C, 0x73, 0x7B, 0x30, 0x2C, 0x31, 0x30, 0x30, 0x7D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x5C, 
af9dc8
 0x73, 0x7B, 0x30, 0x2C, 0x31, 0x30, 0x30, 0x7D, 0x5B, 0x7B, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 
af9dc8
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
af9dc8
diff --git a/ext/fileinfo/libmagic/softmagic.c b/ext/fileinfo/libmagic/softmagic.c
af9dc8
index 01e4977..7e0c856 100644
af9dc8
--- a/ext/fileinfo/libmagic/softmagic.c
af9dc8
+++ b/ext/fileinfo/libmagic/softmagic.c
af9dc8
@@ -58,7 +58,7 @@ private int32_t mprint(struct magic_set *, struct magic *);
af9dc8
 private int32_t moffset(struct magic_set *, struct magic *);
af9dc8
 private void mdebug(uint32_t, const char *, size_t);
af9dc8
 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
af9dc8
-    const unsigned char *, uint32_t, size_t, size_t);
af9dc8
+    const unsigned char *, uint32_t, size_t, struct magic *);
af9dc8
 private int mconvert(struct magic_set *, struct magic *, int);
af9dc8
 private int print_sep(struct magic_set *, int);
af9dc8
 private int handle_annotation(struct magic_set *, struct magic *);
af9dc8
@@ -1003,7 +1003,7 @@ mdebug(uint32_t offset, const char *str, size_t len)
af9dc8
 
af9dc8
 private int
af9dc8
 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
af9dc8
-    const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
af9dc8
+    const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
af9dc8
 {
af9dc8
 	/*
af9dc8
 	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
af9dc8
@@ -1023,15 +1023,24 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
af9dc8
 			const char *last;	/* end of search region */
af9dc8
 			const char *buf;	/* start of search region */
af9dc8
 			const char *end;
af9dc8
-			size_t lines;
af9dc8
+			size_t lines, linecnt, bytecnt;
af9dc8
 
af9dc8
+			linecnt = m->str_range;
af9dc8
+			bytecnt = linecnt * 80;
af9dc8
+
af9dc8
+			if (bytecnt == 0) {
af9dc8
+				bytecnt = 8192;
af9dc8
+			}
af9dc8
+			if (bytecnt > nbytes) {
af9dc8
+				bytecnt = nbytes;
af9dc8
+			}
af9dc8
 			if (s == NULL) {
af9dc8
 				ms->search.s_len = 0;
af9dc8
 				ms->search.s = NULL;
af9dc8
 				return 0;
af9dc8
 			}
af9dc8
 			buf = RCAST(const char *, s) + offset;
af9dc8
-			end = last = RCAST(const char *, s) + nbytes;
af9dc8
+			end = last = RCAST(const char *, s) + bytecnt;
af9dc8
 			/* mget() guarantees buf <= last */
af9dc8
 			for (lines = linecnt, b = buf; lines && b < end &&
af9dc8
 			     ((b = CAST(const char *,
af9dc8
@@ -1044,7 +1053,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
af9dc8
 					b++;
af9dc8
 			}
af9dc8
 			if (lines)
af9dc8
-				last = RCAST(const char *, s) + nbytes;
af9dc8
+				last = RCAST(const char *, s) + bytecnt;
af9dc8
 
af9dc8
 			ms->search.s = buf;
af9dc8
 			ms->search.s_len = last - buf;
af9dc8
@@ -1118,7 +1127,6 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
af9dc8
     int *need_separator, int *returnval)
af9dc8
 {
af9dc8
 	uint32_t soffset, offset = ms->offset;
af9dc8
-	uint32_t count = m->str_range;
af9dc8
 	int rv, oneed_separator;
af9dc8
 	char *sbuf, *rbuf;
af9dc8
 	union VALUETYPE *p = &ms->ms_value;
af9dc8
@@ -1130,13 +1138,12 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
af9dc8
 	}
af9dc8
 
af9dc8
 	if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
af9dc8
-	    (uint32_t)nbytes, count) == -1)
af9dc8
+	    (uint32_t)nbytes, m) == -1)
af9dc8
 		return -1;
af9dc8
 
af9dc8
 	if ((ms->flags & MAGIC_DEBUG) != 0) {
af9dc8
 		fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, "
af9dc8
-		    "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o,
af9dc8
-		    nbytes, count);
af9dc8
+		    "nbytes=%zu)\n", m->type, m->flag, offset, o, nbytes);
af9dc8
 		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
af9dc8
 	}
af9dc8
 
af9dc8
@@ -1627,7 +1634,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
af9dc8
 			if ((ms->flags & MAGIC_DEBUG) != 0)
af9dc8
 				fprintf(stderr, "indirect +offs=%u\n", offset);
af9dc8
 		}
af9dc8
-		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
af9dc8
+		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
af9dc8
 			return -1;
af9dc8
 		ms->offset = offset;
af9dc8
 
af9dc8
@@ -2057,7 +2064,7 @@ magiccheck(struct magic_set *ms, struct magic *m)
af9dc8
 			zval *retval;
af9dc8
 			zval *subpats;
af9dc8
 			char *haystack;
af9dc8
-			
af9dc8
+
af9dc8
 			MAKE_STD_ZVAL(retval);
af9dc8
 			ALLOC_INIT_ZVAL(subpats);
af9dc8
 			
af9dc8
-- 
af9dc8
1.9.2
af9dc8
af9dc8
From 61ec9b5b0f80bc6016548d48f433fe22e2dc24ec Mon Sep 17 00:00:00 2001
af9dc8
From: Stanislav Malyshev <stas@php.net>
af9dc8
Date: Mon, 4 Aug 2014 00:08:08 -0700
af9dc8
Subject: [PATCH] add test
af9dc8
af9dc8
---
af9dc8
 ext/fileinfo/tests/cve-2014-3538.phpt | 35 +++++++++++++++++++++++++++++++++++
af9dc8
 1 file changed, 35 insertions(+)
af9dc8
 create mode 100644 ext/fileinfo/tests/cve-2014-3538.phpt
af9dc8
af9dc8
diff --git a/ext/fileinfo/tests/cve-2014-3538.phpt b/ext/fileinfo/tests/cve-2014-3538.phpt
af9dc8
new file mode 100644
af9dc8
index 0000000..d6bc9c6
af9dc8
--- /dev/null
af9dc8
+++ b/ext/fileinfo/tests/cve-2014-3538.phpt
af9dc8
@@ -0,0 +1,35 @@
af9dc8
+--TEST--
af9dc8
+Bug #66731: file: extensive backtraking
af9dc8
+--SKIPIF--
af9dc8
+
af9dc8
+if (!class_exists('finfo'))
af9dc8
+	die('skip no fileinfo extension');
af9dc8
+--FILE--
af9dc8
+
af9dc8
+$fd = __DIR__.'/cve-2014-3538.data';
af9dc8
+
af9dc8
+file_put_contents($fd,
af9dc8
+  'try:' .
af9dc8
+  str_repeat("\n", 1000000));
af9dc8
+
af9dc8
+$fi = finfo_open(FILEINFO_NONE);
af9dc8
+$t = microtime(true);
af9dc8
+var_dump(finfo_file($fi, $fd));
af9dc8
+$t = microtime(true) - $t;
af9dc8
+finfo_close($fi);
af9dc8
+if ($t < 1) {
af9dc8
+	echo "Ok\n";
af9dc8
+} else {
af9dc8
+	printf("Failed, time=%.2f\n", $t);
af9dc8
+}
af9dc8
+
af9dc8
+?>
af9dc8
+Done
af9dc8
+--CLEAN--
af9dc8
+
af9dc8
+@unlink(__DIR__.'/cve-2014-3538.data');
af9dc8
+?>
af9dc8
+--EXPECTF--
af9dc8
+string(%d) "%s"
af9dc8
+Ok
af9dc8
+Done
af9dc8
\ No newline at end of file
af9dc8
-- 
af9dc8
1.9.2
af9dc8