Skip to content

Commit 8284ef6

Browse files
committed
std: make sure HashMap from_iter uses random initialization by default
It turns out that HashMap's from_iter implementation was being initialized without the sip keys being randomized. This adds a custom default hasher that should avoid this potential vulnerability.
1 parent 287dcb7 commit 8284ef6

File tree

3 files changed

+62
-16
lines changed

3 files changed

+62
-16
lines changed

src/libstd/collections/hashmap.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@ use collections::{Collection, Mutable, Set, MutableSet, Map, MutableMap};
1616
use default::Default;
1717
use fmt::Show;
1818
use fmt;
19-
use hash::{Hash, Hasher, sip};
19+
use hash::{Hash, Hasher, RandomSipHasher};
2020
use iter::{Iterator, FilterMap, Chain, Repeat, Zip, Extendable};
2121
use iter::{range, range_inclusive, FromIterator};
2222
use iter;
2323
use mem::replace;
2424
use num;
2525
use option::{Some, None, Option};
26-
use rand::Rng;
27-
use rand;
2826
use result::{Ok, Err};
2927

3028
mod table {
@@ -733,7 +731,7 @@ impl DefaultResizePolicy {
733731
/// }
734732
/// ```
735733
#[deriving(Clone)]
736-
pub struct HashMap<K, V, H = sip::SipHasher> {
734+
pub struct HashMap<K, V, H = RandomSipHasher> {
737735
// All hashes are keyed on these values, to prevent hash collision attacks.
738736
hasher: H,
739737

@@ -1033,18 +1031,15 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> MutableMap<K, V> for HashMap<K, V, H>
10331031

10341032
}
10351033

1036-
impl<K: Hash + Eq, V> HashMap<K, V, sip::SipHasher> {
1034+
impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> {
10371035
/// Create an empty HashMap.
1038-
pub fn new() -> HashMap<K, V, sip::SipHasher> {
1036+
pub fn new() -> HashMap<K, V, RandomSipHasher> {
10391037
HashMap::with_capacity(INITIAL_CAPACITY)
10401038
}
10411039

10421040
/// Creates an empty hash map with the given initial capacity.
1043-
pub fn with_capacity(capacity: uint) -> HashMap<K, V, sip::SipHasher> {
1044-
let mut r = rand::task_rng();
1045-
let r0 = r.gen();
1046-
let r1 = r.gen();
1047-
let hasher = sip::SipHasher::new_with_keys(r0, r1);
1041+
pub fn with_capacity(capacity: uint) -> HashMap<K, V, RandomSipHasher> {
1042+
let hasher = RandomSipHasher::new();
10481043
HashMap::with_capacity_and_hasher(capacity, hasher)
10491044
}
10501045
}
@@ -1489,7 +1484,7 @@ pub type SetMoveItems<K> =
14891484
/// HashMap where the value is (). As with the `HashMap` type, a `HashSet`
14901485
/// requires that the elements implement the `Eq` and `Hash` traits.
14911486
#[deriving(Clone)]
1492-
pub struct HashSet<T, H = sip::SipHasher> {
1487+
pub struct HashSet<T, H = RandomSipHasher> {
14931488
map: HashMap<T, (), H>
14941489
}
14951490

@@ -1529,15 +1524,15 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> {
15291524
fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }
15301525
}
15311526

1532-
impl<T: Hash + Eq> HashSet<T, sip::SipHasher> {
1527+
impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
15331528
/// Create an empty HashSet
1534-
pub fn new() -> HashSet<T, sip::SipHasher> {
1529+
pub fn new() -> HashSet<T, RandomSipHasher> {
15351530
HashSet::with_capacity(INITIAL_CAPACITY)
15361531
}
15371532

15381533
/// Create an empty HashSet with space for at least `n` elements in
15391534
/// the hash table.
1540-
pub fn with_capacity(capacity: uint) -> HashSet<T, sip::SipHasher> {
1535+
pub fn with_capacity(capacity: uint) -> HashSet<T, RandomSipHasher> {
15411536
HashSet { map: HashMap::with_capacity(capacity) }
15421537
}
15431538
}

src/libstd/hash.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Generic hashing support.
12+
13+
pub use core_collections::hash::{Hash, Hasher, Writer, hash, sip};
14+
15+
use default::Default;
16+
use rand::Rng;
17+
use rand;
18+
19+
/// `RandomSipHasher` computes the SipHash algorithm from a stream of bytes
20+
/// initialized with random keys.
21+
#[deriving(Clone)]
22+
pub struct RandomSipHasher {
23+
hasher: sip::SipHasher,
24+
}
25+
26+
impl RandomSipHasher {
27+
/// Construct a new `RandomSipHasher` that is initialized with random keys.
28+
#[inline]
29+
pub fn new() -> RandomSipHasher {
30+
let mut r = rand::task_rng();
31+
let r0 = r.gen();
32+
let r1 = r.gen();
33+
RandomSipHasher {
34+
hasher: sip::SipHasher::new_with_keys(r0, r1),
35+
}
36+
}
37+
}
38+
39+
impl Hasher<sip::SipState> for RandomSipHasher {
40+
#[inline]
41+
fn hash<T: Hash<sip::SipState>>(&self, value: &T) -> u64 {
42+
self.hasher.hash(value)
43+
}
44+
}
45+
46+
impl Default for RandomSipHasher {
47+
#[inline]
48+
fn default() -> RandomSipHasher {
49+
RandomSipHasher::new()
50+
}
51+
}

src/libstd/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ pub use core::option;
166166
pub use alloc::owned;
167167
pub use alloc::rc;
168168

169-
pub use core_collections::hash;
170169
pub use core_collections::slice;
171170
pub use core_collections::str;
172171
pub use core_collections::string;
@@ -236,6 +235,7 @@ pub mod to_str;
236235
/* Common data structures */
237236

238237
pub mod collections;
238+
pub mod hash;
239239

240240
/* Tasks and communication */
241241

0 commit comments

Comments
 (0)