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