blob: bda0e43cef0f14a172a84996c9c3c363b80ea40c [file]
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/libplatform/default-thread-isolated-allocator.h"
#if V8_HAS_PKU_JIT_WRITE_PROTECT
#if !V8_OS_LINUX
#error pkey support in this file is only implemented on Linux
#endif
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <unistd.h>
#endif
#if V8_HAS_PKU_JIT_WRITE_PROTECT
extern int pkey_alloc(unsigned int flags, unsigned int access_rights) V8_WEAK;
extern int pkey_free(int pkey) V8_WEAK;
namespace {
bool KernelHasPkruFix() {
// PKU was broken on Linux kernels before 5.13 (see
// https://lore.kernel.org/all/20210623121456.399107624@linutronix.de/).
// A fix is also included in the 5.4.182 and 5.10.103 versions ("x86/fpu:
// Correct pkru/xstate inconsistency" by Brian Geffon <bgeffon@google.com>).
// Thus check the kernel version we are running on, and bail out if does not
// contain the fix.
struct utsname uname_buffer;
CHECK_EQ(0, uname(&uname_buffer));
int kernel, major, minor;
// Conservatively return if the release does not match the format we expect.
if (sscanf(uname_buffer.release, "%d.%d.%d", &kernel, &major, &minor) != 3) {
return false;
}
return kernel > 5 || (kernel == 5 && major >= 13) || // anything >= 5.13
(kernel == 5 && major == 4 && minor >= 182) || // 5.4 >= 5.4.182
(kernel == 5 && major == 10 && minor >= 103); // 5.10 >= 5.10.103
}
int PkeyAlloc() {
#ifdef PKEY_DISABLE_WRITE
if (!pkey_alloc) return -1;
static bool kernel_has_pkru_fix = KernelHasPkruFix();
if (!kernel_has_pkru_fix) return -1;
return pkey_alloc(0, PKEY_DISABLE_WRITE);
#else // PKEY_DISABLE_WRITE
return -1;
#endif
}
int PkeyFree(int pkey) {
DCHECK(pkey_free);
return pkey_free(pkey);
}
} // namespace
#endif // V8_HAS_PKU_JIT_WRITE_PROTECT
namespace v8::platform {
DefaultThreadIsolatedAllocator::DefaultThreadIsolatedAllocator()
#if V8_HAS_PKU_JIT_WRITE_PROTECT
: pkey_(PkeyAlloc())
#endif
{
}
DefaultThreadIsolatedAllocator::~DefaultThreadIsolatedAllocator() {
#if V8_HAS_PKU_JIT_WRITE_PROTECT
if (pkey_ != -1) {
PkeyFree(pkey_);
}
#endif
}
// TODO(sroettger): this should return thread isolated (e.g. pkey-tagged) memory
// for testing.
void* DefaultThreadIsolatedAllocator::Allocate(size_t size) {
return malloc(size);
}
void DefaultThreadIsolatedAllocator::Free(void* object) { free(object); }
enum DefaultThreadIsolatedAllocator::Type DefaultThreadIsolatedAllocator::Type()
const {
#if V8_HAS_PKU_JIT_WRITE_PROTECT
return Type::kPkey;
#else
UNREACHABLE();
#endif
}
int DefaultThreadIsolatedAllocator::Pkey() const {
#if V8_HAS_PKU_JIT_WRITE_PROTECT
return pkey_;
#else
UNREACHABLE();
#endif
}
bool DefaultThreadIsolatedAllocator::Valid() const {
#if V8_HAS_PKU_JIT_WRITE_PROTECT
return pkey_ != -1;
#else
return false;
#endif
}
} // namespace v8::platform