diff options
author | Yves Orton <demerphq@gmail.com> | 2013-02-12 10:53:05 +0100 |
---|---|---|
committer | Yves Orton <demerphq@gmail.com> | 2013-02-13 20:25:16 +0100 |
commit | f14269908e5f8b4cab4b55643d7dd9de577e7918 (patch) | |
tree | 04e741c57272b1d12d0216c58c4952c3f944be7b /ext | |
parent | ca8de220718ba91d5a5fdd9779497cd5b0250258 (diff) | |
download | perl-f14269908e5f8b4cab4b55643d7dd9de577e7918.tar.gz |
Prevent premature hsplit() calls, and only trigger REHASH after hsplit()
Triggering a hsplit due to long chain length allows an attacker
to create a carefully chosen set of keys which can cause the hash
to use 2 * (2**32) * sizeof(void *) bytes ram. AKA a DOS via memory
exhaustion. Doing so also takes non trivial time.
Eliminating this check, and only inspecting chain length after a
normal hsplit() (triggered when keys>buckets) prevents the attack
entirely, and makes such attacks relatively benign.
(cherry picked from commit f2a571dae7d70f7e3b59022834d8003ecd2df884)
(which was itself cherry picked (with changes) from commit f1220d61455253b170e81427c9d0357831ca0fac)
Diffstat (limited to 'ext')
-rw-r--r-- | ext/Hash-Util-FieldHash/t/10_hash.t | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/ext/Hash-Util-FieldHash/t/10_hash.t b/ext/Hash-Util-FieldHash/t/10_hash.t index 29c2f4dafa..c266b6a45b 100644 --- a/ext/Hash-Util-FieldHash/t/10_hash.t +++ b/ext/Hash-Util-FieldHash/t/10_hash.t @@ -46,15 +46,29 @@ use constant START => "a"; # some initial hash data fieldhash my %h2; -%h2 = map {$_ => 1} 'a'..'cc'; +my $counter= "a"; +$h2{$counter++}++ while $counter ne 'cd'; ok (!Internals::HvREHASH(%h2), "starting with pre-populated non-pathological hash (rehash flag if off)"); my @keys = get_keys(\%h2); +my $buckets= buckets(\%h2); $h2{$_}++ for @keys; +$h2{$counter++}++ while buckets(\%h2) == $buckets; # force a split ok (Internals::HvREHASH(%h2), - scalar(@keys) . " colliding into the same bucket keys are triggering rehash"); + scalar(@keys) . " colliding into the same bucket keys are triggering rehash after split"); + +# returns the number of buckets in a hash +sub buckets { + my $hr = shift; + my $keys_buckets= scalar(%$hr); + if ($keys_buckets=~m!/([0-9]+)\z!) { + return 0+$1; + } else { + return 8; + } +} sub get_keys { my $hr = shift; |