0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-11-28 16:21:04 -05:00

fix: crash on x86_64 systems that support memory protection keys (#1318)

Co-authored-by: Matt Mastracci <matthew@mastracci.com>
This commit is contained in:
Bert Belder 2023-09-12 16:26:42 -07:00 committed by GitHub
parent 6eb4b811df
commit 53e048ffc7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 124 additions and 5 deletions

View file

@ -1,9 +1,11 @@
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
#include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <memory>
#include "support.h" #include "support.h"
#include "unicode/locid.h" #include "unicode/locid.h"
@ -17,9 +19,12 @@
#include "v8/include/v8.h" #include "v8/include/v8.h"
#include "v8/src/api/api-inl.h" #include "v8/src/api/api-inl.h"
#include "v8/src/api/api.h" #include "v8/src/api/api.h"
#include "v8/src/base/debug/stack_trace.h"
#include "v8/src/base/sys-info.h"
#include "v8/src/execution/isolate-utils-inl.h" #include "v8/src/execution/isolate-utils-inl.h"
#include "v8/src/execution/isolate-utils.h" #include "v8/src/execution/isolate-utils.h"
#include "v8/src/flags/flags.h" #include "v8/src/flags/flags.h"
#include "v8/src/libplatform/default-platform.h"
#include "v8/src/objects/objects-inl.h" #include "v8/src/objects/objects-inl.h"
#include "v8/src/objects/objects.h" #include "v8/src/objects/objects.h"
#include "v8/src/objects/smi.h" #include "v8/src/objects/smi.h"
@ -2579,6 +2584,49 @@ v8::StartupData v8__SnapshotCreator__CreateBlob(
return self->CreateBlob(function_code_handling); return self->CreateBlob(function_code_handling);
} }
class UnprotectedDefaultPlatform : public v8::platform::DefaultPlatform {
using IdleTaskSupport = v8::platform::IdleTaskSupport;
using InProcessStackDumping = v8::platform::InProcessStackDumping;
using PriorityMode = v8::platform::PriorityMode;
using TracingController = v8::TracingController;
static constexpr int kMaxThreadPoolSize = 16;
public:
explicit UnprotectedDefaultPlatform(
int thread_pool_size, IdleTaskSupport idle_task_support,
std::unique_ptr<TracingController> tracing_controller = {},
PriorityMode priority_mode = PriorityMode::kDontApply)
: v8::platform::DefaultPlatform(thread_pool_size, idle_task_support,
std::move(tracing_controller),
priority_mode) {}
static std::unique_ptr<v8::Platform> New(
int thread_pool_size, IdleTaskSupport idle_task_support,
InProcessStackDumping in_process_stack_dumping,
std::unique_ptr<TracingController> tracing_controller = {},
PriorityMode priority_mode = PriorityMode::kDontApply) {
// This implementation is semantically equivalent to the implementation of
// `v8::platform::NewDefaultPlatform()`.
DCHECK_GE(thread_pool_size, 0);
if (thread_pool_size < 1) {
thread_pool_size =
std::max(v8::base::SysInfo::NumberOfProcessors() - 1, 1);
}
thread_pool_size = std::min(thread_pool_size, kMaxThreadPoolSize);
if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
v8::base::debug::EnableInProcessStackDumping();
}
return std::make_unique<UnprotectedDefaultPlatform>(
thread_pool_size, idle_task_support, std::move(tracing_controller),
priority_mode);
}
v8::ThreadIsolatedAllocator* GetThreadIsolatedAllocator() override {
return nullptr;
}
};
v8::Platform* v8__Platform__NewDefaultPlatform(int thread_pool_size, v8::Platform* v8__Platform__NewDefaultPlatform(int thread_pool_size,
bool idle_task_support) { bool idle_task_support) {
return v8::platform::NewDefaultPlatform( return v8::platform::NewDefaultPlatform(
@ -2589,6 +2637,16 @@ v8::Platform* v8__Platform__NewDefaultPlatform(int thread_pool_size,
.release(); .release();
} }
v8::Platform* v8__Platform__NewUnprotectedDefaultPlatform(
int thread_pool_size, bool idle_task_support) {
return UnprotectedDefaultPlatform::New(
thread_pool_size,
idle_task_support ? v8::platform::IdleTaskSupport::kEnabled
: v8::platform::IdleTaskSupport::kDisabled,
v8::platform::InProcessStackDumping::kDisabled, nullptr)
.release();
}
v8::Platform* v8__Platform__NewSingleThreadedDefaultPlatform( v8::Platform* v8__Platform__NewSingleThreadedDefaultPlatform(
bool idle_task_support) { bool idle_task_support) {
return v8::platform::NewSingleThreadedDefaultPlatform( return v8::platform::NewSingleThreadedDefaultPlatform(

View file

@ -120,6 +120,7 @@ pub use module::*;
pub use object::*; pub use object::*;
pub use platform::new_default_platform; pub use platform::new_default_platform;
pub use platform::new_single_threaded_default_platform; pub use platform::new_single_threaded_default_platform;
pub use platform::new_unprotected_default_platform;
pub use platform::Platform; pub use platform::Platform;
pub use primitives::*; pub use primitives::*;
pub use private::*; pub use private::*;

View file

@ -14,6 +14,10 @@ extern "C" {
thread_pool_size: int, thread_pool_size: int,
idle_task_support: bool, idle_task_support: bool,
) -> *mut Platform; ) -> *mut Platform;
fn v8__Platform__NewUnprotectedDefaultPlatform(
thread_pool_size: int,
idle_task_support: bool,
) -> *mut Platform;
fn v8__Platform__NewSingleThreadedDefaultPlatform( fn v8__Platform__NewSingleThreadedDefaultPlatform(
idle_task_support: bool, idle_task_support: bool,
) -> *mut Platform; ) -> *mut Platform;
@ -58,6 +62,16 @@ pub struct Platform(Opaque);
/// If |idle_task_support| is enabled then the platform will accept idle /// If |idle_task_support| is enabled then the platform will accept idle
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder /// tasks (IdleTasksEnabled will return true) and will rely on the embedder
/// calling v8::platform::RunIdleTasks to process the idle tasks. /// calling v8::platform::RunIdleTasks to process the idle tasks.
///
/// The default platform for v8 may include restrictions and caveats on thread
/// creation and initialization. This platform should only be used in cases
/// where v8 can be reliably initialized on the application's main thread, or
/// the parent thread to all threads in the system that will use v8.
///
/// One example of a restriction is the use of Memory Protection Keys (pkeys) on
/// modern Linux systems using modern Intel/AMD processors. This particular
/// technology requires that all threads using v8 are created as descendent
/// threads of the thread that called `v8::Initialize`.
#[inline(always)] #[inline(always)]
pub fn new_default_platform( pub fn new_default_platform(
thread_pool_size: u32, thread_pool_size: u32,
@ -66,6 +80,18 @@ pub fn new_default_platform(
Platform::new(thread_pool_size, idle_task_support) Platform::new(thread_pool_size, idle_task_support)
} }
/// Creates a platform that is identical to the default platform, but does not
/// enforce thread-isolated allocations. This may reduce security in some cases,
/// so this method should be used with caution in cases where the threading
/// guarantees of `new_default_platform` cannot be upheld (generally for tests).
#[inline(always)]
pub fn new_unprotected_default_platform(
thread_pool_size: u32,
idle_task_support: bool,
) -> UniqueRef<Platform> {
Platform::new_unprotected(thread_pool_size, idle_task_support)
}
/// The same as new_default_platform() but disables the worker thread pool. /// The same as new_default_platform() but disables the worker thread pool.
/// It must be used with the --single-threaded V8 flag. /// It must be used with the --single-threaded V8 flag.
/// ///
@ -88,6 +114,16 @@ impl Platform {
/// If |idle_task_support| is enabled then the platform will accept idle /// If |idle_task_support| is enabled then the platform will accept idle
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder /// tasks (IdleTasksEnabled will return true) and will rely on the embedder
/// calling v8::platform::RunIdleTasks to process the idle tasks. /// calling v8::platform::RunIdleTasks to process the idle tasks.
///
/// The default platform for v8 may include restrictions and caveats on thread
/// creation and initialization. This platform should only be used in cases
/// where v8 can be reliably initialized on the application's main thread, or
/// the parent thread to all threads in the system that will use v8.
///
/// One example of a restriction is the use of Memory Protection Keys (pkeys)
/// on modern Linux systems using modern Intel/AMD processors. This particular
/// technology requires that all threads using v8 are created as descendent
/// threads of the thread that called `v8::Initialize`.
#[inline(always)] #[inline(always)]
pub fn new( pub fn new(
thread_pool_size: u32, thread_pool_size: u32,
@ -101,6 +137,24 @@ impl Platform {
} }
} }
/// Creates a platform that is identical to the default platform, but does not
/// enforce thread-isolated allocations. This may reduce security in some
/// cases, so this method should be used with caution in cases where the
/// threading guarantees of `new_default_platform` cannot be upheld (generally
/// for tests).
#[inline(always)]
pub fn new_unprotected(
thread_pool_size: u32,
idle_task_support: bool,
) -> UniqueRef<Self> {
unsafe {
UniqueRef::from_raw(v8__Platform__NewUnprotectedDefaultPlatform(
thread_pool_size.min(16) as i32,
idle_task_support,
))
}
}
/// The same as new() but disables the worker thread pool. /// The same as new() but disables the worker thread pool.
/// It must be used with the --single-threaded V8 flag. /// It must be used with the --single-threaded V8 flag.
/// ///

View file

@ -15,7 +15,7 @@ fn setup() {
START.call_once(|| { START.call_once(|| {
v8::V8::set_flags_from_string("--expose_gc"); v8::V8::set_flags_from_string("--expose_gc");
v8::V8::initialize_platform( v8::V8::initialize_platform(
v8::new_default_platform(0, false).make_shared(), v8::new_unprotected_default_platform(0, false).make_shared(),
); );
v8::V8::initialize(); v8::V8::initialize();
}); });

View file

@ -55,7 +55,7 @@ mod setup {
"--no_freeze_flags_after_init --expose_gc --harmony-import-assertions --harmony-shadow-realm --allow_natives_syntax --turbo_fast_api_calls", "--no_freeze_flags_after_init --expose_gc --harmony-import-assertions --harmony-shadow-realm --allow_natives_syntax --turbo_fast_api_calls",
); );
v8::V8::initialize_platform( v8::V8::initialize_platform(
v8::new_default_platform(0, false).make_shared(), v8::new_unprotected_default_platform(0, false).make_shared(),
); );
v8::V8::initialize(); v8::V8::initialize();
}); });

View file

@ -18,7 +18,9 @@ fn set_entropy_source() {
true true
}); });
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared()); v8::V8::initialize_platform(
v8::new_unprotected_default_platform(0, false).make_shared(),
);
v8::V8::initialize(); v8::V8::initialize();
// Assumes that every isolate creates a PRNG from scratch, which is currently true. // Assumes that every isolate creates a PRNG from scratch, which is currently true.

View file

@ -4,7 +4,9 @@
#[test] #[test]
fn set_flags_from_string() { fn set_flags_from_string() {
v8::V8::set_flags_from_string("--use_strict"); v8::V8::set_flags_from_string("--use_strict");
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared()); v8::V8::initialize_platform(
v8::new_unprotected_default_platform(0, false).make_shared(),
);
v8::V8::initialize(); v8::V8::initialize();
let isolate = &mut v8::Isolate::new(Default::default()); let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate); let scope = &mut v8::HandleScope::new(isolate);

View file

@ -3,7 +3,9 @@ fn atomics_pump_message_loop() {
v8::V8::set_flags_from_string( v8::V8::set_flags_from_string(
"--allow-natives-syntax --harmony-sharedarraybuffer", "--allow-natives-syntax --harmony-sharedarraybuffer",
); );
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared()); v8::V8::initialize_platform(
v8::new_unprotected_default_platform(0, false).make_shared(),
);
v8::V8::initialize(); v8::V8::initialize();
let isolate = &mut v8::Isolate::new(Default::default()); let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate); let scope = &mut v8::HandleScope::new(isolate);