Commit 06b59094 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[embedded] Split blob hash into data/code hashes

.. and add a --text-is-readable flag to support non-readable .text
sections.

This splits the embedded blob hash into two dedicated hashes for data
and code sections. The main benefit is that we can now keep at least a
partial hash even with non-readable .text sections.

The second part of this CL adds a --text-is-readable runtime flag to
support such platforms (with non-readable .text).

It currently doesn't do much; setting it enables a few additional
DCHECKs, disables the constant pool on x64, and and disables
verification of the embedded blob's *code* hash.

Bug: v8:10707
Change-Id: Ib91ed8b50b50f2cd81677f62920bea6fb92af453
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2504251Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70827}
parent df591efb
...@@ -246,6 +246,9 @@ bool ConstPool::AddSharedEntry(uint64_t data, int offset) { ...@@ -246,6 +246,9 @@ bool ConstPool::AddSharedEntry(uint64_t data, int offset) {
bool ConstPool::TryRecordEntry(intptr_t data, RelocInfo::Mode mode) { bool ConstPool::TryRecordEntry(intptr_t data, RelocInfo::Mode mode) {
if (!FLAG_partial_constant_pool) return false; if (!FLAG_partial_constant_pool) return false;
DCHECK_WITH_MSG(
FLAG_text_is_readable,
"The partial constant pool requires a readable .text section");
if (!RelocInfo::IsShareableRelocMode(mode)) return false; if (!RelocInfo::IsShareableRelocMode(mode)) return false;
// Currently, partial constant pool only handles the following kinds of // Currently, partial constant pool only handles the following kinds of
......
...@@ -425,6 +425,8 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, ...@@ -425,6 +425,8 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder,
int Disassembler::Decode(Isolate* isolate, std::ostream* os, byte* begin, int Disassembler::Decode(Isolate* isolate, std::ostream* os, byte* begin,
byte* end, CodeReference code, Address current_pc) { byte* end, CodeReference code, Address current_pc) {
DCHECK_WITH_MSG(FLAG_text_is_readable,
"Builtins disassembly requires a readable .text section");
V8NameConverter v8NameConverter(isolate, code); V8NameConverter v8NameConverter(isolate, code);
if (isolate) { if (isolate) {
// We have an isolate, so support external reference names. // We have an isolate, so support external reference names.
......
...@@ -294,11 +294,20 @@ void Isolate::SetEmbeddedBlob(const uint8_t* code, uint32_t code_size, ...@@ -294,11 +294,20 @@ void Isolate::SetEmbeddedBlob(const uint8_t* code, uint32_t code_size,
// Verify that the contents of the embedded blob are unchanged from // Verify that the contents of the embedded blob are unchanged from
// serialization-time, just to ensure the compiler isn't messing with us. // serialization-time, just to ensure the compiler isn't messing with us.
EmbeddedData d = EmbeddedData::FromBlob(); EmbeddedData d = EmbeddedData::FromBlob();
if (d.EmbeddedBlobHash() != d.CreateEmbeddedBlobHash()) { if (d.EmbeddedBlobDataHash() != d.CreateEmbeddedBlobDataHash()) {
FATAL( FATAL(
"Embedded blob checksum verification failed. This indicates that the " "Embedded blob data section checksum verification failed. This "
"embedded blob has been modified since compilation time. A common " "indicates that the embedded blob has been modified since compilation "
"cause is a debugging breakpoint set within builtin code."); "time.");
}
if (FLAG_text_is_readable) {
if (d.EmbeddedBlobCodeHash() != d.CreateEmbeddedBlobCodeHash()) {
FATAL(
"Embedded blob code section checksum verification failed. This "
"indicates that the embedded blob has been modified since "
"compilation time. A common cause is a debugging breakpoint set "
"within builtin code.");
}
} }
#endif // DEBUG #endif // DEBUG
......
...@@ -1547,6 +1547,11 @@ DEFINE_STRING(turbo_profiling_log_file, nullptr, ...@@ -1547,6 +1547,11 @@ DEFINE_STRING(turbo_profiling_log_file, nullptr,
"Path of the input file containing basic block counters for " "Path of the input file containing basic block counters for "
"builtins. (mksnapshot only)") "builtins. (mksnapshot only)")
// On some platforms, the .text section only has execute permissions.
DEFINE_BOOL(text_is_readable, true,
"Whether the .text section of binary can be read")
DEFINE_NEG_NEG_IMPLICATION(text_is_readable, partial_constant_pool)
// //
// Minor mark compact collector flags. // Minor mark compact collector flags.
// //
......
...@@ -306,13 +306,20 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) { ...@@ -306,13 +306,20 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
// Hash the blob and store the result. // Hash the blob and store the result.
{ {
STATIC_ASSERT(EmbeddedBlobHashSize() == kSizetSize); STATIC_ASSERT(EmbeddedBlobDataHashSize() == kSizetSize);
const size_t hash = d.CreateEmbeddedBlobHash(); const size_t data_hash = d.CreateEmbeddedBlobDataHash();
std::memcpy(blob_data + EmbeddedBlobHashOffset(), &hash, std::memcpy(blob_data + EmbeddedBlobDataHashOffset(), &data_hash,
EmbeddedBlobHashSize()); EmbeddedBlobDataHashSize());
DCHECK_EQ(hash, d.CreateEmbeddedBlobHash()); STATIC_ASSERT(EmbeddedBlobCodeHashSize() == kSizetSize);
DCHECK_EQ(hash, d.EmbeddedBlobHash()); const size_t code_hash = d.CreateEmbeddedBlobCodeHash();
std::memcpy(blob_data + EmbeddedBlobCodeHashOffset(), &code_hash,
EmbeddedBlobCodeHashSize());
DCHECK_EQ(data_hash, d.CreateEmbeddedBlobDataHash());
DCHECK_EQ(data_hash, d.EmbeddedBlobDataHash());
DCHECK_EQ(code_hash, d.CreateEmbeddedBlobCodeHash());
DCHECK_EQ(code_hash, d.EmbeddedBlobCodeHash());
} }
if (FLAG_serialization_statistics) d.PrintStatistics(); if (FLAG_serialization_statistics) d.PrintStatistics();
...@@ -361,14 +368,23 @@ Address EmbeddedData::InstructionEndOfBytecodeHandlers() const { ...@@ -361,14 +368,23 @@ Address EmbeddedData::InstructionEndOfBytecodeHandlers() const {
InstructionSizeOfBuiltin(lastBytecodeHandler); InstructionSizeOfBuiltin(lastBytecodeHandler);
} }
size_t EmbeddedData::CreateEmbeddedBlobHash() const { size_t EmbeddedData::CreateEmbeddedBlobDataHash() const {
STATIC_ASSERT(EmbeddedBlobHashOffset() == 0); STATIC_ASSERT(EmbeddedBlobDataHashOffset() == 0);
STATIC_ASSERT(EmbeddedBlobHashSize() == kSizetSize); STATIC_ASSERT(EmbeddedBlobCodeHashOffset() == EmbeddedBlobDataHashSize());
// Hash the entire blob except the hash field itself. STATIC_ASSERT(IsolateHashOffset() ==
Vector<const byte> payload1(data_ + EmbeddedBlobHashSize(), EmbeddedBlobCodeHashOffset() + EmbeddedBlobCodeHashSize());
data_size_ - EmbeddedBlobHashSize()); static constexpr uint32_t kFirstHashedDataOffset = IsolateHashOffset();
Vector<const byte> payload2(code_, code_size_); // Hash the entire data section except the embedded blob hash fields
return Checksum(payload1, payload2); // themselves.
Vector<const byte> payload(data_ + kFirstHashedDataOffset,
data_size_ - kFirstHashedDataOffset);
return Checksum(payload);
}
size_t EmbeddedData::CreateEmbeddedBlobCodeHash() const {
CHECK(FLAG_text_is_readable);
Vector<const byte> payload(code_, code_size_);
return Checksum(payload);
} }
void EmbeddedData::PrintStatistics() const { void EmbeddedData::PrintStatistics() const {
......
...@@ -90,9 +90,15 @@ class EmbeddedData final { ...@@ -90,9 +90,15 @@ class EmbeddedData final {
return PadAndAlignCode(size); return PadAndAlignCode(size);
} }
size_t CreateEmbeddedBlobHash() const; size_t CreateEmbeddedBlobDataHash() const;
size_t EmbeddedBlobHash() const { size_t CreateEmbeddedBlobCodeHash() const;
return *reinterpret_cast<const size_t*>(data_ + EmbeddedBlobHashOffset()); size_t EmbeddedBlobDataHash() const {
return *reinterpret_cast<const size_t*>(data_ +
EmbeddedBlobDataHashOffset());
}
size_t EmbeddedBlobCodeHash() const {
return *reinterpret_cast<const size_t*>(data_ +
EmbeddedBlobCodeHashOffset());
} }
size_t IsolateHash() const { size_t IsolateHash() const {
...@@ -124,9 +130,10 @@ class EmbeddedData final { ...@@ -124,9 +130,10 @@ class EmbeddedData final {
// The layout of the blob is as follows: // The layout of the blob is as follows:
// //
// data: // data:
// [0] hash of the remaining blob // [0] hash of the data section
// [1] hash of embedded-blob-relevant heap objects // [1] hash of the code section
// [2] layout description of instruction stream 0 // [2] hash of embedded-blob-relevant heap objects
// [3] layout description of instruction stream 0
// ... layout descriptions // ... layout descriptions
// [x] metadata section of builtin 0 // [x] metadata section of builtin 0
// ... metadata sections // ... metadata sections
...@@ -136,10 +143,14 @@ class EmbeddedData final { ...@@ -136,10 +143,14 @@ class EmbeddedData final {
// ... instruction sections // ... instruction sections
static constexpr uint32_t kTableSize = Builtins::builtin_count; static constexpr uint32_t kTableSize = Builtins::builtin_count;
static constexpr uint32_t EmbeddedBlobHashOffset() { return 0; } static constexpr uint32_t EmbeddedBlobDataHashOffset() { return 0; }
static constexpr uint32_t EmbeddedBlobHashSize() { return kSizetSize; } static constexpr uint32_t EmbeddedBlobDataHashSize() { return kSizetSize; }
static constexpr uint32_t EmbeddedBlobCodeHashOffset() {
return EmbeddedBlobDataHashOffset() + EmbeddedBlobDataHashSize();
}
static constexpr uint32_t EmbeddedBlobCodeHashSize() { return kSizetSize; }
static constexpr uint32_t IsolateHashOffset() { static constexpr uint32_t IsolateHashOffset() {
return EmbeddedBlobHashOffset() + EmbeddedBlobHashSize(); return EmbeddedBlobCodeHashOffset() + EmbeddedBlobCodeHashSize();
} }
static constexpr uint32_t IsolateHashSize() { return kSizetSize; } static constexpr uint32_t IsolateHashSize() { return kSizetSize; }
static constexpr uint32_t LayoutDescriptionTableOffset() { static constexpr uint32_t LayoutDescriptionTableOffset() {
......
...@@ -21,20 +21,5 @@ uint32_t Checksum(Vector<const byte> payload) { ...@@ -21,20 +21,5 @@ uint32_t Checksum(Vector<const byte> payload) {
return static_cast<uint32_t>(adler32(0, payload.begin(), payload.length())); return static_cast<uint32_t>(adler32(0, payload.begin(), payload.length()));
} }
V8_EXPORT_PRIVATE uint32_t Checksum(Vector<const byte> payload1,
Vector<const byte> payload2) {
#ifdef MEMORY_SANITIZER
// Computing the checksum includes padding bytes for objects like strings.
// Mark every object as initialized in the code serializer.
MSAN_MEMORY_IS_INITIALIZED(payload1.begin(), payload1.length());
MSAN_MEMORY_IS_INITIALIZED(payload2.begin(), payload2.length());
#endif // MEMORY_SANITIZER
// Priming the adler32 call so it can see what CPU features are available.
adler32(0, nullptr, 0);
auto sum = adler32(0, payload1.begin(), payload1.length());
sum = adler32(sum, payload2.begin(), payload2.length());
return static_cast<uint32_t>(sum);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -11,8 +11,6 @@ namespace v8 { ...@@ -11,8 +11,6 @@ namespace v8 {
namespace internal { namespace internal {
V8_EXPORT_PRIVATE uint32_t Checksum(Vector<const byte> payload); V8_EXPORT_PRIVATE uint32_t Checksum(Vector<const byte> payload);
V8_EXPORT_PRIVATE uint32_t Checksum(Vector<const byte> payload1,
Vector<const byte> payload2);
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment