Run more tests with coverage enabled

PiperOrigin-RevId: 561575508
Change-Id: Ifc9a678b6a6cbcd892a1f8710b941514eb1d9764
pull/171/head
Wiktor Garbacz 2023-08-31 00:43:30 -07:00 committed by Copybara-Service
parent 47c868e6b1
commit f715bd8ba9
9 changed files with 124 additions and 62 deletions

View File

@ -23,9 +23,12 @@ exports_files(["LICENSE"])
cc_library(
name = "config",
srcs = ["config.cc"],
hdrs = ["config.h"],
copts = sapi_platform_copts(),
deps = ["@com_google_absl//absl/base:config"],
deps = [
"@com_google_absl//absl/base:config",
],
)
sapi_proto_library(

View File

@ -22,12 +22,13 @@ add_subdirectory(examples)
# sandboxed_api:config
add_library(sapi_config ${SAPI_LIB_TYPE}
config.cc
config.h
)
add_library(sapi::config ALIAS sapi_config)
target_link_libraries(sapi_config
PRIVATE sapi::base
INTERFACE absl::config
PUBLIC absl::config
)
# sandboxed_api:proto_arg

11
sandboxed_api/config.cc Normal file
View File

@ -0,0 +1,11 @@
#include "sandboxed_api/config.h"
#include <cstdlib>
namespace sapi {
bool IsCoverageRun() {
return getenv("COVERAGE") != nullptr;
}
} // namespace sapi

View File

@ -17,9 +17,8 @@
#include <features.h>
#include <cstdint>
#include <string>
#include "absl/base/config.h"
#include "absl/base/config.h" // IWYU pragma: keep
// GCC/Clang define __x86_64__, Visual Studio uses _M_X64
#if defined(__x86_64__) || defined(_M_X64)
@ -43,6 +42,9 @@
namespace sapi {
// Returns whether the executable running under code coverage.
bool IsCoverageRun();
namespace cpu {
// CPU architectures known to Sandbox2

View File

@ -136,7 +136,7 @@ TEST(PolicyTest, BpfPtracePermissionDenied) {
}
TEST(PolicyTest, IsattyAllowed) {
SKIP_SANITIZERS_AND_COVERAGE;
SKIP_SANITIZERS;
sandbox2::PolicyBuilder builder;
if constexpr (sapi::host_os::IsAndroid()) {
builder.DisableNamespaces().AllowDynamicStartup();
@ -145,7 +145,8 @@ TEST(PolicyTest, IsattyAllowed) {
.AllowExit()
.AllowRead()
.AllowWrite()
.AllowTCGETS();
.AllowTCGETS()
.AllowLlvmCoverage();
const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
std::vector<std::string> args = {path, "6"};
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
@ -155,7 +156,7 @@ TEST(PolicyTest, IsattyAllowed) {
ASSERT_THAT(result.final_status(), Eq(Result::OK));
}
std::unique_ptr<Policy> MinimalTestcasePolicy() {
std::unique_ptr<Policy> MinimalTestcasePolicy(absl::string_view path = "") {
sandbox2::PolicyBuilder builder;
if constexpr (sapi::host_os::IsAndroid()) {
@ -163,7 +164,7 @@ std::unique_ptr<Policy> MinimalTestcasePolicy() {
builder.DisableNamespaces();
}
builder.AllowStaticStartup().AllowExit();
builder.AllowStaticStartup().AllowExit().AllowLlvmCoverage();
return builder.BuildOrDie();
}
@ -172,10 +173,11 @@ std::unique_ptr<Policy> MinimalTestcasePolicy() {
// compile static binaries, and we need to update the policy just above.
TEST(MinimalTest, MinimalBinaryWorks) {
SKIP_ANDROID;
SKIP_SANITIZERS_AND_COVERAGE;
SKIP_SANITIZERS;
const std::string path = GetTestSourcePath("sandbox2/testcases/minimal");
std::vector<std::string> args = {path};
Sandbox2 s2(std::make_unique<Executor>(path, args), MinimalTestcasePolicy());
Sandbox2 s2(std::make_unique<Executor>(path, args),
MinimalTestcasePolicy(path));
auto result = s2.Run();
ASSERT_THAT(result.final_status(), Eq(Result::OK));
@ -184,7 +186,7 @@ TEST(MinimalTest, MinimalBinaryWorks) {
// Test that we can sandbox a minimal non-static binary returning 0.
TEST(MinimalTest, MinimalSharedBinaryWorks) {
SKIP_SANITIZERS_AND_COVERAGE;
SKIP_SANITIZERS;
const std::string path =
GetTestSourcePath("sandbox2/testcases/minimal_dynamic");
std::vector<std::string> args = {path};
@ -197,7 +199,7 @@ TEST(MinimalTest, MinimalSharedBinaryWorks) {
builder.AddLibrariesForBinary(path);
}
builder.AllowDynamicStartup().AllowExit();
builder.AllowDynamicStartup().AllowExit().AllowLlvmCoverage();
auto policy = builder.BuildOrDie();
Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
@ -209,7 +211,7 @@ TEST(MinimalTest, MinimalSharedBinaryWorks) {
// Test that the AllowSystemMalloc helper works as expected.
TEST(MallocTest, SystemMallocWorks) {
SKIP_SANITIZERS_AND_COVERAGE;
SKIP_SANITIZERS;
const std::string path =
GetTestSourcePath("sandbox2/testcases/malloc_system");
std::vector<std::string> args = {path};
@ -224,7 +226,10 @@ TEST(MallocTest, SystemMallocWorks) {
});
}
builder.AllowStaticStartup().AllowSystemMalloc().AllowExit();
builder.AllowStaticStartup()
.AllowSystemMalloc()
.AllowExit()
.AllowLlvmCoverage();
auto policy = builder.BuildOrDie();
Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));

View File

@ -34,6 +34,7 @@
#include <cerrno>
#include <csignal>
#include <cstdint>
#include <cstdlib>
#include <deque>
#include <functional>
#include <iterator>
@ -327,47 +328,49 @@ PolicyBuilder& PolicyBuilder::AllowSystemMalloc() {
}
PolicyBuilder& PolicyBuilder::AllowLlvmSanitizers() {
if constexpr (sapi::sanitizers::IsAny()) {
// *san use a custom allocator that runs mmap/unmap under the hood. For
// example:
// https://github.com/llvm/llvm-project/blob/596d534ac3524052df210be8d3c01a33b2260a42/compiler-rt/lib/asan/asan_allocator.cpp#L980
// https://github.com/llvm/llvm-project/blob/62ec4ac90738a5f2d209ed28c822223e58aaaeb7/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h#L98
AllowMmap();
AllowSyscall(__NR_munmap);
// https://github.com/llvm/llvm-project/blob/4bbc3290a25c0dc26007912a96e0f77b2092ee56/compiler-rt/lib/sanitizer_common/sanitizer_stack_store.cpp#L293
AddPolicyOnSyscall(__NR_mprotect,
{
ARG_32(2),
BPF_STMT(BPF_AND | BPF_ALU | BPF_K,
~uint32_t{PROT_READ | PROT_WRITE}),
JEQ32(PROT_NONE, ALLOW),
});
AddPolicyOnSyscall(__NR_madvise, {
ARG_32(2),
JEQ32(MADV_DONTDUMP, ALLOW),
JEQ32(MADV_NOHUGEPAGE, ALLOW),
});
// Sanitizers read from /proc. For example:
// https://github.com/llvm/llvm-project/blob/634da7a1c61ee8c173e90a841eb1f4ea03caa20b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L1155
AddDirectoryIfNamespaced("/proc");
AllowOpen();
// Sanitizers need pid for reports. For example:
// https://github.com/llvm/llvm-project/blob/634da7a1c61ee8c173e90a841eb1f4ea03caa20b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L740
AllowGetPIDs();
// Sanitizers may try color output. For example:
// https://github.com/llvm/llvm-project/blob/87dd3d350c4ce0115b2cdf91d85ddd05ae2661aa/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp#L157
OverridableBlockSyscallWithErrno(__NR_ioctl, EPERM);
// https://github.com/llvm/llvm-project/blob/9aa39481d9eb718e872993791547053a3c1f16d5/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp#L150
// https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_getattr_np.c;h=de7edfa0928224eb8375e2fe894d6677570fbb3b;hb=HEAD#l188
OverridableBlockSyscallWithErrno(__NR_sched_getaffinity, EPERM);
// https://github.com/llvm/llvm-project/blob/02c2b472b510ff55679844c087b66e7837e13dc2/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L434
#ifdef __NR_readlink
OverridableBlockSyscallWithErrno(__NR_readlink, ENOENT);
#endif
OverridableBlockSyscallWithErrno(__NR_readlinkat, ENOENT);
if constexpr (!sapi::sanitizers::IsAny()) {
return *this;
}
// *san use a custom allocator that runs mmap/unmap under the hood. For
// example:
// https://github.com/llvm/llvm-project/blob/596d534ac3524052df210be8d3c01a33b2260a42/compiler-rt/lib/asan/asan_allocator.cpp#L980
// https://github.com/llvm/llvm-project/blob/62ec4ac90738a5f2d209ed28c822223e58aaaeb7/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h#L98
AllowMmap();
AllowSyscall(__NR_munmap);
AllowSyscall(__NR_sched_yield);
// https://github.com/llvm/llvm-project/blob/4bbc3290a25c0dc26007912a96e0f77b2092ee56/compiler-rt/lib/sanitizer_common/sanitizer_stack_store.cpp#L293
AddPolicyOnSyscall(__NR_mprotect,
{
ARG_32(2),
BPF_STMT(BPF_AND | BPF_ALU | BPF_K,
~uint32_t{PROT_READ | PROT_WRITE}),
JEQ32(PROT_NONE, ALLOW),
});
AddPolicyOnSyscall(__NR_madvise, {
ARG_32(2),
JEQ32(MADV_DONTDUMP, ALLOW),
JEQ32(MADV_NOHUGEPAGE, ALLOW),
});
// Sanitizers read from /proc. For example:
// https://github.com/llvm/llvm-project/blob/634da7a1c61ee8c173e90a841eb1f4ea03caa20b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L1155
AddDirectoryIfNamespaced("/proc");
AllowOpen();
// Sanitizers need pid for reports. For example:
// https://github.com/llvm/llvm-project/blob/634da7a1c61ee8c173e90a841eb1f4ea03caa20b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L740
AllowGetPIDs();
// Sanitizers may try color output. For example:
// https://github.com/llvm/llvm-project/blob/87dd3d350c4ce0115b2cdf91d85ddd05ae2661aa/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp#L157
OverridableBlockSyscallWithErrno(__NR_ioctl, EPERM);
// https://github.com/llvm/llvm-project/blob/9aa39481d9eb718e872993791547053a3c1f16d5/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp#L150
// https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_getattr_np.c;h=de7edfa0928224eb8375e2fe894d6677570fbb3b;hb=HEAD#l188
OverridableBlockSyscallWithErrno(__NR_sched_getaffinity, EPERM);
// https://github.com/llvm/llvm-project/blob/02c2b472b510ff55679844c087b66e7837e13dc2/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L434
#ifdef __NR_readlink
OverridableBlockSyscallWithErrno(__NR_readlink, ENOENT);
#endif
OverridableBlockSyscallWithErrno(__NR_readlinkat, ENOENT);
if constexpr (sapi::sanitizers::IsASan()) {
AllowSyscall(__NR_sigaltstack);
}
@ -377,6 +380,37 @@ PolicyBuilder& PolicyBuilder::AllowLlvmSanitizers() {
return *this;
}
PolicyBuilder& PolicyBuilder::AllowLlvmCoverage() {
if (!sapi::IsCoverageRun()) {
return *this;
}
AllowStat();
AllowGetPIDs();
AllowOpen();
AllowRead();
AllowWrite();
AllowMkdir();
AllowSafeFcntl();
AllowSyscalls({
__NR_munmap, __NR_close, __NR_lseek,
#ifdef __NR__llseek
__NR__llseek, // Newer glibc on PPC
#endif
});
AllowTcMalloc();
AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
return {
ARG_32(2), // prot
JNE32(PROT_READ | PROT_WRITE, JUMP(&labels, mmap_end)),
ARG_32(3), // flags
JEQ32(MAP_SHARED, ALLOW),
LABEL(&labels, mmap_end),
};
});
AddDirectoryIfNamespaced(getenv("COVERAGE_DIR"), /*is_ro=*/false);
return *this;
}
PolicyBuilder& PolicyBuilder::AllowLimitedMadvise() {
return AddPolicyOnSyscall(__NR_madvise, {
ARG_32(2),

View File

@ -239,6 +239,10 @@ class PolicyBuilder final {
// all binaries.
PolicyBuilder& AllowLlvmSanitizers();
// Allows system calls typically used by the LLVM coverage.
// This method is intended as a best effort.
PolicyBuilder& AllowLlvmCoverage();
// Appends code to allow mmap. Specifically this allows mmap and mmap2 syscall
// on architectures where this syscalls exist.
PolicyBuilder& AllowMmap();

View File

@ -20,14 +20,11 @@
#include "absl/strings/string_view.h"
#include "sandboxed_api/config.h"
#include "sandboxed_api/sandbox2/allow_all_syscalls.h"
#include "sandboxed_api/sandbox2/policybuilder.h"
#include "sandboxed_api/util/path.h"
namespace sapi {
bool IsCoverageRun() {
return getenv("COVERAGE") != nullptr;
}
sandbox2::PolicyBuilder CreateDefaultPermissiveTestPolicy(
absl::string_view bin_path) {
sandbox2::PolicyBuilder builder;
@ -35,6 +32,7 @@ sandbox2::PolicyBuilder CreateDefaultPermissiveTestPolicy(
builder.DefaultAction(sandbox2::AllowAllSyscalls());
if (sapi::host_os::IsAndroid()) {
builder.DisableNamespaces();
return builder;
}
if (IsCoverageRun()) {
builder.AddDirectory(getenv("COVERAGE_DIR"), /*is_ro=*/false);

View File

@ -18,7 +18,7 @@
#include <string>
#include "absl/strings/string_view.h"
#include "sandboxed_api/config.h"
#include "sandboxed_api/config.h" // IWYU pragma: export
#include "sandboxed_api/sandbox2/policybuilder.h"
// The macro SKIP_ANDROID can be used in tests to skip running a
@ -66,10 +66,14 @@
} \
} while (0)
namespace sapi {
#define SKIP_SANITIZERS \
do { \
if (sapi::sanitizers::IsAny()) { \
return; \
} \
} while (0)
// Returns whether the executable running under code coverage.
bool IsCoverageRun();
namespace sapi {
sandbox2::PolicyBuilder CreateDefaultPermissiveTestPolicy(
absl::string_view bin_path);