summaryrefslogtreecommitdiffstats
path: root/ipc/chromium/src/base/process_util_linux.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/chromium/src/base/process_util_linux.cc')
-rw-r--r--ipc/chromium/src/base/process_util_linux.cc274
1 files changed, 274 insertions, 0 deletions
diff --git a/ipc/chromium/src/base/process_util_linux.cc b/ipc/chromium/src/base/process_util_linux.cc
new file mode 100644
index 000000000..204017db5
--- /dev/null
+++ b/ipc/chromium/src/base/process_util_linux.cc
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process_util.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <memory>
+#include <unistd.h>
+#include <string>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "nsLiteralString.h"
+#include "mozilla/UniquePtr.h"
+
+#include "prenv.h"
+#include "prmem.h"
+
+#ifdef MOZ_WIDGET_GONK
+/*
+ * AID_APP is the first application UID used by Android. We're using
+ * it as our unprivilegied UID. This ensure the UID used is not
+ * shared with any other processes than our own childs.
+ */
+# include <private/android_filesystem_config.h>
+# define CHILD_UNPRIVILEGED_UID AID_APP
+# define CHILD_UNPRIVILEGED_GID AID_APP
+#else
+/*
+ * On platforms that are not gonk based, we fall back to an arbitrary
+ * UID. This is generally the UID for user `nobody', albeit it is not
+ * always the case.
+ */
+# define CHILD_UNPRIVILEGED_UID 65534
+# define CHILD_UNPRIVILEGED_GID 65534
+#endif
+
+namespace {
+
+enum ParsingState {
+ KEY_NAME,
+ KEY_VALUE
+};
+
+static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
+
+} // namespace
+
+namespace base {
+
+class EnvironmentEnvp
+{
+public:
+ EnvironmentEnvp()
+ : mEnvp(PR_DuplicateEnvironment()) {}
+
+ explicit EnvironmentEnvp(const environment_map &em)
+ {
+ mEnvp = (char **)PR_Malloc(sizeof(char *) * (em.size() + 1));
+ if (!mEnvp) {
+ return;
+ }
+ char **e = mEnvp;
+ for (environment_map::const_iterator it = em.begin();
+ it != em.end(); ++it, ++e) {
+ std::string str = it->first;
+ str += "=";
+ str += it->second;
+ size_t len = str.length() + 1;
+ *e = static_cast<char*>(PR_Malloc(len));
+ memcpy(*e, str.c_str(), len);
+ }
+ *e = NULL;
+ }
+
+ ~EnvironmentEnvp()
+ {
+ if (!mEnvp) {
+ return;
+ }
+ for (char **e = mEnvp; *e; ++e) {
+ PR_Free(*e);
+ }
+ PR_Free(mEnvp);
+ }
+
+ char * const *AsEnvp() { return mEnvp; }
+
+ void ToMap(environment_map &em)
+ {
+ if (!mEnvp) {
+ return;
+ }
+ em.clear();
+ for (char **e = mEnvp; *e; ++e) {
+ const char *eq;
+ if ((eq = strchr(*e, '=')) != NULL) {
+ std::string varname(*e, eq - *e);
+ em[varname.c_str()] = &eq[1];
+ }
+ }
+ }
+
+private:
+ char **mEnvp;
+};
+
+class Environment : public environment_map
+{
+public:
+ Environment()
+ {
+ EnvironmentEnvp envp;
+ envp.ToMap(*this);
+ }
+
+ char * const *AsEnvp() {
+ mEnvp.reset(new EnvironmentEnvp(*this));
+ return mEnvp->AsEnvp();
+ }
+
+ void Merge(const environment_map &em)
+ {
+ for (const_iterator it = em.begin(); it != em.end(); ++it) {
+ (*this)[it->first] = it->second;
+ }
+ }
+private:
+ std::auto_ptr<EnvironmentEnvp> mEnvp;
+};
+
+bool LaunchApp(const std::vector<std::string>& argv,
+ const file_handle_mapping_vector& fds_to_remap,
+ bool wait, ProcessHandle* process_handle) {
+ return LaunchApp(argv, fds_to_remap, environment_map(),
+ wait, process_handle);
+}
+
+bool LaunchApp(const std::vector<std::string>& argv,
+ const file_handle_mapping_vector& fds_to_remap,
+ const environment_map& env_vars_to_set,
+ bool wait, ProcessHandle* process_handle,
+ ProcessArchitecture arch) {
+ return LaunchApp(argv, fds_to_remap, env_vars_to_set,
+ PRIVILEGES_INHERIT,
+ wait, process_handle);
+}
+
+bool LaunchApp(const std::vector<std::string>& argv,
+ const file_handle_mapping_vector& fds_to_remap,
+ const environment_map& env_vars_to_set,
+ ChildPrivileges privs,
+ bool wait, ProcessHandle* process_handle,
+ ProcessArchitecture arch) {
+ mozilla::UniquePtr<char*[]> argv_cstr(new char*[argv.size() + 1]);
+ // Illegal to allocate memory after fork and before execvp
+ InjectiveMultimap fd_shuffle1, fd_shuffle2;
+ fd_shuffle1.reserve(fds_to_remap.size());
+ fd_shuffle2.reserve(fds_to_remap.size());
+
+ Environment env;
+ env.Merge(env_vars_to_set);
+ char * const *envp = env.AsEnvp();
+ if (!envp) {
+ DLOG(ERROR) << "FAILED to duplicate environment for: " << argv_cstr[0];
+ return false;
+ }
+
+ pid_t pid = fork();
+ if (pid < 0)
+ return false;
+
+ if (pid == 0) {
+ for (file_handle_mapping_vector::const_iterator
+ it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
+ fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
+ fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
+ }
+
+ if (!ShuffleFileDescriptors(&fd_shuffle1))
+ _exit(127);
+
+ CloseSuperfluousFds(fd_shuffle2);
+
+ for (size_t i = 0; i < argv.size(); i++)
+ argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+ argv_cstr[argv.size()] = NULL;
+
+ SetCurrentProcessPrivileges(privs);
+
+ execve(argv_cstr[0], argv_cstr.get(), envp);
+ // if we get here, we're in serious trouble and should complain loudly
+ // NOTE: This is async signal unsafe; it could deadlock instead. (But
+ // only on debug builds; otherwise it's a signal-safe no-op.)
+ DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0];
+ _exit(127);
+ } else {
+ gProcessLog.print("==> process %d launched child process %d\n",
+ GetCurrentProcId(), pid);
+ if (wait)
+ HANDLE_EINTR(waitpid(pid, 0, 0));
+
+ if (process_handle)
+ *process_handle = pid;
+ }
+
+ return true;
+}
+
+bool LaunchApp(const CommandLine& cl,
+ bool wait, bool start_hidden,
+ ProcessHandle* process_handle) {
+ file_handle_mapping_vector no_files;
+ return LaunchApp(cl.argv(), no_files, wait, process_handle);
+}
+
+void SetCurrentProcessPrivileges(ChildPrivileges privs) {
+ if (privs == PRIVILEGES_INHERIT) {
+ return;
+ }
+
+ gid_t gid = CHILD_UNPRIVILEGED_GID;
+ uid_t uid = CHILD_UNPRIVILEGED_UID;
+#ifdef MOZ_WIDGET_GONK
+ {
+ static bool checked_pix_max, pix_max_ok;
+ if (!checked_pix_max) {
+ checked_pix_max = true;
+ int fd = open("/proc/sys/kernel/pid_max", O_CLOEXEC | O_RDONLY);
+ if (fd < 0) {
+ DLOG(ERROR) << "Failed to open pid_max";
+ _exit(127);
+ }
+ char buf[PATH_MAX];
+ ssize_t len = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (len < 0) {
+ DLOG(ERROR) << "Failed to read pid_max";
+ _exit(127);
+ }
+ buf[len] = '\0';
+ int pid_max = atoi(buf);
+ pix_max_ok =
+ (pid_max + CHILD_UNPRIVILEGED_UID > CHILD_UNPRIVILEGED_UID);
+ }
+ if (!pix_max_ok) {
+ DLOG(ERROR) << "Can't safely get unique uid/gid";
+ _exit(127);
+ }
+ gid += getpid();
+ uid += getpid();
+ }
+#endif
+ if (setgid(gid) != 0) {
+ DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS";
+ _exit(127);
+ }
+ if (setuid(uid) != 0) {
+ DLOG(ERROR) << "FAILED TO setuid() CHILD PROCESS";
+ _exit(127);
+ }
+ if (chdir("/") != 0)
+ gProcessLog.print("==> could not chdir()\n");
+}
+
+} // namespace base