// Copyright 2015 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/linux/services/namespace_utils.h" #include #include #include #include #include #include #include #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/posix/eintr_wrapper.h" #include "base/process/launch.h" #include "base/strings/safe_sprintf.h" #include "third_party/valgrind/valgrind.h" namespace sandbox { namespace { bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; } const char kProcSelfSetgroups[] = "/proc/self/setgroups"; } // namespace // static bool NamespaceUtils::WriteToIdMapFile(const char* map_file, generic_id_t id) { // This function needs to be async-signal-safe, as it may be called in between // fork and exec. int fd = HANDLE_EINTR(open(map_file, O_WRONLY)); if (fd == -1) { return false; } const generic_id_t inside_id = id; const generic_id_t outside_id = id; char mapping[64]; const ssize_t len = base::strings::SafeSPrintf(mapping, "%d %d 1\n", inside_id, outside_id); const ssize_t rc = HANDLE_EINTR(write(fd, mapping, len)); RAW_CHECK(IGNORE_EINTR(close(fd)) == 0); return rc == len; } // static bool NamespaceUtils::KernelSupportsUnprivilegedNamespace(int type) { // Valgrind will let clone(2) pass-through, but doesn't support unshare(), // so always consider namespaces unsupported there. if (IsRunningOnValgrind()) { return false; } // As of Linux 3.8, /proc/self/ns/* files exist for all namespace types. Since // user namespaces were added in 3.8, it is OK to rely on the existence of // /proc/self/ns/*. if (!base::PathExists(base::FilePath("/proc/self/ns/user"))) { return false; } const char* path; switch (type) { case CLONE_NEWUSER: return true; case CLONE_NEWIPC: path = "/proc/self/ns/ipc"; break; case CLONE_NEWNET: path = "/proc/self/ns/net"; break; case CLONE_NEWNS: path = "/proc/self/ns/mnt"; break; case CLONE_NEWPID: path = "/proc/self/ns/pid"; break; case CLONE_NEWUTS: path = "/proc/self/ns/uts"; break; default: NOTREACHED(); return false; } return base::PathExists(base::FilePath(path)); } // static bool NamespaceUtils::KernelSupportsDenySetgroups() { return base::PathExists(base::FilePath(kProcSelfSetgroups)); } // static bool NamespaceUtils::DenySetgroups() { // This function needs to be async-signal-safe. int fd = HANDLE_EINTR(open(kProcSelfSetgroups, O_WRONLY)); if (fd == -1) { return false; } static const char kDeny[] = "deny"; const ssize_t len = sizeof(kDeny) - 1; const ssize_t rc = HANDLE_EINTR(write(fd, kDeny, len)); RAW_CHECK(IGNORE_EINTR(close(fd)) == 0); return rc == len; } } // namespace sandbox