1f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be 3f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// found in the LICENSE file. 4f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 5f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/services/credentials.h" 6f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 7f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <errno.h> 824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#include <limits.h> 9f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <signal.h> 1024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#include <stddef.h> 11f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <stdint.h> 12f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <stdio.h> 13f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <sys/syscall.h> 14f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <sys/types.h> 15f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <sys/wait.h> 16f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <unistd.h> 17f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 18f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/bind.h" 1994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include "base/compiler_specific.h" 20f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/files/file_path.h" 21f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/files/file_util.h" 22f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/logging.h" 2324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#include "base/macros.h" 24f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/posix/eintr_wrapper.h" 25f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/process/launch.h" 2694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include "base/third_party/valgrind/valgrind.h" 27f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "build/build_config.h" 28f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/services/namespace_utils.h" 29f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/services/proc_util.h" 30f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/services/syscall_wrappers.h" 31f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/services/thread_helpers.h" 32f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/system_headers/capability.h" 33f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/system_headers/linux_signal.h" 34f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 35f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace sandbox { 36f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 37f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace { 38f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 39f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; } 40f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 41f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Checks that the set of RES-uids and the set of RES-gids have 42f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// one element each and return that element in |resuid| and |resgid| 43f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// respectively. It's ok to pass NULL as one or both of the ids. 44f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool GetRESIds(uid_t* resuid, gid_t* resgid) { 45f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko uid_t ruid, euid, suid; 46f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko gid_t rgid, egid, sgid; 47f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(sys_getresuid(&ruid, &euid, &suid) == 0); 48f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(sys_getresgid(&rgid, &egid, &sgid) == 0); 49f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const bool uids_are_equal = (ruid == euid) && (ruid == suid); 50f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const bool gids_are_equal = (rgid == egid) && (rgid == sgid); 51f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (!uids_are_equal || !gids_are_equal) return false; 52f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (resuid) *resuid = euid; 53f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (resgid) *resgid = egid; 54f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return true; 55f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 56f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 57f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoconst int kExitSuccess = 0; 58f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 5924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#if defined(__clang__) 6024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// Disable sanitizers that rely on TLS and may write to non-stack memory. 6124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko__attribute__((no_sanitize_address)) 6224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko__attribute__((no_sanitize_thread)) 6324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko__attribute__((no_sanitize_memory)) 6424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#endif 65f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoint ChrootToSelfFdinfo(void*) { 6624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // This function can be run from a vforked child, so it should not write to 6724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // any memory other than the stack or errno. Reads from TLS may be different 6824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // from in the parent process. 69f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko RAW_CHECK(sys_chroot("/proc/self/fdinfo/") == 0); 70f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 71f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // CWD is essentially an implicit file descriptor, so be careful to not 72f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // leave it behind. 73f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko RAW_CHECK(chdir("/") == 0); 74f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko _exit(kExitSuccess); 75f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 76f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 77f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// chroot() to an empty dir that is "safe". To be safe, it must not contain 78f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// any subdirectory (chroot-ing there would allow a chroot escape) and it must 79f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// be impossible to create an empty directory there. 80f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// We achieve this by doing the following: 81f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 1. We create a new process sharing file system information. 82f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 2. In the child, we chroot to /proc/self/fdinfo/ 83f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// This is already "safe", since fdinfo/ does not contain another directory and 84f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// one cannot create another directory there. 85f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 3. The process dies 86f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// After (3) happens, the directory is not available anymore in /proc. 87f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool ChrootToSafeEmptyDir() { 88f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // We need to chroot to a fdinfo that is unique to a process and have that 89f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // process die. 90f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // 1. We don't want to simply fork() because duplicating the page tables is 91f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // slow with a big address space. 92f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // 2. We do not use a regular thread (that would unshare CLONE_FILES) because 93f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // when we are in a PID namespace, we cannot easily get a handle to the 94f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // /proc/tid directory for the thread (since /proc may not be aware of the 95f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // PID namespace). With a process, we can just use /proc/self. 96f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko pid_t pid = -1; 9794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez char stack_buf[PTHREAD_STACK_MIN] ALIGNAS(16); 98f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ 9994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez defined(ARCH_CPU_MIPS_FAMILY) 100f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // The stack grows downward. 101f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko void* stack = stack_buf + sizeof(stack_buf); 102f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#else 103f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#error "Unsupported architecture" 104f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#endif 105f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 10624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko int clone_flags = CLONE_FS | LINUX_SIGCHLD; 10724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko void* tls = nullptr; 10824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#if defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM_FAMILY) 10924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // Use CLONE_VM | CLONE_VFORK as an optimization to avoid copying page tables. 11024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // Since clone writes to the new child's TLS before returning, we must set a 11124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // new TLS to avoid corrupting the current process's TLS. On ARCH_CPU_X86, 11224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // glibc performs syscalls by calling a function pointer in TLS, so we do not 11324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // attempt this optimization. 11424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko clone_flags |= CLONE_VM | CLONE_VFORK | CLONE_SETTLS; 11524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 11624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko char tls_buf[PTHREAD_STACK_MIN] = {0}; 11724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko tls = tls_buf; 11824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#endif 11924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 12024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko pid = clone(ChrootToSelfFdinfo, stack, clone_flags, nullptr, nullptr, tls, 12124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko nullptr); 122f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(pid != -1); 123f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 124f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko int status = -1; 125f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid); 126f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 127f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return WIFEXITED(status) && WEXITSTATUS(status) == kExitSuccess; 128f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 129f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 130f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// CHECK() that an attempt to move to a new user namespace raised an expected 131f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// errno. 132f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid CheckCloneNewUserErrno(int error) { 133f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // EPERM can happen if already in a chroot. EUSERS if too many nested 134f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // namespaces are used. EINVAL for kernels that don't support the feature. 135f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Valgrind will ENOSYS unshare(). 136f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(error == EPERM || error == EUSERS || error == EINVAL || 137f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko error == ENOSYS); 138f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 139f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 140f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Converts a Capability to the corresponding Linux CAP_XXX value. 141f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoint CapabilityToKernelValue(Credentials::Capability cap) { 142f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko switch (cap) { 143f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko case Credentials::Capability::SYS_CHROOT: 144f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return CAP_SYS_CHROOT; 145f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko case Credentials::Capability::SYS_ADMIN: 146f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return CAP_SYS_ADMIN; 147f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 148f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 149f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko LOG(FATAL) << "Invalid Capability: " << static_cast<int>(cap); 150f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return 0; 151f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 152f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 153f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} // namespace. 154f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 155f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// static 156f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::DropAllCapabilities(int proc_fd) { 157f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (!SetCapabilities(proc_fd, std::vector<Capability>())) { 158f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return false; 159f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 160f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 161f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CHECK(!HasAnyCapability()); 162f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return true; 163f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 164f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 165f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// static 166f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::DropAllCapabilities() { 167f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko base::ScopedFD proc_fd(ProcUtil::OpenProc()); 168f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return Credentials::DropAllCapabilities(proc_fd.get()); 169f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 170f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 171f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// static 172f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::DropAllCapabilitiesOnCurrentThread() { 173f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return SetCapabilitiesOnCurrentThread(std::vector<Capability>()); 174f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 175f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 176f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// static 177f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::SetCapabilitiesOnCurrentThread( 178f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const std::vector<Capability>& caps) { 179f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko struct cap_hdr hdr = {}; 180f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko hdr.version = _LINUX_CAPABILITY_VERSION_3; 181f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}}; 182f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 183f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Initially, cap has no capability flags set. Enable the effective and 184f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // permitted flags only for the requested capabilities. 185f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (const Capability cap : caps) { 186f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const int cap_num = CapabilityToKernelValue(cap); 187f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const size_t index = CAP_TO_INDEX(cap_num); 188f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const uint32_t mask = CAP_TO_MASK(cap_num); 189f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko data[index].effective |= mask; 190f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko data[index].permitted |= mask; 191f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 192f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 193f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return sys_capset(&hdr, data) == 0; 194f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 195f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 196f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// static 197f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::SetCapabilities(int proc_fd, 198f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const std::vector<Capability>& caps) { 199f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DCHECK_LE(0, proc_fd); 200f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 201f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#if !defined(THREAD_SANITIZER) 202f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // With TSAN, accept to break the security model as it is a testing 203f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // configuration. 204f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CHECK(ThreadHelpers::IsSingleThreaded(proc_fd)); 205f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#endif 206f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 207f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return SetCapabilitiesOnCurrentThread(caps); 208f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 209f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 210f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::HasAnyCapability() { 211f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko struct cap_hdr hdr = {}; 212f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko hdr.version = _LINUX_CAPABILITY_VERSION_3; 213f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}}; 214f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 215f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(sys_capget(&hdr, data) == 0); 216f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 217f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (size_t i = 0; i < arraysize(data); ++i) { 218f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (data[i].effective || data[i].permitted || data[i].inheritable) { 219f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return true; 220f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 221f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 222f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 223f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return false; 224f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 225f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 226f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::HasCapability(Capability cap) { 227f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko struct cap_hdr hdr = {}; 228f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko hdr.version = _LINUX_CAPABILITY_VERSION_3; 229f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}}; 230f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 231f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(sys_capget(&hdr, data) == 0); 232f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 233f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const int cap_num = CapabilityToKernelValue(cap); 234f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const size_t index = CAP_TO_INDEX(cap_num); 235f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const uint32_t mask = CAP_TO_MASK(cap_num); 236f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 237f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return (data[index].effective | data[index].permitted | 238f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko data[index].inheritable) & 239f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko mask; 240f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 241f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 242f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// static 243f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::CanCreateProcessInNewUserNS() { 244f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Valgrind will let clone(2) pass-through, but doesn't support unshare(), 245f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // so always consider UserNS unsupported there. 246f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (IsRunningOnValgrind()) { 247f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return false; 248f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 249f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 250f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#if defined(THREAD_SANITIZER) 251f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // With TSAN, processes will always have threads running and can never 252f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // enter a new user namespace with MoveToNewUserNS(). 253f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return false; 254f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#endif 255f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 256f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // This is roughly a fork(). 257f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0); 258f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 259f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (pid == -1) { 260f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CheckCloneNewUserErrno(errno); 261f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return false; 262f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 263f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 264f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // The parent process could have had threads. In the child, these threads 265f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // have disappeared. Make sure to not do anything in the child, as this is a 266f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // fragile execution environment. 267f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (pid == 0) { 268f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko _exit(kExitSuccess); 269f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 270f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 271f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Always reap the child. 272f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko int status = -1; 273f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid); 274f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CHECK(WIFEXITED(status)); 275f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CHECK_EQ(kExitSuccess, WEXITSTATUS(status)); 276f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 277f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // clone(2) succeeded, we can use CLONE_NEWUSER. 278f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return true; 279f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 280f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 281f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::MoveToNewUserNS() { 282f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko uid_t uid; 283f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko gid_t gid; 284f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (!GetRESIds(&uid, &gid)) { 285f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // If all the uids (or gids) are not equal to each other, the security 286f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // model will most likely confuse the caller, abort. 287f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DVLOG(1) << "uids or gids differ!"; 288f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return false; 289f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 290f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko int ret = sys_unshare(CLONE_NEWUSER); 291f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (ret) { 292f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const int unshare_errno = errno; 293f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available " 294f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko << "on this kernel."; 295f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CheckCloneNewUserErrno(unshare_errno); 296f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return false; 297f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 298f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 299f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (NamespaceUtils::KernelSupportsDenySetgroups()) { 300f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(NamespaceUtils::DenySetgroups()); 301f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 302f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 303f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // The current {r,e,s}{u,g}id is now an overflow id (c.f. 304f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // /proc/sys/kernel/overflowuid). Setup the uid and gid maps. 305f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DCHECK(GetRESIds(NULL, NULL)); 306f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const char kGidMapFile[] = "/proc/self/gid_map"; 307f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const char kUidMapFile[] = "/proc/self/uid_map"; 308f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid)); 309f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid)); 310f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DCHECK(GetRESIds(NULL, NULL)); 311f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return true; 312f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 313f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 314f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Credentials::DropFileSystemAccess(int proc_fd) { 315f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CHECK_LE(0, proc_fd); 316f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 317f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CHECK(ChrootToSafeEmptyDir()); 318f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CHECK(!base::DirectoryExists(base::FilePath("/proc"))); 319f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CHECK(!ProcUtil::HasOpenDirectory(proc_fd)); 320f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // We never let this function fail. 321f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return true; 322f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 323f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 32424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkopid_t Credentials::ForkAndDropCapabilitiesInChild() { 32524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko pid_t pid = fork(); 32624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko if (pid != 0) { 32724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko return pid; 32824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko } 32924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 33024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // Since we just forked, we are single threaded. 33124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko PCHECK(DropAllCapabilitiesOnCurrentThread()); 33224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko return 0; 33324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko} 33424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 335f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} // namespace sandbox. 336