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