| Index: sandbox/linux/services/credentials.cc
|
| diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc
|
| index 6f84a66b7a60f2877a7dc2d85ab7a1d31983c27b..2e66d97cf53a45895d0ea7caeb1e8315f0a510a8 100644
|
| --- a/sandbox/linux/services/credentials.cc
|
| +++ b/sandbox/linux/services/credentials.cc
|
| @@ -7,7 +7,6 @@
|
| #include <errno.h>
|
| #include <signal.h>
|
| #include <stdio.h>
|
| -#include <sys/capability.h>
|
| #include <sys/syscall.h>
|
| #include <sys/types.h>
|
| #include <sys/wait.h>
|
| @@ -27,6 +26,7 @@
|
| #include "sandbox/linux/services/proc_util.h"
|
| #include "sandbox/linux/services/syscall_wrappers.h"
|
| #include "sandbox/linux/services/thread_helpers.h"
|
| +#include "sandbox/linux/system_headers/capability.h"
|
|
|
| namespace sandbox {
|
|
|
| @@ -34,26 +34,6 @@ namespace {
|
|
|
| bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
|
|
|
| -struct CapFreeDeleter {
|
| - inline void operator()(cap_t cap) const {
|
| - int ret = cap_free(cap);
|
| - CHECK_EQ(0, ret);
|
| - }
|
| -};
|
| -
|
| -// Wrapper to manage libcap2's cap_t type.
|
| -typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap;
|
| -
|
| -struct CapTextFreeDeleter {
|
| - inline void operator()(char* cap_text) const {
|
| - int ret = cap_free(cap_text);
|
| - CHECK_EQ(0, ret);
|
| - }
|
| -};
|
| -
|
| -// Wrapper to manage the result from libcap2's cap_from_text().
|
| -typedef scoped_ptr<char, CapTextFreeDeleter> ScopedCapText;
|
| -
|
| // Checks that the set of RES-uids and the set of RES-gids have
|
| // one element each and return that element in |resuid| and |resgid|
|
| // respectively. It's ok to pass NULL as one or both of the ids.
|
| @@ -130,21 +110,27 @@ void CheckCloneNewUserErrno(int error) {
|
| error == ENOSYS);
|
| }
|
|
|
| +// Converts a LinuxCapability to the corresponding Linux CAP_XXX value.
|
| +int LinuxCapabilityToKernelValue(LinuxCapability cap) {
|
| + switch (cap) {
|
| + case LinuxCapability::kCapSysChroot:
|
| + return CAP_SYS_CHROOT;
|
| + case LinuxCapability::kCapSysAdmin:
|
| + return CAP_SYS_ADMIN;
|
| + }
|
| +
|
| + LOG(FATAL) << "Invalid LinuxCapability: " << static_cast<int>(cap);
|
| + return 0;
|
| +}
|
| +
|
| } // namespace.
|
|
|
| bool Credentials::DropAllCapabilities(int proc_fd) {
|
| - DCHECK_LE(0, proc_fd);
|
| -#if !defined(THREAD_SANITIZER)
|
| - // With TSAN, accept to break the security model as it is a testing
|
| - // configuration.
|
| - CHECK(ThreadHelpers::IsSingleThreaded(proc_fd));
|
| -#endif
|
| + if (!SetCapabilities(proc_fd, std::vector<LinuxCapability>())) {
|
| + return false;
|
| + }
|
|
|
| - ScopedCap cap(cap_init());
|
| - CHECK(cap);
|
| - PCHECK(0 == cap_set_proc(cap.get()));
|
| CHECK(!HasAnyCapability());
|
| - // We never let this function fail.
|
| return true;
|
| }
|
|
|
| @@ -153,20 +139,64 @@ bool Credentials::DropAllCapabilities() {
|
| return Credentials::DropAllCapabilities(proc_fd.get());
|
| }
|
|
|
| +// static
|
| +bool Credentials::SetCapabilities(int proc_fd,
|
| + const std::vector<LinuxCapability>& caps) {
|
| + DCHECK_LE(0, proc_fd);
|
| +
|
| +#if !defined(THREAD_SANITIZER)
|
| + // With TSAN, accept to break the security model as it is a testing
|
| + // configuration.
|
| + CHECK(ThreadHelpers::IsSingleThreaded(proc_fd));
|
| +#endif
|
| +
|
| + struct cap_hdr hdr = {};
|
| + hdr.version = _LINUX_CAPABILITY_VERSION_3;
|
| + struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
|
| +
|
| + // Initially, cap has no capability flags set. Enable the effective and
|
| + // permitted flags only for the requested capabilities.
|
| + for (const LinuxCapability cap : caps) {
|
| + const int cap_num = LinuxCapabilityToKernelValue(cap);
|
| + const size_t index = CAP_TO_INDEX(cap_num);
|
| + const uint32_t mask = CAP_TO_MASK(cap_num);
|
| + data[index].effective |= mask;
|
| + data[index].permitted |= mask;
|
| + }
|
| +
|
| + return sys_capset(&hdr, data) == 0;
|
| +}
|
| +
|
| bool Credentials::HasAnyCapability() {
|
| - ScopedCap current_cap(cap_get_proc());
|
| - CHECK(current_cap);
|
| - ScopedCap empty_cap(cap_init());
|
| - CHECK(empty_cap);
|
| - return cap_compare(current_cap.get(), empty_cap.get()) != 0;
|
| + struct cap_hdr hdr = {};
|
| + hdr.version = _LINUX_CAPABILITY_VERSION_3;
|
| + struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
|
| +
|
| + PCHECK(sys_capget(&hdr, data) == 0);
|
| +
|
| + for (size_t i = 0; i < arraysize(data); ++i) {
|
| + if (data[i].effective || data[i].permitted || data[i].inheritable) {
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + return false;
|
| }
|
|
|
| -scoped_ptr<std::string> Credentials::GetCurrentCapString() {
|
| - ScopedCap current_cap(cap_get_proc());
|
| - CHECK(current_cap);
|
| - ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL));
|
| - CHECK(cap_text);
|
| - return scoped_ptr<std::string> (new std::string(cap_text.get()));
|
| +bool Credentials::HasCapability(LinuxCapability cap) {
|
| + struct cap_hdr hdr = {};
|
| + hdr.version = _LINUX_CAPABILITY_VERSION_3;
|
| + struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
|
| +
|
| + PCHECK(sys_capget(&hdr, data) == 0);
|
| +
|
| + const int cap_num = LinuxCapabilityToKernelValue(cap);
|
| + const size_t index = CAP_TO_INDEX(cap_num);
|
| + const uint32_t mask = CAP_TO_MASK(cap_num);
|
| +
|
| + return (data[index].effective | data[index].permitted |
|
| + data[index].inheritable) &
|
| + mask;
|
| }
|
|
|
| // static
|
|
|