1*ec63e07aSXin Li // Copyright 2019 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li
15*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util.h"
16*ec63e07aSXin Li
17*ec63e07aSXin Li #include <sched.h>
18*ec63e07aSXin Li #include <spawn.h>
19*ec63e07aSXin Li #include <sys/ptrace.h>
20*ec63e07aSXin Li #include <sys/resource.h>
21*ec63e07aSXin Li #include <sys/uio.h>
22*ec63e07aSXin Li #include <sys/wait.h>
23*ec63e07aSXin Li #include <syscall.h>
24*ec63e07aSXin Li #include <unistd.h>
25*ec63e07aSXin Li
26*ec63e07aSXin Li #include <cerrno>
27*ec63e07aSXin Li #include <csetjmp>
28*ec63e07aSXin Li #include <cstddef>
29*ec63e07aSXin Li #include <cstdint>
30*ec63e07aSXin Li #include <cstdlib>
31*ec63e07aSXin Li #include <cstring>
32*ec63e07aSXin Li #include <string>
33*ec63e07aSXin Li #include <utility>
34*ec63e07aSXin Li #include <vector>
35*ec63e07aSXin Li
36*ec63e07aSXin Li #include "absl/base/attributes.h"
37*ec63e07aSXin Li #include "absl/base/macros.h"
38*ec63e07aSXin Li #include "absl/base/optimization.h"
39*ec63e07aSXin Li #include "absl/status/status.h"
40*ec63e07aSXin Li #include "absl/status/statusor.h"
41*ec63e07aSXin Li #include "absl/strings/ascii.h"
42*ec63e07aSXin Li #include "absl/strings/escaping.h"
43*ec63e07aSXin Li #include "absl/strings/str_cat.h"
44*ec63e07aSXin Li #include "absl/strings/str_format.h"
45*ec63e07aSXin Li #include "absl/strings/str_join.h"
46*ec63e07aSXin Li #include "absl/strings/str_replace.h"
47*ec63e07aSXin Li #include "absl/strings/str_split.h"
48*ec63e07aSXin Li #include "absl/strings/string_view.h"
49*ec63e07aSXin Li #include "sandboxed_api/config.h"
50*ec63e07aSXin Li #include "sandboxed_api/util/file_helpers.h"
51*ec63e07aSXin Li #include "sandboxed_api/util/fileops.h"
52*ec63e07aSXin Li #include "sandboxed_api/util/path.h"
53*ec63e07aSXin Li #include "sandboxed_api/util/raw_logging.h"
54*ec63e07aSXin Li
55*ec63e07aSXin Li namespace sandbox2::util {
56*ec63e07aSXin Li
57*ec63e07aSXin Li namespace file = ::sapi::file;
58*ec63e07aSXin Li namespace file_util = ::sapi::file_util;
59*ec63e07aSXin Li
60*ec63e07aSXin Li namespace {
61*ec63e07aSXin Li
ConcatenateAll(char * const * arr)62*ec63e07aSXin Li std::string ConcatenateAll(char* const* arr) {
63*ec63e07aSXin Li std::string result;
64*ec63e07aSXin Li for (; *arr != nullptr; ++arr) {
65*ec63e07aSXin Li size_t len = strlen(*arr);
66*ec63e07aSXin Li result.append(*arr, len + 1);
67*ec63e07aSXin Li }
68*ec63e07aSXin Li return result;
69*ec63e07aSXin Li }
70*ec63e07aSXin Li
71*ec63e07aSXin Li #ifdef __ELF__
72*ec63e07aSXin Li extern "C" void __gcov_dump() ABSL_ATTRIBUTE_WEAK;
73*ec63e07aSXin Li extern "C" void __gcov_flush() ABSL_ATTRIBUTE_WEAK;
74*ec63e07aSXin Li extern "C" void __gcov_reset() ABSL_ATTRIBUTE_WEAK;
75*ec63e07aSXin Li #endif
76*ec63e07aSXin Li
ResetCoverageData()77*ec63e07aSXin Li void ResetCoverageData() {
78*ec63e07aSXin Li #ifdef __ELF__
79*ec63e07aSXin Li if (&__gcov_reset != nullptr) {
80*ec63e07aSXin Li __gcov_reset();
81*ec63e07aSXin Li }
82*ec63e07aSXin Li #endif
83*ec63e07aSXin Li }
84*ec63e07aSXin Li
85*ec63e07aSXin Li } // namespace
86*ec63e07aSXin Li
DumpCoverageData()87*ec63e07aSXin Li void DumpCoverageData() {
88*ec63e07aSXin Li #ifdef __ELF__
89*ec63e07aSXin Li if (&__gcov_dump != nullptr) {
90*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "Flushing coverage data (dump)");
91*ec63e07aSXin Li __gcov_dump();
92*ec63e07aSXin Li } else if (&__gcov_flush != nullptr) {
93*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "Flushing coverage data (flush)");
94*ec63e07aSXin Li __gcov_flush();
95*ec63e07aSXin Li }
96*ec63e07aSXin Li #endif
97*ec63e07aSXin Li }
98*ec63e07aSXin Li
CharPtrArray(char * const * arr)99*ec63e07aSXin Li CharPtrArray::CharPtrArray(char* const* arr) : content_(ConcatenateAll(arr)) {
100*ec63e07aSXin Li for (auto it = content_.begin(); it != content_.end();
101*ec63e07aSXin Li it += strlen(&*it) + 1) {
102*ec63e07aSXin Li array_.push_back(&*it);
103*ec63e07aSXin Li }
104*ec63e07aSXin Li array_.push_back(nullptr);
105*ec63e07aSXin Li }
106*ec63e07aSXin Li
CharPtrArray(const std::vector<std::string> & vec)107*ec63e07aSXin Li CharPtrArray::CharPtrArray(const std::vector<std::string>& vec)
108*ec63e07aSXin Li : content_(absl::StrJoin(vec, absl::string_view("\0", 1))) {
109*ec63e07aSXin Li size_t len = 0;
110*ec63e07aSXin Li array_.reserve(vec.size() + 1);
111*ec63e07aSXin Li for (const std::string& str : vec) {
112*ec63e07aSXin Li array_.push_back(&content_[len]);
113*ec63e07aSXin Li len += str.size() + 1;
114*ec63e07aSXin Li }
115*ec63e07aSXin Li array_.push_back(nullptr);
116*ec63e07aSXin Li }
117*ec63e07aSXin Li
FromStringVector(const std::vector<std::string> & vec)118*ec63e07aSXin Li CharPtrArray CharPtrArray::FromStringVector(
119*ec63e07aSXin Li const std::vector<std::string>& vec) {
120*ec63e07aSXin Li return CharPtrArray(vec);
121*ec63e07aSXin Li }
122*ec63e07aSXin Li
ToStringVector() const123*ec63e07aSXin Li std::vector<std::string> CharPtrArray::ToStringVector() const {
124*ec63e07aSXin Li std::vector<std::string> result;
125*ec63e07aSXin Li result.reserve(array_.size() - 1);
126*ec63e07aSXin Li for (size_t i = 0; i < array_.size() - 1; ++i) {
127*ec63e07aSXin Li result.push_back(array_[i]);
128*ec63e07aSXin Li }
129*ec63e07aSXin Li return result;
130*ec63e07aSXin Li }
131*ec63e07aSXin Li
GetProgName(pid_t pid)132*ec63e07aSXin Li std::string GetProgName(pid_t pid) {
133*ec63e07aSXin Li std::string fname = file::JoinPath("/proc", absl::StrCat(pid), "exe");
134*ec63e07aSXin Li // Use ReadLink instead of RealPath, as for fd-based executables (e.g. created
135*ec63e07aSXin Li // via memfd_create()) the RealPath will not work, as the destination file
136*ec63e07aSXin Li // doesn't exist on the local file-system.
137*ec63e07aSXin Li return file_util::fileops::Basename(file_util::fileops::ReadLink(fname));
138*ec63e07aSXin Li }
139*ec63e07aSXin Li
GetCmdLine(pid_t pid)140*ec63e07aSXin Li std::string GetCmdLine(pid_t pid) {
141*ec63e07aSXin Li std::string fname = file::JoinPath("/proc", absl::StrCat(pid), "cmdline");
142*ec63e07aSXin Li std::string cmdline;
143*ec63e07aSXin Li auto status =
144*ec63e07aSXin Li sapi::file::GetContents(fname, &cmdline, sapi::file::Defaults());
145*ec63e07aSXin Li if (!status.ok()) {
146*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "%s", std::string(status.message()).c_str());
147*ec63e07aSXin Li return "";
148*ec63e07aSXin Li }
149*ec63e07aSXin Li return absl::StrReplaceAll(cmdline, {{absl::string_view("\0", 1), " "}});
150*ec63e07aSXin Li }
151*ec63e07aSXin Li
GetProcStatusLine(int pid,const std::string & value)152*ec63e07aSXin Li std::string GetProcStatusLine(int pid, const std::string& value) {
153*ec63e07aSXin Li const std::string fname = absl::StrCat("/proc/", pid, "/status");
154*ec63e07aSXin Li std::string procpidstatus;
155*ec63e07aSXin Li auto status =
156*ec63e07aSXin Li sapi::file::GetContents(fname, &procpidstatus, sapi::file::Defaults());
157*ec63e07aSXin Li if (!status.ok()) {
158*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "%s", std::string(status.message()).c_str());
159*ec63e07aSXin Li return "";
160*ec63e07aSXin Li }
161*ec63e07aSXin Li
162*ec63e07aSXin Li for (const auto& line : absl::StrSplit(procpidstatus, '\n')) {
163*ec63e07aSXin Li std::pair<std::string, std::string> kv =
164*ec63e07aSXin Li absl::StrSplit(line, absl::MaxSplits(':', 1));
165*ec63e07aSXin Li SAPI_RAW_VLOG(3, "Key: '%s' Value: '%s'", kv.first.c_str(),
166*ec63e07aSXin Li kv.second.c_str());
167*ec63e07aSXin Li if (kv.first == value) {
168*ec63e07aSXin Li absl::StripLeadingAsciiWhitespace(&kv.second);
169*ec63e07aSXin Li return std::move(kv.second);
170*ec63e07aSXin Li }
171*ec63e07aSXin Li }
172*ec63e07aSXin Li SAPI_RAW_LOG(ERROR, "No '%s' field found in '%s'", value.c_str(),
173*ec63e07aSXin Li fname.c_str());
174*ec63e07aSXin Li return "";
175*ec63e07aSXin Li }
176*ec63e07aSXin Li
Syscall(long sys_no,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5,uintptr_t a6)177*ec63e07aSXin Li long Syscall(long sys_no, // NOLINT
178*ec63e07aSXin Li uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
179*ec63e07aSXin Li uintptr_t a5, uintptr_t a6) {
180*ec63e07aSXin Li return syscall(sys_no, a1, a2, a3, a4, a5, a6);
181*ec63e07aSXin Li }
182*ec63e07aSXin Li
183*ec63e07aSXin Li namespace {
184*ec63e07aSXin Li
ChildFunc(void * arg)185*ec63e07aSXin Li int ChildFunc(void* arg) {
186*ec63e07aSXin Li auto* env_ptr = reinterpret_cast<jmp_buf*>(arg);
187*ec63e07aSXin Li // Restore the old stack.
188*ec63e07aSXin Li longjmp(*env_ptr, 1);
189*ec63e07aSXin Li }
190*ec63e07aSXin Li
191*ec63e07aSXin Li // This code is inspired by base/process/launch_posix.cc in the Chromium source.
192*ec63e07aSXin Li // There are a few things to be careful of here:
193*ec63e07aSXin Li // - Make sure the stack_buf is below the env_ptr to please FORTIFY_SOURCE.
194*ec63e07aSXin Li // - Make sure the stack_buf is not too far away from the real stack to please
195*ec63e07aSXin Li // ASAN. If they are too far away, a warning is printed. This means not only
196*ec63e07aSXin Li // that the temporary stack buffer needs to also be on the stack, but also that
197*ec63e07aSXin Li // we need to disable ASAN for this function, to prevent it from being placed on
198*ec63e07aSXin Li // the fake ASAN stack.
199*ec63e07aSXin Li // - Make sure that the buffer is aligned to whatever is required by the CPU.
200*ec63e07aSXin Li ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
201*ec63e07aSXin Li ABSL_ATTRIBUTE_NOINLINE
CloneAndJump(int flags,jmp_buf * env_ptr)202*ec63e07aSXin Li pid_t CloneAndJump(int flags, jmp_buf* env_ptr) {
203*ec63e07aSXin Li uint8_t stack_buf[PTHREAD_STACK_MIN] ABSL_CACHELINE_ALIGNED;
204*ec63e07aSXin Li static_assert(sapi::host_cpu::IsX8664() || sapi::host_cpu::IsPPC64LE() ||
205*ec63e07aSXin Li sapi::host_cpu::IsArm64() || sapi::host_cpu::IsArm(),
206*ec63e07aSXin Li "Host CPU architecture not supported, see config.h");
207*ec63e07aSXin Li // Stack grows down.
208*ec63e07aSXin Li void* stack = stack_buf + sizeof(stack_buf);
209*ec63e07aSXin Li int r = clone(&ChildFunc, stack, flags, env_ptr, nullptr, nullptr, nullptr);
210*ec63e07aSXin Li if (r == -1) {
211*ec63e07aSXin Li SAPI_RAW_PLOG(ERROR, "clone()");
212*ec63e07aSXin Li }
213*ec63e07aSXin Li return r;
214*ec63e07aSXin Li }
215*ec63e07aSXin Li
216*ec63e07aSXin Li } // namespace
217*ec63e07aSXin Li
ForkWithFlags(int flags)218*ec63e07aSXin Li pid_t ForkWithFlags(int flags) {
219*ec63e07aSXin Li const int unsupported_flags = CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID |
220*ec63e07aSXin Li CLONE_PARENT_SETTID | CLONE_SETTLS | CLONE_VM;
221*ec63e07aSXin Li if (flags & unsupported_flags) {
222*ec63e07aSXin Li SAPI_RAW_LOG(ERROR, "ForkWithFlags used with unsupported flag");
223*ec63e07aSXin Li return -1;
224*ec63e07aSXin Li }
225*ec63e07aSXin Li
226*ec63e07aSXin Li jmp_buf env;
227*ec63e07aSXin Li if (setjmp(env) == 0) {
228*ec63e07aSXin Li return CloneAndJump(flags, &env);
229*ec63e07aSXin Li }
230*ec63e07aSXin Li
231*ec63e07aSXin Li // Child.
232*ec63e07aSXin Li return 0;
233*ec63e07aSXin Li }
234*ec63e07aSXin Li
CreateMemFd(int * fd,const char * name)235*ec63e07aSXin Li bool CreateMemFd(int* fd, const char* name) {
236*ec63e07aSXin Li // Usually defined in linux/memfd.h. Define it here to avoid dependency on
237*ec63e07aSXin Li // UAPI headers.
238*ec63e07aSXin Li constexpr uintptr_t kMfdCloseOnExec = 0x0001;
239*ec63e07aSXin Li constexpr uintptr_t kMfdAllowSealing = 0x0002;
240*ec63e07aSXin Li int tmp_fd = Syscall(__NR_memfd_create, reinterpret_cast<uintptr_t>(name),
241*ec63e07aSXin Li kMfdCloseOnExec | kMfdAllowSealing);
242*ec63e07aSXin Li if (tmp_fd < 0) {
243*ec63e07aSXin Li if (errno == ENOSYS) {
244*ec63e07aSXin Li SAPI_RAW_LOG(ERROR,
245*ec63e07aSXin Li "This system does not seem to support the memfd_create()"
246*ec63e07aSXin Li " syscall. Try running on a newer kernel.");
247*ec63e07aSXin Li } else {
248*ec63e07aSXin Li SAPI_RAW_PLOG(ERROR, "Could not create tmp file '%s'", name);
249*ec63e07aSXin Li }
250*ec63e07aSXin Li return false;
251*ec63e07aSXin Li }
252*ec63e07aSXin Li *fd = tmp_fd;
253*ec63e07aSXin Li return true;
254*ec63e07aSXin Li }
255*ec63e07aSXin Li
Communicate(const std::vector<std::string> & argv,const std::vector<std::string> & envv,std::string * output)256*ec63e07aSXin Li absl::StatusOr<int> Communicate(const std::vector<std::string>& argv,
257*ec63e07aSXin Li const std::vector<std::string>& envv,
258*ec63e07aSXin Li std::string* output) {
259*ec63e07aSXin Li int cout_pipe[2];
260*ec63e07aSXin Li posix_spawn_file_actions_t action;
261*ec63e07aSXin Li
262*ec63e07aSXin Li if (pipe(cout_pipe) == -1) {
263*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "creating pipe");
264*ec63e07aSXin Li }
265*ec63e07aSXin Li file_util::fileops::FDCloser cout_closer{cout_pipe[1]};
266*ec63e07aSXin Li
267*ec63e07aSXin Li posix_spawn_file_actions_init(&action);
268*ec63e07aSXin Li struct ActionCleanup {
269*ec63e07aSXin Li ~ActionCleanup() { posix_spawn_file_actions_destroy(action_); }
270*ec63e07aSXin Li posix_spawn_file_actions_t* action_;
271*ec63e07aSXin Li } action_cleanup{&action};
272*ec63e07aSXin Li
273*ec63e07aSXin Li // Redirect both stdout and stderr to stdout to our pipe.
274*ec63e07aSXin Li posix_spawn_file_actions_addclose(&action, cout_pipe[0]);
275*ec63e07aSXin Li posix_spawn_file_actions_adddup2(&action, cout_pipe[1], 1);
276*ec63e07aSXin Li posix_spawn_file_actions_adddup2(&action, cout_pipe[1], 2);
277*ec63e07aSXin Li posix_spawn_file_actions_addclose(&action, cout_pipe[1]);
278*ec63e07aSXin Li
279*ec63e07aSXin Li CharPtrArray args = CharPtrArray::FromStringVector(argv);
280*ec63e07aSXin Li CharPtrArray envp = CharPtrArray::FromStringVector(envv);
281*ec63e07aSXin Li
282*ec63e07aSXin Li pid_t pid;
283*ec63e07aSXin Li if (posix_spawnp(&pid, args.array()[0], &action, nullptr,
284*ec63e07aSXin Li const_cast<char**>(args.data()),
285*ec63e07aSXin Li const_cast<char**>(envp.data())) != 0) {
286*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "posix_spawnp()");
287*ec63e07aSXin Li }
288*ec63e07aSXin Li
289*ec63e07aSXin Li // Close child end of the pipe.
290*ec63e07aSXin Li cout_closer.Close();
291*ec63e07aSXin Li
292*ec63e07aSXin Li std::string buffer(1024, '\0');
293*ec63e07aSXin Li for (;;) {
294*ec63e07aSXin Li int bytes_read =
295*ec63e07aSXin Li TEMP_FAILURE_RETRY(read(cout_pipe[0], &buffer[0], buffer.length()));
296*ec63e07aSXin Li if (bytes_read < 0) {
297*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "reading from cout pipe");
298*ec63e07aSXin Li }
299*ec63e07aSXin Li if (bytes_read == 0) {
300*ec63e07aSXin Li break; // Nothing left to read
301*ec63e07aSXin Li }
302*ec63e07aSXin Li absl::StrAppend(output, absl::string_view(buffer.data(), bytes_read));
303*ec63e07aSXin Li }
304*ec63e07aSXin Li
305*ec63e07aSXin Li int status;
306*ec63e07aSXin Li SAPI_RAW_PCHECK(TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)) == pid,
307*ec63e07aSXin Li "Waiting for subprocess");
308*ec63e07aSXin Li return WEXITSTATUS(status);
309*ec63e07aSXin Li }
310*ec63e07aSXin Li
GetSignalName(int signo)311*ec63e07aSXin Li std::string GetSignalName(int signo) {
312*ec63e07aSXin Li constexpr absl::string_view kSignalNames[] = {
313*ec63e07aSXin Li "SIG_0", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP",
314*ec63e07aSXin Li "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV",
315*ec63e07aSXin Li "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", "SIGCHLD",
316*ec63e07aSXin Li "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG",
317*ec63e07aSXin Li "SIGXCPU", "SIGXFSZ", "SIGVTALARM", "SIGPROF", "SIGWINCH", "SIGIO",
318*ec63e07aSXin Li "SIGPWR", "SIGSYS"};
319*ec63e07aSXin Li
320*ec63e07aSXin Li if (signo >= SIGRTMIN && signo <= SIGRTMAX) {
321*ec63e07aSXin Li return absl::StrFormat("SIGRT-%d [%d]", signo - SIGRTMIN, signo);
322*ec63e07aSXin Li }
323*ec63e07aSXin Li if (signo < 0 || signo >= static_cast<int>(ABSL_ARRAYSIZE(kSignalNames))) {
324*ec63e07aSXin Li return absl::StrFormat("UNKNOWN_SIGNAL [%d]", signo);
325*ec63e07aSXin Li }
326*ec63e07aSXin Li return absl::StrFormat("%s [%d]", kSignalNames[signo], signo);
327*ec63e07aSXin Li }
328*ec63e07aSXin Li
GetRlimitName(int resource)329*ec63e07aSXin Li std::string GetRlimitName(int resource) {
330*ec63e07aSXin Li switch (resource) {
331*ec63e07aSXin Li case RLIMIT_AS:
332*ec63e07aSXin Li return "RLIMIT_AS";
333*ec63e07aSXin Li case RLIMIT_FSIZE:
334*ec63e07aSXin Li return "RLIMIT_FSIZE";
335*ec63e07aSXin Li case RLIMIT_NOFILE:
336*ec63e07aSXin Li return "RLIMIT_NOFILE";
337*ec63e07aSXin Li case RLIMIT_CPU:
338*ec63e07aSXin Li return "RLIMIT_CPU";
339*ec63e07aSXin Li case RLIMIT_CORE:
340*ec63e07aSXin Li return "RLIMIT_CORE";
341*ec63e07aSXin Li default:
342*ec63e07aSXin Li return absl::StrCat("UNKNOWN: ", resource);
343*ec63e07aSXin Li }
344*ec63e07aSXin Li }
345*ec63e07aSXin Li
GetPtraceEventName(int event)346*ec63e07aSXin Li std::string GetPtraceEventName(int event) {
347*ec63e07aSXin Li #if !defined(PTRACE_EVENT_STOP)
348*ec63e07aSXin Li #define PTRACE_EVENT_STOP 128
349*ec63e07aSXin Li #endif
350*ec63e07aSXin Li
351*ec63e07aSXin Li switch (event) {
352*ec63e07aSXin Li case PTRACE_EVENT_FORK:
353*ec63e07aSXin Li return "PTRACE_EVENT_FORK";
354*ec63e07aSXin Li case PTRACE_EVENT_VFORK:
355*ec63e07aSXin Li return "PTRACE_EVENT_VFORK";
356*ec63e07aSXin Li case PTRACE_EVENT_CLONE:
357*ec63e07aSXin Li return "PTRACE_EVENT_CLONE";
358*ec63e07aSXin Li case PTRACE_EVENT_EXEC:
359*ec63e07aSXin Li return "PTRACE_EVENT_EXEC";
360*ec63e07aSXin Li case PTRACE_EVENT_VFORK_DONE:
361*ec63e07aSXin Li return "PTRACE_EVENT_VFORK_DONE";
362*ec63e07aSXin Li case PTRACE_EVENT_EXIT:
363*ec63e07aSXin Li return "PTRACE_EVENT_EXIT";
364*ec63e07aSXin Li case PTRACE_EVENT_SECCOMP:
365*ec63e07aSXin Li return "PTRACE_EVENT_SECCOMP";
366*ec63e07aSXin Li case PTRACE_EVENT_STOP:
367*ec63e07aSXin Li return "PTRACE_EVENT_STOP";
368*ec63e07aSXin Li default:
369*ec63e07aSXin Li return absl::StrCat("UNKNOWN: ", event);
370*ec63e07aSXin Li }
371*ec63e07aSXin Li }
372*ec63e07aSXin Li
ReadCPathFromPid(pid_t pid,uintptr_t ptr)373*ec63e07aSXin Li absl::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr) {
374*ec63e07aSXin Li std::string path(PATH_MAX, '\0');
375*ec63e07aSXin Li iovec local_iov[] = {{&path[0], path.size()}};
376*ec63e07aSXin Li
377*ec63e07aSXin Li static const uintptr_t page_size = getpagesize();
378*ec63e07aSXin Li static const uintptr_t page_mask = ~(page_size - 1);
379*ec63e07aSXin Li // See 'man process_vm_readv' for details on how to read NUL-terminated
380*ec63e07aSXin Li // strings with this syscall.
381*ec63e07aSXin Li size_t len1 = ((ptr + page_size) & page_mask) - ptr;
382*ec63e07aSXin Li len1 = (len1 > path.size()) ? path.size() : len1;
383*ec63e07aSXin Li size_t len2 = (path.size() <= len1) ? 0UL : path.size() - len1;
384*ec63e07aSXin Li // Second iov is wrapping around to NULL ptr.
385*ec63e07aSXin Li if ((ptr + len1) < ptr) {
386*ec63e07aSXin Li len2 = 0UL;
387*ec63e07aSXin Li }
388*ec63e07aSXin Li
389*ec63e07aSXin Li iovec remote_iov[] = {
390*ec63e07aSXin Li {reinterpret_cast<void*>(ptr), len1},
391*ec63e07aSXin Li {reinterpret_cast<void*>(ptr + len1), len2},
392*ec63e07aSXin Li };
393*ec63e07aSXin Li
394*ec63e07aSXin Li SAPI_RAW_VLOG(4, "ReadCPathFromPid (iovec): len1: %zu, len2: %zu", len1,
395*ec63e07aSXin Li len2);
396*ec63e07aSXin Li if (process_vm_readv(pid, local_iov, ABSL_ARRAYSIZE(local_iov), remote_iov,
397*ec63e07aSXin Li ABSL_ARRAYSIZE(remote_iov), 0) < 0) {
398*ec63e07aSXin Li return absl::ErrnoToStatus(
399*ec63e07aSXin Li errno,
400*ec63e07aSXin Li absl::StrFormat("process_vm_readv() failed for PID: %d at address: %#x",
401*ec63e07aSXin Li pid, reinterpret_cast<uintptr_t>(ptr)));
402*ec63e07aSXin Li }
403*ec63e07aSXin Li
404*ec63e07aSXin Li // Check for whether there's a NUL byte in the buffer. If not, it's an
405*ec63e07aSXin Li // incorrect path (or >PATH_MAX).
406*ec63e07aSXin Li auto pos = path.find('\0');
407*ec63e07aSXin Li if (pos == std::string::npos) {
408*ec63e07aSXin Li return absl::FailedPreconditionError(absl::StrCat(
409*ec63e07aSXin Li "No NUL-byte inside the C string '", absl::CHexEscape(path), "'"));
410*ec63e07aSXin Li }
411*ec63e07aSXin Li path.resize(pos);
412*ec63e07aSXin Li return path;
413*ec63e07aSXin Li }
414*ec63e07aSXin Li
Execveat(int dirfd,const char * pathname,const char * const argv[],const char * const envp[],int flags,uintptr_t extra_arg)415*ec63e07aSXin Li int Execveat(int dirfd, const char* pathname, const char* const argv[],
416*ec63e07aSXin Li const char* const envp[], int flags, uintptr_t extra_arg) {
417*ec63e07aSXin Li // Flush coverage data prior to exec.
418*ec63e07aSXin Li if (extra_arg == 0) {
419*ec63e07aSXin Li DumpCoverageData();
420*ec63e07aSXin Li }
421*ec63e07aSXin Li int res = syscall(__NR_execveat, static_cast<uintptr_t>(dirfd),
422*ec63e07aSXin Li reinterpret_cast<uintptr_t>(pathname),
423*ec63e07aSXin Li reinterpret_cast<uintptr_t>(argv),
424*ec63e07aSXin Li reinterpret_cast<uintptr_t>(envp),
425*ec63e07aSXin Li static_cast<uintptr_t>(flags), extra_arg);
426*ec63e07aSXin Li // Reset coverage data if exec fails as the counters have been already dumped.
427*ec63e07aSXin Li if (extra_arg == 0) {
428*ec63e07aSXin Li ResetCoverageData();
429*ec63e07aSXin Li }
430*ec63e07aSXin Li return res;
431*ec63e07aSXin Li }
432*ec63e07aSXin Li
433*ec63e07aSXin Li } // namespace sandbox2::util
434