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