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 |