xref: /llvm-project/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp (revision 9326633abd0e59fc77072488ee8cded4fe83c8a1)
1 //===-- ProcessLauncherPosixFork.cpp --------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Host/posix/ProcessLauncherPosixFork.h"
10 #include "lldb/Host/FileSystem.h"
11 #include "lldb/Host/Host.h"
12 #include "lldb/Host/HostProcess.h"
13 #include "lldb/Host/Pipe.h"
14 #include "lldb/Host/ProcessLaunchInfo.h"
15 #include "lldb/Utility/FileSpec.h"
16 #include "lldb/Utility/Log.h"
17 #include "llvm/Support/Errno.h"
18 
19 #include <climits>
20 #include <sys/ptrace.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23 
24 #include <csignal>
25 #include <sstream>
26 
27 #if defined(__linux__)
28 #include <sys/personality.h>
29 #endif
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 // Begin code running in the child process
35 // NB: This code needs to be async-signal safe, since we're invoking fork from
36 // multithreaded contexts.
37 
38 static void write_string(int error_fd, const char *str) {
39   int r = write(error_fd, str, strlen(str));
40   (void)r;
41 }
42 
43 [[noreturn]] static void ExitWithError(int error_fd, const char *operation) {
44   int err = errno;
45   write_string(error_fd, operation);
46   write_string(error_fd, " failed: ");
47   // strerror is not guaranteed to be async-signal safe, but it usually is.
48   write_string(error_fd, strerror(err));
49   _exit(1);
50 }
51 
52 static void DisableASLR(int error_fd) {
53 #if defined(__linux__)
54   const unsigned long personality_get_current = 0xffffffff;
55   int value = personality(personality_get_current);
56   if (value == -1)
57     ExitWithError(error_fd, "personality get");
58 
59   value = personality(ADDR_NO_RANDOMIZE | value);
60   if (value == -1)
61     ExitWithError(error_fd, "personality set");
62 #endif
63 }
64 
65 static void DupDescriptor(int error_fd, const char *file, int fd, int flags) {
66   int target_fd = FileSystem::Instance().Open(file, flags, 0666);
67 
68   if (target_fd == -1)
69     ExitWithError(error_fd, "DupDescriptor-open");
70 
71   if (target_fd == fd)
72     return;
73 
74   if (::dup2(target_fd, fd) == -1)
75     ExitWithError(error_fd, "DupDescriptor-dup2");
76 
77   ::close(target_fd);
78 }
79 
80 namespace {
81 struct ForkFileAction {
82   ForkFileAction(const FileAction &act);
83 
84   FileAction::Action action;
85   int fd;
86   std::string path;
87   int arg;
88 };
89 
90 struct ForkLaunchInfo {
91   ForkLaunchInfo(const ProcessLaunchInfo &info);
92 
93   bool separate_process_group;
94   bool debug;
95   bool disable_aslr;
96   std::string wd;
97   const char **argv;
98   Environment::Envp envp;
99   std::vector<ForkFileAction> actions;
100 
101   bool has_action(int fd) const {
102     for (const ForkFileAction &action : actions) {
103       if (action.fd == fd)
104         return true;
105     }
106     return false;
107   }
108 };
109 } // namespace
110 
111 [[noreturn]] static void ChildFunc(int error_fd, const ForkLaunchInfo &info) {
112   if (info.separate_process_group) {
113     if (setpgid(0, 0) != 0)
114       ExitWithError(error_fd, "setpgid");
115   }
116 
117   for (const ForkFileAction &action : info.actions) {
118     switch (action.action) {
119     case FileAction::eFileActionClose:
120       if (close(action.fd) != 0)
121         ExitWithError(error_fd, "close");
122       break;
123     case FileAction::eFileActionDuplicate:
124       if (dup2(action.fd, action.arg) == -1)
125         ExitWithError(error_fd, "dup2");
126       break;
127     case FileAction::eFileActionOpen:
128       DupDescriptor(error_fd, action.path.c_str(), action.fd, action.arg);
129       break;
130     case FileAction::eFileActionNone:
131       break;
132     }
133   }
134 
135   // Change working directory
136   if (!info.wd.empty() && 0 != ::chdir(info.wd.c_str()))
137     ExitWithError(error_fd, "chdir");
138 
139   if (info.disable_aslr)
140     DisableASLR(error_fd);
141 
142   // Clear the signal mask to prevent the child from being affected by any
143   // masking done by the parent.
144   sigset_t set;
145   if (sigemptyset(&set) != 0 ||
146       pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
147     ExitWithError(error_fd, "pthread_sigmask");
148 
149   if (info.debug) {
150     // Do not inherit setgid powers.
151     if (setgid(getgid()) != 0)
152       ExitWithError(error_fd, "setgid");
153 
154     // HACK:
155     // Close everything besides stdin, stdout, and stderr that has no file
156     // action to avoid leaking. Only do this when debugging, as elsewhere we
157     // actually rely on passing open descriptors to child processes.
158     // NB: This code is not async-signal safe, but we currently do not launch
159     // processes for debugging from within multithreaded contexts.
160 
161     const llvm::StringRef proc_fd_path = "/proc/self/fd";
162     std::error_code ec;
163     bool result;
164     ec = llvm::sys::fs::is_directory(proc_fd_path, result);
165     if (result) {
166       std::vector<int> files_to_close;
167       // Directory iterator doesn't ensure any sequence.
168       for (llvm::sys::fs::directory_iterator iter(proc_fd_path, ec), file_end;
169            iter != file_end && !ec; iter.increment(ec)) {
170         int fd = std::stoi(iter->path().substr(proc_fd_path.size() + 1));
171 
172         // Don't close first three entries since they are stdin, stdout and
173         // stderr.
174         if (fd > 2 && !info.has_action(fd) && fd != error_fd)
175           files_to_close.push_back(fd);
176       }
177       for (int file_to_close : files_to_close)
178         close(file_to_close);
179     } else {
180       // Since /proc/self/fd didn't work, trying the slow way instead.
181       int max_fd = sysconf(_SC_OPEN_MAX);
182       for (int fd = 3; fd < max_fd; ++fd)
183         if (!info.has_action(fd) && fd != error_fd)
184           close(fd);
185     }
186 
187     // Start tracing this child that is about to exec.
188 #ifdef _AIX
189     if (ptrace64(PT_TRACE_ME, 0, 0, 0, nullptr) == -1)
190 #else
191     if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
192 #endif
193       ExitWithError(error_fd, "ptrace");
194   }
195 
196   // Execute.  We should never return...
197   execve(info.argv[0], const_cast<char *const *>(info.argv), info.envp);
198 
199 #if defined(__linux__)
200   if (errno == ETXTBSY) {
201     // On android M and earlier we can get this error because the adb daemon
202     // can hold a write handle on the executable even after it has finished
203     // uploading it. This state lasts only a short time and happens only when
204     // there are many concurrent adb commands being issued, such as when
205     // running the test suite. (The file remains open when someone does an "adb
206     // shell" command in the fork() child before it has had a chance to exec.)
207     // Since this state should clear up quickly, wait a while and then give it
208     // one more go.
209     usleep(50000);
210     execve(info.argv[0], const_cast<char *const *>(info.argv), info.envp);
211   }
212 #endif
213 
214   // ...unless exec fails.  In which case we definitely need to end the child
215   // here.
216   ExitWithError(error_fd, "execve");
217 }
218 
219 // End of code running in the child process.
220 
221 ForkFileAction::ForkFileAction(const FileAction &act)
222     : action(act.GetAction()), fd(act.GetFD()), path(act.GetPath().str()),
223       arg(act.GetActionArgument()) {}
224 
225 static std::vector<ForkFileAction>
226 MakeForkActions(const ProcessLaunchInfo &info) {
227   std::vector<ForkFileAction> result;
228   for (size_t i = 0; i < info.GetNumFileActions(); ++i)
229     result.emplace_back(*info.GetFileActionAtIndex(i));
230   return result;
231 }
232 
233 ForkLaunchInfo::ForkLaunchInfo(const ProcessLaunchInfo &info)
234     : separate_process_group(
235           info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)),
236       debug(info.GetFlags().Test(eLaunchFlagDebug)),
237       disable_aslr(info.GetFlags().Test(eLaunchFlagDisableASLR)),
238       wd(info.GetWorkingDirectory().GetPath()),
239       argv(info.GetArguments().GetConstArgumentVector()),
240       envp(info.GetEnvironment().getEnvp()), actions(MakeForkActions(info)) {}
241 
242 HostProcess
243 ProcessLauncherPosixFork::LaunchProcess(const ProcessLaunchInfo &launch_info,
244                                         Status &error) {
245   // A pipe used by the child process to report errors.
246   PipePosix pipe;
247   const bool child_processes_inherit = false;
248   error = pipe.CreateNew(child_processes_inherit);
249   if (error.Fail())
250     return HostProcess();
251 
252   const ForkLaunchInfo fork_launch_info(launch_info);
253 
254   ::pid_t pid = ::fork();
255   if (pid == -1) {
256     // Fork failed
257     error = Status::FromErrorStringWithFormatv(
258         "Fork failed with error message: {0}", llvm::sys::StrError());
259     return HostProcess(LLDB_INVALID_PROCESS_ID);
260   }
261   if (pid == 0) {
262     // child process
263     pipe.CloseReadFileDescriptor();
264     ChildFunc(pipe.ReleaseWriteFileDescriptor(), fork_launch_info);
265   }
266 
267   // parent process
268 
269   pipe.CloseWriteFileDescriptor();
270   llvm::SmallString<0> buf;
271   size_t pos = 0;
272   ssize_t r = 0;
273   do {
274     pos += r;
275     buf.resize_for_overwrite(pos + 100);
276     r = llvm::sys::RetryAfterSignal(-1, read, pipe.GetReadFileDescriptor(),
277                                     buf.begin() + pos, buf.size() - pos);
278   } while (r > 0);
279   assert(r != -1);
280 
281   buf.resize(pos);
282   if (buf.empty())
283     return HostProcess(pid); // No error. We're done.
284 
285   error = Status(buf.str().str());
286 
287   llvm::sys::RetryAfterSignal(-1, waitpid, pid, nullptr, 0);
288 
289   return HostProcess();
290 }
291