LCOV - code coverage report
Current view: top level - ipc/chromium/src/base - process_util_linux.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 71 107 66.4 %
Date: 2017-07-14 16:53:18 Functions: 14 16 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : // Copyright (c) 2008 The Chromium Authors. All rights reserved.
       4             : // Use of this source code is governed by a BSD-style license that can be
       5             : // found in the LICENSE file.
       6             : 
       7             : #include "base/process_util.h"
       8             : 
       9             : #include <ctype.h>
      10             : #include <fcntl.h>
      11             : #include <memory>
      12             : #include <unistd.h>
      13             : #include <string>
      14             : #include <sys/types.h>
      15             : #include <sys/wait.h>
      16             : 
      17             : #include "base/eintr_wrapper.h"
      18             : #include "base/file_util.h"
      19             : #include "base/logging.h"
      20             : #include "base/string_util.h"
      21             : #include "nsLiteralString.h"
      22             : #include "mozilla/UniquePtr.h"
      23             : 
      24             : #include "prenv.h"
      25             : 
      26             : #ifdef MOZ_WIDGET_GONK
      27             : /*
      28             :  * AID_APP is the first application UID used by Android. We're using
      29             :  * it as our unprivilegied UID.  This ensure the UID used is not
      30             :  * shared with any other processes than our own childs.
      31             :  */
      32             : # include <private/android_filesystem_config.h>
      33             : # define CHILD_UNPRIVILEGED_UID AID_APP
      34             : # define CHILD_UNPRIVILEGED_GID AID_APP
      35             : #else
      36             : /*
      37             :  * On platforms that are not gonk based, we fall back to an arbitrary
      38             :  * UID. This is generally the UID for user `nobody', albeit it is not
      39             :  * always the case.
      40             :  */
      41             : # define CHILD_UNPRIVILEGED_UID 65534
      42             : # define CHILD_UNPRIVILEGED_GID 65534
      43             : #endif
      44             : 
      45             : namespace {
      46             : 
      47             : enum ParsingState {
      48             :   KEY_NAME,
      49             :   KEY_VALUE
      50             : };
      51             : 
      52           3 : static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
      53             : 
      54             : }  // namespace
      55             : 
      56             : namespace base {
      57             : 
      58             : class EnvironmentEnvp
      59             : {
      60             : public:
      61           3 :   EnvironmentEnvp()
      62           3 :     : mEnvp(PR_DuplicateEnvironment()) {}
      63             : 
      64           3 :   explicit EnvironmentEnvp(const environment_map &em)
      65           3 :   {
      66           3 :     mEnvp = (char**) malloc(sizeof(char *) * (em.size() + 1));
      67           3 :     if (!mEnvp) {
      68           0 :       return;
      69             :     }
      70           3 :     char **e = mEnvp;
      71         882 :     for (environment_map::const_iterator it = em.begin();
      72         588 :          it != em.end(); ++it, ++e) {
      73         582 :       std::string str = it->first;
      74         291 :       str += "=";
      75         291 :       str += it->second;
      76         291 :       size_t len = str.length() + 1;
      77         291 :       *e = static_cast<char*>(malloc(len));
      78         291 :       memcpy(*e, str.c_str(), len);
      79             :     }
      80           3 :     *e = NULL;
      81             :   }
      82             : 
      83           6 :   ~EnvironmentEnvp()
      84           6 :   {
      85           6 :     if (!mEnvp) {
      86           0 :       return;
      87             :     }
      88         588 :     for (char **e = mEnvp; *e; ++e) {
      89         582 :       free(*e);
      90             :     }
      91           6 :     free(mEnvp);
      92           6 :   }
      93             : 
      94           3 :   char * const *AsEnvp() { return mEnvp; }
      95             : 
      96           3 :   void ToMap(environment_map &em)
      97             :   {
      98           3 :     if (!mEnvp) {
      99           0 :       return;
     100             :     }
     101           3 :     em.clear();
     102         294 :     for (char **e = mEnvp; *e; ++e) {
     103             :       const char *eq;
     104         291 :       if ((eq = strchr(*e, '=')) != NULL) {
     105         582 :         std::string varname(*e, eq - *e);
     106         291 :         em[varname.c_str()] = &eq[1];
     107             :       }
     108             :     }
     109             :   }
     110             : 
     111             : private:
     112             :   char **mEnvp;
     113             : };
     114             : 
     115           3 : class Environment : public environment_map
     116             : {
     117             : public:
     118           3 :   Environment()
     119           3 :   {
     120           6 :     EnvironmentEnvp envp;
     121           3 :     envp.ToMap(*this);
     122           3 :   }
     123             : 
     124           3 :   char * const *AsEnvp() {
     125           3 :     mEnvp.reset(new EnvironmentEnvp(*this));
     126           3 :     return mEnvp->AsEnvp();
     127             :   }
     128             : 
     129           3 :   void Merge(const environment_map &em)
     130             :   {
     131           9 :     for (const_iterator it = em.begin(); it != em.end(); ++it) {
     132           6 :       (*this)[it->first] = it->second;
     133             :     }
     134           3 :   }
     135             : private:
     136             :   std::auto_ptr<EnvironmentEnvp> mEnvp;
     137             : };
     138             : 
     139           1 : bool LaunchApp(const std::vector<std::string>& argv,
     140             :                const file_handle_mapping_vector& fds_to_remap,
     141             :                bool wait, ProcessHandle* process_handle) {
     142           2 :   return LaunchApp(argv, fds_to_remap, environment_map(),
     143           2 :                    wait, process_handle);
     144             : }
     145             : 
     146           1 : bool LaunchApp(const std::vector<std::string>& argv,
     147             :                const file_handle_mapping_vector& fds_to_remap,
     148             :                const environment_map& env_vars_to_set,
     149             :                bool wait, ProcessHandle* process_handle,
     150             :                ProcessArchitecture arch) {
     151           1 :   return LaunchApp(argv, fds_to_remap, env_vars_to_set,
     152             :                    PRIVILEGES_INHERIT,
     153           1 :                    wait, process_handle);
     154             : }
     155             : 
     156           3 : bool LaunchApp(const std::vector<std::string>& argv,
     157             :                const file_handle_mapping_vector& fds_to_remap,
     158             :                const environment_map& env_vars_to_set,
     159             :                ChildPrivileges privs,
     160             :                bool wait, ProcessHandle* process_handle,
     161             :                ProcessArchitecture arch) {
     162           9 :   mozilla::UniquePtr<char*[]> argv_cstr(new char*[argv.size() + 1]);
     163             :   // Illegal to allocate memory after fork and before execvp
     164           6 :   InjectiveMultimap fd_shuffle1, fd_shuffle2;
     165           3 :   fd_shuffle1.reserve(fds_to_remap.size());
     166           3 :   fd_shuffle2.reserve(fds_to_remap.size());
     167             : 
     168           6 :   Environment env;
     169           3 :   env.Merge(env_vars_to_set);
     170           3 :   char * const *envp = env.AsEnvp();
     171           3 :   if (!envp) {
     172           0 :     DLOG(ERROR) << "FAILED to duplicate environment for: " << argv_cstr[0];
     173           0 :     return false;
     174             :   }
     175             : 
     176           3 :   pid_t pid = fork();
     177           3 :   if (pid < 0)
     178           0 :     return false;
     179             : 
     180           3 :   if (pid == 0) {
     181           0 :     for (file_handle_mapping_vector::const_iterator
     182           0 :         it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
     183           0 :       fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
     184           0 :       fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
     185             :     }
     186             : 
     187           0 :     if (!ShuffleFileDescriptors(&fd_shuffle1))
     188           0 :       _exit(127);
     189             : 
     190           0 :     CloseSuperfluousFds(fd_shuffle2);
     191             : 
     192           0 :     for (size_t i = 0; i < argv.size(); i++)
     193           0 :       argv_cstr[i] = const_cast<char*>(argv[i].c_str());
     194           0 :     argv_cstr[argv.size()] = NULL;
     195             : 
     196           0 :     SetCurrentProcessPrivileges(privs);
     197             : 
     198           0 :     execve(argv_cstr[0], argv_cstr.get(), envp);
     199             :     // if we get here, we're in serious trouble and should complain loudly
     200             :     // NOTE: This is async signal unsafe; it could deadlock instead.  (But
     201             :     // only on debug builds; otherwise it's a signal-safe no-op.)
     202           0 :     DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0];
     203           0 :     _exit(127);
     204             :   } else {
     205           3 :     gProcessLog.print("==> process %d launched child process %d\n",
     206           3 :                       GetCurrentProcId(), pid);
     207           3 :     if (wait)
     208           1 :       HANDLE_EINTR(waitpid(pid, 0, 0));
     209             : 
     210           3 :     if (process_handle)
     211           3 :       *process_handle = pid;
     212             :   }
     213             : 
     214           3 :   return true;
     215             : }
     216             : 
     217           0 : bool LaunchApp(const CommandLine& cl,
     218             :                bool wait, bool start_hidden,
     219             :                ProcessHandle* process_handle) {
     220           0 :   file_handle_mapping_vector no_files;
     221           0 :   return LaunchApp(cl.argv(), no_files, wait, process_handle);
     222             : }
     223             : 
     224           0 : void SetCurrentProcessPrivileges(ChildPrivileges privs) {
     225           0 :   if (privs == PRIVILEGES_INHERIT) {
     226           0 :     return;
     227             :   }
     228             : 
     229           0 :   gid_t gid = CHILD_UNPRIVILEGED_GID;
     230           0 :   uid_t uid = CHILD_UNPRIVILEGED_UID;
     231             : #ifdef MOZ_WIDGET_GONK
     232             :   {
     233             :     static bool checked_pix_max, pix_max_ok;
     234             :     if (!checked_pix_max) {
     235             :       checked_pix_max = true;
     236             :       int fd = open("/proc/sys/kernel/pid_max", O_CLOEXEC | O_RDONLY);
     237             :       if (fd < 0) {
     238             :         DLOG(ERROR) << "Failed to open pid_max";
     239             :         _exit(127);
     240             :       }
     241             :       char buf[PATH_MAX];
     242             :       ssize_t len = read(fd, buf, sizeof(buf) - 1);
     243             :       close(fd);
     244             :       if (len < 0) {
     245             :         DLOG(ERROR) << "Failed to read pid_max";
     246             :         _exit(127);
     247             :       }
     248             :       buf[len] = '\0';
     249             :       int pid_max = atoi(buf);
     250             :       pix_max_ok =
     251             :         (pid_max + CHILD_UNPRIVILEGED_UID > CHILD_UNPRIVILEGED_UID);
     252             :     }
     253             :     if (!pix_max_ok) {
     254             :       DLOG(ERROR) << "Can't safely get unique uid/gid";
     255             :       _exit(127);
     256             :     }
     257             :     gid += getpid();
     258             :     uid += getpid();
     259             :   }
     260             : #endif
     261           0 :   if (setgid(gid) != 0) {
     262           0 :     DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS";
     263           0 :     _exit(127);
     264             :   }
     265           0 :   if (setuid(uid) != 0) {
     266           0 :     DLOG(ERROR) << "FAILED TO setuid() CHILD PROCESS";
     267           0 :     _exit(127);
     268             :   }
     269           0 :   if (chdir("/") != 0)
     270           0 :     gProcessLog.print("==> could not chdir()\n");
     271             : }
     272             : 
     273           9 : }  // namespace base

Generated by: LCOV version 1.13