https://bugs.exim.org/show_bug.cgi?id=2077
Bug ID: 2077
Summary: pcre2_serialize_decode() can read from invalid memory
because it does not know bytes length
Product: PCRE
Version: 10.23 (PCRE2)
Hardware: x86
OS: Linux
Status: NEW
Severity: bug
Priority: medium
Component: Code
Assignee: ph10@???
Reporter: ppisar@???
CC: pcre-dev@???
Created attachment 1006
-->
https://bugs.exim.org/attachment.cgi?id=1006&action=edit
malign serialized pattern
A static analyzes revealed pcre2_serialize_decode() can experience a read from
invalid memory, if supplied serialized pattern is malformed.
The function has following code in a for-cycle. First it reads blocksize from
the serialized pattern:
CODE_BLOCKSIZE_TYPE blocksize;
memcpy(&blocksize, src_bytes + offsetof(pcre2_real_code, blocksize),
sizeof(CODE_BLOCKSIZE_TYPE));
Then it checks the value is not too small:
if (blocksize <= sizeof(pcre2_real_code))
return PCRE2_ERROR_BADSERIALIZEDDATA;
Then it allocates dst_re memory for blocksize bytes and, finaly, it copies the
data of the blocksize minus a header size:
memcpy(((uint8_t *)dst_re) + sizeof(pcre2_memctl),
src_bytes + sizeof(pcre2_memctl), blocksize - sizeof(pcre2_memctl));
Here is the problem. The memcpy() blindly trusts blocksize value and if the
value is too big, bigger than valid src_bytes memory area, the memcpy() will
read past the src_bytes memory area.
As an example, you can run this command on the attached /tmp/pattern to see an
invalid memory read:
$ printf '#load /tmp/pattern\n' | libtool --mode=execute valgrind ./pcre2test
[...]
PCRE2 version 10.30-DEV 2017-03-05
#load /tmp/pattern
==25804== Source and destination overlap in memcpy(0x623ccc8, 0x623c768, 65397)
==25804== at 0x4C301F3: memcpy@@GLIBC_2.14 (vg_replace_strmem.c:1018)
==25804== by 0x50F0304: pcre2_serialize_decode_8 (pcre2_serialize.c:212)
==25804== by 0x40EF59: process_command (pcre2test.c:4503)
==25804== by 0x41A9E3: main (pcre2test.c:7813)
The /tmp/pattern has modified blocksize value at offset 502. Original valid
value was 0x8d 0x00 0x00 0x00, current invalid value is 0x8d 0xff 0x00 0x00.
This gives bogus blocksize=65421 instead of valid 141 and instructs memcpy() to
read past the buffer.
The problem is pcre2_serialize_decode() does not validate the parsed data.
Reading the pcre2_serialize_decode() prototype:
PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
pcre2_serialize_decode(pcre2_code **codes, int32_t number_of_codes,
const uint8_t *bytes, pcre2_general_context *gcontext)
I can see there is no length of "bytes" buffer passed to the function, thus its
impossible to do any validation.
I understand why function was written without security on mind (the serialized
pattern isn't portable and not expected to be provided from a nontrusted
party). Proper fix would require API change. If you do not consider it worth of
fixing, a decent notice in the documentation would be great. I wasn't able to
find anything in pcre2serialize about this issue.
--
You are receiving this mail because:
You are on the CC list for the bug.