Skip to content

Commit

Permalink
deps: V8: cherry-pick 64-bit hash seed commits
Browse files Browse the repository at this point in the history
This serves as mitigation for the so-called HashWick vulnerability.

Original commit messages:

  commit 3833fef57368c53c6170559ffa524c8c69f16ee5
    Author: Yang Guo <[email protected]>
    Date: Thu Sep 20 11:43:13 2018

    Refactor integer hashing function names

    We now clearly differentiate between:
    - unseeded hash for 32-bit integers
    - unseeded hash for 64-bit integers
    - seeded hash for 32-bit integers
    - seeded hash for strings

    [email protected]

    Bug: chromium:680662
    Change-Id: I7459958c4158ee3501c962943dff8f33258bb5ce
    Reviewed-on: https://chromium-review.googlesource.com/1235973
    Commit-Queue: Yang Guo <[email protected]>
    Reviewed-by: Benedikt Meurer <[email protected]>
    Cr-Commit-Position: refs/heads/master@{#56068}

  commit 95a979e02d7154e45b293261a6998c99d71fc238
    Author: Yang Guo <[email protected]>
    Date: Thu Sep 20 14:34:48 2018

    Call into C++ to compute seeded integer hash

    [email protected]

    Bug: chromium:680662
    Change-Id: I8dace89d576dfcc5833fd539ce698a9ade1cb5a0
    Reviewed-on: https://chromium-review.googlesource.com/1235928
    Commit-Queue: Yang Guo <[email protected]>
    Reviewed-by: Benedikt Meurer <[email protected]>
    Cr-Commit-Position: refs/heads/master@{#56091}

  commit 2c2af0022d5feb9e525a00a76cb15db9f3e38dba
    Author: Yang Guo <[email protected]>
    Date: Thu Sep 27 16:37:57 2018

    Use 64-bit for seeded integer hashes

    [email protected]

    Bug: chromium:680662
    Change-Id: If48d1043dbe1e1bb695ec890c23e103a6cacf2d4
    Reviewed-on: https://chromium-review.googlesource.com/1244220
    Commit-Queue: Yang Guo <[email protected]>
    Reviewed-by: Peter Marshall <[email protected]>
    Cr-Commit-Position: refs/heads/master@{#56271}

Refs: nodejs#23259

PR-URL: nodejs#23264
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Ali Ijaz Sheikh <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
  • Loading branch information
hashseed committed Oct 8, 2018
1 parent f5ab9d1 commit 314c1fa
Show file tree
Hide file tree
Showing 19 changed files with 70 additions and 108 deletions.
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
'uv_library%': 'static_library',

'clang%': 0,

'openssl_fips%': '',

# Default to -O0 for debug builds.
Expand Down
11 changes: 5 additions & 6 deletions deps/v8/src/builtins/builtins-collections-gen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
Node* key_tagged, Variable* result,
Label* entry_found,
Label* not_found);
Node* ComputeIntegerHashForString(Node* context, Node* string_key);
Node* ComputeStringHash(Node* context, Node* string_key);
void SameValueZeroString(Node* context, Node* key_string, Node* candidate_key,
Label* if_same, Label* if_not_same);

Expand Down Expand Up @@ -846,8 +846,7 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForSmiKey(
Node* table, Node* smi_key, Variable* result, Label* entry_found,
Label* not_found) {
Node* const key_untagged = SmiUntag(smi_key);
Node* const hash =
ChangeInt32ToIntPtr(ComputeIntegerHash(key_untagged, Int32Constant(0)));
Node* const hash = ChangeInt32ToIntPtr(ComputeUnseededHash(key_untagged));
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
result->Bind(hash);
FindOrderedHashTableEntry<CollectionType>(
Expand All @@ -862,7 +861,7 @@ template <typename CollectionType>
void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForStringKey(
Node* context, Node* table, Node* key_tagged, Variable* result,
Label* entry_found, Label* not_found) {
Node* const hash = ComputeIntegerHashForString(context, key_tagged);
Node* const hash = ComputeStringHash(context, key_tagged);
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
result->Bind(hash);
FindOrderedHashTableEntry<CollectionType>(
Expand Down Expand Up @@ -920,8 +919,8 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForOtherKey(
result, entry_found, not_found);
}

Node* CollectionsBuiltinsAssembler::ComputeIntegerHashForString(
Node* context, Node* string_key) {
Node* CollectionsBuiltinsAssembler::ComputeStringHash(Node* context,
Node* string_key) {
VARIABLE(var_result, MachineType::PointerRepresentation());

Label hash_not_computed(this), done(this, &var_result);
Expand Down
69 changes: 18 additions & 51 deletions deps/v8/src/code-stub-assembler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -253,40 +253,6 @@ HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR);
HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST);
#undef HEAP_CONSTANT_TEST

TNode<Int64T> CodeStubAssembler::HashSeed() {
DCHECK(Is64());
TNode<HeapObject> hash_seed_root =
TNode<HeapObject>::UncheckedCast(LoadRoot(Heap::kHashSeedRootIndex));
return TNode<Int64T>::UncheckedCast(LoadObjectField(
hash_seed_root, ByteArray::kHeaderSize, MachineType::Int64()));
}

TNode<Int32T> CodeStubAssembler::HashSeedHigh() {
DCHECK(!Is64());
#ifdef V8_TARGET_BIG_ENDIAN
static int kOffset = 0;
#else
static int kOffset = kInt32Size;
#endif
TNode<HeapObject> hash_seed_root =
TNode<HeapObject>::UncheckedCast(LoadRoot(Heap::kHashSeedRootIndex));
return TNode<Int32T>::UncheckedCast(LoadObjectField(
hash_seed_root, ByteArray::kHeaderSize + kOffset, MachineType::Int32()));
}

TNode<Int32T> CodeStubAssembler::HashSeedLow() {
DCHECK(!Is64());
#ifdef V8_TARGET_BIG_ENDIAN
static int kOffset = kInt32Size;
#else
static int kOffset = 0;
#endif
TNode<HeapObject> hash_seed_root =
TNode<HeapObject>::UncheckedCast(LoadRoot(Heap::kHashSeedRootIndex));
return TNode<Int32T>::UncheckedCast(LoadObjectField(
hash_seed_root, ByteArray::kHeaderSize + kOffset, MachineType::Int32()));
}

Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) {
if (mode == SMI_PARAMETERS) {
return SmiConstant(value);
Expand Down Expand Up @@ -7709,14 +7675,9 @@ template void CodeStubAssembler::NameDictionaryLookup<GlobalDictionary>(
TNode<GlobalDictionary>, TNode<Name>, Label*, TVariable<IntPtrT>*, Label*,
int, LookupMode);

Node* CodeStubAssembler::ComputeIntegerHash(Node* key) {
return ComputeIntegerHash(key, IntPtrConstant(kZeroHashSeed));
}

Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) {
// See v8::internal::ComputeIntegerHash()
Node* CodeStubAssembler::ComputeUnseededHash(Node* key) {
// See v8::internal::ComputeUnseededHash()
Node* hash = TruncateIntPtrToInt32(key);
hash = Word32Xor(hash, seed);
hash = Int32Add(Word32Xor(hash, Int32Constant(0xFFFFFFFF)),
Word32Shl(hash, Int32Constant(15)));
hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(12)));
Expand All @@ -7727,6 +7688,21 @@ Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) {
return Word32And(hash, Int32Constant(0x3FFFFFFF));
}

Node* CodeStubAssembler::ComputeSeededHash(Node* key) {
Node* const function_addr =
ExternalConstant(ExternalReference::compute_integer_hash());
Node* const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));

MachineType type_ptr = MachineType::Pointer();
MachineType type_uint32 = MachineType::Uint32();

Node* const result =
CallCFunction2(type_uint32, type_ptr, type_uint32, function_addr,
isolate_ptr, TruncateIntPtrToInt32(key));
return result;
}

void CodeStubAssembler::NumberDictionaryLookup(
TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
Label* if_found, TVariable<IntPtrT>* var_entry, Label* if_not_found) {
Expand All @@ -7737,16 +7713,7 @@ void CodeStubAssembler::NumberDictionaryLookup(
TNode<IntPtrT> capacity = SmiUntag(GetCapacity<NumberDictionary>(dictionary));
TNode<WordT> mask = IntPtrSub(capacity, IntPtrConstant(1));

TNode<Int32T> int32_seed;

if (Is64()) {
int32_seed = TruncateInt64ToInt32(HashSeed());
} else {
int32_seed = HashSeedLow();
}

TNode<WordT> hash =
ChangeUint32ToWord(ComputeIntegerHash(intptr_index, int32_seed));
TNode<WordT> hash = ChangeUint32ToWord(ComputeSeededHash(intptr_index));
Node* key_as_float64 = RoundIntPtrToFloat64(intptr_index);

// See Dictionary::FirstProbe().
Expand Down
8 changes: 2 additions & 6 deletions deps/v8/src/code-stub-assembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,10 +450,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST)
#undef HEAP_CONSTANT_TEST

TNode<Int64T> HashSeed();
TNode<Int32T> HashSeedHigh();
TNode<Int32T> HashSeedLow();

Node* IntPtrOrSmiConstant(int value, ParameterMode mode);
TNode<Smi> LanguageModeConstant(LanguageMode mode) {
return SmiConstant(static_cast<int>(mode));
Expand Down Expand Up @@ -2288,8 +2284,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
int inlined_probes = kInlinedDictionaryProbes,
LookupMode mode = kFindExisting);

Node* ComputeIntegerHash(Node* key);
Node* ComputeIntegerHash(Node* key, Node* seed);
Node* ComputeUnseededHash(Node* key);
Node* ComputeSeededHash(Node* key);

void NumberDictionaryLookup(TNode<NumberDictionary> dictionary,
TNode<IntPtrT> intptr_index, Label* if_found,
Expand Down
6 changes: 3 additions & 3 deletions deps/v8/src/compiler/effect-control-linearizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4768,8 +4768,8 @@ Node* EffectControlLinearizer::LowerFindOrderedHashMapEntry(Node* node) {
}
}

Node* EffectControlLinearizer::ComputeIntegerHash(Node* value) {
// See v8::internal::ComputeIntegerHash()
Node* EffectControlLinearizer::ComputeUnseededHash(Node* value) {
// See v8::internal::ComputeUnseededHash()
value = __ Int32Add(__ Word32Xor(value, __ Int32Constant(0xFFFFFFFF)),
__ Word32Shl(value, __ Int32Constant(15)));
value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(12)));
Expand All @@ -4787,7 +4787,7 @@ Node* EffectControlLinearizer::LowerFindOrderedHashMapEntryForInt32Key(
Node* key = NodeProperties::GetValueInput(node, 1);

// Compute the integer hash code.
Node* hash = ChangeUint32ToUintPtr(ComputeIntegerHash(key));
Node* hash = ChangeUint32ToUintPtr(ComputeUnseededHash(key));

Node* number_of_buckets = ChangeSmiToIntPtr(__ LoadField(
AccessBuilder::ForOrderedHashTableBaseNumberOfBuckets(), table));
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/compiler/effect-control-linearizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* BuildFloat64RoundDown(Node* value);
Node* BuildFloat64RoundTruncate(Node* input);
Node* BuildUint32Mod(Node* lhs, Node* rhs);
Node* ComputeIntegerHash(Node* value);
Node* ComputeUnseededHash(Node* value);
Node* LowerStringComparison(Callable const& callable, Node* node);
Node* IsElementsKindGreaterThan(Node* kind, ElementsKind reference_kind);

Expand Down
9 changes: 9 additions & 0 deletions deps/v8/src/external-reference.cc
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,15 @@ ExternalReference ExternalReference::jsreceiver_create_identity_hash(
return ExternalReference(Redirect(FUNCTION_ADDR(f)));
}

static uint32_t ComputeSeededIntegerHash(Isolate* isolate, uint32_t key) {
DisallowHeapAllocation no_gc;
return ComputeSeededHash(key, isolate->heap()->HashSeed());
}

ExternalReference ExternalReference::compute_integer_hash() {
return ExternalReference(Redirect(FUNCTION_ADDR(ComputeSeededIntegerHash)));
}

ExternalReference
ExternalReference::copy_fast_number_jsarray_elements_to_typed_array() {
return ExternalReference(
Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/external-reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class StatsCounter;
V(address_of_uint32_bias, "uint32_bias") \
V(bytecode_size_table_address, "Bytecodes::bytecode_size_table_address") \
V(check_object_type, "check_object_type") \
V(compute_integer_hash, "ComputeSeededHash") \
V(compute_output_frames_function, "Deoptimizer::ComputeOutputFrames()") \
V(copy_fast_number_jsarray_elements_to_typed_array, \
"copy_fast_number_jsarray_elements_to_typed_array") \
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/frames.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2133,7 +2133,7 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
isolate_->counters()->pc_to_code()->Increment();
DCHECK(base::bits::IsPowerOfTwo(kInnerPointerToCodeCacheSize));
uint32_t hash = ComputeIntegerHash(
uint32_t hash = ComputeUnseededHash(
ObjectAddressForHashing(reinterpret_cast<void*>(inner_pointer)));
uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
InnerPointerToCodeCacheEntry* entry = cache(index);
Expand Down
12 changes: 6 additions & 6 deletions deps/v8/src/objects-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2980,14 +2980,14 @@ bool NumberDictionaryBaseShape::IsMatch(uint32_t key, Object* other) {
}

uint32_t NumberDictionaryBaseShape::Hash(Isolate* isolate, uint32_t key) {
return ComputeIntegerHash(key, isolate->heap()->HashSeed());
return ComputeSeededHash(key, isolate->heap()->HashSeed());
}

uint32_t NumberDictionaryBaseShape::HashForObject(Isolate* isolate,
Object* other) {
DCHECK(other->IsNumber());
return ComputeIntegerHash(static_cast<uint32_t>(other->Number()),
isolate->heap()->HashSeed());
return ComputeSeededHash(static_cast<uint32_t>(other->Number()),
isolate->heap()->HashSeed());
}

Handle<Object> NumberDictionaryBaseShape::AsHandle(Isolate* isolate,
Expand Down Expand Up @@ -3067,18 +3067,18 @@ uint32_t ObjectHashTableShape::HashForObject(Isolate* isolate, Object* other) {
Object* Object::GetSimpleHash(Object* object) {
DisallowHeapAllocation no_gc;
if (object->IsSmi()) {
uint32_t hash = ComputeIntegerHash(Smi::ToInt(object));
uint32_t hash = ComputeUnseededHash(Smi::ToInt(object));
return Smi::FromInt(hash & Smi::kMaxValue);
}
if (object->IsHeapNumber()) {
double num = HeapNumber::cast(object)->value();
if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
// Use ComputeIntegerHash for all values in Signed32 range, including -0,
// Use ComputeUnseededHash for all values in Signed32 range, including -0,
// which is considered equal to 0 because collections use SameValueZero.
uint32_t hash;
// Check range before conversion to avoid undefined behavior.
if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
hash = ComputeIntegerHash(FastD2I(num));
hash = ComputeUnseededHash(FastD2I(num));
} else {
hash = ComputeLongHash(double_to_uint64(num));
}
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/objects/bigint.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class V8_EXPORT_PRIVATE BigInt : public BigIntBase {
bool ToBoolean() { return !is_zero(); }
uint32_t Hash() {
// TODO(jkummerow): Improve this. At least use length and sign.
return is_zero() ? 0 : ComputeIntegerHash(static_cast<uint32_t>(digit(0)));
return is_zero() ? 0 : ComputeLongHash(static_cast<uint64_t>(digit(0)));
}

static bool EqualToString(Isolate* isolate, Handle<BigInt> x,
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/objects/ordered-hash-table.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class OrderedHashTable : public OrderedHashTableBase {
// This special cases for Smi, so that we avoid the HandleScope
// creation below.
if (key->IsSmi()) {
uint32_t hash = ComputeIntegerHash(Smi::ToInt(key));
uint32_t hash = ComputeUnseededHash(Smi::ToInt(key));
return HashToEntry(hash & Smi::kMaxValue);
}
HandleScope scope(isolate);
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/profiler/allocation-tracker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ void AllocationTracker::AllocationEvent(Address addr, int size) {


static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) {
return ComputeIntegerHash(static_cast<uint32_t>(id));
return ComputeUnseededHash(static_cast<uint32_t>(id));
}


Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/profiler/heap-snapshot-generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ SnapshotObjectId HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
heap_->HashSeed());
intptr_t element_count = info->GetElementCount();
if (element_count != -1) {
id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count));
id ^= ComputeUnseededHash(static_cast<uint32_t>(element_count));
}
return id << 1;
}
Expand Down
4 changes: 2 additions & 2 deletions deps/v8/src/profiler/heap-snapshot-generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ class HeapEntriesMap {

private:
static uint32_t Hash(HeapThing thing) {
return ComputeIntegerHash(
return ComputeUnseededHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)));
}

Expand Down Expand Up @@ -520,7 +520,7 @@ class NativeObjectsExplorer {

struct RetainedInfoHasher {
std::size_t operator()(v8::RetainedObjectInfo* info) const {
return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()));
return ComputeUnseededHash(static_cast<uint32_t>(info->GetHash()));
}
};
struct RetainedInfoEquals {
Expand Down
12 changes: 6 additions & 6 deletions deps/v8/src/profiler/profile-generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,16 @@ CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() {
}

uint32_t CodeEntry::GetHash() const {
uint32_t hash = ComputeIntegerHash(tag());
uint32_t hash = ComputeUnseededHash(tag());
if (script_id_ != v8::UnboundScript::kNoScriptId) {
hash ^= ComputeIntegerHash(static_cast<uint32_t>(script_id_));
hash ^= ComputeIntegerHash(static_cast<uint32_t>(position_));
hash ^= ComputeUnseededHash(static_cast<uint32_t>(script_id_));
hash ^= ComputeUnseededHash(static_cast<uint32_t>(position_));
} else {
hash ^= ComputeIntegerHash(
hash ^= ComputeUnseededHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
hash ^= ComputeIntegerHash(
hash ^= ComputeUnseededHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
hash ^= ComputeIntegerHash(line_number_);
hash ^= ComputeUnseededHash(line_number_);
}
return hash;
}
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/profiler/profile-generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class ProfileNode {
};
struct Hasher {
std::size_t operator()(CodeEntryAndLineNumber pair) const {
return pair.code_entry->GetHash() ^ ComputeIntegerHash(pair.line_number);
return pair.code_entry->GetHash() ^ ComputeUnseededHash(pair.line_number);
}
};

Expand Down
Loading

0 comments on commit 314c1fa

Please sign in to comment.