]> granicus.if.org Git - php/commitdiff
Sanity-check array/object lengths during unserialization
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 16 Sep 2019 09:38:35 +0000 (11:38 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 16 Sep 2019 09:38:35 +0000 (11:38 +0200)
Avoid OOM conditions in unserialize due to overly large array or
object length specifications.

ext/standard/tests/serialize/bug74101.phpt
ext/standard/tests/serialize/unserialize_large.phpt [new file with mode: 0644]
ext/standard/var_unserializer.re

index 323f6c6f4654bf5e7430326800bd9c52ffc5b5d7..3eca747cb13cdd51223816429177d309d2482345 100644 (file)
@@ -8,5 +8,5 @@ var_dump(unserialize($s));
 --EXPECTF--
 Warning: unserialize(): %s in %sbug74101.php on line %d
 
-Notice: unserialize(): Error at offset 48 of 74 bytes in %sbug74101.php on line %d
+Notice: unserialize(): Error at offset 46 of 74 bytes in %sbug74101.php on line %d
 bool(false)
diff --git a/ext/standard/tests/serialize/unserialize_large.phpt b/ext/standard/tests/serialize/unserialize_large.phpt
new file mode 100644 (file)
index 0000000..9726306
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+Unserializing payload with unrealistically large element counts
+--FILE--
+<?php
+
+var_dump(unserialize("a:1000000000:{}"));
+var_dump(unserialize("O:1000000000:\"\":0:{}"));
+var_dump(unserialize("O:1:\"X\":1000000000:{}"));
+var_dump(unserialize("C:1:\"X\":1000000000:{}"));
+
+?>
+--EXPECTF--
+Notice: unserialize(): Error at offset 14 of 15 bytes in %s on line %d
+bool(false)
+
+Notice: unserialize(): Error at offset 2 of 20 bytes in %s on line %d
+bool(false)
+
+Notice: unserialize(): Error at offset 18 of 21 bytes in %s on line %d
+bool(false)
+
+Warning: Insufficient data for unserializing - 1000000000 required, 1 present in %s on line %d
+
+Notice: unserialize(): Error at offset 20 of 21 bytes in %s on line %d
+bool(false)
index cef2eb064081ca8ea2afde5149015b44014b73be..ba425e692eca49d5da7f01510e534e2f8e17cd39 100644 (file)
@@ -953,7 +953,7 @@ use_double:
        *p = YYCURSOR;
     if (!var_hash) return 0;
 
-       if (elements < 0 || elements >= HT_MAX_SIZE) {
+       if (elements < 0 || elements >= HT_MAX_SIZE || elements > max - YYCURSOR) {
                return 0;
        }
 
@@ -1124,10 +1124,11 @@ object ":" uiv ":" ["]  {
        }
 
        elements = parse_iv2(*p + 2, p);
-       if (elements < 0) {
+       if (elements < 0 || elements > max - YYCURSOR) {
                zend_string_release_ex(class_name, 0);
                return 0;
        }
+
        *p += 2;
 
        has_unserialize = !incomplete_class