mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
This change introduces internal experimental support for Android.
PiperOrigin-RevId: 453669315 Change-Id: I6c3278804071caa2bb347cfeb584975339cb50d5
This commit is contained in:
parent
a8a558c66d
commit
598b00103a
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <sys/resource.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
|
@ -42,8 +43,13 @@ using ::sapi::GetTestSourcePath;
|
|||
using ::testing::Eq;
|
||||
|
||||
PolicyBuilder CreatePolicyTestPolicyBuilder() {
|
||||
return PolicyBuilder()
|
||||
.DisableNamespaces()
|
||||
sandbox2::PolicyBuilder builder;
|
||||
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.AllowDynamicStartup();
|
||||
}
|
||||
|
||||
builder.DisableNamespaces()
|
||||
.AllowStaticStartup()
|
||||
.AllowExit()
|
||||
.AllowRead()
|
||||
|
@ -66,6 +72,7 @@ PolicyBuilder CreatePolicyTestPolicyBuilder() {
|
|||
},
|
||||
ENOENT)
|
||||
.BlockSyscallWithErrno(__NR_prlimit64, EPERM);
|
||||
return builder;
|
||||
}
|
||||
|
||||
std::unique_ptr<Policy> PolicyTestcasePolicy() {
|
||||
|
@ -75,6 +82,7 @@ std::unique_ptr<Policy> PolicyTestcasePolicy() {
|
|||
#ifdef SAPI_X86_64
|
||||
// Test that 32-bit syscalls from 64-bit are disallowed.
|
||||
TEST(PolicyTest, AMD64Syscall32PolicyAllowed) {
|
||||
SKIP_ANDROID;
|
||||
SKIP_SANITIZERS_AND_COVERAGE;
|
||||
const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
|
||||
|
||||
|
@ -89,6 +97,7 @@ TEST(PolicyTest, AMD64Syscall32PolicyAllowed) {
|
|||
|
||||
// Test that 32-bit syscalls from 64-bit for FS checks are disallowed.
|
||||
TEST(PolicyTest, AMD64Syscall32FsAllowed) {
|
||||
SKIP_ANDROID;
|
||||
SKIP_SANITIZERS_AND_COVERAGE;
|
||||
const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
|
||||
std::vector<std::string> args = {path, "2"};
|
||||
|
@ -182,20 +191,27 @@ TEST(PolicyTest, IsattyAllowed) {
|
|||
}
|
||||
|
||||
std::unique_ptr<Policy> MinimalTestcasePolicy() {
|
||||
return PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowExit()
|
||||
sandbox2::PolicyBuilder builder;
|
||||
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.AllowDynamicStartup();
|
||||
builder.DisableNamespaces();
|
||||
}
|
||||
|
||||
builder.AllowStaticStartup()
|
||||
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
|
||||
#ifdef __NR_access
|
||||
.BlockSyscallWithErrno(__NR_access, ENOENT)
|
||||
#endif
|
||||
.BuildOrDie();
|
||||
.AllowExit();
|
||||
return builder.BuildOrDie();
|
||||
}
|
||||
|
||||
// Test that we can sandbox a minimal static binary returning 0.
|
||||
// If this starts failing, it means something changed, maybe in the way we
|
||||
// compile static binaries, and we need to update the policy just above.
|
||||
TEST(MinimalTest, MinimalBinaryWorks) {
|
||||
SKIP_ANDROID;
|
||||
SKIP_SANITIZERS_AND_COVERAGE;
|
||||
const std::string path = GetTestSourcePath("sandbox2/testcases/minimal");
|
||||
std::vector<std::string> args = {path};
|
||||
|
@ -213,18 +229,24 @@ TEST(MinimalTest, MinimalSharedBinaryWorks) {
|
|||
GetTestSourcePath("sandbox2/testcases/minimal_dynamic");
|
||||
std::vector<std::string> args = {path};
|
||||
|
||||
auto policy = PolicyBuilder()
|
||||
.AllowDynamicStartup()
|
||||
.AllowOpen()
|
||||
.AllowExit()
|
||||
.AllowMmap()
|
||||
sandbox2::PolicyBuilder builder;
|
||||
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.DisableNamespaces();
|
||||
} else {
|
||||
builder.AddLibrariesForBinary(path);
|
||||
}
|
||||
|
||||
builder.AllowDynamicStartup()
|
||||
.AllowOpen()
|
||||
.AllowExit()
|
||||
.AllowMmap()
|
||||
#ifdef __NR_access
|
||||
// New glibc accesses /etc/ld.so.preload
|
||||
.BlockSyscallWithErrno(__NR_access, ENOENT)
|
||||
// New glibc accesses /etc/ld.so.preload
|
||||
.BlockSyscallWithErrno(__NR_access, ENOENT)
|
||||
#endif
|
||||
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
|
||||
.AddLibrariesForBinary(path)
|
||||
.BuildOrDie();
|
||||
.BlockSyscallWithErrno(__NR_prlimit64, EPERM);
|
||||
auto policy = builder.BuildOrDie();
|
||||
|
||||
Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
|
||||
auto result = s2.Run();
|
||||
|
@ -240,15 +262,24 @@ TEST(MallocTest, SystemMallocWorks) {
|
|||
GetTestSourcePath("sandbox2/testcases/malloc_system");
|
||||
std::vector<std::string> args = {path};
|
||||
|
||||
auto policy = PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
|
||||
sandbox2::PolicyBuilder builder;
|
||||
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.DisableNamespaces();
|
||||
builder.AllowDynamicStartup();
|
||||
builder.AllowSyscalls({
|
||||
__NR_madvise,
|
||||
});
|
||||
}
|
||||
|
||||
builder.AllowStaticStartup()
|
||||
.AllowSystemMalloc()
|
||||
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
|
||||
#ifdef __NR_access
|
||||
.BlockSyscallWithErrno(__NR_access, ENOENT)
|
||||
.BlockSyscallWithErrno(__NR_access, ENOENT)
|
||||
#endif
|
||||
.BuildOrDie();
|
||||
.AllowExit();
|
||||
auto policy = builder.BuildOrDie();
|
||||
|
||||
Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
|
||||
auto result = s2.Run();
|
||||
|
@ -268,57 +299,62 @@ TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
|
|||
GetTestSourcePath("sandbox2/testcases/add_policy_on_syscalls");
|
||||
std::vector<std::string> args = {path};
|
||||
|
||||
auto policy = PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowTcMalloc()
|
||||
.AllowExit()
|
||||
.AddPolicyOnSyscalls(
|
||||
{
|
||||
__NR_getuid,
|
||||
__NR_getgid,
|
||||
__NR_geteuid,
|
||||
__NR_getegid,
|
||||
sandbox2::PolicyBuilder builder;
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.DisableNamespaces();
|
||||
builder.AllowDynamicStartup();
|
||||
}
|
||||
|
||||
builder.AllowStaticStartup()
|
||||
.AllowTcMalloc()
|
||||
.AllowExit()
|
||||
.AddPolicyOnSyscalls(
|
||||
{
|
||||
__NR_getuid,
|
||||
__NR_getgid,
|
||||
__NR_geteuid,
|
||||
__NR_getegid,
|
||||
#ifdef __NR_getuid32
|
||||
__NR_getuid32,
|
||||
__NR_getuid32,
|
||||
#endif
|
||||
#ifdef __NR_getgid32
|
||||
__NR_getgid32,
|
||||
__NR_getgid32,
|
||||
#endif
|
||||
#ifdef __NR_geteuid32
|
||||
__NR_geteuid32,
|
||||
__NR_geteuid32,
|
||||
#endif
|
||||
#ifdef __NR_getegid32
|
||||
__NR_getegid32,
|
||||
__NR_getegid32,
|
||||
#endif
|
||||
},
|
||||
{ALLOW})
|
||||
.AddPolicyOnSyscalls(
|
||||
{
|
||||
__NR_getresuid,
|
||||
__NR_getresgid,
|
||||
},
|
||||
{ALLOW})
|
||||
.AddPolicyOnSyscalls(
|
||||
{
|
||||
__NR_getresuid,
|
||||
__NR_getresgid,
|
||||
#ifdef __NR_getresuid32
|
||||
__NR_getresuid32,
|
||||
__NR_getresuid32,
|
||||
#endif
|
||||
#ifdef __NR_getresgid32
|
||||
__NR_getresgid32,
|
||||
__NR_getresgid32,
|
||||
#endif
|
||||
},
|
||||
{ERRNO(42)})
|
||||
.AddPolicyOnSyscalls({__NR_read, __NR_write}, {ERRNO(43)})
|
||||
.AddPolicyOnSyscall(__NR_umask, {DENY})
|
||||
.BlockSyscallsWithErrno(
|
||||
{
|
||||
},
|
||||
{ERRNO(42)})
|
||||
.AddPolicyOnSyscalls({__NR_read, __NR_write}, {ERRNO(43)})
|
||||
.AddPolicyOnSyscall(__NR_umask, {DENY})
|
||||
.BlockSyscallsWithErrno(
|
||||
{
|
||||
#ifdef __NR_open
|
||||
__NR_open,
|
||||
__NR_open,
|
||||
#endif
|
||||
__NR_openat,
|
||||
__NR_openat,
|
||||
#ifdef __NR_access
|
||||
__NR_access,
|
||||
__NR_access,
|
||||
#endif
|
||||
},
|
||||
ENOENT)
|
||||
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
|
||||
.BuildOrDie();
|
||||
},
|
||||
ENOENT)
|
||||
.BlockSyscallWithErrno(__NR_prlimit64, EPERM);
|
||||
auto policy = builder.BuildOrDie();
|
||||
|
||||
Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
|
||||
auto result = s2.Run();
|
||||
|
|
|
@ -724,6 +724,77 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
|
|||
}
|
||||
|
||||
PolicyBuilder& PolicyBuilder::AllowDynamicStartup() {
|
||||
#ifdef __ANDROID__
|
||||
AllowAccess();
|
||||
AllowSafeFcntl();
|
||||
AllowGetIDs();
|
||||
AllowGetPIDs();
|
||||
AllowGetRandom();
|
||||
AllowOpen();
|
||||
AllowSyscalls({
|
||||
#ifdef __NR_fstatfs
|
||||
__NR_fstatfs,
|
||||
#endif
|
||||
#ifdef __NR_fstatfs64
|
||||
__NR_fstatfs64,
|
||||
#endif
|
||||
__NR_readlinkat,
|
||||
__NR_sched_getaffinity,
|
||||
__NR_sched_getscheduler,
|
||||
});
|
||||
AllowHandleSignals();
|
||||
AllowFutexOp(FUTEX_WAKE_PRIVATE);
|
||||
AddPolicyOnSyscall(__NR_prctl,
|
||||
[](bpf_labels& labels) -> std::vector<sock_filter> {
|
||||
return {
|
||||
ARG_32(0), // option
|
||||
JEQ32(PR_GET_DUMPABLE, ALLOW),
|
||||
JNE32(PR_SET_VMA, JUMP(&labels, prctl_end)),
|
||||
|
||||
ARG_32(1), // arg2
|
||||
JEQ32(PR_SET_VMA_ANON_NAME, ALLOW),
|
||||
|
||||
LABEL(&labels, prctl_end),
|
||||
};
|
||||
});
|
||||
AddPolicyOnSyscall(__NR_mremap,
|
||||
{
|
||||
ARG_32(3),
|
||||
JEQ32(MREMAP_MAYMOVE | MREMAP_FIXED, ALLOW),
|
||||
});
|
||||
AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
|
||||
return {
|
||||
ARG_32(2), // prot
|
||||
JEQ32(PROT_NONE, JUMP(&labels, prot_none)),
|
||||
JEQ32(PROT_READ, JUMP(&labels, prot_read)),
|
||||
JEQ32(PROT_READ | PROT_WRITE, JUMP(&labels, prot_RW_or_RX)),
|
||||
JEQ32(PROT_READ | PROT_EXEC, JUMP(&labels, prot_RW_or_RX)),
|
||||
|
||||
// PROT_NONE
|
||||
LABEL(&labels, prot_none),
|
||||
ARG_32(3), // flags
|
||||
JEQ32(MAP_PRIVATE | MAP_ANONYMOUS, ALLOW),
|
||||
JEQ32(MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, ALLOW),
|
||||
JUMP(&labels, mmap_end),
|
||||
|
||||
// PROT_READ
|
||||
LABEL(&labels, prot_read),
|
||||
ARG_32(3), // flags
|
||||
JEQ32(MAP_SHARED, ALLOW),
|
||||
JEQ32(MAP_PRIVATE, ALLOW),
|
||||
JEQ32(MAP_PRIVATE | MAP_FIXED, ALLOW),
|
||||
JUMP(&labels, mmap_end),
|
||||
|
||||
// PROT_READ | PROT_WRITE
|
||||
// PROT_READ | PROT_EXEC
|
||||
LABEL(&labels, prot_RW_or_RX),
|
||||
ARG_32(3), // flags
|
||||
JEQ32(MAP_PRIVATE | MAP_FIXED, ALLOW),
|
||||
|
||||
LABEL(&labels, mmap_end),
|
||||
};
|
||||
});
|
||||
#endif
|
||||
|
||||
AllowRead();
|
||||
AllowStat();
|
||||
|
|
|
@ -73,7 +73,8 @@ using ::sapi::StatusIs;
|
|||
|
||||
class PolicyBuilderTest : public testing::Test {
|
||||
protected:
|
||||
static std::string Run(std::vector<std::string> args, bool network = false);
|
||||
static std::string Run(const std::vector<std::string>& args,
|
||||
bool network = false);
|
||||
};
|
||||
|
||||
TEST_F(PolicyBuilderTest, Testpolicy_size) {
|
||||
|
@ -157,12 +158,18 @@ TEST_F(PolicyBuilderTest, TestValidateAbsolutePath) {
|
|||
}
|
||||
}
|
||||
|
||||
std::string PolicyBuilderTest::Run(std::vector<std::string> args,
|
||||
std::string PolicyBuilderTest::Run(const std::vector<std::string>& args,
|
||||
bool network) {
|
||||
PolicyBuilder builder;
|
||||
// Don't restrict the syscalls at all.
|
||||
builder.DangerDefaultAllowAll();
|
||||
builder.AddLibrariesForBinary(args[0]);
|
||||
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.DisableNamespaces();
|
||||
} else {
|
||||
builder.AddLibrariesForBinary(args[0]);
|
||||
}
|
||||
|
||||
if (network) {
|
||||
builder.AllowUnrestrictedNetworking();
|
||||
}
|
||||
|
@ -216,6 +223,7 @@ TEST_F(PolicyBuilderTest, TestEcho) {
|
|||
}
|
||||
|
||||
TEST_F(PolicyBuilderTest, TestInterfacesNoNetwork) {
|
||||
SKIP_ANDROID;
|
||||
auto lines = absl::StrSplit(Run({"/sbin/ip", "addr", "show", "up"}), '\n');
|
||||
|
||||
int count = 0;
|
||||
|
@ -230,6 +238,7 @@ TEST_F(PolicyBuilderTest, TestInterfacesNoNetwork) {
|
|||
}
|
||||
|
||||
TEST_F(PolicyBuilderTest, TestInterfacesNetwork) {
|
||||
SKIP_ANDROID;
|
||||
auto lines =
|
||||
absl::StrSplit(Run({"/sbin/ip", "addr", "show", "up"}, true), '\n');
|
||||
|
||||
|
@ -245,11 +254,19 @@ TEST_F(PolicyBuilderTest, TestInterfacesNetwork) {
|
|||
}
|
||||
|
||||
TEST_F(PolicyBuilderTest, TestUid) {
|
||||
EXPECT_THAT(Run({"/usr/bin/id", "-u"}), StrEq("1000\n"));
|
||||
if constexpr (!sapi::host_os::IsAndroid()) {
|
||||
EXPECT_THAT(Run({"/usr/bin/id", "-u"}), StrEq("1000\n"));
|
||||
} else {
|
||||
EXPECT_THAT(Run({"/bin/id", "-u"}), StrEq("0\n"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PolicyBuilderTest, TestGid) {
|
||||
EXPECT_THAT(Run({"/usr/bin/id", "-g"}), StrEq("1000\n"));
|
||||
if constexpr (!sapi::host_os::IsAndroid()) {
|
||||
EXPECT_THAT(Run({"/usr/bin/id", "-g"}), StrEq("1000\n"));
|
||||
} else {
|
||||
EXPECT_THAT(Run({"/bin/id", "-g"}), StrEq("0\n"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PolicyBuilderTest, TestOpenFds) {
|
||||
|
|
|
@ -117,26 +117,6 @@ TEST(ExecutorTest, ExecutorFdConstructor) {
|
|||
ASSERT_EQ(result.final_status(), Result::OK);
|
||||
}
|
||||
|
||||
TEST(StackTraceTest, StackTraceOnExitWorks) {
|
||||
SKIP_SANITIZERS_AND_COVERAGE;
|
||||
|
||||
const std::string path = GetTestSourcePath("sandbox2/testcases/minimal");
|
||||
std::vector<std::string> args = {path};
|
||||
auto executor = absl::make_unique<Executor>(path, args);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
|
||||
PolicyBuilder()
|
||||
// Don't restrict the syscalls at all.
|
||||
.DangerDefaultAllowAll()
|
||||
.CollectStacktracesOnExit(true)
|
||||
.TryBuild());
|
||||
Sandbox2 sandbox(std::move(executor), std::move(policy));
|
||||
auto result = sandbox.Run();
|
||||
|
||||
ASSERT_EQ(result.final_status(), Result::OK);
|
||||
EXPECT_THAT(result.stack_trace(), Not(IsEmpty()));
|
||||
}
|
||||
|
||||
// Tests that we return the correct state when the sandboxee was killed by an
|
||||
// external signal. Also make sure that we do not have the stack trace.
|
||||
TEST(RunAsyncTest, SandboxeeExternalKill) {
|
||||
|
@ -162,6 +142,7 @@ TEST(RunAsyncTest, SandboxeeExternalKill) {
|
|||
|
||||
// Tests that we return the correct state when the sandboxee timed out.
|
||||
TEST(RunAsyncTest, SandboxeeTimeoutWithStacktraces) {
|
||||
SKIP_ANDROID;
|
||||
const std::string path = GetTestSourcePath("sandbox2/testcases/sleep");
|
||||
|
||||
std::vector<std::string> args = {path};
|
||||
|
@ -193,28 +174,6 @@ TEST(RunAsyncTest, SandboxeeTimeoutDisabledStacktraces) {
|
|||
PolicyBuilder()
|
||||
// Don't restrict the syscalls at all.
|
||||
.DangerDefaultAllowAll()
|
||||
.CollectStacktracesOnTimeout(false)
|
||||
.TryBuild());
|
||||
Sandbox2 sandbox(std::move(executor), std::move(policy));
|
||||
ASSERT_TRUE(sandbox.RunAsync());
|
||||
sandbox.set_walltime_limit(absl::Seconds(1));
|
||||
auto result = sandbox.AwaitResult();
|
||||
EXPECT_EQ(result.final_status(), Result::TIMEOUT);
|
||||
EXPECT_THAT(result.GetStackTrace(), IsEmpty());
|
||||
}
|
||||
|
||||
// Tests that we do not collect stack traces if it was disabled (violation).
|
||||
TEST(RunAsyncTest, SandboxeeViolationDisabledStacktraces) {
|
||||
const std::string path = GetTestSourcePath("sandbox2/testcases/sleep");
|
||||
|
||||
std::vector<std::string> args = {path};
|
||||
std::vector<std::string> envs;
|
||||
auto executor = absl::make_unique<Executor>(path, args, envs);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
auto policy, PolicyBuilder()
|
||||
// Don't allow anything - Make sure that we'll crash.
|
||||
.CollectStacktracesOnViolation(false)
|
||||
.TryBuild());
|
||||
Sandbox2 sandbox(std::move(executor), std::move(policy));
|
||||
ASSERT_TRUE(sandbox.RunAsync());
|
||||
|
|
|
@ -20,6 +20,22 @@
|
|||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
// The macro SKIP_ANDROID can be used in tests to skip running a
|
||||
// given test (by emitting 'retrun') when running on Android. Example:
|
||||
//
|
||||
// TEST(Foo, Bar) {
|
||||
// SKIP_ANDROID;
|
||||
// [...]
|
||||
// }
|
||||
//
|
||||
// The reason for this is because certain unit tests require the use of user
|
||||
// namespaces which are not present on Android.
|
||||
#if defined(__ANDROID__)
|
||||
#define SKIP_ANDROID return
|
||||
#else
|
||||
#define SKIP_ANDROID
|
||||
#endif
|
||||
|
||||
// The macro SKIP_SANITIZERS_AND_COVERAGE can be used in tests to skip running
|
||||
// a given test (by emitting 'return') when running under one of the sanitizers
|
||||
// (ASan, MSan, TSan) or under code coverage. Example:
|
||||
|
|
Loading…
Reference in New Issue
Block a user