]> granicus.if.org Git - php/commitdiff
Limit unserialization element count more aggressively
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 15 Jan 2021 16:07:51 +0000 (17:07 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 15 Jan 2021 16:07:51 +0000 (17:07 +0100)
This is slightly more aggressive about rejecting obviously incorrect
element counts. Previously the number of elements was allowed to
match the number of characters. Now it is the number of characters
divided by two (this can actually be increased further to at least 4).

This doesn't really matter in the grand scheme of things (as it
just cuts maximum memory usage by half), but should fix
oss-fuzz #29356.

ext/standard/var_unserializer.re

index c5a14769389ebd84f2caf6cf7be7bfdaeb668823..3c620613eef3fc0733719491bf49b274b34d3df3 100644 (file)
 #define VAR_WAKEUP_FLAG 1
 #define VAR_UNSERIALIZE_FLAG 2
 
+/* Each element is encoded using at least 2 characters. */
+#define IS_FAKE_ELEM_COUNT(num_elems, serialized_len) \
+       ((num_elems) > (serialized_len) / 2)
+
 typedef struct {
        zend_long used_slots;
        void *next;
@@ -1001,7 +1005,7 @@ use_double:
        *p = YYCURSOR;
     if (!var_hash) return 0;
 
-       if (elements < 0 || elements >= HT_MAX_SIZE || elements > max - YYCURSOR) {
+       if (elements < 0 || elements >= HT_MAX_SIZE || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
                return 0;
        }
 
@@ -1169,7 +1173,7 @@ object ":" uiv ":" ["]    {
        }
 
        elements = parse_iv2(*p + 2, p);
-       if (elements < 0 || elements > max - YYCURSOR) {
+       if (elements < 0 || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
                zend_string_release_ex(class_name, 0);
                return 0;
        }