From eeaec70758bfc0c0e2c0f8944c8dbeae02866206 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 4 Aug 2014 00:01:57 -0700 Subject: Fix bug #67705 (extensive backtracking in rule regular expression) --- NEWS | 4 +++ ext/fileinfo/data_file.c | 2 +- ext/fileinfo/libmagic/softmagic.c | 29 +++++++++++------- ext/fileinfo/magicdata.patch | 62 +++++++++++++++++++++++++++++++++------ 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/NEWS b/NEWS index 32da757bb3..15d286da2a 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - COM: . Fixed missing type checks in com_event_sink (Yussuf Khalil, Stas). +- 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) diff --git a/ext/fileinfo/data_file.c b/ext/fileinfo/data_file.c index fba4edd90f..15e0fa6a8a 100644 --- a/ext/fileinfo/data_file.c +++ b/ext/fileinfo/data_file.c @@ -115198,7 +115198,7 @@ const unsigned char php_magic_database[2606480] = { 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, diff --git a/ext/fileinfo/libmagic/softmagic.c b/ext/fileinfo/libmagic/softmagic.c index 01e49778bf..7e0c8560e3 100644 --- a/ext/fileinfo/libmagic/softmagic.c +++ b/ext/fileinfo/libmagic/softmagic.c @@ -58,7 +58,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 *); @@ -1003,7 +1003,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 @@ -1023,15 +1023,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 *, @@ -1044,7 +1053,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; @@ -1118,7 +1127,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; char *sbuf, *rbuf; union VALUETYPE *p = &ms->ms_value; @@ -1130,13 +1138,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)); } @@ -1627,7 +1634,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; @@ -2057,7 +2064,7 @@ magiccheck(struct magic_set *ms, struct magic *m) zval *retval; zval *subpats; char *haystack; - + MAKE_STD_ZVAL(retval); ALLOC_INIT_ZVAL(subpats); diff --git a/ext/fileinfo/magicdata.patch b/ext/fileinfo/magicdata.patch index 26d3bbb656..12fbd3ff56 100644 --- a/ext/fileinfo/magicdata.patch +++ b/ext/fileinfo/magicdata.patch @@ -1,4 +1,4 @@ -Patches applied to file sources tree before generating magic.mgc +Patches applied to file 5.14 sources tree before generating magic.mgc and before running create_data_file.php to create data_file.c. @@ -17,14 +17,6 @@ diff --git a/magic/Magdir/commands b/magic/Magdir/commands index 67c3eee..4a7d8dd 100644 --- a/magic/Magdir/commands +++ b/magic/Magdir/commands -@@ -1,6 +1,6 @@ - - #------------------------------------------------------------------------------ --# $File: commands,v 1.44 2013/02/05 15:20:47 christos Exp $ -+# $File: commands,v 1.45 2013/02/06 14:18:52 christos Exp $ - # commands: file(1) magic for various shells and interpreters - # - #0 string/w : shell archive or script for antique kernel text @@ -49,7 +49,7 @@ !:mime text/x-awk 0 string/wt #!\ /usr/bin/awk awk script text executable @@ -36,4 +28,56 @@ index 67c3eee..4a7d8dd 100644 0 string/wt #!\ /bin/rc Plan 9 rc shell script text executable -- 1.8.5.5 +From 0b478f445b6b7540b58af5d1fe583fa9e48fd745 Mon Sep 17 00:00:00 2001 +From: Christos Zoulas +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 +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 -- cgit v1.2.1 From 61ec9b5b0f80bc6016548d48f433fe22e2dc24ec Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 4 Aug 2014 00:08:08 -0700 Subject: add test --- ext/fileinfo/tests/cve-2014-3538.phpt | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 ext/fileinfo/tests/cve-2014-3538.phpt diff --git a/ext/fileinfo/tests/cve-2014-3538.phpt b/ext/fileinfo/tests/cve-2014-3538.phpt new file mode 100644 index 0000000000..d6bc9c68c8 --- /dev/null +++ b/ext/fileinfo/tests/cve-2014-3538.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #66731: file: extensive backtraking +--SKIPIF-- + +Done +--CLEAN-- + +--EXPECTF-- +string(%d) "%s" +Ok +Done \ No newline at end of file -- cgit v1.2.1 From 28786a2f82addf7035a4871157f0b63492ac608b Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 4 Aug 2014 00:08:35 -0700 Subject: Fix bug #67705 (extensive backtracking in rule regular expression) --- NEWS | 4 +++ ext/fileinfo/data_file.c | 2 +- ext/fileinfo/libmagic/softmagic.c | 29 +++++++++++------- ext/fileinfo/magicdata.patch | 56 ++++++++++++++++++++++++++++++++++- ext/fileinfo/tests/cve-2014-3538.phpt | 35 ++++++++++++++++++++++ 5 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 ext/fileinfo/tests/cve-2014-3538.phpt diff --git a/NEWS b/NEWS index 88ebb8cd59..8598b46d6b 100644 --- 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) diff --git a/ext/fileinfo/data_file.c b/ext/fileinfo/data_file.c index 8bcd5aa0e1..5b24670a72 100644 --- a/ext/fileinfo/data_file.c +++ b/ext/fileinfo/data_file.c @@ -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, diff --git a/ext/fileinfo/libmagic/softmagic.c b/ext/fileinfo/libmagic/softmagic.c index 3dd07820a4..e000dff92e 100644 --- a/ext/fileinfo/libmagic/softmagic.c +++ b/ext/fileinfo/libmagic/softmagic.c @@ -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); diff --git a/ext/fileinfo/magicdata.patch b/ext/fileinfo/magicdata.patch index fb34c3c533..524d40b567 100644 --- a/ext/fileinfo/magicdata.patch +++ b/ext/fileinfo/magicdata.patch @@ -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 +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 +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 index 0000000000..d6bc9c68c8 --- /dev/null +++ b/ext/fileinfo/tests/cve-2014-3538.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #66731: file: extensive backtraking +--SKIPIF-- + +Done +--CLEAN-- + +--EXPECTF-- +string(%d) "%s" +Ok +Done \ No newline at end of file -- cgit v1.2.1