diff options
Diffstat (limited to 'sandbox/mac/bootstrap_sandbox_unittest.mm')
-rw-r--r-- | sandbox/mac/bootstrap_sandbox_unittest.mm | 518 |
1 files changed, 0 insertions, 518 deletions
diff --git a/sandbox/mac/bootstrap_sandbox_unittest.mm b/sandbox/mac/bootstrap_sandbox_unittest.mm deleted file mode 100644 index 717f3f99f3..0000000000 --- a/sandbox/mac/bootstrap_sandbox_unittest.mm +++ /dev/null @@ -1,518 +0,0 @@ -// Copyright 2014 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 "sandbox/mac/bootstrap_sandbox.h" - -#include <CoreFoundation/CoreFoundation.h> -#import <Foundation/Foundation.h> -#include <mach/mach.h> -#include <servers/bootstrap.h> - -#include "base/logging.h" -#include "base/mac/mac_util.h" -#include "base/mac/mach_logging.h" -#include "base/mac/scoped_mach_port.h" -#include "base/mac/scoped_nsobject.h" -#include "base/process/kill.h" -#include "base/strings/stringprintf.h" -#include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" -#import "testing/gtest_mac.h" -#include "testing/multiprocess_func_list.h" - -NSString* const kTestNotification = @"org.chromium.bootstrap_sandbox_test"; - -@interface DistributedNotificationObserver : NSObject { - @private - int receivedCount_; - base::scoped_nsobject<NSString> object_; -} -- (int)receivedCount; -- (NSString*)object; -- (void)waitForNotification; -@end - -@implementation DistributedNotificationObserver -- (id)init { - if ((self = [super init])) { - [[NSDistributedNotificationCenter defaultCenter] - addObserver:self - selector:@selector(observeNotification:) - name:kTestNotification - object:nil]; - } - return self; -} - -- (void)dealloc { - [[NSDistributedNotificationCenter defaultCenter] - removeObserver:self - name:kTestNotification - object:nil]; - [super dealloc]; -} - -- (int)receivedCount { - return receivedCount_; -} - -- (NSString*)object { - return object_.get(); -} - -- (void)waitForNotification { - object_.reset(); - CFRunLoopRunInMode(kCFRunLoopDefaultMode, - TestTimeouts::action_timeout().InSeconds(), false); -} - -- (void)observeNotification:(NSNotification*)notification { - ++receivedCount_; - object_.reset([[notification object] copy]); - CFRunLoopStop(CFRunLoopGetCurrent()); -} -@end - -//////////////////////////////////////////////////////////////////////////////// - -namespace sandbox { - -class BootstrapSandboxTest : public base::MultiProcessTest { - public: - void SetUp() override { - base::MultiProcessTest::SetUp(); - - sandbox_ = BootstrapSandbox::Create(); - ASSERT_TRUE(sandbox_.get()); - } - - BootstrapSandboxPolicy BaselinePolicy() { - BootstrapSandboxPolicy policy; - if (base::mac::IsOSSnowLeopard()) - policy.rules["com.apple.SecurityServer"] = Rule(POLICY_ALLOW); - return policy; - } - - void RunChildWithPolicy(int policy_id, - const char* child_name, - base::ProcessHandle* out_pid) { - sandbox_->PrepareToForkWithPolicy(policy_id); - base::LaunchOptions options; - options.replacement_bootstrap_name = sandbox_->server_bootstrap_name(); - base::Process process = SpawnChildWithOptions(child_name, options); - ASSERT_TRUE(process.IsValid()); - sandbox_->FinishedFork(process.Handle()); - int code = 0; - EXPECT_TRUE(process.WaitForExit(&code)); - EXPECT_EQ(0, code); - if (out_pid) - *out_pid = process.Pid(); - } - - protected: - scoped_ptr<BootstrapSandbox> sandbox_; -}; - -const char kNotificationTestMain[] = "PostNotification"; - -// Run the test without the sandbox. -TEST_F(BootstrapSandboxTest, DistributedNotifications_Unsandboxed) { - base::scoped_nsobject<DistributedNotificationObserver> observer( - [[DistributedNotificationObserver alloc] init]); - - base::Process process = SpawnChild(kNotificationTestMain); - ASSERT_TRUE(process.IsValid()); - int code = 0; - EXPECT_TRUE(process.WaitForExit(&code)); - EXPECT_EQ(0, code); - - [observer waitForNotification]; - EXPECT_EQ(1, [observer receivedCount]); - EXPECT_EQ(process.Pid(), [[observer object] intValue]); -} - -// Run the test with the sandbox enabled without notifications on the policy -// whitelist. -TEST_F(BootstrapSandboxTest, DistributedNotifications_SandboxDeny) { - base::scoped_nsobject<DistributedNotificationObserver> observer( - [[DistributedNotificationObserver alloc] init]); - - sandbox_->RegisterSandboxPolicy(1, BaselinePolicy()); - RunChildWithPolicy(1, kNotificationTestMain, NULL); - - [observer waitForNotification]; - EXPECT_EQ(0, [observer receivedCount]); - EXPECT_EQ(nil, [observer object]); -} - -// Run the test with notifications permitted. -TEST_F(BootstrapSandboxTest, DistributedNotifications_SandboxAllow) { - base::scoped_nsobject<DistributedNotificationObserver> observer( - [[DistributedNotificationObserver alloc] init]); - - BootstrapSandboxPolicy policy(BaselinePolicy()); - // 10.9: - policy.rules["com.apple.distributed_notifications@Uv3"] = Rule(POLICY_ALLOW); - policy.rules["com.apple.distributed_notifications@1v3"] = Rule(POLICY_ALLOW); - // 10.6: - policy.rules["com.apple.system.notification_center"] = Rule(POLICY_ALLOW); - policy.rules["com.apple.distributed_notifications.2"] = Rule(POLICY_ALLOW); - sandbox_->RegisterSandboxPolicy(2, policy); - - base::ProcessHandle pid; - RunChildWithPolicy(2, kNotificationTestMain, &pid); - - [observer waitForNotification]; - EXPECT_EQ(1, [observer receivedCount]); - EXPECT_EQ(pid, [[observer object] intValue]); -} - -MULTIPROCESS_TEST_MAIN(PostNotification) { - [[NSDistributedNotificationCenter defaultCenter] - postNotificationName:kTestNotification - object:[NSString stringWithFormat:@"%d", getpid()]]; - return 0; -} - -const char kTestServer[] = "org.chromium.test_bootstrap_server"; - -TEST_F(BootstrapSandboxTest, PolicyDenyError) { - BootstrapSandboxPolicy policy(BaselinePolicy()); - policy.rules[kTestServer] = Rule(POLICY_DENY_ERROR); - sandbox_->RegisterSandboxPolicy(1, policy); - - RunChildWithPolicy(1, "PolicyDenyError", NULL); -} - -MULTIPROCESS_TEST_MAIN(PolicyDenyError) { - mach_port_t port = MACH_PORT_NULL; - kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer, - &port); - CHECK_EQ(BOOTSTRAP_UNKNOWN_SERVICE, kr); - CHECK(port == MACH_PORT_NULL); - - kr = bootstrap_look_up(bootstrap_port, "org.chromium.some_other_server", - &port); - CHECK_EQ(BOOTSTRAP_UNKNOWN_SERVICE, kr); - CHECK(port == MACH_PORT_NULL); - - return 0; -} - -TEST_F(BootstrapSandboxTest, PolicyDenyDummyPort) { - BootstrapSandboxPolicy policy(BaselinePolicy()); - policy.rules[kTestServer] = Rule(POLICY_DENY_DUMMY_PORT); - sandbox_->RegisterSandboxPolicy(1, policy); - - RunChildWithPolicy(1, "PolicyDenyDummyPort", NULL); -} - -MULTIPROCESS_TEST_MAIN(PolicyDenyDummyPort) { - mach_port_t port = MACH_PORT_NULL; - kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer, - &port); - CHECK_EQ(KERN_SUCCESS, kr); - CHECK(port != MACH_PORT_NULL); - return 0; -} - -struct SubstitutePortAckSend { - mach_msg_header_t header; - char buf[32]; -}; - -struct SubstitutePortAckRecv : public SubstitutePortAckSend { - mach_msg_trailer_t trailer; -}; - -const char kSubstituteAck[] = "Hello, this is doge!"; - -TEST_F(BootstrapSandboxTest, PolicySubstitutePort) { - mach_port_t task = mach_task_self(); - - mach_port_t port; - ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, - &port)); - base::mac::ScopedMachReceiveRight scoped_port(port); - - mach_port_urefs_t send_rights = 0; - ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND, - &send_rights)); - EXPECT_EQ(0u, send_rights); - - ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port, - MACH_MSG_TYPE_MAKE_SEND)); - base::mac::ScopedMachSendRight scoped_port_send(port); - - send_rights = 0; - ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND, - &send_rights)); - EXPECT_EQ(1u, send_rights); - - BootstrapSandboxPolicy policy(BaselinePolicy()); - policy.rules[kTestServer] = Rule(port); - sandbox_->RegisterSandboxPolicy(1, policy); - - RunChildWithPolicy(1, "PolicySubstitutePort", NULL); - - struct SubstitutePortAckRecv msg; - bzero(&msg, sizeof(msg)); - msg.header.msgh_size = sizeof(msg); - msg.header.msgh_local_port = port; - kern_return_t kr = mach_msg(&msg.header, MACH_RCV_MSG, 0, - msg.header.msgh_size, port, - TestTimeouts::tiny_timeout().InMilliseconds(), MACH_PORT_NULL); - EXPECT_EQ(KERN_SUCCESS, kr); - - send_rights = 0; - ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND, - &send_rights)); - EXPECT_EQ(1u, send_rights); - - EXPECT_EQ(0, strncmp(kSubstituteAck, msg.buf, sizeof(msg.buf))); -} - -MULTIPROCESS_TEST_MAIN(PolicySubstitutePort) { - mach_port_t port = MACH_PORT_NULL; - kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer, &port); - CHECK_EQ(KERN_SUCCESS, kr); - CHECK(port != MACH_PORT_NULL); - - struct SubstitutePortAckSend msg; - bzero(&msg, sizeof(msg)); - msg.header.msgh_size = sizeof(msg); - msg.header.msgh_remote_port = port; - msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND); - strncpy(msg.buf, kSubstituteAck, sizeof(msg.buf)); - - CHECK_EQ(KERN_SUCCESS, mach_msg_send(&msg.header)); - - return 0; -} - -TEST_F(BootstrapSandboxTest, ForwardMessageInProcess) { - mach_port_t task = mach_task_self(); - - mach_port_t port; - ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, - &port)); - base::mac::ScopedMachReceiveRight scoped_port_recv(port); - - mach_port_urefs_t send_rights = 0; - ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND, - &send_rights)); - EXPECT_EQ(0u, send_rights); - - ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port, - MACH_MSG_TYPE_MAKE_SEND)); - base::mac::ScopedMachSendRight scoped_port_send(port); - - send_rights = 0; - ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND, - &send_rights)); - EXPECT_EQ(1u, send_rights); - - mach_port_t bp; - ASSERT_EQ(KERN_SUCCESS, task_get_bootstrap_port(task, &bp)); - base::mac::ScopedMachSendRight scoped_bp(bp); - - char service_name[] = "org.chromium.sandbox.test.ForwardMessageInProcess"; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - kern_return_t kr = bootstrap_register(bp, service_name, port); -#pragma GCC diagnostic pop - EXPECT_EQ(KERN_SUCCESS, kr); - - send_rights = 0; - ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND, - &send_rights)); - EXPECT_EQ(1u, send_rights); - - mach_port_t service_port; - EXPECT_EQ(KERN_SUCCESS, bootstrap_look_up(bp, service_name, &service_port)); - base::mac::ScopedMachSendRight scoped_service_port(service_port); - - send_rights = 0; - ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND, - &send_rights)); - // On 10.6, bootstrap_lookup2 may add an extra right to place it in a per- - // process cache. - if (base::mac::IsOSSnowLeopard()) - EXPECT_TRUE(send_rights == 3u || send_rights == 2u) << send_rights; - else - EXPECT_EQ(2u, send_rights); -} - -const char kDefaultRuleTestAllow[] = - "org.chromium.sandbox.test.DefaultRuleAllow"; -const char kDefaultRuleTestDeny[] = - "org.chromium.sandbox.test.DefaultRuleAllow.Deny"; - -TEST_F(BootstrapSandboxTest, DefaultRuleAllow) { - mach_port_t task = mach_task_self(); - - mach_port_t port; - ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, - &port)); - base::mac::ScopedMachReceiveRight scoped_port_recv(port); - - ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port, - MACH_MSG_TYPE_MAKE_SEND)); - base::mac::ScopedMachSendRight scoped_port_send(port); - - BootstrapSandboxPolicy policy; - policy.default_rule = Rule(POLICY_ALLOW); - policy.rules[kDefaultRuleTestAllow] = Rule(port); - policy.rules[kDefaultRuleTestDeny] = Rule(POLICY_DENY_ERROR); - sandbox_->RegisterSandboxPolicy(3, policy); - - base::scoped_nsobject<DistributedNotificationObserver> observer( - [[DistributedNotificationObserver alloc] init]); - - int pid = 0; - RunChildWithPolicy(3, "DefaultRuleAllow", &pid); - EXPECT_GT(pid, 0); - - [observer waitForNotification]; - EXPECT_EQ(1, [observer receivedCount]); - EXPECT_EQ(pid, [[observer object] intValue]); - - struct SubstitutePortAckRecv msg; - bzero(&msg, sizeof(msg)); - msg.header.msgh_size = sizeof(msg); - msg.header.msgh_local_port = port; - kern_return_t kr = mach_msg(&msg.header, MACH_RCV_MSG, 0, - msg.header.msgh_size, port, - TestTimeouts::tiny_timeout().InMilliseconds(), MACH_PORT_NULL); - EXPECT_EQ(KERN_SUCCESS, kr); - - EXPECT_EQ(0, strncmp(kSubstituteAck, msg.buf, sizeof(msg.buf))); -} - -MULTIPROCESS_TEST_MAIN(DefaultRuleAllow) { - [[NSDistributedNotificationCenter defaultCenter] - postNotificationName:kTestNotification - object:[NSString stringWithFormat:@"%d", getpid()]]; - - mach_port_t port = MACH_PORT_NULL; - CHECK_EQ(BOOTSTRAP_UNKNOWN_SERVICE, bootstrap_look_up(bootstrap_port, - const_cast<char*>(kDefaultRuleTestDeny), &port)); - CHECK(port == MACH_PORT_NULL); - - CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port, - const_cast<char*>(kDefaultRuleTestAllow), &port)); - CHECK(port != MACH_PORT_NULL); - - struct SubstitutePortAckSend msg; - bzero(&msg, sizeof(msg)); - msg.header.msgh_size = sizeof(msg); - msg.header.msgh_remote_port = port; - msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND); - strncpy(msg.buf, kSubstituteAck, sizeof(msg.buf)); - - CHECK_EQ(KERN_SUCCESS, mach_msg_send(&msg.header)); - - return 0; -} - -TEST_F(BootstrapSandboxTest, ChildOutliveSandbox) { - const int kTestPolicyId = 1; - mach_port_t task = mach_task_self(); - - // Create a server port. - mach_port_t port; - ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, - &port)); - base::mac::ScopedMachReceiveRight scoped_port_recv(port); - - ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port, - MACH_MSG_TYPE_MAKE_SEND)); - base::mac::ScopedMachSendRight scoped_port_send(port); - - // Set up the policy and register the port. - BootstrapSandboxPolicy policy(BaselinePolicy()); - policy.rules["sync"] = Rule(port); - sandbox_->RegisterSandboxPolicy(kTestPolicyId, policy); - - // Launch the child. - sandbox_->PrepareToForkWithPolicy(kTestPolicyId); - base::LaunchOptions options; - options.replacement_bootstrap_name = sandbox_->server_bootstrap_name(); - base::Process process = SpawnChildWithOptions("ChildOutliveSandbox", options); - ASSERT_TRUE(process.IsValid()); - sandbox_->FinishedFork(process.Handle()); - - // Synchronize with the child. - mach_msg_empty_rcv_t rcv_msg; - bzero(&rcv_msg, sizeof(rcv_msg)); - kern_return_t kr = mach_msg(&rcv_msg.header, MACH_RCV_MSG, 0, - sizeof(rcv_msg), port, - TestTimeouts::tiny_timeout().InMilliseconds(), MACH_PORT_NULL); - ASSERT_EQ(KERN_SUCCESS, kr) << mach_error_string(kr); - - // Destroy the sandbox. - sandbox_.reset(); - - // Synchronize again with the child. - mach_msg_empty_send_t send_msg; - bzero(&send_msg, sizeof(send_msg)); - send_msg.header.msgh_size = sizeof(send_msg); - send_msg.header.msgh_remote_port = rcv_msg.header.msgh_remote_port; - send_msg.header.msgh_bits = - MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE); - kr = mach_msg(&send_msg.header, MACH_SEND_MSG, send_msg.header.msgh_size, 0, - MACH_PORT_NULL, TestTimeouts::tiny_timeout().InMilliseconds(), - MACH_PORT_NULL); - EXPECT_EQ(KERN_SUCCESS, kr) << mach_error_string(kr); - - int code = 0; - EXPECT_TRUE(process.WaitForExit(&code)); - EXPECT_EQ(0, code); -} - -MULTIPROCESS_TEST_MAIN(ChildOutliveSandbox) { - // Get the synchronization channel. - mach_port_t port = MACH_PORT_NULL; - CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port, "sync", &port)); - - // Create a reply port. - mach_port_t reply_port; - CHECK_EQ(KERN_SUCCESS, mach_port_allocate(mach_task_self(), - MACH_PORT_RIGHT_RECEIVE, &reply_port)); - base::mac::ScopedMachReceiveRight scoped_reply_port(reply_port); - - // Send a message to shutdown the sandbox. - mach_msg_empty_send_t send_msg; - bzero(&send_msg, sizeof(send_msg)); - send_msg.header.msgh_size = sizeof(send_msg); - send_msg.header.msgh_local_port = reply_port; - send_msg.header.msgh_remote_port = port; - send_msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, - MACH_MSG_TYPE_MAKE_SEND_ONCE); - kern_return_t kr = mach_msg_send(&send_msg.header); - MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_msg_send"; - - // Flood the server's message queue with messages. There should be some - // pending when the sandbox is destroyed. - for (int i = 0; i < 20; ++i) { - mach_port_t tmp = MACH_PORT_NULL; - std::string name = base::StringPrintf("test.%d", i); - bootstrap_look_up(bootstrap_port, const_cast<char*>(name.c_str()), &tmp); - } - - // Ack that the sandbox has been shutdown. - mach_msg_empty_rcv_t rcv_msg; - bzero(&rcv_msg, sizeof(rcv_msg)); - rcv_msg.header.msgh_size = sizeof(rcv_msg); - rcv_msg.header.msgh_local_port = reply_port; - kr = mach_msg_receive(&rcv_msg.header); - MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_msg_receive"; - - // Try to message the sandbox. - bootstrap_look_up(bootstrap_port, "test", &port); - - return 0; -} - -} // namespace sandbox |