Re-apply: Implement mapping randomization for 64-bit Linux.

- 32-bit Linux already seems to scatter the mmap() chunks around;
  64-bit didn't.

- Seed the system random number generator a little better (we needlessly trunctaed microsecond resolution to millisecond resolution).

- Will automatically take advantage of better entropy when V8::RandomPrivate uses it.

R=fschneider@chromium.org,cevans@chromium.org
BUG=v8:805
TEST=

Review URL: http://codereview.chromium.org/7464022
Patch from Chris Evans <cevans@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8705 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
ager@chromium.org 2011-07-21 11:01:50 +00:00
parent 7a0adba963
commit 5fba76891b

View File

@ -78,13 +78,33 @@ double ceiling(double x) {
static Mutex* limit_mutex = NULL; static Mutex* limit_mutex = NULL;
static void* GetRandomMmapAddr() {
Isolate* isolate = Isolate::UncheckedCurrent();
// Note that the current isolate isn't set up in a call path via
// CpuFeatures::Probe. We don't care about randomization in this case because
// the code page is immediately freed.
if (isolate != NULL) {
#ifdef V8_TARGET_ARCH_X64
uint64_t rnd1 = V8::RandomPrivate(isolate);
uint64_t rnd2 = V8::RandomPrivate(isolate);
uint64_t raw_addr = (rnd1 << 32) ^ rnd2;
raw_addr &= V8_UINT64_C(0x3ffffffff000);
#else
uint32_t raw_addr = V8::RandomPrivate(isolate);
// The range 0x20000000 - 0x60000000 is relatively unpopulated across a
// variety of ASLR modes (PAE kernel, NX compat mode, etc).
raw_addr &= 0x3ffff000;
raw_addr += 0x20000000;
#endif
return reinterpret_cast<void*>(raw_addr);
}
return NULL;
}
void OS::Setup() { void OS::Setup() {
// Seed the random number generator. // Seed the random number generator. We preserve microsecond resolution.
// Convert the current time to a 64-bit integer first, before converting it uint64_t seed = Ticks() ^ (getpid() << 16);
// to an unsigned. Going directly can cause an overflow and the seed to be
// set to all ones. The seed will be identical for different instances that
// call this setup code within the same millisecond.
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed)); srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex(); limit_mutex = CreateMutex();
@ -367,10 +387,10 @@ size_t OS::AllocateAlignment() {
void* OS::Allocate(const size_t requested, void* OS::Allocate(const size_t requested,
size_t* allocated, size_t* allocated,
bool is_executable) { bool is_executable) {
// TODO(805): Port randomization of allocated executable memory to Linux.
const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE)); const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); void* addr = GetRandomMmapAddr();
void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mbase == MAP_FAILED) { if (mbase == MAP_FAILED) {
LOG(i::Isolate::Current(), LOG(i::Isolate::Current(),
StringEvent("OS::Allocate", "mmap failed")); StringEvent("OS::Allocate", "mmap failed"));
@ -586,7 +606,7 @@ static const int kMmapFdOffset = 0;
VirtualMemory::VirtualMemory(size_t size) { VirtualMemory::VirtualMemory(size_t size) {
address_ = mmap(NULL, size, PROT_NONE, address_ = mmap(GetRandomMmapAddr(), size, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
kMmapFd, kMmapFdOffset); kMmapFd, kMmapFdOffset);
size_ = size; size_ = size;