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