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: p...@hermes.cam.ac.uk Reporter: ppi...@redhat.com CC: pcre-dev@exim.org 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. -- ## List details at https://lists.exim.org/mailman/listinfo/pcre-dev