Commit b25043dd authored by Greg Kerr's avatar Greg Kerr Committed by Commit Bot

macOS Sandbox: Add unit test for pasteboard in sandboxed processes.

This converts the V1 unit test, checking pasteboard access in sandboxed
processes, to the V2 sandbox.

Bug: 902597
Change-Id: Id11e2c597a55f9e66f45d1edf6b7c7bcb8396f57
Reviewed-on: https://chromium-review.googlesource.com/c/1327545
Commit-Queue: Greg Kerr <kerrnel@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611202}
parent 033021e6
......@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
#include "base/strings/stringprintf.h"
......@@ -14,11 +18,19 @@
#include "content/browser/sandbox_parameters_mac.h"
#include "sandbox/mac/seatbelt.h"
#include "sandbox/mac/seatbelt_exec.h"
#include "services/service_manager/sandbox/mac/audio.sb.h"
#include "services/service_manager/sandbox/mac/cdm.sb.h"
#include "services/service_manager/sandbox/mac/common_v2.sb.h"
#include "services/service_manager/sandbox/mac/gpu_v2.sb.h"
#include "services/service_manager/sandbox/mac/nacl_loader.sb.h"
#include "services/service_manager/sandbox/mac/pdf_compositor.sb.h"
#include "services/service_manager/sandbox/mac/ppapi_v2.sb.h"
#include "services/service_manager/sandbox/mac/renderer_v2.sb.h"
#include "services/service_manager/sandbox/mac/utility.sb.h"
#include "services/service_manager/sandbox/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
#import "ui/base/clipboard/clipboard_util_mac.h"
namespace content {
namespace {
......@@ -27,6 +39,7 @@ namespace {
// and is safe since this is only a unit test.
constexpr char kTempDirSuffix[] =
"(allow file* (subpath \"/private/var/folders\"))";
constexpr char kClipboardArg[] = "pasteboard-name";
class SandboxMacTest : public base::MultiProcessTest {
protected:
......@@ -37,9 +50,115 @@ class SandboxMacTest : public base::MultiProcessTest {
return cl;
}
std::string ProfileForSandbox(const std::string& sandbox_profile) {
return std::string(service_manager::kSeatbeltPolicyString_common_v2) +
sandbox_profile + kTempDirSuffix;
}
void ExecuteWithParams(const std::string& procname,
const std::string& sub_profile,
void (*setup)(sandbox::SeatbeltExecClient*)) {
std::string profile = ProfileForSandbox(sub_profile);
sandbox::SeatbeltExecClient client;
client.SetProfile(profile);
setup(&client);
pipe_ = client.GetReadFD();
ASSERT_GE(pipe_, 0);
base::LaunchOptions options;
options.fds_to_remap.push_back(std::make_pair(pipe_, pipe_));
base::Process process = SpawnChildWithOptions(procname, options);
ASSERT_TRUE(process.IsValid());
ASSERT_TRUE(client.SendProfile());
int rv = -1;
ASSERT_TRUE(base::WaitForMultiprocessTestChildExit(
process, TestTimeouts::action_timeout(), &rv));
EXPECT_EQ(0, rv);
}
void ExecuteInAudioSandbox(const std::string& procname) {
ExecuteWithParams(procname, service_manager::kSeatbeltPolicyString_audio,
&content::SetupCommonSandboxParameters);
}
void ExecuteInCDMSandbox(const std::string& procname) {
ExecuteWithParams(procname, service_manager::kSeatbeltPolicyString_cdm,
&content::SetupCDMSandboxParameters);
}
void ExecuteInGPUSandbox(const std::string& procname) {
ExecuteWithParams(procname, service_manager::kSeatbeltPolicyString_gpu_v2,
&content::SetupCommonSandboxParameters);
}
void ExecuteInNaClSandbox(const std::string& procname) {
ExecuteWithParams(procname,
service_manager::kSeatbeltPolicyString_nacl_loader,
&content::SetupCommonSandboxParameters);
}
void ExecuteInPDFSandbox(const std::string& procname) {
ExecuteWithParams(procname,
service_manager::kSeatbeltPolicyString_pdf_compositor,
&content::SetupCommonSandboxParameters);
}
void ExecuteInPpapiSandbox(const std::string& procname) {
ExecuteWithParams(procname, service_manager::kSeatbeltPolicyString_ppapi_v2,
&content::SetupPPAPISandboxParameters);
}
void ExecuteInRendererSandbox(const std::string& procname) {
ExecuteWithParams(procname,
service_manager::kSeatbeltPolicyString_renderer_v2,
&content::SetupCommonSandboxParameters);
}
void ExecuteInUtilitySandbox(const std::string& procname) {
ExecuteWithParams(procname, service_manager::kSeatbeltPolicyString_utility,
[](sandbox::SeatbeltExecClient* client) -> void {
content::SetupUtilitySandboxParameters(
client, *base::CommandLine::ForCurrentProcess());
});
}
void ExecuteInAllSandboxTypes(const std::string& multiprocess_main,
base::RepeatingClosure after_each) {
using ExecuteFuncT = void (SandboxMacTest::*)(const std::string&);
constexpr ExecuteFuncT kExecuteFuncs[] = {
&SandboxMacTest::ExecuteInAudioSandbox,
&SandboxMacTest::ExecuteInCDMSandbox,
&SandboxMacTest::ExecuteInGPUSandbox,
&SandboxMacTest::ExecuteInNaClSandbox,
&SandboxMacTest::ExecuteInPDFSandbox,
&SandboxMacTest::ExecuteInPpapiSandbox,
&SandboxMacTest::ExecuteInRendererSandbox,
&SandboxMacTest::ExecuteInUtilitySandbox,
};
for (ExecuteFuncT execute_func : kExecuteFuncs) {
(this->*execute_func)(multiprocess_main);
after_each.Run();
}
}
int pipe_{0};
};
class SandboxMacClipboardTest : public SandboxMacTest {
protected:
base::CommandLine MakeCmdLine(const std::string& procname) override {
base::CommandLine cl = SandboxMacTest::MakeCmdLine(procname);
cl.AppendSwitchASCII(kClipboardArg, pasteboard_name_);
return cl;
}
std::string pasteboard_name_{};
};
void CheckCreateSeatbeltServer() {
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
const base::CommandLine::StringVector& argv = cl->argv();
......@@ -72,29 +191,35 @@ MULTIPROCESS_TEST_MAIN(RendererWriteProcess) {
}
TEST_F(SandboxMacTest, RendererCannotWriteHomeDir) {
std::string profile =
std::string(service_manager::kSeatbeltPolicyString_common_v2) +
service_manager::kSeatbeltPolicyString_renderer_v2 + kTempDirSuffix;
ExecuteInRendererSandbox("RendererWriteProcess");
}
sandbox::SeatbeltExecClient client;
client.SetProfile(profile);
content::SetupCommonSandboxParameters(&client);
MULTIPROCESS_TEST_MAIN(ClipboardAccessProcess) {
CheckCreateSeatbeltServer();
pipe_ = client.GetReadFD();
ASSERT_GE(pipe_, 0);
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
std::string pasteboard_name = cl->GetSwitchValueASCII(kClipboardArg);
CHECK(!pasteboard_name.empty());
CHECK([NSPasteboard pasteboardWithName:base::SysUTF8ToNSString(
pasteboard_name)] == nil);
CHECK([NSPasteboard generalPasteboard] == nil);
return 0;
}
base::LaunchOptions options;
options.fds_to_remap.push_back(std::make_pair(pipe_, pipe_));
TEST_F(SandboxMacClipboardTest, ClipboardAccess) {
scoped_refptr<ui::UniquePasteboard> pb = new ui::UniquePasteboard;
ASSERT_TRUE(pb->get());
EXPECT_EQ([[pb->get() types] count], 0U);
base::Process process =
SpawnChildWithOptions("RendererWriteProcess", options);
ASSERT_TRUE(process.IsValid());
ASSERT_TRUE(client.SendProfile());
pasteboard_name_ = base::SysNSStringToUTF8([pb->get() name]);
int rv = -1;
ASSERT_TRUE(base::WaitForMultiprocessTestChildExit(
process, TestTimeouts::action_timeout(), &rv));
EXPECT_EQ(0, rv);
ExecuteInAllSandboxTypes("ClipboardAccessProcess",
base::BindRepeating(
[](scoped_refptr<ui::UniquePasteboard> pb) {
ASSERT_EQ([[pb->get() types] count], 0U);
},
pb));
}
} // namespace content
......@@ -19,113 +19,6 @@
namespace content {
//--------------------- Clipboard Sandboxing ----------------------
// Test case for checking sandboxing of clipboard access.
class MacSandboxedClipboardTestCase : public MacSandboxTestCase {
public:
MacSandboxedClipboardTestCase();
~MacSandboxedClipboardTestCase() override;
bool SandboxedTest() override;
void SetTestData(const char* test_data) override;
private:
NSString* clipboard_name_;
};
REGISTER_SANDBOX_TEST_CASE(MacSandboxedClipboardTestCase);
MacSandboxedClipboardTestCase::MacSandboxedClipboardTestCase() :
clipboard_name_(nil) {}
MacSandboxedClipboardTestCase::~MacSandboxedClipboardTestCase() {
[clipboard_name_ release];
}
bool MacSandboxedClipboardTestCase::SandboxedTest() {
// Shouldn't be able to open the pasteboard in the sandbox.
if ([clipboard_name_ length] == 0) {
LOG(ERROR) << "Clipboard name is empty";
return false;
}
NSPasteboard* pb = [NSPasteboard pasteboardWithName:clipboard_name_];
if (pb != nil) {
LOG(ERROR) << "Was able to access named clipboard";
return false;
}
pb = [NSPasteboard generalPasteboard];
if (pb != nil) {
LOG(ERROR) << "Was able to access system clipboard";
return false;
}
return true;
}
void MacSandboxedClipboardTestCase::SetTestData(const char* test_data) {
clipboard_name_ = [base::SysUTF8ToNSString(test_data) retain];
}
TEST_F(MacSandboxTest, ClipboardAccess) {
scoped_refptr<ui::UniquePasteboard> pb = new ui::UniquePasteboard;
ASSERT_TRUE(pb->get());
EXPECT_EQ([[pb->get() types] count], 0U);
std::string pasteboard_name = base::SysNSStringToUTF8([pb->get() name]);
EXPECT_TRUE(RunTestInAllSandboxTypes("MacSandboxedClipboardTestCase",
pasteboard_name.c_str()));
// After executing the test, the clipboard should still be empty.
EXPECT_EQ([[pb->get() types] count], 0U);
}
//--------------------- File Access Sandboxing ----------------------
// Test case for checking sandboxing of filesystem apis.
class MacSandboxedFileAccessTestCase : public MacSandboxTestCase {
public:
bool SandboxedTest() override;
};
REGISTER_SANDBOX_TEST_CASE(MacSandboxedFileAccessTestCase);
bool MacSandboxedFileAccessTestCase::SandboxedTest() {
base::ScopedFD fdes(HANDLE_EINTR(open("/etc/passwd", O_RDONLY)));
return !fdes.is_valid();
}
TEST_F(MacSandboxTest, FileAccess) {
EXPECT_TRUE(RunTestInAllSandboxTypes("MacSandboxedFileAccessTestCase", NULL));
}
//--------------------- /dev/urandom Sandboxing ----------------------
// /dev/urandom is available to any sandboxed process.
class MacSandboxedUrandomTestCase : public MacSandboxTestCase {
public:
bool SandboxedTest() override;
};
REGISTER_SANDBOX_TEST_CASE(MacSandboxedUrandomTestCase);
bool MacSandboxedUrandomTestCase::SandboxedTest() {
base::ScopedFD fdes(HANDLE_EINTR(open("/dev/urandom", O_RDONLY)));
// Opening /dev/urandom succeeds under the sandbox.
if (!fdes.is_valid())
return false;
char buf[16];
int rc = HANDLE_EINTR(read(fdes.get(), buf, sizeof(buf)));
return rc == sizeof(buf);
}
TEST_F(MacSandboxTest, UrandomAccess) {
EXPECT_TRUE(RunTestInAllSandboxTypes("MacSandboxedUrandomTestCase", NULL));
}
//--------------------- OpenSSL Sandboxing ----------------------
// Test case for checking sandboxing of OpenSSL initialization.
class MacSandboxedOpenSSLTestCase : public MacSandboxTestCase {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment