summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorYves Orton <demerphq@gmail.com>2013-02-12 10:53:05 +0100
committerYves Orton <demerphq@gmail.com>2013-02-13 20:25:16 +0100
commitf14269908e5f8b4cab4b55643d7dd9de577e7918 (patch)
tree04e741c57272b1d12d0216c58c4952c3f944be7b /ext
parentca8de220718ba91d5a5fdd9779497cd5b0250258 (diff)
downloadperl-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.t18
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;