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