blob: 536aa3a232fdeb548a7e2dcca1699212d0c6073c [file] [log] [blame]
// Copyright 2018 The Chromium 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 "base/metrics/field_trial_memory_mac.h"
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include "base/mac/mach_logging.h"
#include "base/mac/scoped_mach_vm.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
#include "testing/multiprocess_func_list.h"
namespace base {
namespace {
enum ChildExitCode {
kChildExitInvalid,
kChildExitNoPort,
kChildExitMapFailed,
kChildExitBadPattern,
kChildExitSuccess,
};
constexpr char kMemoryTestPattern[] = "Hello there, bear";
constexpr mach_vm_size_t kMemoryAllocationSize = 1024;
} // namespace
class FieldTrialMemoryServerTest : public MultiProcessTest {
public:
void SetUp() override {
mach_vm_address_t address = 0;
mach_vm_size_t size = mach_vm_round_page(kMemoryAllocationSize);
kern_return_t kr =
mach_vm_allocate(mach_task_self(), &address, size, VM_FLAGS_ANYWHERE);
ASSERT_EQ(kr, KERN_SUCCESS) << "mach_vm_allocate";
memory_.reset(address, size);
kr = mach_make_memory_entry_64(
mach_task_self(), &size, address, VM_PROT_READ,
mac::ScopedMachSendRight::Receiver(memory_object_).get(),
MACH_PORT_NULL);
ASSERT_EQ(kr, KERN_SUCCESS) << "mach_make_memory_entry_64";
memcpy(reinterpret_cast<void*>(address), kMemoryTestPattern,
sizeof(kMemoryTestPattern));
}
void SetServerPid(FieldTrialMemoryServer* server, pid_t server_pid) {
server->set_server_pid(server_pid);
}
mach_port_t memory_object() { return memory_object_.get(); }
private:
mac::ScopedMachVM memory_;
mac::ScopedMachSendRight memory_object_;
};
MULTIPROCESS_TEST_MAIN(AcquireMemoryObjectAndMap) {
mac::ScopedMachSendRight memory_object =
FieldTrialMemoryClient::AcquireMemoryObject();
if (memory_object == MACH_PORT_NULL)
return kChildExitNoPort;
mach_vm_address_t address = 0;
kern_return_t kr =
mach_vm_map(mach_task_self(), &address, kMemoryAllocationSize, 0,
VM_FLAGS_ANYWHERE, memory_object.get(), 0, false,
VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
if (kr != KERN_SUCCESS) {
MACH_LOG(ERROR, kr) << "mach_vm_map";
return kChildExitMapFailed;
}
if (memcmp(kMemoryTestPattern, reinterpret_cast<void*>(address),
sizeof(kMemoryTestPattern)) != 0) {
return kChildExitBadPattern;
}
return kChildExitSuccess;
}
TEST_F(FieldTrialMemoryServerTest, AllowedPid) {
FieldTrialMemoryServer server(memory_object());
ASSERT_TRUE(server.Start());
Process child = SpawnChild("AcquireMemoryObjectAndMap");
int exit_code;
ASSERT_TRUE(WaitForMultiprocessTestChildExit(
child, TestTimeouts::action_timeout(), &exit_code));
EXPECT_EQ(kChildExitSuccess, exit_code);
}
TEST_F(FieldTrialMemoryServerTest, BlockedPid) {
FieldTrialMemoryServer server(memory_object());
// Override the server's PID so that the request does not look like it is
// coming from a process that is the child of the server.
SetServerPid(&server, 1);
ASSERT_TRUE(server.Start());
Process child = SpawnChild("AcquireMemoryObjectAndMap");
int exit_code;
ASSERT_TRUE(WaitForMultiprocessTestChildExit(
child, TestTimeouts::action_timeout(), &exit_code));
EXPECT_EQ(kChildExitNoPort, exit_code);
}
} // namespace base