15ffd83dbSDimitry Andric //===-- ProcessLauncherPosixFork.cpp --------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Host/posix/ProcessLauncherPosixFork.h"
10*06c3fb27SDimitry Andric #include "lldb/Host/FileSystem.h"
110b57cec5SDimitry Andric #include "lldb/Host/Host.h"
120b57cec5SDimitry Andric #include "lldb/Host/HostProcess.h"
130b57cec5SDimitry Andric #include "lldb/Host/Pipe.h"
140b57cec5SDimitry Andric #include "lldb/Host/ProcessLaunchInfo.h"
150b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h"
160b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
170b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
180b57cec5SDimitry Andric
19fe6060f1SDimitry Andric #include <climits>
200b57cec5SDimitry Andric #include <sys/ptrace.h>
210b57cec5SDimitry Andric #include <sys/wait.h>
220b57cec5SDimitry Andric #include <unistd.h>
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric #include <sstream>
250b57cec5SDimitry Andric #include <csignal>
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric #ifdef __ANDROID__
280b57cec5SDimitry Andric #include <android/api-level.h>
290b57cec5SDimitry Andric #define PT_TRACE_ME PTRACE_TRACEME
300b57cec5SDimitry Andric #endif
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric #if defined(__ANDROID_API__) && __ANDROID_API__ < 15
330b57cec5SDimitry Andric #include <linux/personality.h>
340b57cec5SDimitry Andric #elif defined(__linux__)
350b57cec5SDimitry Andric #include <sys/personality.h>
360b57cec5SDimitry Andric #endif
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric using namespace lldb;
390b57cec5SDimitry Andric using namespace lldb_private;
400b57cec5SDimitry Andric
4104eeddc0SDimitry Andric // Begin code running in the child process
4204eeddc0SDimitry Andric // NB: This code needs to be async-signal safe, since we're invoking fork from
4304eeddc0SDimitry Andric // multithreaded contexts.
4404eeddc0SDimitry Andric
write_string(int error_fd,const char * str)4504eeddc0SDimitry Andric static void write_string(int error_fd, const char *str) {
4604eeddc0SDimitry Andric int r = write(error_fd, str, strlen(str));
4704eeddc0SDimitry Andric (void)r;
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
ExitWithError(int error_fd,const char * operation)50349cc55cSDimitry Andric [[noreturn]] static void ExitWithError(int error_fd,
510b57cec5SDimitry Andric const char *operation) {
520b57cec5SDimitry Andric int err = errno;
5304eeddc0SDimitry Andric write_string(error_fd, operation);
5404eeddc0SDimitry Andric write_string(error_fd, " failed: ");
5504eeddc0SDimitry Andric // strerror is not guaranteed to be async-signal safe, but it usually is.
5604eeddc0SDimitry Andric write_string(error_fd, strerror(err));
570b57cec5SDimitry Andric _exit(1);
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
DisableASLR(int error_fd)6004eeddc0SDimitry Andric static void DisableASLR(int error_fd) {
610b57cec5SDimitry Andric #if defined(__linux__)
620b57cec5SDimitry Andric const unsigned long personality_get_current = 0xffffffff;
630b57cec5SDimitry Andric int value = personality(personality_get_current);
640b57cec5SDimitry Andric if (value == -1)
650b57cec5SDimitry Andric ExitWithError(error_fd, "personality get");
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric value = personality(ADDR_NO_RANDOMIZE | value);
680b57cec5SDimitry Andric if (value == -1)
690b57cec5SDimitry Andric ExitWithError(error_fd, "personality set");
700b57cec5SDimitry Andric #endif
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric
DupDescriptor(int error_fd,const char * file,int fd,int flags)7304eeddc0SDimitry Andric static void DupDescriptor(int error_fd, const char *file, int fd, int flags) {
74*06c3fb27SDimitry Andric int target_fd = FileSystem::Instance().Open(file, flags, 0666);
750b57cec5SDimitry Andric
760b57cec5SDimitry Andric if (target_fd == -1)
770b57cec5SDimitry Andric ExitWithError(error_fd, "DupDescriptor-open");
780b57cec5SDimitry Andric
790b57cec5SDimitry Andric if (target_fd == fd)
800b57cec5SDimitry Andric return;
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric if (::dup2(target_fd, fd) == -1)
830b57cec5SDimitry Andric ExitWithError(error_fd, "DupDescriptor-dup2");
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric ::close(target_fd);
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric
8804eeddc0SDimitry Andric namespace {
8904eeddc0SDimitry Andric struct ForkFileAction {
9004eeddc0SDimitry Andric ForkFileAction(const FileAction &act);
9104eeddc0SDimitry Andric
9204eeddc0SDimitry Andric FileAction::Action action;
9304eeddc0SDimitry Andric int fd;
9404eeddc0SDimitry Andric std::string path;
9504eeddc0SDimitry Andric int arg;
9604eeddc0SDimitry Andric };
9704eeddc0SDimitry Andric
9804eeddc0SDimitry Andric struct ForkLaunchInfo {
9904eeddc0SDimitry Andric ForkLaunchInfo(const ProcessLaunchInfo &info);
10004eeddc0SDimitry Andric
10104eeddc0SDimitry Andric bool separate_process_group;
10204eeddc0SDimitry Andric bool debug;
10304eeddc0SDimitry Andric bool disable_aslr;
10404eeddc0SDimitry Andric std::string wd;
10504eeddc0SDimitry Andric const char **argv;
10604eeddc0SDimitry Andric Environment::Envp envp;
10704eeddc0SDimitry Andric std::vector<ForkFileAction> actions;
10804eeddc0SDimitry Andric
has_action__anonee230ac40111::ForkLaunchInfo10904eeddc0SDimitry Andric bool has_action(int fd) const {
11004eeddc0SDimitry Andric for (const ForkFileAction &action : actions) {
11104eeddc0SDimitry Andric if (action.fd == fd)
11204eeddc0SDimitry Andric return true;
11304eeddc0SDimitry Andric }
11404eeddc0SDimitry Andric return false;
11504eeddc0SDimitry Andric }
11604eeddc0SDimitry Andric };
11704eeddc0SDimitry Andric } // namespace
11804eeddc0SDimitry Andric
ChildFunc(int error_fd,const ForkLaunchInfo & info)11904eeddc0SDimitry Andric [[noreturn]] static void ChildFunc(int error_fd, const ForkLaunchInfo &info) {
12004eeddc0SDimitry Andric if (info.separate_process_group) {
1210b57cec5SDimitry Andric if (setpgid(0, 0) != 0)
1220b57cec5SDimitry Andric ExitWithError(error_fd, "setpgid");
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric
12504eeddc0SDimitry Andric for (const ForkFileAction &action : info.actions) {
12604eeddc0SDimitry Andric switch (action.action) {
1270b57cec5SDimitry Andric case FileAction::eFileActionClose:
12804eeddc0SDimitry Andric if (close(action.fd) != 0)
1290b57cec5SDimitry Andric ExitWithError(error_fd, "close");
1300b57cec5SDimitry Andric break;
1310b57cec5SDimitry Andric case FileAction::eFileActionDuplicate:
13204eeddc0SDimitry Andric if (dup2(action.fd, action.arg) == -1)
1330b57cec5SDimitry Andric ExitWithError(error_fd, "dup2");
1340b57cec5SDimitry Andric break;
1350b57cec5SDimitry Andric case FileAction::eFileActionOpen:
13604eeddc0SDimitry Andric DupDescriptor(error_fd, action.path.c_str(), action.fd, action.arg);
1370b57cec5SDimitry Andric break;
1380b57cec5SDimitry Andric case FileAction::eFileActionNone:
1390b57cec5SDimitry Andric break;
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric
1430b57cec5SDimitry Andric // Change working directory
14404eeddc0SDimitry Andric if (!info.wd.empty() && 0 != ::chdir(info.wd.c_str()))
1450b57cec5SDimitry Andric ExitWithError(error_fd, "chdir");
1460b57cec5SDimitry Andric
14704eeddc0SDimitry Andric if (info.disable_aslr)
14804eeddc0SDimitry Andric DisableASLR(error_fd);
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric // Clear the signal mask to prevent the child from being affected by any
1510b57cec5SDimitry Andric // masking done by the parent.
1520b57cec5SDimitry Andric sigset_t set;
1530b57cec5SDimitry Andric if (sigemptyset(&set) != 0 ||
1540b57cec5SDimitry Andric pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
1550b57cec5SDimitry Andric ExitWithError(error_fd, "pthread_sigmask");
1560b57cec5SDimitry Andric
15704eeddc0SDimitry Andric if (info.debug) {
1580b57cec5SDimitry Andric // Do not inherit setgid powers.
1590b57cec5SDimitry Andric if (setgid(getgid()) != 0)
1600b57cec5SDimitry Andric ExitWithError(error_fd, "setgid");
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric // HACK:
1630b57cec5SDimitry Andric // Close everything besides stdin, stdout, and stderr that has no file
1640b57cec5SDimitry Andric // action to avoid leaking. Only do this when debugging, as elsewhere we
1650b57cec5SDimitry Andric // actually rely on passing open descriptors to child processes.
16604eeddc0SDimitry Andric // NB: This code is not async-signal safe, but we currently do not launch
16704eeddc0SDimitry Andric // processes for debugging from within multithreaded contexts.
168349cc55cSDimitry Andric
169349cc55cSDimitry Andric const llvm::StringRef proc_fd_path = "/proc/self/fd";
170349cc55cSDimitry Andric std::error_code ec;
171349cc55cSDimitry Andric bool result;
172349cc55cSDimitry Andric ec = llvm::sys::fs::is_directory(proc_fd_path, result);
173349cc55cSDimitry Andric if (result) {
174349cc55cSDimitry Andric std::vector<int> files_to_close;
175349cc55cSDimitry Andric // Directory iterator doesn't ensure any sequence.
176349cc55cSDimitry Andric for (llvm::sys::fs::directory_iterator iter(proc_fd_path, ec), file_end;
177349cc55cSDimitry Andric iter != file_end && !ec; iter.increment(ec)) {
178349cc55cSDimitry Andric int fd = std::stoi(iter->path().substr(proc_fd_path.size() + 1));
179349cc55cSDimitry Andric
180349cc55cSDimitry Andric // Don't close first three entries since they are stdin, stdout and
181349cc55cSDimitry Andric // stderr.
18204eeddc0SDimitry Andric if (fd > 2 && !info.has_action(fd) && fd != error_fd)
183349cc55cSDimitry Andric files_to_close.push_back(fd);
184349cc55cSDimitry Andric }
185349cc55cSDimitry Andric for (int file_to_close : files_to_close)
186349cc55cSDimitry Andric close(file_to_close);
187349cc55cSDimitry Andric } else {
188349cc55cSDimitry Andric // Since /proc/self/fd didn't work, trying the slow way instead.
189349cc55cSDimitry Andric int max_fd = sysconf(_SC_OPEN_MAX);
190349cc55cSDimitry Andric for (int fd = 3; fd < max_fd; ++fd)
19104eeddc0SDimitry Andric if (!info.has_action(fd) && fd != error_fd)
1920b57cec5SDimitry Andric close(fd);
193349cc55cSDimitry Andric }
1940b57cec5SDimitry Andric
1950b57cec5SDimitry Andric // Start tracing this child that is about to exec.
1960b57cec5SDimitry Andric if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
1970b57cec5SDimitry Andric ExitWithError(error_fd, "ptrace");
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric // Execute. We should never return...
20104eeddc0SDimitry Andric execve(info.argv[0], const_cast<char *const *>(info.argv), info.envp);
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric #if defined(__linux__)
2040b57cec5SDimitry Andric if (errno == ETXTBSY) {
2050b57cec5SDimitry Andric // On android M and earlier we can get this error because the adb daemon
2060b57cec5SDimitry Andric // can hold a write handle on the executable even after it has finished
2070b57cec5SDimitry Andric // uploading it. This state lasts only a short time and happens only when
2080b57cec5SDimitry Andric // there are many concurrent adb commands being issued, such as when
2090b57cec5SDimitry Andric // running the test suite. (The file remains open when someone does an "adb
2100b57cec5SDimitry Andric // shell" command in the fork() child before it has had a chance to exec.)
2110b57cec5SDimitry Andric // Since this state should clear up quickly, wait a while and then give it
2120b57cec5SDimitry Andric // one more go.
2130b57cec5SDimitry Andric usleep(50000);
21404eeddc0SDimitry Andric execve(info.argv[0], const_cast<char *const *>(info.argv), info.envp);
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric #endif
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric // ...unless exec fails. In which case we definitely need to end the child
2190b57cec5SDimitry Andric // here.
2200b57cec5SDimitry Andric ExitWithError(error_fd, "execve");
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric
22304eeddc0SDimitry Andric // End of code running in the child process.
22404eeddc0SDimitry Andric
ForkFileAction(const FileAction & act)22504eeddc0SDimitry Andric ForkFileAction::ForkFileAction(const FileAction &act)
22604eeddc0SDimitry Andric : action(act.GetAction()), fd(act.GetFD()), path(act.GetPath().str()),
22704eeddc0SDimitry Andric arg(act.GetActionArgument()) {}
22804eeddc0SDimitry Andric
22904eeddc0SDimitry Andric static std::vector<ForkFileAction>
MakeForkActions(const ProcessLaunchInfo & info)23004eeddc0SDimitry Andric MakeForkActions(const ProcessLaunchInfo &info) {
23104eeddc0SDimitry Andric std::vector<ForkFileAction> result;
23204eeddc0SDimitry Andric for (size_t i = 0; i < info.GetNumFileActions(); ++i)
23304eeddc0SDimitry Andric result.emplace_back(*info.GetFileActionAtIndex(i));
23404eeddc0SDimitry Andric return result;
23504eeddc0SDimitry Andric }
23604eeddc0SDimitry Andric
FixupEnvironment(Environment env)23704eeddc0SDimitry Andric static Environment::Envp FixupEnvironment(Environment env) {
23804eeddc0SDimitry Andric #ifdef __ANDROID__
23904eeddc0SDimitry Andric // If there is no PATH variable specified inside the environment then set the
24004eeddc0SDimitry Andric // path to /system/bin. It is required because the default path used by
24104eeddc0SDimitry Andric // execve() is wrong on android.
24204eeddc0SDimitry Andric env.try_emplace("PATH", "/system/bin");
24304eeddc0SDimitry Andric #endif
24404eeddc0SDimitry Andric return env.getEnvp();
24504eeddc0SDimitry Andric }
24604eeddc0SDimitry Andric
ForkLaunchInfo(const ProcessLaunchInfo & info)24704eeddc0SDimitry Andric ForkLaunchInfo::ForkLaunchInfo(const ProcessLaunchInfo &info)
24804eeddc0SDimitry Andric : separate_process_group(
24904eeddc0SDimitry Andric info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)),
25004eeddc0SDimitry Andric debug(info.GetFlags().Test(eLaunchFlagDebug)),
25104eeddc0SDimitry Andric disable_aslr(info.GetFlags().Test(eLaunchFlagDisableASLR)),
25204eeddc0SDimitry Andric wd(info.GetWorkingDirectory().GetPath()),
25304eeddc0SDimitry Andric argv(info.GetArguments().GetConstArgumentVector()),
25404eeddc0SDimitry Andric envp(FixupEnvironment(info.GetEnvironment())),
25504eeddc0SDimitry Andric actions(MakeForkActions(info)) {}
25604eeddc0SDimitry Andric
2570b57cec5SDimitry Andric HostProcess
LaunchProcess(const ProcessLaunchInfo & launch_info,Status & error)2580b57cec5SDimitry Andric ProcessLauncherPosixFork::LaunchProcess(const ProcessLaunchInfo &launch_info,
2590b57cec5SDimitry Andric Status &error) {
2600b57cec5SDimitry Andric // A pipe used by the child process to report errors.
2610b57cec5SDimitry Andric PipePosix pipe;
2620b57cec5SDimitry Andric const bool child_processes_inherit = false;
2630b57cec5SDimitry Andric error = pipe.CreateNew(child_processes_inherit);
2640b57cec5SDimitry Andric if (error.Fail())
2650b57cec5SDimitry Andric return HostProcess();
2660b57cec5SDimitry Andric
26704eeddc0SDimitry Andric const ForkLaunchInfo fork_launch_info(launch_info);
26804eeddc0SDimitry Andric
2690b57cec5SDimitry Andric ::pid_t pid = ::fork();
2700b57cec5SDimitry Andric if (pid == -1) {
2710b57cec5SDimitry Andric // Fork failed
2720b57cec5SDimitry Andric error.SetErrorStringWithFormatv("Fork failed with error message: {0}",
2730b57cec5SDimitry Andric llvm::sys::StrError());
2740b57cec5SDimitry Andric return HostProcess(LLDB_INVALID_PROCESS_ID);
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric if (pid == 0) {
2770b57cec5SDimitry Andric // child process
2780b57cec5SDimitry Andric pipe.CloseReadFileDescriptor();
27904eeddc0SDimitry Andric ChildFunc(pipe.ReleaseWriteFileDescriptor(), fork_launch_info);
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric
2820b57cec5SDimitry Andric // parent process
2830b57cec5SDimitry Andric
2840b57cec5SDimitry Andric pipe.CloseWriteFileDescriptor();
285bdd1243dSDimitry Andric llvm::SmallString<0> buf;
286bdd1243dSDimitry Andric size_t pos = 0;
287bdd1243dSDimitry Andric ssize_t r = 0;
288bdd1243dSDimitry Andric do {
289bdd1243dSDimitry Andric pos += r;
290bdd1243dSDimitry Andric buf.resize_for_overwrite(pos + 100);
291bdd1243dSDimitry Andric r = llvm::sys::RetryAfterSignal(-1, read, pipe.GetReadFileDescriptor(),
292bdd1243dSDimitry Andric buf.begin() + pos, buf.size() - pos);
293bdd1243dSDimitry Andric } while (r > 0);
294bdd1243dSDimitry Andric assert(r != -1);
2950b57cec5SDimitry Andric
296bdd1243dSDimitry Andric buf.resize(pos);
297bdd1243dSDimitry Andric if (buf.empty())
2980b57cec5SDimitry Andric return HostProcess(pid); // No error. We're done.
2990b57cec5SDimitry Andric
3000b57cec5SDimitry Andric error.SetErrorString(buf);
3010b57cec5SDimitry Andric
3020b57cec5SDimitry Andric llvm::sys::RetryAfterSignal(-1, waitpid, pid, nullptr, 0);
3030b57cec5SDimitry Andric
3040b57cec5SDimitry Andric return HostProcess();
3050b57cec5SDimitry Andric }
306