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/Host.h"
11 #include "lldb/Host/HostProcess.h"
12 #include "lldb/Host/Pipe.h"
13 #include "lldb/Host/ProcessLaunchInfo.h"
14 #include "lldb/Utility/FileSpec.h"
15 #include "lldb/Utility/Log.h"
16 #include "llvm/Support/Errno.h"
17 #include "llvm/Support/FileSystem.h"
18
19 #include <climits>
20 #include <sys/ptrace.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23
24 #include <sstream>
25 #include <csignal>
26
27 #ifdef __ANDROID__
28 #include <android/api-level.h>
29 #define PT_TRACE_ME PTRACE_TRACEME
30 #endif
31
32 #if defined(__ANDROID_API__) && __ANDROID_API__ < 15
33 #include <linux/personality.h>
34 #elif defined(__linux__)
35 #include <sys/personality.h>
36 #endif
37
38 using namespace lldb;
39 using namespace lldb_private;
40
41 // Begin code running in the child process
42 // NB: This code needs to be async-signal safe, since we're invoking fork from
43 // multithreaded contexts.
44
write_string(int error_fd,const char * str)45 static void write_string(int error_fd, const char *str) {
46 int r = write(error_fd, str, strlen(str));
47 (void)r;
48 }
49
ExitWithError(int error_fd,const char * operation)50 [[noreturn]] static void ExitWithError(int error_fd,
51 const char *operation) {
52 int err = errno;
53 write_string(error_fd, operation);
54 write_string(error_fd, " failed: ");
55 // strerror is not guaranteed to be async-signal safe, but it usually is.
56 write_string(error_fd, strerror(err));
57 _exit(1);
58 }
59
DisableASLR(int error_fd)60 static void DisableASLR(int error_fd) {
61 #if defined(__linux__)
62 const unsigned long personality_get_current = 0xffffffff;
63 int value = personality(personality_get_current);
64 if (value == -1)
65 ExitWithError(error_fd, "personality get");
66
67 value = personality(ADDR_NO_RANDOMIZE | value);
68 if (value == -1)
69 ExitWithError(error_fd, "personality set");
70 #endif
71 }
72
DupDescriptor(int error_fd,const char * file,int fd,int flags)73 static void DupDescriptor(int error_fd, const char *file, int fd, int flags) {
74 int target_fd = llvm::sys::RetryAfterSignal(-1, ::open, file, flags, 0666);
75
76 if (target_fd == -1)
77 ExitWithError(error_fd, "DupDescriptor-open");
78
79 if (target_fd == fd)
80 return;
81
82 if (::dup2(target_fd, fd) == -1)
83 ExitWithError(error_fd, "DupDescriptor-dup2");
84
85 ::close(target_fd);
86 }
87
88 namespace {
89 struct ForkFileAction {
90 ForkFileAction(const FileAction &act);
91
92 FileAction::Action action;
93 int fd;
94 std::string path;
95 int arg;
96 };
97
98 struct ForkLaunchInfo {
99 ForkLaunchInfo(const ProcessLaunchInfo &info);
100
101 bool separate_process_group;
102 bool debug;
103 bool disable_aslr;
104 std::string wd;
105 const char **argv;
106 Environment::Envp envp;
107 std::vector<ForkFileAction> actions;
108
has_action__anon0f31c83f0111::ForkLaunchInfo109 bool has_action(int fd) const {
110 for (const ForkFileAction &action : actions) {
111 if (action.fd == fd)
112 return true;
113 }
114 return false;
115 }
116 };
117 } // namespace
118
ChildFunc(int error_fd,const ForkLaunchInfo & info)119 [[noreturn]] static void ChildFunc(int error_fd, const ForkLaunchInfo &info) {
120 if (info.separate_process_group) {
121 if (setpgid(0, 0) != 0)
122 ExitWithError(error_fd, "setpgid");
123 }
124
125 for (const ForkFileAction &action : info.actions) {
126 switch (action.action) {
127 case FileAction::eFileActionClose:
128 if (close(action.fd) != 0)
129 ExitWithError(error_fd, "close");
130 break;
131 case FileAction::eFileActionDuplicate:
132 if (dup2(action.fd, action.arg) == -1)
133 ExitWithError(error_fd, "dup2");
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 if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
197 ExitWithError(error_fd, "ptrace");
198 }
199
200 // Execute. We should never return...
201 execve(info.argv[0], const_cast<char *const *>(info.argv), info.envp);
202
203 #if defined(__linux__)
204 if (errno == ETXTBSY) {
205 // On android M and earlier we can get this error because the adb daemon
206 // can hold a write handle on the executable even after it has finished
207 // uploading it. This state lasts only a short time and happens only when
208 // there are many concurrent adb commands being issued, such as when
209 // running the test suite. (The file remains open when someone does an "adb
210 // shell" command in the fork() child before it has had a chance to exec.)
211 // Since this state should clear up quickly, wait a while and then give it
212 // one more go.
213 usleep(50000);
214 execve(info.argv[0], const_cast<char *const *>(info.argv), info.envp);
215 }
216 #endif
217
218 // ...unless exec fails. In which case we definitely need to end the child
219 // here.
220 ExitWithError(error_fd, "execve");
221 }
222
223 // End of code running in the child process.
224
ForkFileAction(const FileAction & act)225 ForkFileAction::ForkFileAction(const FileAction &act)
226 : action(act.GetAction()), fd(act.GetFD()), path(act.GetPath().str()),
227 arg(act.GetActionArgument()) {}
228
229 static std::vector<ForkFileAction>
MakeForkActions(const ProcessLaunchInfo & info)230 MakeForkActions(const ProcessLaunchInfo &info) {
231 std::vector<ForkFileAction> result;
232 for (size_t i = 0; i < info.GetNumFileActions(); ++i)
233 result.emplace_back(*info.GetFileActionAtIndex(i));
234 return result;
235 }
236
FixupEnvironment(Environment env)237 static Environment::Envp FixupEnvironment(Environment env) {
238 #ifdef __ANDROID__
239 // If there is no PATH variable specified inside the environment then set the
240 // path to /system/bin. It is required because the default path used by
241 // execve() is wrong on android.
242 env.try_emplace("PATH", "/system/bin");
243 #endif
244 return env.getEnvp();
245 }
246
ForkLaunchInfo(const ProcessLaunchInfo & info)247 ForkLaunchInfo::ForkLaunchInfo(const ProcessLaunchInfo &info)
248 : separate_process_group(
249 info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)),
250 debug(info.GetFlags().Test(eLaunchFlagDebug)),
251 disable_aslr(info.GetFlags().Test(eLaunchFlagDisableASLR)),
252 wd(info.GetWorkingDirectory().GetPath()),
253 argv(info.GetArguments().GetConstArgumentVector()),
254 envp(FixupEnvironment(info.GetEnvironment())),
255 actions(MakeForkActions(info)) {}
256
257 HostProcess
LaunchProcess(const ProcessLaunchInfo & launch_info,Status & error)258 ProcessLauncherPosixFork::LaunchProcess(const ProcessLaunchInfo &launch_info,
259 Status &error) {
260 // A pipe used by the child process to report errors.
261 PipePosix pipe;
262 const bool child_processes_inherit = false;
263 error = pipe.CreateNew(child_processes_inherit);
264 if (error.Fail())
265 return HostProcess();
266
267 const ForkLaunchInfo fork_launch_info(launch_info);
268
269 ::pid_t pid = ::fork();
270 if (pid == -1) {
271 // Fork failed
272 error.SetErrorStringWithFormatv("Fork failed with error message: {0}",
273 llvm::sys::StrError());
274 return HostProcess(LLDB_INVALID_PROCESS_ID);
275 }
276 if (pid == 0) {
277 // child process
278 pipe.CloseReadFileDescriptor();
279 ChildFunc(pipe.ReleaseWriteFileDescriptor(), fork_launch_info);
280 }
281
282 // parent process
283
284 pipe.CloseWriteFileDescriptor();
285 llvm::SmallString<0> buf;
286 size_t pos = 0;
287 ssize_t r = 0;
288 do {
289 pos += r;
290 buf.resize_for_overwrite(pos + 100);
291 r = llvm::sys::RetryAfterSignal(-1, read, pipe.GetReadFileDescriptor(),
292 buf.begin() + pos, buf.size() - pos);
293 } while (r > 0);
294 assert(r != -1);
295
296 buf.resize(pos);
297 if (buf.empty())
298 return HostProcess(pid); // No error. We're done.
299
300 error.SetErrorString(buf);
301
302 llvm::sys::RetryAfterSignal(-1, waitpid, pid, nullptr, 0);
303
304 return HostProcess();
305 }
306