1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/process_util_bsd.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,374 @@ 1.4 +// Copyright (c) 2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +// derived from process_util_linux.cc and process_util_mac.cc 1.9 + 1.10 +#include "base/process_util.h" 1.11 + 1.12 +#include <sys/param.h> 1.13 +#include <sys/sysctl.h> 1.14 +#include <sys/wait.h> 1.15 +#if defined(OS_DRAGONFLY) || defined(OS_FREEBSD) 1.16 +#include <sys/user.h> 1.17 +#endif 1.18 + 1.19 +#include <ctype.h> 1.20 +#include <fcntl.h> 1.21 +#include <kvm.h> 1.22 +#include <unistd.h> 1.23 + 1.24 +#include <string> 1.25 + 1.26 +#include "base/debug_util.h" 1.27 +#include "base/eintr_wrapper.h" 1.28 +#include "base/file_util.h" 1.29 +#include "base/logging.h" 1.30 +#include "base/string_tokenizer.h" 1.31 +#include "base/string_util.h" 1.32 + 1.33 +#if defined(_POSIX_SPAWN) && _POSIX_SPAWN > 0 1.34 +#define HAVE_POSIX_SPAWN 1 1.35 +#endif 1.36 + 1.37 +/* 1.38 + * On platforms that are not gonk based, we fall back to an arbitrary 1.39 + * UID. This is generally the UID for user `nobody', albeit it is not 1.40 + * always the case. 1.41 + */ 1.42 + 1.43 +#if defined(OS_NETBSD) || defined(OS_OPENBSD) 1.44 +# define CHILD_UNPRIVILEGED_UID 32767 1.45 +# define CHILD_UNPRIVILEGED_GID 32767 1.46 +#else 1.47 +# define CHILD_UNPRIVILEGED_UID 65534 1.48 +# define CHILD_UNPRIVILEGED_GID 65534 1.49 +#endif 1.50 + 1.51 +#ifndef __dso_public 1.52 +# ifdef __exported 1.53 +# define __dso_public __exported 1.54 +# else 1.55 +# define __dso_public __attribute__((__visibility__("default"))) 1.56 +# endif 1.57 +#endif 1.58 + 1.59 +#ifdef HAVE_POSIX_SPAWN 1.60 +#include <spawn.h> 1.61 +extern "C" char **environ __dso_public; 1.62 +#endif 1.63 + 1.64 +namespace { 1.65 + 1.66 +enum ParsingState { 1.67 + KEY_NAME, 1.68 + KEY_VALUE 1.69 +}; 1.70 + 1.71 +static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG"); 1.72 + 1.73 +} // namespace 1.74 + 1.75 +namespace base { 1.76 + 1.77 +#ifdef HAVE_POSIX_SPAWN 1.78 + 1.79 +void FreeEnvVarsArray(char* array[], int length) 1.80 +{ 1.81 + for (int i = 0; i < length; i++) { 1.82 + free(array[i]); 1.83 + } 1.84 + delete[] array; 1.85 +} 1.86 + 1.87 +bool LaunchApp(const std::vector<std::string>& argv, 1.88 + const file_handle_mapping_vector& fds_to_remap, 1.89 + bool wait, ProcessHandle* process_handle) { 1.90 + return LaunchApp(argv, fds_to_remap, environment_map(), 1.91 + wait, process_handle); 1.92 +} 1.93 + 1.94 +bool LaunchApp(const std::vector<std::string>& argv, 1.95 + const file_handle_mapping_vector& fds_to_remap, 1.96 + const environment_map& env_vars_to_set, 1.97 + bool wait, ProcessHandle* process_handle, 1.98 + ProcessArchitecture arch) { 1.99 + return LaunchApp(argv, fds_to_remap, env_vars_to_set, 1.100 + PRIVILEGES_INHERIT, 1.101 + wait, process_handle); 1.102 +} 1.103 + 1.104 +bool LaunchApp(const std::vector<std::string>& argv, 1.105 + const file_handle_mapping_vector& fds_to_remap, 1.106 + const environment_map& env_vars_to_set, 1.107 + ChildPrivileges privs, 1.108 + bool wait, ProcessHandle* process_handle, 1.109 + ProcessArchitecture arch) { 1.110 + bool retval = true; 1.111 + 1.112 + char* argv_copy[argv.size() + 1]; 1.113 + for (size_t i = 0; i < argv.size(); i++) { 1.114 + argv_copy[i] = const_cast<char*>(argv[i].c_str()); 1.115 + } 1.116 + argv_copy[argv.size()] = NULL; 1.117 + 1.118 + // Make sure we don't leak any FDs to the child process by marking all FDs 1.119 + // as close-on-exec. 1.120 + SetAllFDsToCloseOnExec(); 1.121 + 1.122 + // Copy environment to a new char array and add the variables 1.123 + // in env_vars_to_set. 1.124 + // Existing variables are overwritten by env_vars_to_set. 1.125 + int pos = 0; 1.126 + environment_map combined_env_vars = env_vars_to_set; 1.127 + while(environ[pos] != NULL) { 1.128 + std::string varString = environ[pos]; 1.129 + std::string varName = varString.substr(0, varString.find_first_of('=')); 1.130 + std::string varValue = varString.substr(varString.find_first_of('=') + 1); 1.131 + if (combined_env_vars.find(varName) == combined_env_vars.end()) { 1.132 + combined_env_vars[varName] = varValue; 1.133 + } 1.134 + pos++; 1.135 + } 1.136 + int varsLen = combined_env_vars.size() + 1; 1.137 + 1.138 + char** vars = new char*[varsLen]; 1.139 + int i = 0; 1.140 + for (environment_map::const_iterator it = combined_env_vars.begin(); 1.141 + it != combined_env_vars.end(); ++it) { 1.142 + std::string entry(it->first); 1.143 + entry += "="; 1.144 + entry += it->second; 1.145 + vars[i] = strdup(entry.c_str()); 1.146 + i++; 1.147 + } 1.148 + vars[i] = NULL; 1.149 + 1.150 + posix_spawn_file_actions_t file_actions; 1.151 + if (posix_spawn_file_actions_init(&file_actions) != 0) { 1.152 + FreeEnvVarsArray(vars, varsLen); 1.153 + return false; 1.154 + } 1.155 + 1.156 + // Turn fds_to_remap array into a set of dup2 calls. 1.157 + for (file_handle_mapping_vector::const_iterator it = fds_to_remap.begin(); 1.158 + it != fds_to_remap.end(); 1.159 + ++it) { 1.160 + int src_fd = it->first; 1.161 + int dest_fd = it->second; 1.162 + 1.163 + if (src_fd == dest_fd) { 1.164 + int flags = fcntl(src_fd, F_GETFD); 1.165 + if (flags != -1) { 1.166 + fcntl(src_fd, F_SETFD, flags & ~FD_CLOEXEC); 1.167 + } 1.168 + } else { 1.169 + if (posix_spawn_file_actions_adddup2(&file_actions, src_fd, dest_fd) != 0) { 1.170 + posix_spawn_file_actions_destroy(&file_actions); 1.171 + FreeEnvVarsArray(vars, varsLen); 1.172 + return false; 1.173 + } 1.174 + } 1.175 + } 1.176 + 1.177 + pid_t pid = 0; 1.178 + int spawn_succeeded = (posix_spawnp(&pid, 1.179 + argv_copy[0], 1.180 + &file_actions, 1.181 + NULL, 1.182 + argv_copy, 1.183 + vars) == 0); 1.184 + 1.185 + FreeEnvVarsArray(vars, varsLen); 1.186 + 1.187 + posix_spawn_file_actions_destroy(&file_actions); 1.188 + 1.189 + bool process_handle_valid = pid > 0; 1.190 + if (!spawn_succeeded || !process_handle_valid) { 1.191 + retval = false; 1.192 + } else { 1.193 + if (wait) 1.194 + HANDLE_EINTR(waitpid(pid, 0, 0)); 1.195 + 1.196 + if (process_handle) 1.197 + *process_handle = pid; 1.198 + } 1.199 + 1.200 + return retval; 1.201 +} 1.202 + 1.203 +bool LaunchApp(const CommandLine& cl, 1.204 + bool wait, bool start_hidden, ProcessHandle* process_handle) { 1.205 + // TODO(playmobil): Do we need to respect the start_hidden flag? 1.206 + file_handle_mapping_vector no_files; 1.207 + return LaunchApp(cl.argv(), no_files, wait, process_handle); 1.208 +} 1.209 + 1.210 +void SetCurrentProcessPrivileges(ChildPrivileges privs) { 1.211 + 1.212 +} 1.213 + 1.214 +#else // no posix_spawn, use fork/exec 1.215 + 1.216 +bool LaunchApp(const std::vector<std::string>& argv, 1.217 + const file_handle_mapping_vector& fds_to_remap, 1.218 + bool wait, ProcessHandle* process_handle) { 1.219 + return LaunchApp(argv, fds_to_remap, environment_map(), 1.220 + wait, process_handle); 1.221 +} 1.222 + 1.223 +bool LaunchApp(const std::vector<std::string>& argv, 1.224 + const file_handle_mapping_vector& fds_to_remap, 1.225 + const environment_map& env_vars_to_set, 1.226 + bool wait, ProcessHandle* process_handle, 1.227 + ProcessArchitecture arch) { 1.228 + return LaunchApp(argv, fds_to_remap, env_vars_to_set, 1.229 + PRIVILEGES_INHERIT, 1.230 + wait, process_handle); 1.231 +} 1.232 + 1.233 +bool LaunchApp(const std::vector<std::string>& argv, 1.234 + const file_handle_mapping_vector& fds_to_remap, 1.235 + const environment_map& env_vars_to_set, 1.236 + ChildPrivileges privs, 1.237 + bool wait, ProcessHandle* process_handle, 1.238 + ProcessArchitecture arch) { 1.239 + scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); 1.240 + // Illegal to allocate memory after fork and before execvp 1.241 + InjectiveMultimap fd_shuffle1, fd_shuffle2; 1.242 + fd_shuffle1.reserve(fds_to_remap.size()); 1.243 + fd_shuffle2.reserve(fds_to_remap.size()); 1.244 + 1.245 + pid_t pid = fork(); 1.246 + if (pid < 0) 1.247 + return false; 1.248 + 1.249 + if (pid == 0) { 1.250 + for (file_handle_mapping_vector::const_iterator 1.251 + it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) { 1.252 + fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); 1.253 + fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); 1.254 + } 1.255 + 1.256 + if (!ShuffleFileDescriptors(&fd_shuffle1)) 1.257 + _exit(127); 1.258 + 1.259 + CloseSuperfluousFds(fd_shuffle2); 1.260 + 1.261 + for (size_t i = 0; i < argv.size(); i++) 1.262 + argv_cstr[i] = const_cast<char*>(argv[i].c_str()); 1.263 + argv_cstr[argv.size()] = NULL; 1.264 + 1.265 + SetCurrentProcessPrivileges(privs); 1.266 + 1.267 + for (environment_map::const_iterator it = env_vars_to_set.begin(); 1.268 + it != env_vars_to_set.end(); ++it) { 1.269 + if (setenv(it->first.c_str(), it->second.c_str(), 1/*overwrite*/)) 1.270 + _exit(127); 1.271 + } 1.272 + execv(argv_cstr[0], argv_cstr.get()); 1.273 + // if we get here, we're in serious trouble and should complain loudly 1.274 + DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0]; 1.275 + _exit(127); 1.276 + } else { 1.277 + gProcessLog.print("==> process %d launched child process %d\n", 1.278 + GetCurrentProcId(), pid); 1.279 + if (wait) 1.280 + HANDLE_EINTR(waitpid(pid, 0, 0)); 1.281 + 1.282 + if (process_handle) 1.283 + *process_handle = pid; 1.284 + } 1.285 + 1.286 + return true; 1.287 +} 1.288 + 1.289 +bool LaunchApp(const CommandLine& cl, 1.290 + bool wait, bool start_hidden, 1.291 + ProcessHandle* process_handle) { 1.292 + file_handle_mapping_vector no_files; 1.293 + return LaunchApp(cl.argv(), no_files, wait, process_handle); 1.294 +} 1.295 + 1.296 +void SetCurrentProcessPrivileges(ChildPrivileges privs) { 1.297 + if (privs == PRIVILEGES_INHERIT) { 1.298 + return; 1.299 + } 1.300 + 1.301 + gid_t gid = CHILD_UNPRIVILEGED_GID; 1.302 + uid_t uid = CHILD_UNPRIVILEGED_UID; 1.303 + if (setgid(gid) != 0) { 1.304 + DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS"; 1.305 + _exit(127); 1.306 + } 1.307 + if (setuid(uid) != 0) { 1.308 + DLOG(ERROR) << "FAILED TO setuid() CHILD PROCESS"; 1.309 + _exit(127); 1.310 + } 1.311 + if (chdir("/") != 0) 1.312 + gProcessLog.print("==> could not chdir()\n"); 1.313 +} 1.314 + 1.315 +#endif 1.316 + 1.317 +NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name, 1.318 + const ProcessFilter* filter) 1.319 +{ 1.320 + int numEntries; 1.321 + kvm_t *kvm; 1.322 + std::string exe(WideToASCII(executable_name)); 1.323 + 1.324 +#if defined(OS_DRAGONFLY) || defined(OS_FREEBSD) 1.325 + kvm = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL); 1.326 + struct kinfo_proc* procs = kvm_getprocs(kvm, KERN_PROC_UID, getuid(), &numEntries); 1.327 + if (procs != NULL && numEntries > 0) { 1.328 + for (int i = 0; i < numEntries; i++) { 1.329 +# if defined(OS_DRAGONFLY) 1.330 + if (exe != procs[i].kp_comm) continue; 1.331 + if (filter && !filter->Includes(procs[i].kp_pid, procs[i].kp_ppid)) continue; 1.332 + ProcessEntry e; 1.333 + e.pid = procs[i].kp_pid; 1.334 + e.ppid = procs[i].kp_ppid; 1.335 + strlcpy(e.szExeFile, procs[i].kp_comm, sizeof e.szExeFile); 1.336 + content.push_back(e); 1.337 +# elif defined(OS_FREEBSD) 1.338 + if (exe != procs[i].ki_comm) continue; 1.339 + if (filter && !filter->Includes(procs[i].ki_pid, procs[i].ki_ppid)) continue; 1.340 + ProcessEntry e; 1.341 + e.pid = procs[i].ki_pid; 1.342 + e.ppid = procs[i].ki_ppid; 1.343 + strlcpy(e.szExeFile, procs[i].ki_comm, sizeof e.szExeFile); 1.344 + content.push_back(e); 1.345 +# endif 1.346 +#else 1.347 + kvm = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL); 1.348 +#if defined(OS_OPENBSD) 1.349 + struct kinfo_proc* procs = kvm_getprocs(kvm, KERN_PROC_UID, getuid(), sizeof(struct kinfo_proc), &numEntries); 1.350 +#else 1.351 + struct kinfo_proc2* procs = kvm_getproc2(kvm, KERN_PROC_UID, getuid(), sizeof(struct kinfo_proc2), &numEntries); 1.352 +#endif 1.353 + if (procs != NULL && numEntries > 0) { 1.354 + for (int i = 0; i < numEntries; i++) { 1.355 + if (exe != procs[i].p_comm) continue; 1.356 + if (filter && !filter->Includes(procs[i].p_pid, procs[i].p_ppid)) continue; 1.357 + ProcessEntry e; 1.358 + e.pid = procs[i].p_pid; 1.359 + e.ppid = procs[i].p_ppid; 1.360 + strlcpy(e.szExeFile, procs[i].p_comm, sizeof e.szExeFile); 1.361 + content.push_back(e); 1.362 +#endif 1.363 + } 1.364 + } 1.365 + nextEntry = 0; 1.366 + kvm_close(kvm); 1.367 +} 1.368 + 1.369 +NamedProcessIterator::~NamedProcessIterator() { 1.370 +} 1.371 + 1.372 +const ProcessEntry* NamedProcessIterator::NextProcessEntry() { 1.373 + if (nextEntry >= content.size()) return NULL; 1.374 + return &content[nextEntry++]; 1.375 +} 1.376 + 1.377 +} // namespace base