posix: Make DoubleForkAndExec accept an envp parameter

This will be useful to allow setting variables such as CLASSPATH or
LD_LIBRARY_PATH without modifying or depending upon the application's
current environment.

Bug: crashpad:30
Change-Id: I34f31bcc397e51d789b48eb654d80f992a719074
Reviewed-on: https://chromium-review.googlesource.com/1194399
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Joshua Peraza 2018-08-29 07:28:10 -07:00 committed by Commit Bot
parent 8068e2dd6d
commit 0204fbd38b
4 changed files with 28 additions and 1 deletions

View File

@ -201,7 +201,7 @@ bool CrashpadClient::StartHandlerForClient(
argv.push_back(FormatArgumentInt("initial-client-fd", socket)); argv.push_back(FormatArgumentInt("initial-client-fd", socket));
return DoubleForkAndExec(argv, socket, true, nullptr); return DoubleForkAndExec(argv, nullptr, socket, true, nullptr);
} }
// static // static

View File

@ -338,6 +338,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface {
// this interface. // this interface.
if (!DoubleForkAndExec( if (!DoubleForkAndExec(
argv, argv,
nullptr,
server_write_fd.get(), server_write_fd.get(),
true, true,
restart ? CrashpadClient::UseSystemDefaultHandler : nullptr)) { restart ? CrashpadClient::UseSystemDefaultHandler : nullptr)) {

View File

@ -27,9 +27,12 @@
namespace crashpad { namespace crashpad {
bool DoubleForkAndExec(const std::vector<std::string>& argv, bool DoubleForkAndExec(const std::vector<std::string>& argv,
const std::vector<std::string>* envp,
int preserve_fd, int preserve_fd,
bool use_path, bool use_path,
void (*child_function)()) { void (*child_function)()) {
DCHECK(!envp || !use_path);
// argv_c contains const char* pointers and is terminated by nullptr. This is // argv_c contains const char* pointers and is terminated by nullptr. This is
// suitable for passing to execv(). Although argv_c is not used in the parent // suitable for passing to execv(). Although argv_c is not used in the parent
// process, it must be built in the parent process because its unsafe to do // process, it must be built in the parent process because its unsafe to do
@ -41,6 +44,15 @@ bool DoubleForkAndExec(const std::vector<std::string>& argv,
} }
argv_c.push_back(nullptr); argv_c.push_back(nullptr);
std::vector<const char*> envp_c;
if (envp) {
envp_c.reserve(envp->size() + 1);
for (const std::string& variable : *envp) {
envp_c.push_back(variable.c_str());
}
envp_c.push_back(nullptr);
}
// Double-fork(). The three processes involved are parent, child, and // Double-fork(). The three processes involved are parent, child, and
// grandchild. The grandchild will call execv(). The child exits immediately // grandchild. The grandchild will call execv(). The child exits immediately
// after spawning the grandchild, so the grandchild becomes an orphan and its // after spawning the grandchild, so the grandchild becomes an orphan and its
@ -102,6 +114,13 @@ bool DoubleForkAndExec(const std::vector<std::string>& argv,
// const_cast is safe. // const_cast is safe.
char* const* argv_for_execv = const_cast<char* const*>(&argv_c[0]); char* const* argv_for_execv = const_cast<char* const*>(&argv_c[0]);
if (envp) {
// This cast is safe for the same reason that the argv_for_execv cast is.
char* const* envp_for_execv = const_cast<char* const*>(&envp_c[0]);
execve(argv_for_execv[0], argv_for_execv, envp_for_execv);
PLOG(FATAL) << "execve " << argv_for_execv[0];
}
if (use_path) { if (use_path) {
execvp(argv_for_execv[0], argv_for_execv); execvp(argv_for_execv[0], argv_for_execv);
PLOG(FATAL) << "execvp " << argv_for_execv[0]; PLOG(FATAL) << "execvp " << argv_for_execv[0];

View File

@ -36,6 +36,9 @@ namespace crashpad {
//! //!
//! \param[in] argv The argument vector to start the grandchild process with. //! \param[in] argv The argument vector to start the grandchild process with.
//! `argv[0]` is used as the path to the executable. //! `argv[0]` is used as the path to the executable.
//! \param[in] envp A vector of environment variables of the form `var=value` to
//! be passed to `execve()`. If this value is `nullptr`, the current
//! environment is used.
//! \param[in] preserve_fd A file descriptor to be inherited by the grandchild //! \param[in] preserve_fd A file descriptor to be inherited by the grandchild
//! process. This file descriptor is inherited in addition to the three file //! process. This file descriptor is inherited in addition to the three file
//! descriptors associated with the standard input/output streams. Use `-1` //! descriptors associated with the standard input/output streams. Use `-1`
@ -49,6 +52,9 @@ namespace crashpad {
//! that this function will run in the context of a forked process, and must //! that this function will run in the context of a forked process, and must
//! be safe for that purpose. //! be safe for that purpose.
//! //!
//! Setting both \a envp to a value other than `nullptr` and \a use_path to
//! `true` is not currently supported.
//!
//! \return `true` on success, and `false` on failure with a message logged. //! \return `true` on success, and `false` on failure with a message logged.
//! Only failures that occur in the parent process that indicate a definite //! Only failures that occur in the parent process that indicate a definite
//! failure to start the the grandchild are reported in the return value. //! failure to start the the grandchild are reported in the return value.
@ -58,6 +64,7 @@ namespace crashpad {
//! failures, for example, by observing a failure to perform a successful //! failures, for example, by observing a failure to perform a successful
//! handshake with the grandchild process. //! handshake with the grandchild process.
bool DoubleForkAndExec(const std::vector<std::string>& argv, bool DoubleForkAndExec(const std::vector<std::string>& argv,
const std::vector<std::string>* envp,
int preserve_fd, int preserve_fd,
bool use_path, bool use_path,
void (*child_function)()); void (*child_function)());