1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "sandbox/linux/services/namespace_utils.h" 6 7 #include <fcntl.h> 8 #include <sched.h> 9 #include <stddef.h> 10 #include <sys/stat.h> 11 #include <sys/types.h> 12 #include <unistd.h> 13 14 #include <string> 15 16 #include "base/files/file_path.h" 17 #include "base/files/file_util.h" 18 #include "base/files/scoped_file.h" 19 #include "base/logging.h" 20 #include "base/posix/eintr_wrapper.h" 21 #include "base/process/launch.h" 22 #include "base/strings/safe_sprintf.h" 23 #include "base/third_party/valgrind/valgrind.h" 24 25 namespace sandbox { 26 27 namespace { 28 bool IsRunningOnValgrind() { 29 return RUNNING_ON_VALGRIND; 30 } 31 32 const char kProcSelfSetgroups[] = "/proc/self/setgroups"; 33 } // namespace 34 35 // static 36 bool NamespaceUtils::WriteToIdMapFile(const char* map_file, generic_id_t id) { 37 // This function needs to be async-signal-safe, as it may be called in between 38 // fork and exec. 39 40 int fd = HANDLE_EINTR(open(map_file, O_WRONLY)); 41 if (fd == -1) { 42 return false; 43 } 44 45 const generic_id_t inside_id = id; 46 const generic_id_t outside_id = id; 47 48 char mapping[64]; 49 const ssize_t len = 50 base::strings::SafeSPrintf(mapping, "%d %d 1\n", inside_id, outside_id); 51 const ssize_t rc = HANDLE_EINTR(write(fd, mapping, len)); 52 RAW_CHECK(IGNORE_EINTR(close(fd)) == 0); 53 return rc == len; 54 } 55 56 // static 57 bool NamespaceUtils::KernelSupportsUnprivilegedNamespace(int type) { 58 // Valgrind will let clone(2) pass-through, but doesn't support unshare(), 59 // so always consider namespaces unsupported there. 60 if (IsRunningOnValgrind()) { 61 return false; 62 } 63 64 // As of Linux 3.8, /proc/self/ns/* files exist for all namespace types. Since 65 // user namespaces were added in 3.8, it is OK to rely on the existence of 66 // /proc/self/ns/*. 67 if (!base::PathExists(base::FilePath("/proc/self/ns/user"))) { 68 return false; 69 } 70 71 const char* path; 72 switch (type) { 73 case CLONE_NEWUSER: 74 return true; 75 case CLONE_NEWIPC: 76 path = "/proc/self/ns/ipc"; 77 break; 78 case CLONE_NEWNET: 79 path = "/proc/self/ns/net"; 80 break; 81 case CLONE_NEWNS: 82 path = "/proc/self/ns/mnt"; 83 break; 84 case CLONE_NEWPID: 85 path = "/proc/self/ns/pid"; 86 break; 87 case CLONE_NEWUTS: 88 path = "/proc/self/ns/uts"; 89 break; 90 default: 91 NOTREACHED(); 92 return false; 93 } 94 95 return base::PathExists(base::FilePath(path)); 96 } 97 98 // static 99 bool NamespaceUtils::KernelSupportsDenySetgroups() { 100 return base::PathExists(base::FilePath(kProcSelfSetgroups)); 101 } 102 103 // static 104 bool NamespaceUtils::DenySetgroups() { 105 // This function needs to be async-signal-safe. 106 int fd = HANDLE_EINTR(open(kProcSelfSetgroups, O_WRONLY)); 107 if (fd == -1) { 108 return false; 109 } 110 111 static const char kDeny[] = "deny"; 112 const ssize_t len = sizeof(kDeny) - 1; 113 const ssize_t rc = HANDLE_EINTR(write(fd, kDeny, len)); 114 RAW_CHECK(IGNORE_EINTR(close(fd)) == 0); 115 return rc == len; 116 } 117 118 } // namespace sandbox 119