Fix use-after-free serializing an array grown by an element's hook#22714
Conversation
| smart_str_appendl(buf, "a:", 2); | ||
| myht = Z_ARRVAL_P(struc); | ||
| bool rcn = !is_root && (in_rcn_array || GC_REFCOUNT(myht) > 1); | ||
| if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) { |
| buf, struc, myht, zend_array_count(myht), /* incomplete_class */ 0, var_hash, | ||
| !is_root && (in_rcn_array || GC_REFCOUNT(myht) > 1)); | ||
| rcn); | ||
| if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) { |
f2cd4b0 to
8ae20f7
Compare
|
I would only merge this in master though |
Any reason for master only? Change seem fairly safe to me and does address UAF. |
Generally, for maliciously-crafted code we only do these changes on master to avoid breakage. |
Fair enough I'll update the PR to master |
The IS_ARRAY case of php_var_serialize_intern() walked the array's HashTable without holding a reference across php_var_serialize_nested_data(), which recurses into user hooks (__serialize, __sleep, Serializable::serialize). A hook that grows the same array through a by-reference alias reallocs the backing store mid-walk, so the iterator reads freed memory. Hold a ref across the walk, as the object path and var_dump/var_export already do, so the append separates a copy instead of reallocating in place.
8ae20f7 to
01107d8
Compare
The IS_ARRAY case of php_var_serialize_intern() walks the array's HashTable without holding a reference while php_var_serialize_nested_data() recurses into user hooks, so a __serialize() that grows the same array through a by-reference alias reallocs the backing store mid-walk and the iterator reads freed memory. The object case, var_dump, and var_export already hold a ref across the walk; this adds the same GC_ADDREF/GC_DTOR_NO_REF for arrays, so the append separates a copy instead of reallocating in place. __sleep() and Serializable::serialize() reach the same walk, so one test covers all three.
Reproducer (invalid read in php_var_serialize_nested_data under ASan/valgrind; a normal build usually reads the freed memory and passes, so the test is an ASan canary):