ipc/chromium/src/base/process_util_bsd.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2008 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.
     5 // derived from process_util_linux.cc and process_util_mac.cc
     7 #include "base/process_util.h"
     9 #include <sys/param.h>
    10 #include <sys/sysctl.h>
    11 #include <sys/wait.h>
    12 #if defined(OS_DRAGONFLY) || defined(OS_FREEBSD)
    13 #include <sys/user.h>
    14 #endif
    16 #include <ctype.h>
    17 #include <fcntl.h>
    18 #include <kvm.h>
    19 #include <unistd.h>
    21 #include <string>
    23 #include "base/debug_util.h"
    24 #include "base/eintr_wrapper.h"
    25 #include "base/file_util.h"
    26 #include "base/logging.h"
    27 #include "base/string_tokenizer.h"
    28 #include "base/string_util.h"
    30 #if defined(_POSIX_SPAWN) && _POSIX_SPAWN > 0
    31 #define HAVE_POSIX_SPAWN	1
    32 #endif
    34 /*
    35  * On platforms that are not gonk based, we fall back to an arbitrary
    36  * UID. This is generally the UID for user `nobody', albeit it is not
    37  * always the case.
    38  */
    40 #if defined(OS_NETBSD) || defined(OS_OPENBSD)
    41 # define CHILD_UNPRIVILEGED_UID 32767
    42 # define CHILD_UNPRIVILEGED_GID 32767
    43 #else
    44 # define CHILD_UNPRIVILEGED_UID 65534
    45 # define CHILD_UNPRIVILEGED_GID 65534
    46 #endif
    48 #ifndef __dso_public
    49 # ifdef __exported
    50 #  define __dso_public	__exported
    51 # else
    52 #  define __dso_public	__attribute__((__visibility__("default")))
    53 # endif
    54 #endif
    56 #ifdef HAVE_POSIX_SPAWN
    57 #include <spawn.h>
    58 extern "C" char **environ __dso_public;
    59 #endif
    61 namespace {
    63 enum ParsingState {
    64   KEY_NAME,
    65   KEY_VALUE
    66 };
    68 static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
    70 }  // namespace
    72 namespace base {
    74 #ifdef HAVE_POSIX_SPAWN
    76 void FreeEnvVarsArray(char* array[], int length)
    77 {
    78   for (int i = 0; i < length; i++) {
    79     free(array[i]);
    80   }
    81   delete[] array;
    82 }
    84 bool LaunchApp(const std::vector<std::string>& argv,
    85                const file_handle_mapping_vector& fds_to_remap,
    86                bool wait, ProcessHandle* process_handle) {
    87   return LaunchApp(argv, fds_to_remap, environment_map(),
    88                    wait, process_handle);
    89 }
    91 bool LaunchApp(const std::vector<std::string>& argv,
    92                const file_handle_mapping_vector& fds_to_remap,
    93                const environment_map& env_vars_to_set,
    94                bool wait, ProcessHandle* process_handle,
    95                ProcessArchitecture arch) {
    96   return LaunchApp(argv, fds_to_remap, env_vars_to_set,
    97                    PRIVILEGES_INHERIT,
    98                    wait, process_handle);
    99 }
   101 bool LaunchApp(const std::vector<std::string>& argv,
   102                const file_handle_mapping_vector& fds_to_remap,
   103                const environment_map& env_vars_to_set,
   104                ChildPrivileges privs,
   105                bool wait, ProcessHandle* process_handle,
   106                ProcessArchitecture arch) {
   107   bool retval = true;
   109   char* argv_copy[argv.size() + 1];
   110   for (size_t i = 0; i < argv.size(); i++) {
   111     argv_copy[i] = const_cast<char*>(argv[i].c_str());
   112   }
   113   argv_copy[argv.size()] = NULL;
   115   // Make sure we don't leak any FDs to the child process by marking all FDs
   116   // as close-on-exec.
   117   SetAllFDsToCloseOnExec();
   119   // Copy environment to a new char array and add the variables
   120   // in env_vars_to_set.
   121   // Existing variables are overwritten by env_vars_to_set.
   122   int pos = 0;
   123   environment_map combined_env_vars = env_vars_to_set;
   124   while(environ[pos] != NULL) {
   125     std::string varString = environ[pos];
   126     std::string varName = varString.substr(0, varString.find_first_of('='));
   127     std::string varValue = varString.substr(varString.find_first_of('=') + 1);
   128     if (combined_env_vars.find(varName) == combined_env_vars.end()) {
   129       combined_env_vars[varName] = varValue;
   130     }
   131     pos++;
   132   }
   133   int varsLen = combined_env_vars.size() + 1;
   135   char** vars = new char*[varsLen];
   136   int i = 0;
   137   for (environment_map::const_iterator it = combined_env_vars.begin();
   138        it != combined_env_vars.end(); ++it) {
   139     std::string entry(it->first);
   140     entry += "=";
   141     entry += it->second;
   142     vars[i] = strdup(entry.c_str());
   143     i++;
   144   }
   145   vars[i] = NULL;
   147   posix_spawn_file_actions_t file_actions;
   148   if (posix_spawn_file_actions_init(&file_actions) != 0) {
   149     FreeEnvVarsArray(vars, varsLen);
   150     return false;
   151   }
   153   // Turn fds_to_remap array into a set of dup2 calls.
   154   for (file_handle_mapping_vector::const_iterator it = fds_to_remap.begin();
   155        it != fds_to_remap.end();
   156        ++it) {
   157     int src_fd = it->first;
   158     int dest_fd = it->second;
   160     if (src_fd == dest_fd) {
   161       int flags = fcntl(src_fd, F_GETFD);
   162       if (flags != -1) {
   163         fcntl(src_fd, F_SETFD, flags & ~FD_CLOEXEC);
   164       }
   165     } else {
   166       if (posix_spawn_file_actions_adddup2(&file_actions, src_fd, dest_fd) != 0) {
   167         posix_spawn_file_actions_destroy(&file_actions);
   168         FreeEnvVarsArray(vars, varsLen);
   169         return false;
   170       }
   171     }
   172   }
   174   pid_t pid = 0;
   175   int spawn_succeeded = (posix_spawnp(&pid,
   176                                       argv_copy[0],
   177                                       &file_actions,
   178                                       NULL,
   179                                       argv_copy,
   180                                       vars) == 0);
   182   FreeEnvVarsArray(vars, varsLen);
   184   posix_spawn_file_actions_destroy(&file_actions);
   186   bool process_handle_valid = pid > 0;
   187   if (!spawn_succeeded || !process_handle_valid) {
   188     retval = false;
   189   } else {
   190     if (wait)
   191       HANDLE_EINTR(waitpid(pid, 0, 0));
   193     if (process_handle)
   194       *process_handle = pid;
   195   }
   197   return retval;
   198 }
   200 bool LaunchApp(const CommandLine& cl,
   201                bool wait, bool start_hidden, ProcessHandle* process_handle) {
   202   // TODO(playmobil): Do we need to respect the start_hidden flag?
   203   file_handle_mapping_vector no_files;
   204   return LaunchApp(cl.argv(), no_files, wait, process_handle);
   205 }
   207 void SetCurrentProcessPrivileges(ChildPrivileges privs) {
   209 }
   211 #else // no posix_spawn, use fork/exec
   213 bool LaunchApp(const std::vector<std::string>& argv,
   214                const file_handle_mapping_vector& fds_to_remap,
   215                bool wait, ProcessHandle* process_handle) {
   216   return LaunchApp(argv, fds_to_remap, environment_map(),
   217                    wait, process_handle);
   218 }
   220 bool LaunchApp(const std::vector<std::string>& argv,
   221                const file_handle_mapping_vector& fds_to_remap,
   222                const environment_map& env_vars_to_set,
   223                bool wait, ProcessHandle* process_handle,
   224                ProcessArchitecture arch) {
   225   return LaunchApp(argv, fds_to_remap, env_vars_to_set,
   226                    PRIVILEGES_INHERIT,
   227                    wait, process_handle);
   228 }
   230 bool LaunchApp(const std::vector<std::string>& argv,
   231                const file_handle_mapping_vector& fds_to_remap,
   232                const environment_map& env_vars_to_set,
   233                ChildPrivileges privs,
   234                bool wait, ProcessHandle* process_handle,
   235                ProcessArchitecture arch) {
   236   scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
   237   // Illegal to allocate memory after fork and before execvp
   238   InjectiveMultimap fd_shuffle1, fd_shuffle2;
   239   fd_shuffle1.reserve(fds_to_remap.size());
   240   fd_shuffle2.reserve(fds_to_remap.size());
   242   pid_t pid = fork();
   243   if (pid < 0)
   244     return false;
   246   if (pid == 0) {
   247     for (file_handle_mapping_vector::const_iterator
   248         it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
   249       fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
   250       fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
   251     }
   253     if (!ShuffleFileDescriptors(&fd_shuffle1))
   254       _exit(127);
   256     CloseSuperfluousFds(fd_shuffle2);
   258     for (size_t i = 0; i < argv.size(); i++)
   259       argv_cstr[i] = const_cast<char*>(argv[i].c_str());
   260     argv_cstr[argv.size()] = NULL;
   262     SetCurrentProcessPrivileges(privs);
   264     for (environment_map::const_iterator it = env_vars_to_set.begin();
   265          it != env_vars_to_set.end(); ++it) {
   266       if (setenv(it->first.c_str(), it->second.c_str(), 1/*overwrite*/))
   267         _exit(127);
   268     }
   269     execv(argv_cstr[0], argv_cstr.get());
   270     // if we get here, we're in serious trouble and should complain loudly
   271     DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0];
   272     _exit(127);
   273   } else {
   274     gProcessLog.print("==> process %d launched child process %d\n",
   275                       GetCurrentProcId(), pid);
   276     if (wait)
   277       HANDLE_EINTR(waitpid(pid, 0, 0));
   279     if (process_handle)
   280       *process_handle = pid;
   281   }
   283   return true;
   284 }
   286 bool LaunchApp(const CommandLine& cl,
   287                bool wait, bool start_hidden,
   288                ProcessHandle* process_handle) {
   289   file_handle_mapping_vector no_files;
   290   return LaunchApp(cl.argv(), no_files, wait, process_handle);
   291 }
   293 void SetCurrentProcessPrivileges(ChildPrivileges privs) {
   294   if (privs == PRIVILEGES_INHERIT) {
   295     return;
   296   }
   298   gid_t gid = CHILD_UNPRIVILEGED_GID;
   299   uid_t uid = CHILD_UNPRIVILEGED_UID;
   300   if (setgid(gid) != 0) {
   301     DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS";
   302     _exit(127);
   303   }
   304   if (setuid(uid) != 0) {
   305     DLOG(ERROR) << "FAILED TO setuid() CHILD PROCESS";
   306     _exit(127);
   307   }
   308   if (chdir("/") != 0)
   309     gProcessLog.print("==> could not chdir()\n");
   310 }
   312 #endif
   314 NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
   315                                            const ProcessFilter* filter)
   316 {
   317   int numEntries;
   318   kvm_t *kvm;
   319   std::string exe(WideToASCII(executable_name));
   321 #if defined(OS_DRAGONFLY) || defined(OS_FREEBSD)
   322   kvm  = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
   323   struct kinfo_proc* procs = kvm_getprocs(kvm, KERN_PROC_UID, getuid(), &numEntries);
   324   if (procs != NULL && numEntries > 0) {
   325     for (int i = 0; i < numEntries; i++) {
   326 #  if defined(OS_DRAGONFLY)
   327     if (exe != procs[i].kp_comm) continue;
   328       if (filter && !filter->Includes(procs[i].kp_pid, procs[i].kp_ppid)) continue;
   329       ProcessEntry e;
   330       e.pid = procs[i].kp_pid;
   331       e.ppid = procs[i].kp_ppid;
   332       strlcpy(e.szExeFile, procs[i].kp_comm, sizeof e.szExeFile);
   333       content.push_back(e);
   334 #  elif defined(OS_FREEBSD)
   335     if (exe != procs[i].ki_comm) continue;
   336       if (filter && !filter->Includes(procs[i].ki_pid, procs[i].ki_ppid)) continue;
   337       ProcessEntry e;
   338       e.pid = procs[i].ki_pid;
   339       e.ppid = procs[i].ki_ppid;
   340       strlcpy(e.szExeFile, procs[i].ki_comm, sizeof e.szExeFile);
   341       content.push_back(e);
   342 #  endif
   343 #else
   344   kvm  = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
   345 #if defined(OS_OPENBSD)
   346   struct kinfo_proc* procs = kvm_getprocs(kvm, KERN_PROC_UID, getuid(), sizeof(struct kinfo_proc), &numEntries);
   347 #else
   348   struct kinfo_proc2* procs = kvm_getproc2(kvm, KERN_PROC_UID, getuid(), sizeof(struct kinfo_proc2), &numEntries);
   349 #endif
   350   if (procs != NULL && numEntries > 0) {
   351     for (int i = 0; i < numEntries; i++) {
   352     if (exe != procs[i].p_comm) continue;
   353       if (filter && !filter->Includes(procs[i].p_pid, procs[i].p_ppid)) continue;
   354       ProcessEntry e;
   355       e.pid = procs[i].p_pid;
   356       e.ppid = procs[i].p_ppid;
   357       strlcpy(e.szExeFile, procs[i].p_comm, sizeof e.szExeFile);
   358       content.push_back(e);
   359 #endif
   360     }
   361   }
   362   nextEntry = 0;
   363   kvm_close(kvm);
   364 }
   366 NamedProcessIterator::~NamedProcessIterator() {
   367 }
   369 const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
   370   if (nextEntry >= content.size()) return NULL;
   371   return &content[nextEntry++];
   372 }
   374 }  // namespace base

mercurial