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 <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 | |
45 | static void write_string(int error_fd, const char *str) { |
46 | int r = write(fd: error_fd, buf: str, n: strlen(s: str)); |
47 | (void)r; |
48 | } |
49 | |
50 | [[noreturn]] static void ExitWithError(int error_fd, |
51 | const char *operation) { |
52 | int err = errno; |
53 | write_string(error_fd, str: operation); |
54 | write_string(error_fd, str: " failed: " ); |
55 | // strerror is not guaranteed to be async-signal safe, but it usually is. |
56 | write_string(error_fd, str: strerror(errnum: err)); |
57 | _exit(status: 1); |
58 | } |
59 | |
60 | static void DisableASLR(int error_fd) { |
61 | #if defined(__linux__) |
62 | const unsigned long personality_get_current = 0xffffffff; |
63 | int value = personality(persona: personality_get_current); |
64 | if (value == -1) |
65 | ExitWithError(error_fd, operation: "personality get" ); |
66 | |
67 | value = personality(persona: ADDR_NO_RANDOMIZE | value); |
68 | if (value == -1) |
69 | ExitWithError(error_fd, operation: "personality set" ); |
70 | #endif |
71 | } |
72 | |
73 | static void DupDescriptor(int error_fd, const char *file, int fd, int flags) { |
74 | int target_fd = FileSystem::Instance().Open(path: file, flags, mode: 0666); |
75 | |
76 | if (target_fd == -1) |
77 | ExitWithError(error_fd, operation: "DupDescriptor-open" ); |
78 | |
79 | if (target_fd == fd) |
80 | return; |
81 | |
82 | if (::dup2(fd: target_fd, fd2: fd) == -1) |
83 | ExitWithError(error_fd, operation: "DupDescriptor-dup2" ); |
84 | |
85 | ::close(fd: 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 | |
109 | 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 | |
119 | [[noreturn]] static void ChildFunc(int error_fd, const ForkLaunchInfo &info) { |
120 | if (info.separate_process_group) { |
121 | if (setpgid(pid: 0, pgid: 0) != 0) |
122 | ExitWithError(error_fd, operation: "setpgid" ); |
123 | } |
124 | |
125 | for (const ForkFileAction &action : info.actions) { |
126 | switch (action.action) { |
127 | case FileAction::eFileActionClose: |
128 | if (close(fd: action.fd) != 0) |
129 | ExitWithError(error_fd, operation: "close" ); |
130 | break; |
131 | case FileAction::eFileActionDuplicate: |
132 | if (dup2(fd: action.fd, fd2: action.arg) == -1) |
133 | ExitWithError(error_fd, operation: "dup2" ); |
134 | break; |
135 | case FileAction::eFileActionOpen: |
136 | DupDescriptor(error_fd, file: action.path.c_str(), fd: action.fd, flags: action.arg); |
137 | break; |
138 | case FileAction::eFileActionNone: |
139 | break; |
140 | } |
141 | } |
142 | |
143 | // Change working directory |
144 | if (!info.wd.empty() && 0 != ::chdir(path: info.wd.c_str())) |
145 | ExitWithError(error_fd, operation: "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: &set) != 0 || |
154 | pthread_sigmask(SIG_SETMASK, newmask: &set, oldmask: nullptr) != 0) |
155 | ExitWithError(error_fd, operation: "pthread_sigmask" ); |
156 | |
157 | if (info.debug) { |
158 | // Do not inherit setgid powers. |
159 | if (setgid(getgid()) != 0) |
160 | ExitWithError(error_fd, operation: "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(path: 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(str: iter->path().substr(pos: 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(x: fd); |
184 | } |
185 | for (int file_to_close : files_to_close) |
186 | close(fd: 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: 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, operation: "ptrace" ); |
198 | } |
199 | |
200 | // Execute. We should never return... |
201 | execve(path: info.argv[0], argv: const_cast<char *const *>(info.argv), envp: 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(useconds: 50000); |
214 | execve(path: info.argv[0], argv: const_cast<char *const *>(info.argv), envp: 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, operation: "execve" ); |
221 | } |
222 | |
223 | // End of code running in the child process. |
224 | |
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> |
230 | MakeForkActions(const ProcessLaunchInfo &info) { |
231 | std::vector<ForkFileAction> result; |
232 | for (size_t i = 0; i < info.GetNumFileActions(); ++i) |
233 | result.emplace_back(args: *info.GetFileActionAtIndex(idx: i)); |
234 | return result; |
235 | } |
236 | |
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 | |
247 | ForkLaunchInfo::ForkLaunchInfo(const ProcessLaunchInfo &info) |
248 | : separate_process_group( |
249 | info.GetFlags().Test(bit: eLaunchFlagLaunchInSeparateProcessGroup)), |
250 | debug(info.GetFlags().Test(bit: eLaunchFlagDebug)), |
251 | disable_aslr(info.GetFlags().Test(bit: eLaunchFlagDisableASLR)), |
252 | wd(info.GetWorkingDirectory().GetPath()), |
253 | argv(info.GetArguments().GetConstArgumentVector()), |
254 | envp(FixupEnvironment(env: info.GetEnvironment())), |
255 | actions(MakeForkActions(info)) {} |
256 | |
257 | HostProcess |
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_process_inherit: 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(format: "Fork failed with error message: {0}" , |
273 | args: llvm::sys::StrError()); |
274 | return HostProcess(LLDB_INVALID_PROCESS_ID); |
275 | } |
276 | if (pid == 0) { |
277 | // child process |
278 | pipe.CloseReadFileDescriptor(); |
279 | ChildFunc(error_fd: pipe.ReleaseWriteFileDescriptor(), info: 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(N: pos + 100); |
291 | r = llvm::sys::RetryAfterSignal(Fail: -1, F&: read, As: pipe.GetReadFileDescriptor(), |
292 | As: buf.begin() + pos, As: buf.size() - pos); |
293 | } while (r > 0); |
294 | assert(r != -1); |
295 | |
296 | buf.resize(N: pos); |
297 | if (buf.empty()) |
298 | return HostProcess(pid); // No error. We're done. |
299 | |
300 | error.SetErrorString(buf); |
301 | |
302 | llvm::sys::RetryAfterSignal(Fail: -1, F&: waitpid, As: pid, As: nullptr, As: 0); |
303 | |
304 | return HostProcess(); |
305 | } |
306 | |