summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-01-15 17:07:51 +0100
committerNikita Popov <nikita.ppv@gmail.com>2021-01-15 17:07:51 +0100
commit141c4be70a97ea9dd99b3a80543098c677d12c1e (patch)
treecfd79e53852dc4d1dbf9ec8bb58090911fd4e447
parent21562aa98dd423a988770aee974377a77d980839 (diff)
downloadphp-git-141c4be70a97ea9dd99b3a80543098c677d12c1e.tar.gz
Limit unserialization element count more aggressively
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.
-rw-r--r--ext/standard/var_unserializer.re8
1 files changed, 6 insertions, 2 deletions
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index c5a1476938..3c620613ee 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -29,6 +29,10 @@
#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;
}