Subject: file does not properly restrict the amount of data read during a regex search ID: CVE-2014-3538 Author: Christos Zoulas Date: Tue Jun 3 19:01:34 2014 +0000 Origin: commit 4a284c89d6ef11aca34da65da7d673050a5ea320 Debian-Author: Christoph Biedl Comment: Taken from the fix in php5 (5.4.4-14+deb7u13), with minor corrections. Last-Update: 2014-09-07 * Enforce limit of 8K on regex searches that have no limits * Allow the l modifier for regex to mean line count. Default to byte count. If line count is specified, assume a max of 80 characters per line to limit the byte count. * Don't allow conversions to be used for dates, allowing the mask field to be used as an offset. * Bump the version of the magic format so that regex changes are visible. --- a/src/softmagic.c +++ b/src/softmagic.c @@ -51,7 +51,7 @@ 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 *); private int print_sep(struct magic_set *, int); private int handle_annotation(struct magic_set *, struct magic *); @@ -918,7 +918,7 @@ 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 @@ -938,15 +938,24 @@ 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 *, @@ -959,7 +968,7 @@ 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; @@ -1032,7 +1041,6 @@ int recursion_level) { uint32_t offset = ms->offset; - uint32_t count = m->str_range; union VALUETYPE *p = &ms->ms_value; if (recursion_level >= 20) { @@ -1040,7 +1048,8 @@ return -1; } - if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1) + if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, + (uint32_t)nbytes, m) == -1) return -1; if ((ms->flags & MAGIC_DEBUG) != 0) { @@ -1527,7 +1536,7 @@ if (m->flag & INDIROFFADD) { offset += ms->c.li[cont_level-1].off; } - 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;