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_sandbox.h" 6 7 #include <sched.h> 8 #include <signal.h> 9 #include <stddef.h> 10 #include <stdlib.h> 11 #include <sys/types.h> 12 #include <unistd.h> 13 14 #include <string> 15 #include <utility> 16 #include <vector> 17 18 #include "base/command_line.h" 19 #include "base/environment.h" 20 #include "base/files/scoped_file.h" 21 #include "base/logging.h" 22 #include "base/macros.h" 23 #include "base/posix/eintr_wrapper.h" 24 #include "base/process/launch.h" 25 #include "base/process/process.h" 26 #include "sandbox/linux/services/credentials.h" 27 #include "sandbox/linux/services/namespace_utils.h" 28 #include "sandbox/linux/services/syscall_wrappers.h" 29 #include "sandbox/linux/system_headers/linux_signal.h" 30 31 namespace sandbox { 32 33 namespace { 34 35 const char kSandboxUSERNSEnvironmentVarName[] = "SBX_USER_NS"; 36 const char kSandboxPIDNSEnvironmentVarName[] = "SBX_PID_NS"; 37 const char kSandboxNETNSEnvironmentVarName[] = "SBX_NET_NS"; 38 39 #if !defined(OS_NACL_NONSFI) 40 class WriteUidGidMapDelegate : public base::LaunchOptions::PreExecDelegate { 41 public: 42 WriteUidGidMapDelegate() 43 : uid_(getuid()), 44 gid_(getgid()), 45 supports_deny_setgroups_( 46 NamespaceUtils::KernelSupportsDenySetgroups()) {} 47 48 ~WriteUidGidMapDelegate() override {} 49 50 void RunAsyncSafe() override { 51 if (supports_deny_setgroups_) { 52 RAW_CHECK(NamespaceUtils::DenySetgroups()); 53 } 54 RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/uid_map", uid_)); 55 RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/gid_map", gid_)); 56 } 57 58 private: 59 const uid_t uid_; 60 const gid_t gid_; 61 const bool supports_deny_setgroups_; 62 DISALLOW_COPY_AND_ASSIGN(WriteUidGidMapDelegate); 63 }; 64 65 void SetEnvironForNamespaceType(base::EnvironmentMap* environ, 66 base::NativeEnvironmentString env_var, 67 bool value) { 68 // An empty string causes the env var to be unset in the child process. 69 (*environ)[env_var] = value ? "1" : ""; 70 } 71 #endif // !defined(OS_NACL_NONSFI) 72 73 // Linux supports up to 64 signals. This should be updated if that ever changes. 74 int g_signal_exit_codes[64]; 75 76 void TerminationSignalHandler(int sig) { 77 // Return a special exit code so that the process is detected as terminated by 78 // a signal. 79 const size_t sig_idx = static_cast<size_t>(sig); 80 if (sig_idx < arraysize(g_signal_exit_codes)) { 81 _exit(g_signal_exit_codes[sig_idx]); 82 } 83 84 _exit(NamespaceSandbox::SignalExitCode(sig)); 85 } 86 87 } // namespace 88 89 #if !defined(OS_NACL_NONSFI) 90 NamespaceSandbox::Options::Options() 91 : ns_types(CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET), 92 fail_on_unsupported_ns_type(false) {} 93 94 NamespaceSandbox::Options::~Options() {} 95 96 // static 97 base::Process NamespaceSandbox::LaunchProcess( 98 const base::CommandLine& cmdline, 99 const base::LaunchOptions& launch_options) { 100 return LaunchProcessWithOptions(cmdline.argv(), launch_options, Options()); 101 } 102 103 // static 104 base::Process NamespaceSandbox::LaunchProcess( 105 const std::vector<std::string>& argv, 106 const base::LaunchOptions& launch_options) { 107 return LaunchProcessWithOptions(argv, launch_options, Options()); 108 } 109 110 // static 111 base::Process NamespaceSandbox::LaunchProcessWithOptions( 112 const base::CommandLine& cmdline, 113 const base::LaunchOptions& launch_options, 114 const Options& ns_sandbox_options) { 115 return LaunchProcessWithOptions(cmdline.argv(), launch_options, 116 ns_sandbox_options); 117 } 118 119 // static 120 base::Process NamespaceSandbox::LaunchProcessWithOptions( 121 const std::vector<std::string>& argv, 122 const base::LaunchOptions& launch_options, 123 const Options& ns_sandbox_options) { 124 // These fields may not be set by the caller. 125 CHECK(launch_options.pre_exec_delegate == nullptr); 126 CHECK_EQ(0, launch_options.clone_flags); 127 128 int clone_flags = 0; 129 const int kSupportedTypes[] = {CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET}; 130 for (const int ns_type : kSupportedTypes) { 131 if ((ns_type & ns_sandbox_options.ns_types) == 0) { 132 continue; 133 } 134 135 if (NamespaceUtils::KernelSupportsUnprivilegedNamespace(ns_type)) { 136 clone_flags |= ns_type; 137 } else if (ns_sandbox_options.fail_on_unsupported_ns_type) { 138 return base::Process(); 139 } 140 } 141 CHECK(clone_flags & CLONE_NEWUSER); 142 143 WriteUidGidMapDelegate write_uid_gid_map_delegate; 144 145 base::LaunchOptions launch_options_copy = launch_options; 146 launch_options_copy.pre_exec_delegate = &write_uid_gid_map_delegate; 147 launch_options_copy.clone_flags = clone_flags; 148 149 const std::pair<int, const char*> clone_flag_environ[] = { 150 std::make_pair(CLONE_NEWUSER, kSandboxUSERNSEnvironmentVarName), 151 std::make_pair(CLONE_NEWPID, kSandboxPIDNSEnvironmentVarName), 152 std::make_pair(CLONE_NEWNET, kSandboxNETNSEnvironmentVarName), 153 }; 154 155 base::EnvironmentMap* environ = &launch_options_copy.environ; 156 for (const auto& entry : clone_flag_environ) { 157 const int flag = entry.first; 158 const char* environ_name = entry.second; 159 SetEnvironForNamespaceType(environ, environ_name, clone_flags & flag); 160 } 161 162 return base::LaunchProcess(argv, launch_options_copy); 163 } 164 #endif // !defined(OS_NACL_NONSFI) 165 166 // static 167 pid_t NamespaceSandbox::ForkInNewPidNamespace(bool drop_capabilities_in_child) { 168 const pid_t pid = 169 base::ForkWithFlags(CLONE_NEWPID | LINUX_SIGCHLD, nullptr, nullptr); 170 if (pid < 0) { 171 return pid; 172 } 173 174 if (pid == 0) { 175 DCHECK_EQ(1, getpid()); 176 if (drop_capabilities_in_child) { 177 // Since we just forked, we are single-threaded, so this should be safe. 178 CHECK(Credentials::DropAllCapabilitiesOnCurrentThread()); 179 } 180 return 0; 181 } 182 183 return pid; 184 } 185 186 // static 187 void NamespaceSandbox::InstallDefaultTerminationSignalHandlers() { 188 static const int kDefaultTermSignals[] = { 189 LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGABRT, LINUX_SIGQUIT, 190 LINUX_SIGPIPE, LINUX_SIGTERM, LINUX_SIGUSR1, LINUX_SIGUSR2, 191 }; 192 193 for (const int sig : kDefaultTermSignals) { 194 InstallTerminationSignalHandler(sig, SignalExitCode(sig)); 195 } 196 } 197 198 // static 199 bool NamespaceSandbox::InstallTerminationSignalHandler( 200 int sig, 201 int exit_code) { 202 struct sigaction old_action; 203 PCHECK(sys_sigaction(sig, nullptr, &old_action) == 0); 204 205 #if !defined(OS_NACL_NONSFI) 206 if (old_action.sa_flags & SA_SIGINFO && 207 old_action.sa_sigaction != nullptr) { 208 return false; 209 } 210 #endif 211 212 if (old_action.sa_handler != LINUX_SIG_DFL) { 213 return false; 214 } 215 216 const size_t sig_idx = static_cast<size_t>(sig); 217 CHECK_LT(sig_idx, arraysize(g_signal_exit_codes)); 218 219 DCHECK_GE(exit_code, 0); 220 DCHECK_LT(exit_code, 256); 221 222 g_signal_exit_codes[sig_idx] = exit_code; 223 224 struct sigaction action = {}; 225 action.sa_handler = &TerminationSignalHandler; 226 PCHECK(sys_sigaction(sig, &action, nullptr) == 0); 227 return true; 228 } 229 230 // static 231 bool NamespaceSandbox::InNewUserNamespace() { 232 return getenv(kSandboxUSERNSEnvironmentVarName) != nullptr; 233 } 234 235 // static 236 bool NamespaceSandbox::InNewPidNamespace() { 237 return getenv(kSandboxPIDNSEnvironmentVarName) != nullptr; 238 } 239 240 // static 241 bool NamespaceSandbox::InNewNetNamespace() { 242 return getenv(kSandboxNETNSEnvironmentVarName) != nullptr; 243 } 244 245 } // namespace sandbox 246