summaryrefslogtreecommitdiff
path: root/chromium/sandbox
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-01-23 17:21:03 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-01-23 16:25:15 +0000
commitc551f43206405019121bd2b2c93714319a0a3300 (patch)
tree1f48c30631c421fd4bbb3c36da20183c8a2ed7d7 /chromium/sandbox
parent7961cea6d1041e3e454dae6a1da660b453efd238 (diff)
downloadqtwebengine-chromium-c551f43206405019121bd2b2c93714319a0a3300.tar.gz
BASELINE: Update Chromium to 79.0.3945.139
Change-Id: I336b7182fab9bca80b709682489c07db112eaca5 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/sandbox')
-rw-r--r--chromium/sandbox/constants.h4
-rw-r--r--chromium/sandbox/linux/bpf_dsl/bpf_dsl.h48
-rw-r--r--chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h3
-rw-r--r--chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc2
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android_unittest.cc5
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc26
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc232
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc3
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h3
-rw-r--r--chromium/sandbox/linux/services/scoped_process.cc4
-rw-r--r--chromium/sandbox/linux/services/scoped_process.h2
-rw-r--r--chromium/sandbox/linux/services/scoped_process_unittest.cc10
-rw-r--r--chromium/sandbox/linux/services/thread_helpers.cc14
-rw-r--r--chromium/sandbox/linux/services/yama_unittests.cc6
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_process.cc4
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_process.h2
-rw-r--r--chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h288
-rw-r--r--chromium/sandbox/mac/mojom/mojom_traits_unittest.cc14
-rw-r--r--chromium/sandbox/win/BUILD.gn4
-rw-r--r--chromium/sandbox/win/src/acl.cc17
-rw-r--r--chromium/sandbox/win/src/acl.h8
-rw-r--r--chromium/sandbox/win/src/broker_services.cc251
-rw-r--r--chromium/sandbox/win/src/broker_services.h19
-rw-r--r--chromium/sandbox/win/src/handle_closer_agent.cc3
-rw-r--r--chromium/sandbox/win/src/process_mitigations_unittest.cc6
-rw-r--r--chromium/sandbox/win/src/restricted_token_unittest.cc79
-rw-r--r--chromium/sandbox/win/src/restricted_token_utils.cc3
-rw-r--r--chromium/sandbox/win/src/sandbox.h47
-rw-r--r--chromium/sandbox/win/src/sandbox_constants.cc17
-rw-r--r--chromium/sandbox/win/src/sandbox_constants.h21
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_base.cc45
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_base.h3
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_diagnostic.cc197
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_diagnostic.h51
-rw-r--r--chromium/sandbox/win/src/sandbox_types.h26
-rw-r--r--chromium/sandbox/win/src/target_interceptions.cc7
-rw-r--r--chromium/sandbox/win/src/target_process.cc8
37 files changed, 1088 insertions, 394 deletions
diff --git a/chromium/sandbox/constants.h b/chromium/sandbox/constants.h
index 7fa11cf7e5c..3e0ebc16fe4 100644
--- a/chromium/sandbox/constants.h
+++ b/chromium/sandbox/constants.h
@@ -15,11 +15,11 @@ namespace sandbox {
// JOBOBJECT_EXTENDED_LIMIT_INFORMATION.JobMemoryLimit on Windows.
//
#if defined(ARCH_CPU_64_BITS)
-const size_t kDataSizeLimit = 1ULL << 32;
+constexpr size_t kDataSizeLimit = size_t{1} << 34; // 16 GB
#else
// Limit the data memory to a size that prevents allocations that can't be
// indexed by an int.
-const size_t kDataSizeLimit =
+constexpr size_t kDataSizeLimit =
static_cast<size_t>(std::numeric_limits<int>::max());
#endif
diff --git a/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h b/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h
index 6f0dd4eb39c..555d820e017 100644
--- a/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h
+++ b/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h
@@ -27,34 +27,32 @@
// An idiomatic and demonstrative (albeit silly) example of this API
// would be:
//
-// #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+// #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
//
-// using namespace sandbox::bpf_dsl;
+// namespace dsl = sandbox::bpf_dsl;
//
-// class SillyPolicy : public Policy {
-// public:
-// SillyPolicy() {}
-// ~SillyPolicy() override {}
-// ResultExpr EvaluateSyscall(int sysno) const override {
-// if (sysno == __NR_fcntl) {
-// Arg<int> fd(0), cmd(1);
-// Arg<unsigned long> flags(2);
-// const uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK;
-// return If(AllOf(fd == 0,
-// cmd == F_SETFL,
-// (flags & ~kGoodFlags) == 0),
-// Allow())
-// .ElseIf(AnyOf(cmd == F_DUPFD, cmd == F_DUPFD_CLOEXEC),
-// Error(EMFILE))
-// .Else(Trap(SetFlagHandler, NULL));
-// } else {
-// return Allow();
-// }
-// }
+// class SillyPolicy : public dsl::Policy {
+// public:
+// SillyPolicy() = default;
+// SillyPolicy(const SillyPolicy&) = delete;
+// SillyPolicy& operator=(const SillyPolicy&) = delete;
+// ~SillyPolicy() override = default;
//
-// private:
-// DISALLOW_COPY_AND_ASSIGN(SillyPolicy);
-// };
+// dsl::ResultExpr EvaluateSyscall(int sysno) const override {
+// if (sysno != __NR_fcntl)
+// return dsl::Allow();
+// dsl::Arg<int> fd(0), cmd(1);
+// dsl::Arg<unsigned long> flags(2);
+// constexpr uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK;
+// return dsl::If(dsl::AllOf(fd == 0,
+// cmd == F_SETFL,
+// (flags & ~kGoodFlags) == 0),
+// dsl::Allow())
+// .dsl::ElseIf(dsl::AnyOf(cmd == F_DUPFD, cmd == F_DUPFD_CLOEXEC),
+// dsl::Error(EMFILE))
+// .dsl::Else(dsl::Trap(SetFlagHandler, nullptr));
+// }
+// };
//
// More generally, the DSL currently supports the following grammar:
//
diff --git a/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h b/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
index 73c26c4ba66..313511f22e9 100644
--- a/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
+++ b/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
@@ -51,8 +51,9 @@
#elif defined(__aarch64__)
+#include <asm-generic/unistd.h>
#define MIN_SYSCALL 0u
-#define MAX_PUBLIC_SYSCALL 279u
+#define MAX_PUBLIC_SYSCALL __NR_syscalls
#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
#else
diff --git a/chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc b/chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
index 6840dba8616..55ecf588227 100644
--- a/chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
+++ b/chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
@@ -49,7 +49,7 @@ class InitializedOpenBroker {
syscall_broker::BrokerFilePermission::ReadOnly("/proc/cpuinfo")};
broker_process_ = std::make_unique<syscall_broker::BrokerProcess>(
EPERM, command_set, permissions);
- BPF_ASSERT(broker_process_->Init(base::Bind([]() { return true; })));
+ BPF_ASSERT(broker_process_->Init(base::BindOnce([]() { return true; })));
initialized_ = true;
}
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android_unittest.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android_unittest.cc
index e119a462de2..bc0db815abc 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android_unittest.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android_unittest.cc
@@ -33,5 +33,10 @@ BPF_TEST_C(BaselinePolicyAndroid, CanOpenProcCpuinfo, BaselinePolicyAndroid) {
BPF_ASSERT_NE(-1, open("/proc/cpuinfo", O_RDONLY));
}
+BPF_TEST_C(BaselinePolicyAndroid, Membarrier, BaselinePolicyAndroid) {
+ // Should not crash.
+ syscall(__NR_membarrier, 32 /* cmd */, 0 /* flags */);
+}
+
} // namespace
} // namespace sandbox
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
index 060181bd42f..b56b2944f17 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -243,7 +243,7 @@ BPF_TEST_C(BaselinePolicy, EPERM_getcwd, BaselinePolicy) {
errno = 0;
char buf[1024];
char* cwd = getcwd(buf, sizeof(buf));
- BPF_ASSERT_EQ(NULL, cwd);
+ BPF_ASSERT_EQ(nullptr, cwd);
BPF_ASSERT_EQ(EPERM, errno);
}
@@ -301,7 +301,7 @@ BPF_TEST_C(BaselinePolicy, FutexEINVAL, BaselinePolicy) {
};
for (int op : ops) {
- BPF_ASSERT_EQ(-1, syscall(__NR_futex, NULL, op, 0, NULL, NULL, 0));
+ BPF_ASSERT_EQ(-1, syscall(__NR_futex, nullptr, op, 0, nullptr, nullptr, 0));
BPF_ASSERT_EQ(EINVAL, errno);
}
}
@@ -310,7 +310,7 @@ BPF_DEATH_TEST_C(BaselinePolicy,
FutexWithRequeuePriorityInheritence,
DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
BaselinePolicy) {
- syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI, 0, NULL, NULL, 0);
+ syscall(__NR_futex, nullptr, FUTEX_CMP_REQUEUE_PI, 0, nullptr, nullptr, 0);
_exit(1);
}
@@ -318,7 +318,8 @@ BPF_DEATH_TEST_C(BaselinePolicy,
FutexWithRequeuePriorityInheritencePrivate,
DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
BaselinePolicy) {
- syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, NULL, NULL, 0);
+ syscall(__NR_futex, nullptr, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, nullptr,
+ nullptr, 0);
_exit(1);
}
@@ -326,7 +327,7 @@ BPF_DEATH_TEST_C(BaselinePolicy,
FutexWithUnlockPIPrivate,
DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
BaselinePolicy) {
- syscall(__NR_futex, NULL, FUTEX_UNLOCK_PI_PRIVATE, 0, NULL, NULL, 0);
+ syscall(__NR_futex, nullptr, FUTEX_UNLOCK_PI_PRIVATE, 0, nullptr, nullptr, 0);
_exit(1);
}
#endif // defined(LIBC_GLIBC) && !defined(OS_CHROMEOS)
@@ -390,7 +391,7 @@ BPF_DEATH_TEST_C(BaselinePolicy,
BPF_DEATH_TEST_C(BaselinePolicy,
ClockGettimeWithDisallowedClockCrashes,
- DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
BaselinePolicy) {
struct timespec ts;
syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, &ts);
@@ -402,15 +403,15 @@ BPF_DEATH_TEST_C(BaselinePolicy,
BPF_DEATH_TEST_C(BaselinePolicy,
GetRandomOfDevRandomCrashes,
- DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
BaselinePolicy) {
- syscall(__NR_getrandom, NULL, 0, GRND_RANDOM);
+ syscall(__NR_getrandom, nullptr, 0, GRND_RANDOM);
}
#if !defined(__i386__)
BPF_DEATH_TEST_C(BaselinePolicy,
GetSockOptWrongLevelSigsys,
- DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
BaselinePolicy) {
int fds[2];
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
@@ -421,7 +422,7 @@ BPF_DEATH_TEST_C(BaselinePolicy,
BPF_DEATH_TEST_C(BaselinePolicy,
GetSockOptWrongOptionSigsys,
- DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
BaselinePolicy) {
int fds[2];
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
@@ -432,7 +433,7 @@ BPF_DEATH_TEST_C(BaselinePolicy,
BPF_DEATH_TEST_C(BaselinePolicy,
SetSockOptWrongLevelSigsys,
- DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
BaselinePolicy) {
int fds[2];
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
@@ -440,10 +441,9 @@ BPF_DEATH_TEST_C(BaselinePolicy,
setsockopt(fds[0], IPPROTO_TCP, SO_PEEK_OFF, &id, sizeof(id));
}
-
BPF_DEATH_TEST_C(BaselinePolicy,
SetSockOptWrongOptionSigsys,
- DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
BaselinePolicy) {
int fds[2];
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
index f1160ff45ea..fdd954cc0fd 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
@@ -248,15 +248,9 @@ BPF_DEATH_TEST_C(ParameterRestrictions,
getrusage(RUSAGE_CHILDREN, &usage);
}
-// ptace() Tests ///////////////////////////////////////////////////////////////
-
-// Tests for ptrace involve a slightly complex setup in order to properly test
-// ptrace and the variety of ways it is access-checked. The BPF_TEST macro,
-// the body of which already runs in its own process, spawns another process
-// called the "tracee". The "tracee" then spawns another process called the
-// "tracer". The child then traces the parent and performs the test operations.
-// The tracee must be careful to un-stop the tracer if the tracee expects to
-// die.
+// The following ptrace() tests do not actually set up a tracer/tracee
+// relationship, so allowed operations return ESRCH errors. Blocked operations
+// are tested with death tests.
class RestrictPtracePolicy : public bpf_dsl::Policy {
public:
@@ -273,208 +267,48 @@ class RestrictPtracePolicy : public bpf_dsl::Policy {
}
};
-constexpr char kExitPtraceChildClean = '!';
-
-class PtraceTestHarness {
- public:
- using PtraceChildTracerFunc = void (*)(pid_t tracee);
-
- PtraceTestHarness(PtraceChildTracerFunc tracer_func, bool expect_death)
- : tracer_func_(tracer_func), expect_death_(expect_death) {}
- ~PtraceTestHarness() = default;
-
- void Run() {
- // Fork the tracee process that will be traced by its child.
- pid_t pid = fork();
- BPF_ASSERT_GE(pid, 0);
-
- if (pid == 0) {
- RunTracee();
- } else {
- // The tracee should always exit cleanly.
- int status = 0;
- int rv = waitpid(pid, &status, 0);
- BPF_ASSERT_EQ(pid, rv);
- BPF_ASSERT_EQ(0, WEXITSTATUS(status));
- }
- }
-
- private:
- void RunTracee() {
- // Create a communications pipe between tracer and tracee.
- int rv = pipe2(pipes_, O_NONBLOCK);
- BPF_ASSERT_EQ(0, rv);
-
- // Pipes for redirecting output.
- int output_pipes[2];
- BPF_ASSERT_EQ(0, pipe(output_pipes));
-
- // Create the tracer process.
- pid_t pid = fork();
- BPF_ASSERT_GE(pid, 0);
-
- if (pid == 0) {
- // Close the pipe read ends and redirect output.
- close(pipes_[0]);
- close(output_pipes[0]);
-
- close(STDOUT_FILENO);
- dup2(output_pipes[1], STDOUT_FILENO);
-
- close(STDERR_FILENO);
- dup2(output_pipes[1], STDERR_FILENO);
-
- RunTracer();
-
- close(output_pipes[1]);
- } else {
- close(pipes_[1]);
- close(output_pipes[1]);
-
- // Ensure the tracer can trace the tracee. This may fail on systems
- // without YAMA, so the result is not checked.
- prctl(PR_SET_PTRACER, pid);
-
- char c = 0;
- while (c != kExitPtraceChildClean) {
- // Read from the control channel in a non-blocking fashion.
- // If no data are present, loop.
- ignore_result(read(pipes_[0], &c, 1));
-
- // Poll the exit status of the child.
- int status = 0;
- rv = waitpid(pid, &status, WNOHANG);
- if (rv != 0) {
- BPF_ASSERT_EQ(pid, rv);
- CheckTracerStatus(status, output_pipes[0]);
- _exit(0);
- }
- }
-
- _exit(0);
- }
- }
-
- void RunTracer() {
- pid_t ppid = getppid();
- BPF_ASSERT_NE(0, ppid);
-
- // Attach to the tracee and then call out to the test function.
- BPF_ASSERT_EQ(0, ptrace(PTRACE_ATTACH, ppid, nullptr, nullptr));
-
- tracer_func_(ppid);
-
- BPF_ASSERT_EQ(1, HANDLE_EINTR(write(pipes_[1], &kExitPtraceChildClean, 1)));
- close(pipes_[1]);
-
- _exit(0);
- }
-
- void CheckTracerStatus(int status, int output_pipe) {
- // The child has exited. Test that it did so in the way we were
- // expecting.
- if (expect_death_) {
- // This duplicates a bit of what //sandbox/linux/tests/unit_tests.cc does
- // but that code is not shareable here.
- std::string output;
- const size_t kBufferSize = 1024;
- size_t total_bytes_read = 0;
- ssize_t read_this_pass = 0;
- do {
- output.resize(output.size() + kBufferSize);
- read_this_pass = HANDLE_EINTR(
- read(output_pipe, &output[total_bytes_read], kBufferSize));
- if (read_this_pass >= 0) {
- total_bytes_read += read_this_pass;
- output.resize(total_bytes_read);
- }
- } while (read_this_pass > 0);
-
-#if !defined(SANDBOX_USES_BASE_TEST_SUITE)
- const bool subprocess_got_sigsegv =
- WIFSIGNALED(status) && (SIGSEGV == WTERMSIG(status));
-#else
- // This hack is required when a signal handler is installed
- // for SEGV that will _exit(1).
- const bool subprocess_got_sigsegv =
- WIFEXITED(status) && (1 == WEXITSTATUS(status));
-#endif
- BPF_ASSERT(subprocess_got_sigsegv);
- BPF_ASSERT_NE(output.find(GetPtraceErrorMessageContentForTests()),
- std::string::npos);
- } else {
- BPF_ASSERT(WIFEXITED(status));
- BPF_ASSERT_EQ(0, WEXITSTATUS(status));
- }
- }
-
- PtraceChildTracerFunc tracer_func_;
- bool expect_death_;
- int pipes_[2];
-
- DISALLOW_COPY_AND_ASSIGN(PtraceTestHarness);
-};
-
-// Fails on Android L and M.
-// See https://crbug.com/934930
BPF_TEST_C(ParameterRestrictions,
- DISABLED_ptrace_getregs_allowed,
+ ptrace_getregs_allowed,
RestrictPtracePolicy) {
- auto tracer = [](pid_t pid) {
#if defined(__arm__)
- user_regs regs;
+ user_regs regs;
#else
- user_regs_struct regs;
+ user_regs_struct regs;
#endif
- iovec iov;
- iov.iov_base = &regs;
- iov.iov_len = sizeof(regs);
- BPF_ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid,
- reinterpret_cast<void*>(NT_PRSTATUS), &iov));
-
- BPF_ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, nullptr, nullptr));
- };
- PtraceTestHarness(tracer, false).Run();
+ iovec iov;
+ iov.iov_base = &regs;
+ iov.iov_len = sizeof(regs);
+ errno = 0;
+ int rv = ptrace(PTRACE_GETREGSET, getpid(),
+ reinterpret_cast<void*>(NT_PRSTATUS), &iov);
+ BPF_ASSERT_EQ(-1, rv);
+ BPF_ASSERT_EQ(ESRCH, errno);
}
-// Fails on Android L and M.
-// See https://crbug.com/934930
-BPF_TEST_C(ParameterRestrictions,
- DISABLED_ptrace_syscall_blocked,
- RestrictPtracePolicy) {
- auto tracer = [](pid_t pid) {
- // The tracer is about to die. Make sure the tracee is not stopped so it
- // can reap it and inspect its death signal.
- kill(pid, SIGCONT);
-
- BPF_ASSERT_NE(0, ptrace(PTRACE_SYSCALL, 0, nullptr, nullptr));
- };
- PtraceTestHarness(tracer, true).Run();
+BPF_DEATH_TEST_C(
+ ParameterRestrictions,
+ ptrace_syscall_blocked,
+ DEATH_SEGV_MESSAGE(sandbox::GetPtraceErrorMessageContentForTests()),
+ RestrictPtracePolicy) {
+ ptrace(PTRACE_SYSCALL, getpid(), nullptr, nullptr);
}
-BPF_TEST_C(ParameterRestrictions,
- DISABLED_ptrace_setregs_blocked,
- RestrictPtracePolicy) {
- auto tracer = [](pid_t pid) {
+BPF_DEATH_TEST_C(
+ ParameterRestrictions,
+ ptrace_setregs_blocked,
+ DEATH_SEGV_MESSAGE(sandbox::GetPtraceErrorMessageContentForTests()),
+ RestrictPtracePolicy) {
#if defined(__arm__)
- user_regs regs;
+ user_regs regs{};
#else
- user_regs_struct regs;
+ user_regs_struct regs{};
#endif
- iovec iov;
- iov.iov_base = &regs;
- iov.iov_len = sizeof(regs);
- BPF_ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid,
- reinterpret_cast<void*>(NT_PRSTATUS), &iov));
-
- // The tracer is about to die. Make sure the tracee is not stopped so it
- // can reap it and inspect its death signal.
- kill(pid, SIGCONT);
-
- BPF_ASSERT_NE(0, ptrace(PTRACE_SETREGSET, pid,
- reinterpret_cast<void*>(NT_PRSTATUS), &iov));
- };
- PtraceTestHarness(tracer, true).Run();
+ iovec iov;
+ iov.iov_base = &regs;
+ iov.iov_len = sizeof(regs);
+ errno = 0;
+ ptrace(PTRACE_SETREGSET, getpid(), reinterpret_cast<void*>(NT_PRSTATUS),
+ &iov);
}
} // namespace
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
index 816c0d63dee..4e0ad046299 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -845,7 +845,8 @@ bool SyscallSets::IsSystemVSemaphores(int sysno) {
}
#endif
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
+ defined(__aarch64__) || \
(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS))
// These give a lot of ambient authority and bypass the setuid sandbox.
bool SyscallSets::IsSystemVSharedMemory(int sysno) {
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
index acd92da3956..923533ec9fd 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
@@ -75,7 +75,8 @@ class SANDBOX_EXPORT SyscallSets {
(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS))
static bool IsSystemVSemaphores(int sysno);
#endif
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
+ defined(__aarch64__) || \
(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS))
// These give a lot of ambient authority and bypass the setuid sandbox.
static bool IsSystemVSharedMemory(int sysno);
diff --git a/chromium/sandbox/linux/services/scoped_process.cc b/chromium/sandbox/linux/services/scoped_process.cc
index 65af4873a44..6ad405b6a2f 100644
--- a/chromium/sandbox/linux/services/scoped_process.cc
+++ b/chromium/sandbox/linux/services/scoped_process.cc
@@ -33,7 +33,7 @@ void WaitForever() {
} // namespace
-ScopedProcess::ScopedProcess(const base::Closure& child_callback)
+ScopedProcess::ScopedProcess(base::OnceClosure child_callback)
: child_process_id_(-1), process_id_(getpid()) {
PCHECK(0 == pipe(pipe_fds_));
#if !defined(THREAD_SANITIZER)
@@ -46,7 +46,7 @@ ScopedProcess::ScopedProcess(const base::Closure& child_callback)
if (0 == child_process_id_) {
PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0])));
pipe_fds_[0] = -1;
- child_callback.Run();
+ std::move(child_callback).Run();
// Notify the parent that the closure has run.
CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds_[1], kSynchronisationChar, 1)));
WaitForever();
diff --git a/chromium/sandbox/linux/services/scoped_process.h b/chromium/sandbox/linux/services/scoped_process.h
index bddbd5529b0..d0f8954d611 100644
--- a/chromium/sandbox/linux/services/scoped_process.h
+++ b/chromium/sandbox/linux/services/scoped_process.h
@@ -24,7 +24,7 @@ class SANDBOX_EXPORT ScopedProcess {
// A new process will be created and |child_callback| will run in the child
// process. This callback is allowed to terminate the process or to simply
// return. If the callback returns, the process will wait forever.
- explicit ScopedProcess(const base::Closure& child_callback);
+ explicit ScopedProcess(base::OnceClosure child_callback);
~ScopedProcess();
// Wait for the process to exit.
diff --git a/chromium/sandbox/linux/services/scoped_process_unittest.cc b/chromium/sandbox/linux/services/scoped_process_unittest.cc
index 696e38be598..e019d6d33b1 100644
--- a/chromium/sandbox/linux/services/scoped_process_unittest.cc
+++ b/chromium/sandbox/linux/services/scoped_process_unittest.cc
@@ -38,7 +38,7 @@ void RaiseAndExit(int signal) {
TEST(ScopedProcess, ScopedProcessNormalExit) {
const int kCustomExitCode = 12;
- ScopedProcess process(base::Bind(&ExitWithCode, kCustomExitCode));
+ ScopedProcess process(base::BindOnce(&ExitWithCode, kCustomExitCode));
bool got_signaled = true;
int exit_code = process.WaitForExit(&got_signaled);
EXPECT_FALSE(got_signaled);
@@ -55,7 +55,7 @@ TEST(ScopedProcess, ScopedProcessNormalExit) {
// Disable this test on Android, SIGABRT is funky there.
TEST(ScopedProcess, DISABLE_ON_ANDROID(ScopedProcessAbort)) {
PCHECK(SIG_ERR != signal(SIGABRT, SIG_DFL));
- ScopedProcess process(base::Bind(&RaiseAndExit, SIGABRT));
+ ScopedProcess process(base::BindOnce(&RaiseAndExit, SIGABRT));
bool got_signaled = false;
int exit_code = process.WaitForExit(&got_signaled);
EXPECT_TRUE(got_signaled);
@@ -77,7 +77,7 @@ TEST(ScopedProcess, DiesForReal) {
base::ScopedFD read_end_closer(pipe_fds[0]);
base::ScopedFD write_end_closer(pipe_fds[1]);
- { ScopedProcess process(base::Bind(&DoExit)); }
+ { ScopedProcess process(base::BindOnce(&DoExit)); }
// Close writing end of the pipe.
write_end_closer.reset();
@@ -94,7 +94,7 @@ TEST(ScopedProcess, SynchronizationBasic) {
ScopedProcess process1{base::DoNothing()};
EXPECT_TRUE(process1.WaitForClosureToRun());
- ScopedProcess process2(base::Bind(&DoExit));
+ ScopedProcess process2(base::BindOnce(&DoExit));
// The closure didn't finish running normally. This case is simple enough
// that process.WaitForClosureToRun() should return false, even though the
// API does not guarantees that it will return at all.
@@ -114,7 +114,7 @@ TEST(ScopedProcess, SynchronizationWorks) {
// Start a process with a closure that takes a little bit to run.
ScopedProcess process(
- base::Bind(&SleepInMsAndWriteOneByte, 100, pipe_fds[1]));
+ base::BindOnce(&SleepInMsAndWriteOneByte, 100, pipe_fds[1]));
EXPECT_TRUE(process.WaitForClosureToRun());
// Verify that the closure did, indeed, run.
diff --git a/chromium/sandbox/linux/services/thread_helpers.cc b/chromium/sandbox/linux/services/thread_helpers.cc
index d27cfe6dcf7..9f23a0a0fa1 100644
--- a/chromium/sandbox/linux/services/thread_helpers.cc
+++ b/chromium/sandbox/linux/services/thread_helpers.cc
@@ -71,7 +71,8 @@ bool IsNotThreadPresentInProcFS(int proc_fd,
// Debug builds (2s on Release builds).
// This is guaranteed to not sleep more than twice as much as the bare minimum
// amount of time.
-void RunWhileTrue(const base::Callback<bool(void)>& cb, const char* message) {
+void RunWhileTrue(const base::RepeatingCallback<bool(void)>& cb,
+ const char* message) {
#if defined(NDEBUG)
// In Release mode, crash after 30 iterations, which means having spent
// roughly 2s in
@@ -117,7 +118,7 @@ bool ChangeThreadStateAndWatchProcFS(
DCHECK(thread);
DCHECK(action == ThreadAction::Start || action == ThreadAction::Stop);
- base::Callback<bool(void)> cb;
+ base::RepeatingCallback<bool(void)> cb;
const char* message;
if (action == ThreadAction::Start) {
@@ -140,10 +141,12 @@ bool ChangeThreadStateAndWatchProcFS(
// /proc. Start() above or following Stop(), the thread is started or joined,
// but entries in /proc may not have been updated.
if (action == ThreadAction::Start) {
- cb = base::Bind(&IsNotThreadPresentInProcFS, proc_fd, thread_id_dir_str);
+ cb = base::BindRepeating(&IsNotThreadPresentInProcFS, proc_fd,
+ thread_id_dir_str);
message = kAssertThreadDoesNotAppearInProcFS;
} else {
- cb = base::Bind(&IsThreadPresentInProcFS, proc_fd, thread_id_dir_str);
+ cb = base::BindRepeating(&IsThreadPresentInProcFS, proc_fd,
+ thread_id_dir_str);
message = kAssertThreadDoesNotDisappearInProcFS;
}
RunWhileTrue(cb, message);
@@ -171,7 +174,8 @@ bool ThreadHelpers::IsSingleThreaded() {
// static
void ThreadHelpers::AssertSingleThreaded(int proc_fd) {
DCHECK_LE(0, proc_fd);
- const base::Callback<bool(void)> cb = base::Bind(&IsMultiThreaded, proc_fd);
+ const base::RepeatingCallback<bool(void)> cb =
+ base::BindRepeating(&IsMultiThreaded, proc_fd);
RunWhileTrue(cb, kAssertSingleThreadedError);
}
diff --git a/chromium/sandbox/linux/services/yama_unittests.cc b/chromium/sandbox/linux/services/yama_unittests.cc
index 0b3817e8dcc..e693917c417 100644
--- a/chromium/sandbox/linux/services/yama_unittests.cc
+++ b/chromium/sandbox/linux/services/yama_unittests.cc
@@ -66,7 +66,7 @@ void ExitZeroIfCanPtrace(pid_t pid) {
}
bool CanSubProcessPtrace(pid_t pid) {
- ScopedProcess process(base::Bind(&ExitZeroIfCanPtrace, pid));
+ ScopedProcess process(base::BindOnce(&ExitZeroIfCanPtrace, pid));
bool signaled;
int exit_code = process.WaitForExit(&signaled);
CHECK(!signaled);
@@ -134,7 +134,7 @@ TEST(Yama, RestrictPtraceWorks) {
if (HasLinux32Bug())
return;
- ScopedProcess process1(base::Bind(&SetYamaRestrictions, true));
+ ScopedProcess process1(base::BindOnce(&SetYamaRestrictions, true));
ASSERT_TRUE(process1.WaitForClosureToRun());
if (Yama::IsEnforcing()) {
@@ -147,7 +147,7 @@ TEST(Yama, RestrictPtraceWorks) {
ASSERT_TRUE(CanPtrace(process1.GetPid()));
// A sibling can ptrace process2 which disables any Yama protection.
- ScopedProcess process2(base::Bind(&SetYamaRestrictions, false));
+ ScopedProcess process2(base::BindOnce(&SetYamaRestrictions, false));
ASSERT_TRUE(process2.WaitForClosureToRun());
ASSERT_TRUE(CanSubProcessPtrace(process2.GetPid()));
}
diff --git a/chromium/sandbox/linux/syscall_broker/broker_process.cc b/chromium/sandbox/linux/syscall_broker/broker_process.cc
index 56d4964cfdc..800888f9024 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_process.cc
+++ b/chromium/sandbox/linux/syscall_broker/broker_process.cc
@@ -59,7 +59,7 @@ BrokerProcess::~BrokerProcess() {
}
bool BrokerProcess::Init(
- const base::Callback<bool(void)>& broker_process_init_callback) {
+ base::OnceCallback<bool(void)> broker_process_init_callback) {
CHECK(!initialized_);
BrokerChannel::EndPoint ipc_reader;
BrokerChannel::EndPoint ipc_writer;
@@ -86,7 +86,7 @@ bool BrokerProcess::Init(
// We are the broker process. Make sure to close the writer's end so that
// we get notified if the client disappears.
ipc_writer.reset();
- CHECK(broker_process_init_callback.Run());
+ CHECK(std::move(broker_process_init_callback).Run());
BrokerHost broker_host(broker_permission_list_, allowed_command_set_,
std::move(ipc_reader));
for (;;) {
diff --git a/chromium/sandbox/linux/syscall_broker/broker_process.h b/chromium/sandbox/linux/syscall_broker/broker_process.h
index 849238f48e6..e23d9e3544a 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_process.h
+++ b/chromium/sandbox/linux/syscall_broker/broker_process.h
@@ -71,7 +71,7 @@ class SANDBOX_EXPORT BrokerProcess {
// point, since we need to fork().
// broker_process_init_callback will be called in the new broker process,
// after fork() returns.
- bool Init(const base::Callback<bool(void)>& broker_process_init_callback);
+ bool Init(base::OnceCallback<bool(void)> broker_process_init_callback);
// Return the PID of the child created by Init().
int broker_pid() const { return broker_pid_; }
diff --git a/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h b/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
index a6afc62d990..7613c9bbcdc 100644
--- a/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
+++ b/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
@@ -1422,5 +1422,293 @@
#define __NR_memfd_create 356
#endif
+#if !defined(__NR_bpf)
+#define __NR_bpf 357
+#endif
+
+#if !defined(__NR_execveat)
+#define __NR_execveat 358
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket 359
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair 360
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind 361
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect 362
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen 363
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 364
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt 365
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt 366
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname 367
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername 368
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto 369
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg 370
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom 371
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg 372
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown 373
+#endif
+
+#if !defined(__NR_userfaultfd)
+#define __NR_userfaultfd 374
+#endif
+
+#if !defined(__NR_membarrier)
+#define __NR_membarrier 375
+#endif
+
+#if !defined(__NR_mlock2)
+#define __NR_mlock2 376
+#endif
+
+#if !defined(__NR_copy_file_range)
+#define __NR_copy_file_range 377
+#endif
+
+#if !defined(__NR_preadv2)
+#define __NR_preadv2 378
+#endif
+
+#if !defined(__NR_pwritev2)
+#define __NR_pwritev2 379
+#endif
+
+#if !defined(__NR_pkey_mprotect)
+#define __NR_pkey_mprotect 380
+#endif
+
+#if !defined(__NR_pkey_alloc)
+#define __NR_pkey_alloc 381
+#endif
+
+#if !defined(__NR_pkey_free)
+#define __NR_pkey_free 382
+#endif
+
+#if !defined(__NR_statx)
+#define __NR_statx 383
+#endif
+
+#if !defined(__NR_arch_prctl)
+#define __NR_arch_prctl 384
+#endif
+
+#if !defined(__NR_io_pgetevents)
+#define __NR_io_pgetevents 385
+#endif
+
+#if !defined(__NR_rseq)
+#define __NR_rseq 386
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget 393
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl 394
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget 395
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl 396
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat 397
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt 398
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget 399
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd 400
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv 401
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl 402
+#endif
+
+#if !defined(__NR_clock_gettime64)
+#define __NR_clock_gettime64 403
+#endif
+
+#if !defined(__NR_clock_settime64)
+#define __NR_clock_settime64 404
+#endif
+
+#if !defined(__NR_clock_adjtime64)
+#define __NR_clock_adjtime64 405
+#endif
+
+#if !defined(__NR_clock_getres_time64)
+#define __NR_clock_getres_time64 406
+#endif
+
+#if !defined(__NR_clock_nanosleep_time64)
+#define __NR_clock_nanosleep_time64 407
+#endif
+
+#if !defined(__NR_timer_gettime64)
+#define __NR_timer_gettime64 408
+#endif
+
+#if !defined(__NR_timer_settime64)
+#define __NR_timer_settime64 409
+#endif
+
+#if !defined(__NR_timerfd_gettime64)
+#define __NR_timerfd_gettime64 410
+#endif
+
+#if !defined(__NR_timerfd_settime64)
+#define __NR_timerfd_settime64 411
+#endif
+
+#if !defined(__NR_utimensat_time64)
+#define __NR_utimensat_time64 412
+#endif
+
+#if !defined(__NR_pselect6_time64)
+#define __NR_pselect6_time64 413
+#endif
+
+#if !defined(__NR_ppoll_time64)
+#define __NR_ppoll_time64 414
+#endif
+
+#if !defined(__NR_io_pgetevents_time64)
+#define __NR_io_pgetevents_time64 416
+#endif
+
+#if !defined(__NR_recvmmsg_time64)
+#define __NR_recvmmsg_time64 417
+#endif
+
+#if !defined(__NR_mq_timedsend_time64)
+#define __NR_mq_timedsend_time64 418
+#endif
+
+#if !defined(__NR_mq_timedreceive_time64)
+#define __NR_mq_timedreceive_time64 419
+#endif
+
+#if !defined(__NR_semtimedop_time64)
+#define __NR_semtimedop_time64 420
+#endif
+
+#if !defined(__NR_rt_sigtimedwait_time64)
+#define __NR_rt_sigtimedwait_time64 421
+#endif
+
+#if !defined(__NR_futex_time64)
+#define __NR_futex_time64 422
+#endif
+
+#if !defined(__NR_sched_rr_get_interval_time64)
+#define __NR_sched_rr_get_interval_time64 423
+#endif
+
+#if !defined(__NR_pidfd_send_signal)
+#define __NR_pidfd_send_signal 424
+#endif
+
+#if !defined(__NR_io_uring_setup)
+#define __NR_io_uring_setup 425
+#endif
+
+#if !defined(__NR_io_uring_enter)
+#define __NR_io_uring_enter 426
+#endif
+
+#if !defined(__NR_io_uring_register)
+#define __NR_io_uring_register 427
+#endif
+
+#if !defined(__NR_open_tree)
+#define __NR_open_tree 428
+#endif
+
+#if !defined(__NR_move_mount)
+#define __NR_move_mount 429
+#endif
+
+#if !defined(__NR_fsopen)
+#define __NR_fsopen 430
+#endif
+
+#if !defined(__NR_fsconfig)
+#define __NR_fsconfig 431
+#endif
+
+#if !defined(__NR_fsmount)
+#define __NR_fsmount 432
+#endif
+
+#if !defined(__NR_fspick)
+#define __NR_fspick 433
+#endif
+
+#if !defined(__NR_pidfd_open)
+#define __NR_pidfd_open 434
+#endif
+
+#if !defined(__NR_clone3)
+#define __NR_clone3 435
+#endif
+
#endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
diff --git a/chromium/sandbox/mac/mojom/mojom_traits_unittest.cc b/chromium/sandbox/mac/mojom/mojom_traits_unittest.cc
index e6f38797d9f..dce182807a9 100644
--- a/chromium/sandbox/mac/mojom/mojom_traits_unittest.cc
+++ b/chromium/sandbox/mac/mojom/mojom_traits_unittest.cc
@@ -3,7 +3,8 @@
// found in the LICENSE file.
#include "base/test/task_environment.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.h"
#include "sandbox/mac/mojom/traits_test_service.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -14,12 +15,9 @@ namespace {
class StructTraitsTest : public testing::Test,
public sandbox::mac::mojom::TraitsTestService {
public:
- StructTraitsTest()
- : interface_ptr_(), binding_(this, mojo::MakeRequest(&interface_ptr_)) {}
+ StructTraitsTest() : receiver_(this, remote_.BindNewPipeAndPassReceiver()) {}
- sandbox::mac::mojom::TraitsTestService* interface() {
- return interface_ptr_.get();
- }
+ sandbox::mac::mojom::TraitsTestService* interface() { return remote_.get(); }
private:
// TraitsTestService:
@@ -31,8 +29,8 @@ class StructTraitsTest : public testing::Test,
base::test::TaskEnvironment task_environment_;
- sandbox::mac::mojom::TraitsTestServicePtr interface_ptr_;
- mojo::Binding<sandbox::mac::mojom::TraitsTestService> binding_;
+ mojo::Remote<sandbox::mac::mojom::TraitsTestService> remote_;
+ mojo::Receiver<sandbox::mac::mojom::TraitsTestService> receiver_;
};
TEST_F(StructTraitsTest, SeatbeltExtensionToken) {
diff --git a/chromium/sandbox/win/BUILD.gn b/chromium/sandbox/win/BUILD.gn
index 63864dcfef6..919820cd689 100644
--- a/chromium/sandbox/win/BUILD.gn
+++ b/chromium/sandbox/win/BUILD.gn
@@ -94,6 +94,8 @@ static_library("sandbox") {
"src/restricted_token_utils.h",
"src/sandbox.cc",
"src/sandbox.h",
+ "src/sandbox_constants.cc",
+ "src/sandbox_constants.h",
"src/sandbox_factory.h",
"src/sandbox_globals.cc",
"src/sandbox_nt_types.h",
@@ -102,6 +104,8 @@ static_library("sandbox") {
"src/sandbox_policy.h",
"src/sandbox_policy_base.cc",
"src/sandbox_policy_base.h",
+ "src/sandbox_policy_diagnostic.cc",
+ "src/sandbox_policy_diagnostic.h",
"src/sandbox_rand.cc",
"src/sandbox_rand.h",
"src/sandbox_types.h",
diff --git a/chromium/sandbox/win/src/acl.cc b/chromium/sandbox/win/src/acl.cc
index 2f78c164069..bd0b1818332 100644
--- a/chromium/sandbox/win/src/acl.cc
+++ b/chromium/sandbox/win/src/acl.cc
@@ -151,4 +151,21 @@ bool AddKnownSidToObject(HANDLE object,
return true;
}
+bool ReplacePackageSidInDacl(HANDLE object,
+ SE_OBJECT_TYPE object_type,
+ const Sid& package_sid,
+ ACCESS_MASK access) {
+ if (!AddKnownSidToObject(object, object_type, package_sid, REVOKE_ACCESS,
+ 0)) {
+ return false;
+ }
+
+ Sid any_package_sid(::WinBuiltinAnyPackageSid);
+ if (!AddKnownSidToObject(object, object_type, any_package_sid, GRANT_ACCESS,
+ access)) {
+ return false;
+ }
+ return true;
+}
+
} // namespace sandbox
diff --git a/chromium/sandbox/win/src/acl.h b/chromium/sandbox/win/src/acl.h
index 86bb92f9b11..194edb09881 100644
--- a/chromium/sandbox/win/src/acl.h
+++ b/chromium/sandbox/win/src/acl.h
@@ -51,6 +51,14 @@ bool AddKnownSidToObject(HANDLE object,
ACCESS_MODE access_mode,
ACCESS_MASK access);
+// Replace package SID in DACL to the "any package" SID. It allows Low-IL
+// tokens to open the object which is important for warm up when using renderer
+// AppContainer.
+bool ReplacePackageSidInDacl(HANDLE object,
+ SE_OBJECT_TYPE object_type,
+ const Sid& package_sid,
+ ACCESS_MASK access);
+
} // namespace sandbox
#endif // SANDBOX_SRC_ACL_H_
diff --git a/chromium/sandbox/win/src/broker_services.cc b/chromium/sandbox/win/src/broker_services.cc
index 7c7c53397ba..bc9da0ce0ca 100644
--- a/chromium/sandbox/win/src/broker_services.cc
+++ b/chromium/sandbox/win/src/broker_services.cc
@@ -22,6 +22,7 @@
#include "sandbox/win/src/process_mitigations.h"
#include "sandbox/win/src/sandbox.h"
#include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/sandbox_policy_diagnostic.h"
#include "sandbox/win/src/target_process.h"
#include "sandbox/win/src/win2k_threadpool.h"
#include "sandbox/win/src/win_utils.h"
@@ -50,6 +51,10 @@ sandbox::ResultCode SpawnCleanup(sandbox::TargetProcess* target) {
// executes TargetEventsThread().
enum {
THREAD_CTRL_NONE,
+ THREAD_CTRL_NEW_JOB_TRACKER,
+ THREAD_CTRL_NEW_PROCESS_TRACKER,
+ THREAD_CTRL_PROCESS_SIGNALLED,
+ THREAD_CTRL_GET_POLICY_INFO,
THREAD_CTRL_QUIT,
THREAD_CTRL_LAST,
};
@@ -58,8 +63,9 @@ enum {
// with a job object and with a policy.
struct JobTracker {
JobTracker(base::win::ScopedHandle job,
- scoped_refptr<sandbox::PolicyBase> policy)
- : job(std::move(job)), policy(policy) {}
+ scoped_refptr<sandbox::PolicyBase> policy,
+ DWORD process_id)
+ : job(std::move(job)), policy(policy), process_id(process_id) {}
~JobTracker() { FreeResources(); }
// Releases the Job and notifies the associated Policy object to release its
@@ -68,6 +74,7 @@ struct JobTracker {
base::win::ScopedHandle job;
scoped_refptr<sandbox::PolicyBase> policy;
+ DWORD process_id;
};
void JobTracker::FreeResources() {
@@ -85,6 +92,61 @@ void JobTracker::FreeResources() {
}
}
+// tracks processes that are not in jobs
+struct ProcessTracker {
+ ProcessTracker(scoped_refptr<sandbox::PolicyBase> policy,
+ DWORD process_id,
+ base::win::ScopedHandle process)
+ : policy(policy), process_id(process_id), process(std::move(process)) {}
+ ~ProcessTracker() { FreeResources(); }
+
+ void FreeResources();
+
+ scoped_refptr<sandbox::PolicyBase> policy;
+ DWORD process_id;
+ base::win::ScopedHandle process;
+ // Used to UnregisterWait. Not a real handle so cannot CloseHandle().
+ HANDLE wait_handle;
+ // IOCP that is tracking this non-job process
+ HANDLE iocp;
+};
+
+void ProcessTracker::FreeResources() {
+ if (policy) {
+ policy->OnJobEmpty(nullptr);
+ policy = nullptr;
+ }
+}
+
+// Helper redispatches process events to tracker thread.
+void WINAPI ProcessEventCallback(PVOID param, BOOLEAN ignored) {
+ // This callback should do very little, and must be threadpool safe.
+ ProcessTracker* tracker = reinterpret_cast<ProcessTracker*>(param);
+ // If this fails we can do nothing... we will leak the policy.
+ ::PostQueuedCompletionStatus(tracker->iocp, 0, THREAD_CTRL_PROCESS_SIGNALLED,
+ reinterpret_cast<LPOVERLAPPED>(tracker));
+}
+
+// Helper class to send policy lists
+class PolicyDiagnosticList final : public sandbox::PolicyList {
+ public:
+ PolicyDiagnosticList() {}
+ ~PolicyDiagnosticList() override {}
+ void push_back(std::unique_ptr<sandbox::PolicyInfo> info) {
+ internal_list_.push_back(std::move(info));
+ }
+ std::vector<std::unique_ptr<sandbox::PolicyInfo>>::iterator begin() override {
+ return internal_list_.begin();
+ }
+ std::vector<std::unique_ptr<sandbox::PolicyInfo>>::iterator end() override {
+ return internal_list_.end();
+ }
+ size_t size() const override { return internal_list_.size(); }
+
+ private:
+ std::vector<std::unique_ptr<sandbox::PolicyInfo>> internal_list_;
+};
+
} // namespace
namespace sandbox {
@@ -97,18 +159,16 @@ ResultCode BrokerServicesBase::Init() {
if (job_port_.IsValid() || thread_pool_)
return SBOX_ERROR_UNEXPECTED_CALL;
- ::InitializeCriticalSection(&lock_);
-
job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0));
if (!job_port_.IsValid())
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_INIT_BROKERSERVICES;
no_targets_.Set(::CreateEventW(nullptr, true, false, nullptr));
job_thread_.Set(::CreateThread(nullptr, 0, // Default security and stack.
TargetEventsThread, this, 0, nullptr));
if (!job_thread_.IsValid())
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_INIT_BROKERSERVICES;
return SBOX_ALL_OK;
}
@@ -135,11 +195,7 @@ BrokerServicesBase::~BrokerServicesBase() {
NOTREACHED();
return;
}
-
- tracker_list_.clear();
thread_pool_.reset();
-
- ::DeleteCriticalSection(&lock_);
}
scoped_refptr<TargetPolicy> BrokerServicesBase::CreatePolicy() {
@@ -165,6 +221,9 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
HANDLE port = broker->job_port_.Get();
HANDLE no_targets = broker->no_targets_.Get();
+ std::set<DWORD> child_process_ids;
+ std::list<std::unique_ptr<JobTracker>> jobs;
+ std::list<std::unique_ptr<ProcessTracker>> processes;
int target_counter = 0;
int untracked_target_counter = 0;
::ResetEvent(no_targets);
@@ -189,23 +248,25 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
switch (events) {
case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: {
// The job object has signaled that the last process associated
- // with it has terminated. Assuming there is no way for a process
- // to appear out of thin air in this job, it safe to assume that
- // we can tell the policy to destroy the target object, and for
- // us to release our reference to the policy object.
- tracker->FreeResources();
+ // with it has terminated. It is safe to free the tracker
+ // and release its reference to the associated policy object
+ // which will Close the job handle.
+ HANDLE job_handle = tracker->job.Get();
+
+ // Erase by comparing with the job handle.
+ jobs.erase(std::remove_if(
+ jobs.begin(), jobs.end(),
+ [&](auto&& p) -> bool { return p->job.Get() == job_handle; }));
break;
}
case JOB_OBJECT_MSG_NEW_PROCESS: {
- DWORD handle = static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl));
- {
- AutoLock lock(&broker->lock_);
- size_t count = broker->child_process_ids_.count(handle);
- // Child process created from sandboxed process.
- if (count == 0)
- untracked_target_counter++;
- }
+ // Child process created from sandboxed process.
+ DWORD process_id =
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl));
+ size_t count = child_process_ids.count(process_id);
+ if (count == 0)
+ untracked_target_counter++;
++target_counter;
if (1 == target_counter) {
::ResetEvent(no_targets);
@@ -215,12 +276,8 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
case JOB_OBJECT_MSG_EXIT_PROCESS:
case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: {
- size_t erase_result = 0;
- {
- AutoLock lock(&broker->lock_);
- erase_result = broker->child_process_ids_.erase(
- static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
- }
+ size_t erase_result = child_process_ids.erase(
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
if (erase_result != 1U) {
// The process was untracked e.g. a child process of the target.
--untracked_target_counter;
@@ -254,8 +311,75 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
break;
}
}
+ } else if (THREAD_CTRL_NEW_JOB_TRACKER == key) {
+ std::unique_ptr<JobTracker> tracker;
+ tracker.reset(reinterpret_cast<JobTracker*>(ovl));
+ DCHECK(tracker->job.IsValid());
+
+ child_process_ids.insert(tracker->process_id);
+ jobs.push_back(std::move(tracker));
+
+ } else if (THREAD_CTRL_NEW_PROCESS_TRACKER == key) {
+ std::unique_ptr<ProcessTracker> tracker;
+ tracker.reset(reinterpret_cast<ProcessTracker*>(ovl));
+
+ if (child_process_ids.empty()) {
+ ::SetEvent(broker->no_targets_.Get());
+ }
+
+ tracker->iocp = port;
+ if (!::RegisterWaitForSingleObject(&(tracker->wait_handle),
+ tracker->process.Get(),
+ ProcessEventCallback, tracker.get(),
+ INFINITE, WT_EXECUTEONLYONCE)) {
+ // Failed. Invalidate the wait_handle and store anyway.
+ tracker->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ processes.push_back(std::move(tracker));
+
+ } else if (THREAD_CTRL_PROCESS_SIGNALLED == key) {
+ ProcessTracker* tracker =
+ static_cast<ProcessTracker*>(reinterpret_cast<void*>(ovl));
+
+ ::UnregisterWait(tracker->wait_handle);
+ tracker->wait_handle = INVALID_HANDLE_VALUE;
+
+ // PID is unique until the process handle is closed in dtor.
+ processes.erase(std::remove_if(
+ processes.begin(), processes.end(), [&](auto&& p) -> bool {
+ return p->process_id == tracker->process_id;
+ }));
+
+ } else if (THREAD_CTRL_GET_POLICY_INFO == key) {
+ // Clone the policies for sandbox diagnostics.
+ std::unique_ptr<PolicyDiagnosticsReceiver> receiver;
+ receiver.reset(static_cast<PolicyDiagnosticsReceiver*>(
+ reinterpret_cast<void*>(ovl)));
+ // The PollicyInfo ctor copies essential information from the trackers.
+ auto policy_list = std::make_unique<PolicyDiagnosticList>();
+ for (auto&& process_tracker : processes) {
+ if (process_tracker->policy) {
+ policy_list->push_back(std::make_unique<PolicyDiagnostic>(
+ process_tracker->policy.get()));
+ }
+ }
+ for (auto&& job_tracker : jobs) {
+ if (job_tracker->policy) {
+ policy_list->push_back(
+ std::make_unique<PolicyDiagnostic>(job_tracker->policy.get()));
+ }
+ }
+ // Receiver should return quickly.
+ receiver->ReceiveDiagnostics(std::move(policy_list));
+
} else if (THREAD_CTRL_QUIT == key) {
// The broker object is being destroyed so the thread needs to exit.
+ for (auto&& tracker : processes) {
+ ::UnregisterWait(tracker->wait_handle);
+ tracker->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ // After this point, so further calls to ProcessEventCallback can
+ // occur. Other tracked objects are destroyed as this thread ends.
return 0;
} else {
// We have not implemented more commands.
@@ -290,8 +414,6 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
DCHECK(thread_id == ::GetCurrentThreadId());
*last_warning = SBOX_ALL_OK;
- AutoLock lock(&lock_);
-
// Launcher thread only needs to be opted out of ACG once. Do this on the
// first child process being spawned.
static bool launcher_thread_opted_out = false;
@@ -493,32 +615,39 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
return result;
}
- // We are going to keep a pointer to the policy because we'll call it when
- // the job object generates notifications using the completion port.
if (job.IsValid()) {
- std::unique_ptr<JobTracker> tracker =
- std::make_unique<JobTracker>(std::move(job), policy_base);
-
+ JobTracker* tracker =
+ new JobTracker(std::move(job), policy_base, process_info.process_id());
+
+ // Post the tracker to the tracking thread, then associate the job with
+ // the tracker. The worker thread takes ownership of these objects.
+ CHECK(::PostQueuedCompletionStatus(
+ job_port_.Get(), 0, THREAD_CTRL_NEW_JOB_TRACKER,
+ reinterpret_cast<LPOVERLAPPED>(tracker)));
// There is no obvious recovery after failure here. Previous version with
// SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639
- CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(),
- tracker.get()));
-
- // Save the tracker because in cleanup we might need to force closing
- // the Jobs.
- tracker_list_.push_back(std::move(tracker));
- child_process_ids_.insert(process_info.process_id());
+ CHECK(
+ AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), tracker));
} else {
- // Leak policy_base. This needs to outlive the child process, but there's
- // nothing that tracks that lifetime properly if there's no job object.
- // TODO(wfh): Find a way to make this have the correct lifetime.
- policy_base->AddRef();
-
- // We have to signal the event once here because the completion port will
- // never get a message that this target is being terminated thus we should
- // not block WaitForAllTargets until we have at least one target with job.
- if (child_process_ids_.empty())
- ::SetEvent(no_targets_.Get());
+ // Duplicate the process handle to give the tracking machinery
+ // something valid to wait on in the tracking thread.
+ HANDLE tmp_process_handle = INVALID_HANDLE_VALUE;
+ if (!::DuplicateHandle(::GetCurrentProcess(), process_info.process_handle(),
+ ::GetCurrentProcess(), &tmp_process_handle,
+ SYNCHRONIZE, false, 0 /*no options*/)) {
+ *last_error = ::GetLastError();
+ // This may fail in the same way as Job associated processes.
+ // crbug.com/480639.
+ SpawnCleanup(target);
+ return SBOX_ERROR_CANNOT_DUPLICATE_PROCESS_HANDLE;
+ }
+ base::win::ScopedHandle dup_process_handle(tmp_process_handle);
+ ProcessTracker* tracker = new ProcessTracker(
+ policy_base, process_info.process_id(), std::move(dup_process_handle));
+ // The tracker and policy will leak if this call fails.
+ ::PostQueuedCompletionStatus(job_port_.Get(), 0,
+ THREAD_CTRL_NEW_PROCESS_TRACKER,
+ reinterpret_cast<LPOVERLAPPED>(tracker));
}
*target_info = process_info.Take();
@@ -530,4 +659,20 @@ ResultCode BrokerServicesBase::WaitForAllTargets() {
return SBOX_ALL_OK;
}
+ResultCode BrokerServicesBase::GetPolicyDiagnostics(
+ std::unique_ptr<PolicyDiagnosticsReceiver> receiver) {
+ CHECK(job_thread_.IsValid());
+ // Post to the job thread.
+ if (!::PostQueuedCompletionStatus(
+ job_port_.Get(), 0, THREAD_CTRL_GET_POLICY_INFO,
+ reinterpret_cast<LPOVERLAPPED>(receiver.get()))) {
+ receiver->OnError(SBOX_ERROR_GENERIC);
+ return SBOX_ERROR_GENERIC;
+ }
+
+ // Ownership has passed to tracker thread.
+ receiver.release();
+ return SBOX_ALL_OK;
+}
+
} // namespace sandbox
diff --git a/chromium/sandbox/win/src/broker_services.h b/chromium/sandbox/win/src/broker_services.h
index 701d29a40d1..c268b074efe 100644
--- a/chromium/sandbox/win/src/broker_services.h
+++ b/chromium/sandbox/win/src/broker_services.h
@@ -22,12 +22,6 @@
#include "sandbox/win/src/win2k_threadpool.h"
#include "sandbox/win/src/win_utils.h"
-namespace {
-
-struct JobTracker;
-
-} // namespace
-
namespace sandbox {
// BrokerServicesBase ---------------------------------------------------------
@@ -54,6 +48,8 @@ class BrokerServicesBase final : public BrokerServices,
DWORD* last_error,
PROCESS_INFORMATION* target) override;
ResultCode WaitForAllTargets() override;
+ ResultCode GetPolicyDiagnostics(
+ std::unique_ptr<PolicyDiagnosticsReceiver> receiver) override;
private:
// The routine that the worker thread executes. It is in charge of
@@ -71,20 +67,9 @@ class BrokerServicesBase final : public BrokerServices,
// Handle to the worker thread that reacts to job notifications.
base::win::ScopedHandle job_thread_;
- // Lock used to protect the list of targets from being modified by 2
- // threads at the same time.
- CRITICAL_SECTION lock_;
-
// Provides a pool of threads that are used to wait on the IPC calls.
std::unique_ptr<ThreadProvider> thread_pool_;
- // List of the trackers for closing and cleanup purposes.
- std::list<std::unique_ptr<JobTracker>> tracker_list_;
-
- // Provides a fast lookup to identify sandboxed processes that belong to a
- // job.
- std::set<DWORD> child_process_ids_;
-
DISALLOW_COPY_AND_ASSIGN(BrokerServicesBase);
};
diff --git a/chromium/sandbox/win/src/handle_closer_agent.cc b/chromium/sandbox/win/src/handle_closer_agent.cc
index 65410b19815..a0f12a52f4f 100644
--- a/chromium/sandbox/win/src/handle_closer_agent.cc
+++ b/chromium/sandbox/win/src/handle_closer_agent.cc
@@ -8,6 +8,7 @@
#include <stddef.h>
#include "base/logging.h"
+#include "base/win/static_constants.h"
#include "sandbox/win/src/nt_internals.h"
#include "sandbox/win/src/win_utils.h"
@@ -173,7 +174,7 @@ bool HandleCloserAgent::CloseHandles() {
// Skip closing these handles when Application Verifier is in use in order to
// avoid invalid-handle exceptions.
- if (GetModuleHandleW(L"vrfcore.dll"))
+ if (GetModuleHandleA(base::win::kApplicationVerifierDllName))
return true;
// Set up buffers for the type info and the name.
diff --git a/chromium/sandbox/win/src/process_mitigations_unittest.cc b/chromium/sandbox/win/src/process_mitigations_unittest.cc
index 81f96451882..a4d404db582 100644
--- a/chromium/sandbox/win/src/process_mitigations_unittest.cc
+++ b/chromium/sandbox/win/src/process_mitigations_unittest.cc
@@ -9,6 +9,7 @@
#include "base/files/file_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/path_service.h"
+#include "base/process/kill.h"
#include "base/scoped_native_library.h"
#include "base/test/test_timeouts.h"
#include "base/win/windows_version.h"
@@ -878,6 +879,11 @@ TEST(ProcessMitigationsTest, MAYBE_CheckWin10MsSigned_FailurePreSpawn) {
ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex);
+ // Other code in base/process relies on this invariant.
+ static_assert(
+ base::win::kStatusInvalidImageHashExitCode == STATUS_INVALID_IMAGE_HASH,
+ "Invalid hash exit code does not match between base and sandbox.");
+
#if defined(COMPONENT_BUILD)
// In a component build, the executable will fail to start-up because
// imports e.g. base.dll cannot be resolved.
diff --git a/chromium/sandbox/win/src/restricted_token_unittest.cc b/chromium/sandbox/win/src/restricted_token_unittest.cc
index d8798e9e0a4..88cae12e3d5 100644
--- a/chromium/sandbox/win/src/restricted_token_unittest.cc
+++ b/chromium/sandbox/win/src/restricted_token_unittest.cc
@@ -11,6 +11,7 @@
#include "base/win/atl.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
+#include "sandbox/win/src/acl.h"
#include "sandbox/win/src/security_capabilities.h"
#include "sandbox/win/src/sid.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -84,6 +85,46 @@ bool GetVariableTokenInformation(const base::win::ScopedHandle& token,
information);
}
+void CheckDaclForPackageSid(const base::win::ScopedHandle& token,
+ PSECURITY_CAPABILITIES security_capabilities,
+ bool package_sid_required) {
+ DWORD length_needed = 0;
+ ::GetKernelObjectSecurity(token.Get(), DACL_SECURITY_INFORMATION, nullptr, 0,
+ &length_needed);
+ ASSERT_EQ(::GetLastError(), DWORD{ERROR_INSUFFICIENT_BUFFER});
+
+ std::vector<char> security_desc_buffer(length_needed);
+ SECURITY_DESCRIPTOR* security_desc =
+ reinterpret_cast<SECURITY_DESCRIPTOR*>(security_desc_buffer.data());
+
+ ASSERT_TRUE(::GetKernelObjectSecurity(token.Get(), DACL_SECURITY_INFORMATION,
+ security_desc, length_needed,
+ &length_needed));
+
+ ATL::CSecurityDesc token_sd(*security_desc);
+ ATL::CDacl dacl;
+ ASSERT_TRUE(token_sd.GetDacl(&dacl));
+
+ ATL::CSid package_sid(
+ static_cast<SID*>(security_capabilities->AppContainerSid));
+ ATL::CSid all_package_sid(
+ static_cast<SID*>(sandbox::Sid(::WinBuiltinAnyPackageSid).GetPSID()));
+
+ unsigned int ace_count = dacl.GetAceCount();
+ for (unsigned int i = 0; i < ace_count; ++i) {
+ ATL::CSid sid;
+ ACCESS_MASK mask = 0;
+ BYTE type = 0;
+ dacl.GetAclEntry(i, &sid, &mask, &type);
+ if (mask != TOKEN_ALL_ACCESS || type != ACCESS_ALLOWED_ACE_TYPE)
+ continue;
+ if (sid == package_sid)
+ EXPECT_TRUE(package_sid_required);
+ else if (sid == all_package_sid)
+ EXPECT_FALSE(package_sid_required);
+ }
+}
+
void CheckLowBoxToken(const base::win::ScopedHandle& token,
TOKEN_TYPE token_type,
PSECURITY_CAPABILITIES security_capabilities) {
@@ -126,38 +167,7 @@ void CheckLowBoxToken(const base::win::ScopedHandle& token,
security_capabilities->Capabilities[index].Sid));
}
- DWORD length_needed = 0;
- ::GetKernelObjectSecurity(token.Get(), DACL_SECURITY_INFORMATION, nullptr, 0,
- &length_needed);
- ASSERT_EQ(::GetLastError(), DWORD{ERROR_INSUFFICIENT_BUFFER});
-
- std::vector<char> security_desc_buffer(length_needed);
- SECURITY_DESCRIPTOR* security_desc =
- reinterpret_cast<SECURITY_DESCRIPTOR*>(security_desc_buffer.data());
-
- ASSERT_TRUE(::GetKernelObjectSecurity(token.Get(), DACL_SECURITY_INFORMATION,
- security_desc, length_needed,
- &length_needed));
-
- ATL::CSecurityDesc token_sd(*security_desc);
- ATL::CSid check_sid(
- static_cast<SID*>(security_capabilities->AppContainerSid));
- bool package_sid_found = false;
-
- ATL::CDacl dacl;
- ASSERT_TRUE(token_sd.GetDacl(&dacl));
- unsigned int ace_count = dacl.GetAceCount();
- for (unsigned int i = 0; i < ace_count; ++i) {
- ATL::CSid sid;
- ACCESS_MASK mask = 0;
- BYTE type = 0;
- dacl.GetAclEntry(i, &sid, &mask, &type);
- if (sid == check_sid && mask == TOKEN_ALL_ACCESS &&
- type == ACCESS_ALLOWED_ACE_TYPE) {
- package_sid_found = true;
- }
- }
- ASSERT_TRUE(package_sid_found);
+ CheckDaclForPackageSid(token, security_capabilities, true);
}
// Checks if a sid is in the restricting list of the restricted token.
@@ -761,6 +771,11 @@ TEST(RestrictedTokenTest, LowBoxToken) {
ASSERT_TRUE(token.IsValid());
CheckLowBoxToken(token, ::TokenPrimary, &caps_no_capabilities);
+ ASSERT_TRUE(ReplacePackageSidInDacl(token.Get(), SE_KERNEL_OBJECT,
+ Sid(caps_no_capabilities.AppContainerSid),
+ TOKEN_ALL_ACCESS));
+ CheckDaclForPackageSid(token, &caps_no_capabilities, false);
+
ASSERT_EQ(DWORD{ERROR_SUCCESS},
CreateLowBoxToken(nullptr, IMPERSONATION, &caps_no_capabilities,
nullptr, 0, &token));
diff --git a/chromium/sandbox/win/src/restricted_token_utils.cc b/chromium/sandbox/win/src/restricted_token_utils.cc
index 53f86e07d87..496fb37272d 100644
--- a/chromium/sandbox/win/src/restricted_token_utils.cc
+++ b/chromium/sandbox/win/src/restricted_token_utils.cc
@@ -368,7 +368,8 @@ DWORD CreateLowBoxToken(HANDLE base_token,
&token_lowbox, base_token, TOKEN_ALL_ACCESS, &obj_attr,
security_capabilities->AppContainerSid,
security_capabilities->CapabilityCount,
- security_capabilities->Capabilities, saved_handles_count, saved_handles);
+ security_capabilities->Capabilities, saved_handles_count,
+ saved_handles_count > 0 ? saved_handles : nullptr);
if (!NT_SUCCESS(status))
return GetLastErrorFromNtStatus(status);
diff --git a/chromium/sandbox/win/src/sandbox.h b/chromium/sandbox/win/src/sandbox.h
index f8b7c8f6f63..9dfebfcc172 100644
--- a/chromium/sandbox/win/src/sandbox.h
+++ b/chromium/sandbox/win/src/sandbox.h
@@ -25,6 +25,10 @@
#include "sandbox/win/fuzzer/fuzzer_types.h"
#endif
+#include <stddef.h>
+#include <memory>
+#include <vector>
+
#include "base/memory/ref_counted.h"
#include "sandbox/win/src/sandbox_policy.h"
#include "sandbox/win/src/sandbox_types.h"
@@ -33,6 +37,7 @@
namespace sandbox {
class BrokerServices;
+class PolicyDiagnosticsReceiver;
class ProcessState;
class TargetPolicy;
class TargetServices;
@@ -96,6 +101,18 @@ class BrokerServices {
// more information.
virtual ResultCode WaitForAllTargets() = 0;
+ // This call creates a snapshot of policies managed by the sandbox and
+ // returns them via a helper class.
+ // Parameters:
+ // receiver: The |PolicyDiagnosticsReceiver| implementation will be
+ // called to accept the results of the call.
+ // Returns:
+ // ALL_OK if the request was dispatched. All other return values
+ // imply failure, and the responder will not receive its completion
+ // callback.
+ virtual ResultCode GetPolicyDiagnostics(
+ std::unique_ptr<PolicyDiagnosticsReceiver> receiver) = 0;
+
protected:
~BrokerServices() {}
};
@@ -145,6 +162,36 @@ class TargetServices {
~TargetServices() {}
};
+class PolicyInfo {
+ public:
+ // Returns a JSON representation of the policy snapshot.
+ // This pointer has the same lifetime as this PolicyInfo object.
+ virtual const char* JsonString() = 0;
+ virtual ~PolicyInfo() {}
+};
+
+// This is returned by BrokerServices::GetPolicyDiagnostics().
+// PolicyInfo entries need not be ordered.
+class PolicyList {
+ public:
+ virtual std::vector<std::unique_ptr<PolicyInfo>>::iterator begin() = 0;
+ virtual std::vector<std::unique_ptr<PolicyInfo>>::iterator end() = 0;
+ virtual size_t size() const = 0;
+ virtual ~PolicyList() {}
+};
+
+// This class mediates calls to BrokerServices::GetPolicyDiagnostics().
+class PolicyDiagnosticsReceiver {
+ public:
+ // ReceiveDiagnostics() should return quickly and should not block the
+ // thread on which it is called.
+ virtual void ReceiveDiagnostics(std::unique_ptr<PolicyList> policies) = 0;
+ // OnError() is passed any errors encountered and |ReceiveDiagnostics|
+ // will not be called.
+ virtual void OnError(ResultCode code) = 0;
+ virtual ~PolicyDiagnosticsReceiver() {}
+};
+
} // namespace sandbox
#endif // SANDBOX_WIN_SRC_SANDBOX_H_
diff --git a/chromium/sandbox/win/src/sandbox_constants.cc b/chromium/sandbox/win/src/sandbox_constants.cc
new file mode 100644
index 00000000000..1d932427d13
--- /dev/null
+++ b/chromium/sandbox/win/src/sandbox_constants.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 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/win/src/sandbox_constants.h"
+
+namespace sandbox {
+// Strings used as keys in base::Value snapshots of Policies for WebUI.
+extern const char kAppContainerSid[] = "appContainerSid";
+extern const char kDesiredIntegrityLevel[] = "desiredIntegrityLevel";
+extern const char kDesiredMitigations[] = "desiredMitigations";
+extern const char kJobLevel[] = "jobLevel";
+extern const char kLockdownLevel[] = "lockdownLevel";
+extern const char kLowboxSid[] = "lowboxSid";
+extern const char kPlatformMitigations[] = "platformMitigations";
+extern const char kProcessIds[] = "processIds";
+} // namespace sandbox
diff --git a/chromium/sandbox/win/src/sandbox_constants.h b/chromium/sandbox/win/src/sandbox_constants.h
new file mode 100644
index 00000000000..baf9a1e48d4
--- /dev/null
+++ b/chromium/sandbox/win/src/sandbox_constants.h
@@ -0,0 +1,21 @@
+// Copyright 2019 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.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_CONSTANTS_H_
+#define SANDBOX_WIN_SRC_SANDBOX_CONSTANTS_H_
+
+namespace sandbox {
+// Strings used as keys in base::Value snapshots of Policies.
+extern const char kAppContainerSid[];
+extern const char kDesiredIntegrityLevel[];
+extern const char kDesiredMitigations[];
+extern const char kJobLevel[];
+extern const char kLockdownLevel[];
+extern const char kLowboxSid[];
+extern const char kPlatformMitigations[];
+extern const char kProcessIds[];
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SANDBOX_CONSTANTS_H_
diff --git a/chromium/sandbox/win/src/sandbox_policy_base.cc b/chromium/sandbox/win/src/sandbox_policy_base.cc
index dc4375b3f36..ab27faf874f 100644
--- a/chromium/sandbox/win/src/sandbox_policy_base.cc
+++ b/chromium/sandbox/win/src/sandbox_policy_base.cc
@@ -15,6 +15,7 @@
#include "base/strings/stringprintf.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
+#include "sandbox/win/src/acl.h"
#include "sandbox/win/src/filesystem_policy.h"
#include "sandbox/win/src/interception.h"
#include "sandbox/win/src/job.h"
@@ -299,7 +300,7 @@ ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
return SBOX_ERROR_BAD_PARAMS;
if (!ConvertStringSidToSid(sid, &lowbox_sid_))
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_INVALID_LOWBOX_SID;
return SBOX_ALL_OK;
}
@@ -403,7 +404,7 @@ ResultCode PolicyBase::MakeJobObject(base::win::ScopedHandle* job) {
DWORD result =
job_obj.Init(job_level_, nullptr, ui_exceptions_, memory_limit_);
if (ERROR_SUCCESS != result)
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_INIT_JOB;
*job = job_obj.Take();
return SBOX_ALL_OK;
@@ -418,7 +419,7 @@ ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
CreateRestrictedToken(effective_token_, lockdown_level_, integrity_level_,
PRIMARY, lockdown_default_dacl_, lockdown);
if (ERROR_SUCCESS != result)
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_TOKEN;
// If we're launching on the alternate desktop we need to make sure the
// integrity label on the object is no higher than the sandboxed process's
@@ -444,7 +445,7 @@ ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
SetObjectIntegrityLabel(desktop_handle, SE_WINDOW_OBJECT, L"",
GetIntegrityLevelString(integrity_level_));
if (ERROR_SUCCESS != result)
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_SET_DESKTOP_INTEGRITY;
if (use_alternate_winstation_) {
alternate_desktop_integrity_level_label_ = integrity_level_;
@@ -471,7 +472,12 @@ ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
SecurityCapabilities caps(package_sid);
if (CreateLowBoxToken(lockdown->Get(), PRIMARY, &caps, saved_handles,
saved_handles_count, lowbox) != ERROR_SUCCESS) {
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_CREATE_LOWBOX_TOKEN;
+ }
+
+ if (!ReplacePackageSidInDacl(lowbox->Get(), SE_KERNEL_OBJECT, package_sid,
+ TOKEN_ALL_ACCESS)) {
+ return SBOX_ERROR_CANNOT_MODIFY_LOWBOX_TOKEN_DACL;
}
}
@@ -482,7 +488,7 @@ ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
CreateRestrictedToken(effective_token_, initial_level_, integrity_level_,
IMPERSONATION, lockdown_default_dacl_, initial);
if (ERROR_SUCCESS != result)
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_IMP_TOKEN;
return SBOX_ALL_OK;
}
@@ -753,17 +759,30 @@ ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
break;
}
case SUBSYS_WIN32K_LOCKDOWN: {
- if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
- pattern, semantics, policy_maker_)) {
- NOTREACHED();
- return SBOX_ERROR_BAD_PARAMS;
+ // Win32k intercept rules only supported on Windows 8 and above. This must
+ // match the version checks in process_mitigations.cc for consistency.
+ if (base::win::GetVersion() >= base::win::Version::WIN8) {
+ DCHECK_EQ(MITIGATION_WIN32K_DISABLE,
+ mitigations_ & MITIGATION_WIN32K_DISABLE)
+ << "Enable MITIGATION_WIN32K_DISABLE before adding win32k policy "
+ "rules.";
+ if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
+ pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
}
break;
}
case SUBSYS_SIGNED_BINARY: {
- // These rules only need to be added if the
- // MITIGATION_FORCE_MS_SIGNED_BINS pre-startup mitigation is set.
- if (mitigations_ & MITIGATION_FORCE_MS_SIGNED_BINS) {
+ // Signed intercept rules only supported on Windows 10 TH2 and above. This
+ // must match the version checks in process_mitigations.cc for
+ // consistency.
+ if (base::win::GetVersion() >= base::win::Version::WIN10_TH2) {
+ DCHECK_EQ(MITIGATION_FORCE_MS_SIGNED_BINS,
+ mitigations_ & MITIGATION_FORCE_MS_SIGNED_BINS)
+ << "Enable MITIGATION_FORCE_MS_SIGNED_BINS before adding signed "
+ "policy rules.";
if (!SignedPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
NOTREACHED();
return SBOX_ERROR_BAD_PARAMS;
diff --git a/chromium/sandbox/win/src/sandbox_policy_base.h b/chromium/sandbox/win/src/sandbox_policy_base.h
index 631f974df70..03a8948b789 100644
--- a/chromium/sandbox/win/src/sandbox_policy_base.h
+++ b/chromium/sandbox/win/src/sandbox_policy_base.h
@@ -32,6 +32,7 @@
namespace sandbox {
class LowLevelPolicy;
+class PolicyDiagnostic;
class TargetProcess;
struct PolicyGlobal;
@@ -113,6 +114,8 @@ class PolicyBase final : public TargetPolicy {
const base::HandlesToInheritVector& GetHandlesBeingShared();
private:
+ // Allow PolicyInfo to snapshot PolicyBase for diagnostics.
+ friend class PolicyDiagnostic;
~PolicyBase();
// Sets up interceptions for a new target.
diff --git a/chromium/sandbox/win/src/sandbox_policy_diagnostic.cc b/chromium/sandbox/win/src/sandbox_policy_diagnostic.cc
new file mode 100644
index 00000000000..190b7296ea0
--- /dev/null
+++ b/chromium/sandbox/win/src/sandbox_policy_diagnostic.cc
@@ -0,0 +1,197 @@
+// Copyright 2019 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/win/src/sandbox_policy_diagnostic.h"
+
+#include <stddef.h>
+
+#include <cinttypes>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "sandbox/win/src/sandbox_constants.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+namespace {
+
+base::Value ProcessIdList(std::vector<uint32_t> process_ids) {
+ base::Value results(base::Value::Type::LIST);
+ for (const auto pid : process_ids) {
+ results.GetList().push_back(base::Value(base::strict_cast<double>(pid)));
+ }
+ return results;
+}
+
+std::string GetTokenLevelInEnglish(TokenLevel token) {
+ switch (token) {
+ case USER_LOCKDOWN:
+ return "Lockdown";
+ case USER_RESTRICTED:
+ return "Restricted";
+ case USER_LIMITED:
+ return "Limited";
+ case USER_INTERACTIVE:
+ return "Interactive";
+ case USER_NON_ADMIN:
+ return "Non Admin";
+ case USER_RESTRICTED_SAME_ACCESS:
+ return "Restricted Same Access";
+ case USER_UNPROTECTED:
+ return "Unprotected";
+ case USER_RESTRICTED_NON_ADMIN:
+ return "Restricted Non Admin";
+ case USER_LAST:
+ default:
+ DCHECK(false) << "Unknown TokenType";
+ return "Unknown";
+ }
+}
+
+std::string GetJobLevelInEnglish(JobLevel job) {
+ switch (job) {
+ case JOB_LOCKDOWN:
+ return "Lockdown";
+ case JOB_RESTRICTED:
+ return "Restricted";
+ case JOB_LIMITED_USER:
+ return "Limited User";
+ case JOB_INTERACTIVE:
+ return "Interactive";
+ case JOB_UNPROTECTED:
+ return "Unprotected";
+ case JOB_NONE:
+ return "None";
+ default:
+ DCHECK(false) << "Unknown JobLevel";
+ return "Unknown";
+ }
+}
+
+std::string GetIntegrityLevelInEnglish(IntegrityLevel integrity) {
+ switch (integrity) {
+ case INTEGRITY_LEVEL_SYSTEM:
+ return "S-1-16-16384 System";
+ case INTEGRITY_LEVEL_HIGH:
+ return "S-1-16-12288 High";
+ case INTEGRITY_LEVEL_MEDIUM:
+ return "S-1-16-8192 Medium";
+ case INTEGRITY_LEVEL_MEDIUM_LOW:
+ return "S-1-16-6144 Medium Low";
+ case INTEGRITY_LEVEL_LOW:
+ return "S-1-16-4096 Low";
+ case INTEGRITY_LEVEL_BELOW_LOW:
+ return "S-1-16-2048 Below Low";
+ case INTEGRITY_LEVEL_UNTRUSTED:
+ return "S-1-16-0 Untrusted";
+ case INTEGRITY_LEVEL_LAST:
+ return "Default";
+ default:
+ DCHECK(false) << "Unknown IntegrityLevel";
+ return "Unknown";
+ }
+}
+
+base::string16 GetSidAsString(const Sid* sid) {
+ base::string16 result;
+ if (!sid->ToSddlString(&result))
+ DCHECK(false) << "Failed to make sddl string";
+ return result;
+}
+
+std::string GetMitigationsAsHex(MitigationFlags mitigations) {
+ return base::StringPrintf("%016" PRIx64,
+ base::checked_cast<uint64_t>(mitigations));
+}
+
+std::string GetPlatformMitigationsAsHex(MitigationFlags mitigations) {
+ DWORD64 platform_flags[2] = {0};
+ size_t flags_size = 0;
+ sandbox::ConvertProcessMitigationsToPolicy(mitigations, &(platform_flags[0]),
+ &flags_size);
+ DCHECK(flags_size / sizeof(DWORD64) <= 2)
+ << "Unexpected mitigation flags size";
+ if (flags_size == 2 * sizeof(DWORD64))
+ return base::StringPrintf("%016" PRIx64 "%016" PRIx64, platform_flags[0],
+ platform_flags[1]);
+ return base::StringPrintf("%016" PRIx64, platform_flags[0]);
+}
+
+} // namespace
+
+// We are a friend of PolicyBase so that we can steal its private members
+// quickly in the BrokerServices tracker thread.
+PolicyDiagnostic::PolicyDiagnostic(PolicyBase* policy) {
+ DCHECK(policy);
+ // TODO(crbug/997273) Add more fields once webui plumbing is complete.
+ {
+ AutoLock lock(&policy->lock_);
+ for (auto&& target_process : policy->targets_) {
+ process_ids_.push_back(
+ base::strict_cast<uint32_t>(target_process->ProcessId()));
+ }
+ }
+ lockdown_level_ = policy->lockdown_level_;
+ job_level_ = policy->job_level_;
+
+ // Select the final integrity level.
+ if (policy->delayed_integrity_level_ == INTEGRITY_LEVEL_LAST)
+ desired_integrity_level_ = policy->integrity_level_;
+ else
+ desired_integrity_level_ = policy->delayed_integrity_level_;
+
+ desired_mitigations_ = policy->mitigations_ | policy->delayed_mitigations_;
+
+ if (policy->app_container_profile_)
+ app_container_sid_ =
+ std::make_unique<Sid>(policy->app_container_profile_->GetPackageSid());
+ if (policy->lowbox_sid_)
+ lowbox_sid_ = std::make_unique<Sid>(policy->lowbox_sid_);
+}
+
+PolicyDiagnostic::~PolicyDiagnostic() = default;
+
+const char* PolicyDiagnostic::JsonString() {
+ // Lazily constructs json_string_.
+ if (json_string_)
+ return json_string_->c_str();
+
+ base::Value value(base::Value::Type::DICTIONARY);
+ value.SetKey(kProcessIds, ProcessIdList(process_ids_));
+ value.SetKey(kLockdownLevel,
+ base::Value(GetTokenLevelInEnglish(lockdown_level_)));
+ value.SetKey(kJobLevel, base::Value(GetJobLevelInEnglish(job_level_)));
+ value.SetKey(
+ kDesiredIntegrityLevel,
+ base::Value(GetIntegrityLevelInEnglish(desired_integrity_level_)));
+ value.SetKey(kDesiredMitigations,
+ base::Value(GetMitigationsAsHex(desired_mitigations_)));
+ value.SetKey(kPlatformMitigations,
+ base::Value(GetPlatformMitigationsAsHex(desired_mitigations_)));
+
+ if (app_container_sid_)
+ value.SetKey(kAppContainerSid,
+ base::Value(GetSidAsString(app_container_sid_.get())));
+
+ if (lowbox_sid_)
+ value.SetKey(kLowboxSid, base::Value(GetSidAsString(lowbox_sid_.get())));
+
+ auto json_string = std::make_unique<std::string>();
+ JSONStringValueSerializer to_json(json_string.get());
+ CHECK(to_json.Serialize(value));
+ json_string_ = std::move(json_string);
+ return json_string_->c_str();
+}
+
+} // namespace sandbox
diff --git a/chromium/sandbox/win/src/sandbox_policy_diagnostic.h b/chromium/sandbox/win/src/sandbox_policy_diagnostic.h
new file mode 100644
index 00000000000..0fb4da7bfd7
--- /dev/null
+++ b/chromium/sandbox/win/src/sandbox_policy_diagnostic.h
@@ -0,0 +1,51 @@
+// Copyright 2019 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.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
+#define SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/security_level.h"
+#include "sandbox/win/src/sid.h"
+
+namespace sandbox {
+
+class PolicyBase;
+
+// Intended to rhyme with TargetPolicy, may eventually share a common base
+// with a configuration holding class (i.e. this class will extend with dynamic
+// members such as the |process_ids_| list.)
+class PolicyDiagnostic final : public PolicyInfo {
+ public:
+ // This should quickly copy what it needs from PolicyBase.
+ PolicyDiagnostic(PolicyBase* policy);
+ ~PolicyDiagnostic() override;
+ const char* JsonString() override;
+
+ private:
+ // |json_string_| is lazily constructed.
+ std::unique_ptr<std::string> json_string_;
+ std::vector<uint32_t> process_ids_;
+ TokenLevel lockdown_level_ = USER_LAST;
+ JobLevel job_level_ = JOB_NONE;
+ IntegrityLevel desired_integrity_level_ = INTEGRITY_LEVEL_LAST;
+ MitigationFlags desired_mitigations_ = 0;
+ std::unique_ptr<Sid> app_container_sid_ = nullptr;
+ std::unique_ptr<Sid> lowbox_sid_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(PolicyDiagnostic);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
diff --git a/chromium/sandbox/win/src/sandbox_types.h b/chromium/sandbox/win/src/sandbox_types.h
index e2638996185..2b97b50c201 100644
--- a/chromium/sandbox/win/src/sandbox_types.h
+++ b/chromium/sandbox/win/src/sandbox_types.h
@@ -113,6 +113,32 @@ enum ResultCode : int {
SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_ACCESS_CHECK = 45,
// Cannot create the AppContainer as adding a capability failed.
SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_CAPABILITY = 46,
+ // Cannot initialize a job object.
+ SBOX_ERROR_CANNOT_INIT_JOB = 47,
+ // Invalid LowBox SID string.
+ SBOX_ERROR_INVALID_LOWBOX_SID = 48,
+ // Cannot create restricted token.
+ SBOX_ERROR_CANNOT_CREATE_RESTRICTED_TOKEN = 49,
+ // Cannot set the integrity level on a desktop object.
+ SBOX_ERROR_CANNOT_SET_DESKTOP_INTEGRITY = 50,
+ // Cannot create a LowBox token.
+ SBOX_ERROR_CANNOT_CREATE_LOWBOX_TOKEN = 51,
+ // Cannot modify LowBox token's DACL.
+ SBOX_ERROR_CANNOT_MODIFY_LOWBOX_TOKEN_DACL = 52,
+ // Cannot create restricted impersonation token.
+ SBOX_ERROR_CANNOT_CREATE_RESTRICTED_IMP_TOKEN = 53,
+ // Cannot duplicate target process handle.
+ SBOX_ERROR_CANNOT_DUPLICATE_PROCESS_HANDLE = 54,
+ // Cannot load executable for variable transfer.
+ SBOX_ERROR_CANNOT_LOADLIBRARY_EXECUTABLE = 55,
+ // Cannot find variable address for transfer.
+ SBOX_ERROR_CANNOT_FIND_VARIABLE_ADDRESS = 56,
+ // Cannot write variable value.
+ SBOX_ERROR_CANNOT_WRITE_VARIABLE_VALUE = 57,
+ // Short write to variable.
+ SBOX_ERROR_INVALID_WRITE_VARIABLE_SIZE = 58,
+ // Cannot initialize BrokerServices.
+ SBOX_ERROR_CANNOT_INIT_BROKERSERVICES = 59,
// Placeholder for last item of the enum.
SBOX_ERROR_LAST
};
diff --git a/chromium/sandbox/win/src/target_interceptions.cc b/chromium/sandbox/win/src/target_interceptions.cc
index 2dc2fd1456d..1b467814c6c 100644
--- a/chromium/sandbox/win/src/target_interceptions.cc
+++ b/chromium/sandbox/win/src/target_interceptions.cc
@@ -4,6 +4,7 @@
#include "sandbox/win/src/target_interceptions.h"
+#include "base/win/static_constants.h"
#include "sandbox/win/src/interception_agent.h"
#include "sandbox/win/src/sandbox_factory.h"
#include "sandbox/win/src/sandbox_nt_util.h"
@@ -12,7 +13,6 @@ namespace sandbox {
SANDBOX_INTERCEPT NtExports g_nt;
-const char VERIFIER_DLL_NAME[] = "verifier.dll";
const char KERNEL32_DLL_NAME[] = "kernel32.dll";
enum SectionLoadState {
@@ -60,8 +60,9 @@ TargetNtMapViewOfSection(NtMapViewOfSectionFunction orig_MapViewOfSection,
// indicates Application Verifier is enabled and we should wait until
// the next module is loaded.
if (ansi_module_name &&
- (g_nt._strnicmp(ansi_module_name, VERIFIER_DLL_NAME,
- sizeof(VERIFIER_DLL_NAME)) == 0))
+ (g_nt._strnicmp(
+ ansi_module_name, base::win::kApplicationVerifierDllName,
+ g_nt.strlen(base::win::kApplicationVerifierDllName) + 1) == 0))
break;
if (ansi_module_name &&
diff --git a/chromium/sandbox/win/src/target_process.cc b/chromium/sandbox/win/src/target_process.cc
index 0d999187b16..ff831ada601 100644
--- a/chromium/sandbox/win/src/target_process.cc
+++ b/chromium/sandbox/win/src/target_process.cc
@@ -234,13 +234,13 @@ ResultCode TargetProcess::TransferVariable(const char* name,
#if SANDBOX_EXPORTS
HMODULE module = ::LoadLibrary(exe_name_.get());
if (!module)
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_LOADLIBRARY_EXECUTABLE;
child_var = ::GetProcAddress(module, name);
::FreeLibrary(module);
if (!child_var)
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_FIND_VARIABLE_ADDRESS;
size_t offset =
reinterpret_cast<char*>(child_var) - reinterpret_cast<char*>(module);
@@ -250,10 +250,10 @@ ResultCode TargetProcess::TransferVariable(const char* name,
SIZE_T written;
if (!::WriteProcessMemory(sandbox_process_info_.process_handle(), child_var,
address, size, &written))
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_CANNOT_WRITE_VARIABLE_VALUE;
if (written != size)
- return SBOX_ERROR_GENERIC;
+ return SBOX_ERROR_INVALID_WRITE_VARIABLE_SIZE;
return SBOX_ALL_OK;
}