Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 1 | /* -*- Mode: C++; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 2 | |
Robert O'Callahan | 3bb518b | 2014-09-27 15:35:25 -0400 | [diff] [blame] | 3 | #include "AutoRemoteSyscalls.h" |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 4 | |
Robert O'Callahan | fb93534 | 2016-06-24 23:26:03 +1200 | [diff] [blame] | 5 | #include <limits.h> |
| 6 | #include <linux/net.h> |
Keno Fischer | c094892 | 2016-06-04 22:13:20 -0400 | [diff] [blame] | 7 | #include <sys/socket.h> |
Robert O'Callahan | 6ca06de | 2018-04-25 00:18:10 +1200 | [diff] [blame] | 8 | #include <sys/types.h> |
Robert O'Callahan | 8782ae9 | 2015-07-30 00:14:28 +1200 | [diff] [blame] | 9 | |
Bernhard Übelacker | 8a84023 | 2023-03-03 00:04:39 +0100 | [diff] [blame] | 10 | #include <sstream> |
| 11 | |
Robert O'Callahan | bd0d2cf | 2015-04-17 16:20:45 +1200 | [diff] [blame] | 12 | #include "rr/rr.h" |
| 13 | |
Kyle Huey | cd145d1 | 2019-07-07 20:07:13 -0700 | [diff] [blame] | 14 | #include "RecordSession.h" |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 15 | #include "RecordTask.h" |
Robert O'Callahan | 3ecaab0 | 2015-05-01 14:05:52 +1200 | [diff] [blame] | 16 | #include "ReplaySession.h" |
Robert O'Callahan | 0e9fe83 | 2015-03-14 00:09:00 +1300 | [diff] [blame] | 17 | #include "Session.h" |
Robert O'Callahan | eed6915 | 2016-03-19 16:10:49 +1300 | [diff] [blame] | 18 | #include "Task.h" |
Robert O'Callahan | d218a53 | 2017-08-07 17:20:51 +1200 | [diff] [blame] | 19 | #include "core.h" |
Robert O'Callahan | d83c361 | 2023-01-02 20:51:14 +1300 | [diff] [blame] | 20 | #include "kernel_abi.h" |
Robert O'Callahan | fb93534 | 2016-06-24 23:26:03 +1200 | [diff] [blame] | 21 | #include "kernel_metadata.h" |
| 22 | #include "log.h" |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 23 | #include "util.h" |
| 24 | |
Robert O'Callahan | 978e59e | 2014-11-20 16:22:24 +1300 | [diff] [blame] | 25 | using namespace std; |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 26 | |
Robert O'Callahan | 3ce49c6 | 2016-03-22 18:31:02 +1300 | [diff] [blame] | 27 | namespace rr { |
| 28 | |
Robert O'Callahan | e0f7a3d | 2014-11-20 15:30:45 +1300 | [diff] [blame] | 29 | /** |
| 30 | * The ABI of the socketcall syscall is a nightmare; the first arg to |
| 31 | * the kernel is the sub-operation, and the second argument is a |
| 32 | * pointer to the args. The args depend on the sub-op. |
| 33 | */ |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 34 | template <typename Arch> struct socketcall_args { |
| 35 | typename Arch::signed_long args[3]; |
Robert O'Callahan | e0f7a3d | 2014-11-20 15:30:45 +1300 | [diff] [blame] | 36 | } __attribute__((packed)); |
| 37 | |
Robert O'Callahan | 128123a | 2016-04-26 17:34:44 +1200 | [diff] [blame] | 38 | void AutoRestoreMem::init(const void* mem, ssize_t num_bytes) { |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 39 | ASSERT(remote.task(), |
| 40 | remote.enable_mem_params() == AutoRemoteSyscalls::ENABLE_MEMORY_PARAMS) |
Robert O'Callahan | 8412c2a | 2015-07-23 12:08:15 +1200 | [diff] [blame] | 41 | << "Memory parameters were disabled"; |
| 42 | |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 43 | len = num_bytes; |
Robert O'Callahan | bc8c7ee | 2014-09-22 10:06:31 -0400 | [diff] [blame] | 44 | saved_sp = remote.regs().sp(); |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 45 | |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 46 | remote.regs().set_sp(remote.regs().sp() - len); |
| 47 | remote.task()->set_regs(remote.regs()); |
Robert O'Callahan | bc8c7ee | 2014-09-22 10:06:31 -0400 | [diff] [blame] | 48 | addr = remote.regs().sp(); |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 49 | |
Robert O'Callahan | 0a9e58f | 2014-09-27 18:18:54 -0400 | [diff] [blame] | 50 | data.resize(len); |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 51 | bool ok = true; |
| 52 | remote.task()->read_bytes_helper(addr, len, data.data(), &ok); |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 53 | if (mem) { |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 54 | remote.task()->write_bytes_helper(addr, len, mem, &ok); |
| 55 | } |
| 56 | if (!ok) { |
| 57 | addr = nullptr; |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 58 | } |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 59 | } |
| 60 | |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 61 | AutoRestoreMem::~AutoRestoreMem() { |
Robert O'Callahan | d218a53 | 2017-08-07 17:20:51 +1200 | [diff] [blame] | 62 | DEBUG_ASSERT(saved_sp == remote.regs().sp() + len); |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 63 | |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 64 | if (addr) { |
| 65 | // XXX what should we do if this task was sigkilled but the address |
| 66 | // space is used by other live tasks? |
| 67 | remote.task()->write_bytes_helper(addr, len, data.data()); |
| 68 | } |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 69 | remote.regs().set_sp(remote.regs().sp() + len); |
Robert O'Callahan | 8c468fb | 2023-09-18 19:28:02 +1200 | [diff] [blame] | 70 | remote.task()->set_regs(remote.regs()); |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 71 | } |
| 72 | |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 73 | static bool is_SIGTRAP_default_and_unblocked(Task* t) { |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 74 | if (!t->session().is_recording()) { |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 75 | return true; |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 76 | } |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 77 | RecordTask* rt = static_cast<RecordTask*>(t); |
| 78 | return rt->sig_disposition(SIGTRAP) == SIGNAL_DEFAULT && |
| 79 | !rt->is_sig_blocked(SIGTRAP); |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 80 | } |
| 81 | |
Robert O'Callahan | 8412c2a | 2015-07-23 12:08:15 +1200 | [diff] [blame] | 82 | AutoRemoteSyscalls::AutoRemoteSyscalls(Task* t, |
| 83 | MemParamsEnabled enable_mem_params) |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 84 | : t(t), |
| 85 | initial_regs(t->regs()), |
| 86 | initial_ip(t->ip()), |
Robert O'Callahan | 0e9fe83 | 2015-03-14 00:09:00 +1300 | [diff] [blame] | 87 | initial_sp(t->regs().sp()), |
Keno Fischer | 3bef84d | 2021-01-13 03:46:57 -0500 | [diff] [blame] | 88 | initial_at_seccomp(t->ptrace_event() == PTRACE_EVENT_SECCOMP), |
Robert O'Callahan | 955b5e0 | 2017-08-12 16:59:09 +1200 | [diff] [blame] | 89 | restore_wait_status(t->status()), |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 90 | new_tid_(-1), |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 91 | scratch_mem_was_mapped(false), |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 92 | use_singlestep_path(false), |
Keno Fischer | 8721ae8 | 2022-04-13 23:17:37 +0000 | [diff] [blame] | 93 | enable_mem_params_(enable_mem_params), |
Keno Fischer | 42728be | 2022-04-12 00:23:09 +0000 | [diff] [blame] | 94 | restore_sigmask(false), |
Keno Fischer | 8721ae8 | 2022-04-13 23:17:37 +0000 | [diff] [blame] | 95 | need_sigpending_renable(false) { |
Keno Fischer | 3bef84d | 2021-01-13 03:46:57 -0500 | [diff] [blame] | 96 | if (initial_at_seccomp) { |
| 97 | // This should only ever happen during recording - we don't use the |
| 98 | // seccomp traps during replay. |
| 99 | ASSERT(t, t->session().is_recording()); |
| 100 | } |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 101 | // We support two paths for syscalls: |
| 102 | // -- a fast path using a privileged untraced syscall and PTRACE_SINGLESTEP. |
| 103 | // This only requires a single task-wait. |
| 104 | // -- a slower path using a privileged traced syscall and PTRACE_SYSCALL/ |
| 105 | // PTRACE_CONT via Task::enter_syscall(). This requires 2 or 3 task-waits |
| 106 | // depending on whether the seccomp event fires before the syscall-entry |
| 107 | // event. |
| 108 | // Use the slow path when running under rr, because the rr recording us |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 109 | // needs to see and trace these tracee syscalls, and if they're untraced by |
| 110 | // us they're also untraced by the outer rr. |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 111 | // Use the slow path if SIGTRAP is blocked or ignored because otherwise |
| 112 | // the PTRACE_SINGLESTEP will cause the kernel to unblock it. |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 113 | setup_path(t->vm()->has_rr_page() && !running_under_rr() && |
| 114 | is_SIGTRAP_default_and_unblocked(t)); |
| 115 | if (enable_mem_params == ENABLE_MEMORY_PARAMS) { |
| 116 | maybe_fix_stack_pointer(); |
| 117 | } |
Keno Fischer | 8721ae8 | 2022-04-13 23:17:37 +0000 | [diff] [blame] | 118 | if (t->status().is_syscall() && t->regs().syscall_may_restart()) { |
| 119 | // VERY rare corner case alert: It is possible for the following sequence |
| 120 | // of events to occur: |
| 121 | // |
| 122 | // 1. Thread A is in a blocking may-restart syscall and gets interrupted by a tg-targeted signal |
| 123 | // 2. Thread B dequeues the signal |
| 124 | // 3. Thread A is in the syscall-exit-stop with TIF_SIGPENDING set (with registers indicating syscall restart) |
| 125 | // 4. We get here to perform an AutoRemoteSyscall |
| 126 | // 5. During AutoRemoteSyscall, TIF_SIGPENDING gets cleared on return to userspace |
| 127 | // 6. We finish the AutoRemoteSyscall and re-apply the registers. |
| 128 | // 7. ... As a result, the kernel does not check whether it needs to perform the |
| 129 | /// syscall-restart register adjustment because TIF_SIGPENDING is not set. |
| 130 | // 8. The -ERESTART error code leaks to userspace. |
| 131 | // |
| 132 | // Arguably this is a kernel bug, but it's not clear how the behavior should be changed. |
| 133 | // |
| 134 | // To work around this, we forcibly re-enable TIF_SIGPENDING when cleaning up |
| 135 | // AutoRemoteSyscall (see below). |
| 136 | need_sigpending_renable = true; |
| 137 | } |
Keno Fischer | 42728be | 2022-04-12 00:23:09 +0000 | [diff] [blame] | 138 | if (t->session().is_recording()) { |
| 139 | RecordTask *rt = static_cast<RecordTask*>(t); |
| 140 | if (rt->schedule_frozen) { |
| 141 | // If we're explicitly controlling the schedule, make sure not to accidentally run |
| 142 | // any signals that we were not meant to be able to see. |
| 143 | restore_sigmask = true; |
| 144 | sigmask_to_restore = rt->get_sigmask(); |
| 145 | sig_set_t all_blocked; |
| 146 | memset(&all_blocked, 0xff, sizeof(all_blocked)); |
Keno Fischer | de0f22f | 2022-07-02 21:24:32 +0000 | [diff] [blame] | 147 | // Ignore the process dying here - we'll notice later. |
| 148 | (void)rt->set_sigmask(all_blocked); |
Keno Fischer | 42728be | 2022-04-12 00:23:09 +0000 | [diff] [blame] | 149 | } |
| 150 | } |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | void AutoRemoteSyscalls::setup_path(bool enable_singlestep_path) { |
Kyle Huey | 26fccb3 | 2021-06-28 11:28:11 -0700 | [diff] [blame] | 154 | #if defined(__aarch64__) |
| 155 | // XXXkhuey this fast path doesn't work on AArch64 yet, go slow instead |
| 156 | enable_singlestep_path = false; |
| 157 | #endif |
| 158 | |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 159 | if (!replaced_bytes.empty()) { |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 160 | // XXX what to do here to clean up if the task died unexpectedly? |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 161 | t->write_mem(remote_ptr<uint8_t>(initial_regs.ip().to_data_ptr<uint8_t>()), |
| 162 | replaced_bytes.data(), replaced_bytes.size()); |
| 163 | } |
| 164 | |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 165 | remote_code_ptr syscall_ip; |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 166 | use_singlestep_path = enable_singlestep_path; |
Robert O'Callahan | 4a9e24b | 2018-09-05 13:57:34 +1200 | [diff] [blame] | 167 | if (use_singlestep_path) { |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 168 | syscall_ip = AddressSpace::rr_page_syscall_entry_point( |
| 169 | AddressSpace::UNTRACED, AddressSpace::PRIVILEGED, |
| 170 | AddressSpace::RECORDING_AND_REPLAY, t->arch()); |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 171 | } else { |
| 172 | syscall_ip = t->vm()->traced_syscall_ip(); |
| 173 | } |
| 174 | initial_regs.set_ip(syscall_ip); |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 175 | |
Keno Fischer | 3d78236 | 2016-06-05 20:01:35 -0400 | [diff] [blame] | 176 | // We need to make sure to clear any breakpoints or other alterations of |
| 177 | // the syscall instruction we're using. Note that the tracee may have set its |
| 178 | // own breakpoints or otherwise modified the instruction, so suspending our |
| 179 | // own breakpoint is insufficient. |
| 180 | std::vector<uint8_t> syscall = rr::syscall_instruction(t->arch()); |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 181 | bool ok = true; |
Keno Fischer | 3d78236 | 2016-06-05 20:01:35 -0400 | [diff] [blame] | 182 | replaced_bytes = |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 183 | t->read_mem(initial_regs.ip().to_data_ptr<uint8_t>(), syscall.size(), &ok); |
| 184 | if (!ok) { |
| 185 | // The task died |
| 186 | return; |
| 187 | } |
Keno Fischer | a8d922e | 2016-06-05 22:10:13 -0400 | [diff] [blame] | 188 | if (replaced_bytes == syscall) { |
| 189 | replaced_bytes.clear(); |
| 190 | } else { |
| 191 | t->write_mem(initial_regs.ip().to_data_ptr<uint8_t>(), syscall.data(), |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 192 | syscall.size(), &ok); |
Keno Fischer | a8d922e | 2016-06-05 22:10:13 -0400 | [diff] [blame] | 193 | } |
Robert O'Callahan | 0e9fe83 | 2015-03-14 00:09:00 +1300 | [diff] [blame] | 194 | } |
| 195 | |
Robert O'Callahan | f8c2fee | 2015-08-28 23:41:09 +1200 | [diff] [blame] | 196 | static bool is_usable_area(const KernelMapping& km) { |
| 197 | return (km.prot() & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE) && |
Robert O'Callahan | b7e4052 | 2015-09-15 23:59:32 +1200 | [diff] [blame] | 198 | (km.flags() & MAP_PRIVATE); |
Robert O'Callahan | f8c2fee | 2015-08-28 23:41:09 +1200 | [diff] [blame] | 199 | } |
| 200 | |
Robert O'Callahan | 0e9fe83 | 2015-03-14 00:09:00 +1300 | [diff] [blame] | 201 | void AutoRemoteSyscalls::maybe_fix_stack_pointer() { |
Robert O'Callahan | 0e6ac7e | 2016-03-02 17:27:02 +1300 | [diff] [blame] | 202 | if (!t->session().done_initial_exec()) { |
Robert O'Callahan | 0e9fe83 | 2015-03-14 00:09:00 +1300 | [diff] [blame] | 203 | return; |
| 204 | } |
| 205 | |
| 206 | remote_ptr<void> last_stack_byte = t->regs().sp() - 1; |
| 207 | if (t->vm()->has_mapping(last_stack_byte)) { |
| 208 | auto m = t->vm()->mapping_of(last_stack_byte); |
Robert O'Callahan | f8c2fee | 2015-08-28 23:41:09 +1200 | [diff] [blame] | 209 | if (is_usable_area(m.map) && m.map.start() + 2048 <= t->regs().sp()) { |
Robert O'Callahan | 0e9fe83 | 2015-03-14 00:09:00 +1300 | [diff] [blame] | 210 | // 'sp' is in a stack region and there's plenty of space there. No need |
| 211 | // to fix anything. |
| 212 | return; |
| 213 | } |
| 214 | } |
| 215 | |
Robert O'Callahan | a48afd1 | 2015-07-27 16:15:54 +1200 | [diff] [blame] | 216 | MemoryRange found_stack; |
Robert O'Callahan | f26ca55 | 2017-08-03 23:03:46 +1200 | [diff] [blame] | 217 | for (const auto& m : t->vm()->maps()) { |
Robert O'Callahan | f8c2fee | 2015-08-28 23:41:09 +1200 | [diff] [blame] | 218 | if (is_usable_area(m.map)) { |
| 219 | found_stack = m.map; |
| 220 | break; |
Robert O'Callahan | 0e9fe83 | 2015-03-14 00:09:00 +1300 | [diff] [blame] | 221 | } |
| 222 | }; |
Robert O'Callahan | 0e9fe83 | 2015-03-14 00:09:00 +1300 | [diff] [blame] | 223 | |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 224 | if (found_stack.start().is_null()) { |
| 225 | AutoRemoteSyscalls remote(t, DISABLE_MEMORY_PARAMS); |
| 226 | found_stack = |
Robert O'Callahan | 4bd2467 | 2022-03-26 14:23:23 +1300 | [diff] [blame] | 227 | MemoryRange(remote.infallible_mmap_syscall_if_alive( |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 228 | remote_ptr<void>(), 4096, PROT_READ | PROT_WRITE, |
| 229 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0), |
| 230 | 4096); |
Robert O'Callahan | 4bd2467 | 2022-03-26 14:23:23 +1300 | [diff] [blame] | 231 | ASSERT(t, !found_stack.start().is_null()) |
| 232 | << "Tracee unexpectedly died here"; |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 233 | scratch_mem_was_mapped = true; |
| 234 | } |
| 235 | |
| 236 | fixed_sp = found_stack.end(); |
Robert O'Callahan | d218a53 | 2017-08-07 17:20:51 +1200 | [diff] [blame] | 237 | DEBUG_ASSERT(!fixed_sp.is_null()); |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 238 | initial_regs.set_sp(fixed_sp); |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 239 | } |
| 240 | |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 241 | AutoRemoteSyscalls::~AutoRemoteSyscalls() { restore_state_to(t); } |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 242 | |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 243 | void AutoRemoteSyscalls::restore_state_to(Task* t) { |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 244 | // Check if the task was unexpectedly killed via SIGKILL or equivalent. |
| 245 | bool is_exiting = !t->is_stopped() || t->ptrace_event() == PTRACE_EVENT_EXIT || |
| 246 | t->was_reaped(); |
| 247 | |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 248 | // Unmap our scatch region if required |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 249 | if (scratch_mem_was_mapped && !is_exiting) { |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 250 | AutoRemoteSyscalls remote(t, DISABLE_MEMORY_PARAMS); |
Robert O'Callahan | 1659fd3 | 2018-01-24 23:58:32 +1300 | [diff] [blame] | 251 | remote.infallible_syscall(syscall_number_for_munmap(arch()), |
| 252 | fixed_sp - 4096, 4096); |
Keno Fischer | 55e68a9 | 2016-09-21 19:53:13 -0400 | [diff] [blame] | 253 | } |
Keno Fischer | a8d922e | 2016-06-05 22:10:13 -0400 | [diff] [blame] | 254 | if (!replaced_bytes.empty()) { |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 255 | // XXX how to clean up if the task died and the address space is shared with live task? |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 256 | t->write_mem(remote_ptr<uint8_t>(initial_regs.ip().to_data_ptr<uint8_t>()), |
Keno Fischer | a8d922e | 2016-06-05 22:10:13 -0400 | [diff] [blame] | 257 | replaced_bytes.data(), replaced_bytes.size()); |
| 258 | } |
Kyle Huey | 9d2c674 | 2017-10-18 12:47:44 -0700 | [diff] [blame] | 259 | auto regs = initial_regs; |
| 260 | regs.set_ip(initial_ip); |
| 261 | regs.set_sp(initial_sp); |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 262 | if (is_exiting) { |
| 263 | // Don't restore status; callers need to see the task is exiting. |
| 264 | // And the other stuff we don't below won't work. |
| 265 | // But do restore registers so it looks like the exit happened in a clean state. |
Robert O'Callahan | 8c468fb | 2023-09-18 19:28:02 +1200 | [diff] [blame] | 266 | t->set_regs(regs); |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 267 | return; |
| 268 | } |
| 269 | |
Yichao Yu | 5871ae5 | 2022-06-17 00:41:38 -0400 | [diff] [blame] | 270 | if (t->arch() == aarch64 && regs.syscall_may_restart()) { |
| 271 | // On AArch64, the kernel restarts aborted syscalls using an internal `orig_x0`. |
| 272 | // This gets overwritten everytime we make a syscall so we need to restore it |
| 273 | // if we are at a syscall that may restart. |
| 274 | // The kernel `orig_x0` isn't accessible from ptrace AFAICT but fortunately |
| 275 | // it does **NOT** get reset on syscall exit so we can actually set it's value |
| 276 | // just by making a dummy syscall with the correct x0 value. |
| 277 | auto restart_res = regs.syscall_result(); |
| 278 | regs.set_ip(t->vm()->traced_syscall_ip()); |
| 279 | // This can be any side-effect-free syscall that doesn't care about arg1. |
| 280 | // The kernel sets its `orig_x0` no matter whether the syscall actually needs it. |
| 281 | regs.set_syscallno(rr::ARM64Arch::getpid); |
| 282 | regs.set_arg1(regs.orig_arg1()); |
| 283 | t->set_regs(regs); |
| 284 | if (t->enter_syscall(true)) { |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 285 | if (!t->resume_execution(RESUME_SYSCALL, RESUME_WAIT_NO_EXIT, RESUME_NO_TICKS)) { |
| 286 | // Tracee died unexpectedly, there is nothing more we can do. |
| 287 | // Do not restore the status, we want callers to see that the task died. |
| 288 | return; |
| 289 | } |
Yichao Yu | 5871ae5 | 2022-06-17 00:41:38 -0400 | [diff] [blame] | 290 | } |
| 291 | regs.set_ip(initial_ip); |
| 292 | regs.set_syscallno(regs.original_syscallno()); |
| 293 | regs.set_syscall_result(restart_res); |
| 294 | } |
Keno Fischer | 3bef84d | 2021-01-13 03:46:57 -0500 | [diff] [blame] | 295 | // If we were sitting at a seccomp trap, try to get back there by resuming |
| 296 | // here. Since the original register contents caused a seccomp trap, |
| 297 | // re-running the syscall with the same registers should put us right back |
| 298 | // to this same seccomp trap. |
| 299 | if (initial_at_seccomp && t->ptrace_event() != PTRACE_EVENT_SECCOMP) { |
Keno Fischer | 31140d0 | 2022-04-13 22:32:52 +0000 | [diff] [blame] | 300 | regs.set_ip(initial_ip.decrement_by_syscall_insn_length(t->arch())); |
| 301 | regs.set_syscallno(regs.original_syscallno()); |
| 302 | t->set_regs(regs); |
Keno Fischer | 3bef84d | 2021-01-13 03:46:57 -0500 | [diff] [blame] | 303 | RecordTask* rt = static_cast<RecordTask*>(t); |
| 304 | while (true) { |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 305 | if (!rt->resume_execution(RESUME_CONT, RESUME_WAIT_NO_EXIT, RESUME_NO_TICKS)) { |
| 306 | // Tracee died unexpectedly, there is nothing more we can do. |
| 307 | // Do not restore the status, we want callers to see that the task died. |
| 308 | return; |
| 309 | } |
Keno Fischer | 3bef84d | 2021-01-13 03:46:57 -0500 | [diff] [blame] | 310 | if (rt->ptrace_event()) |
| 311 | break; |
| 312 | rt->stash_sig(); |
| 313 | } |
| 314 | ASSERT(rt, rt->ptrace_event() == PTRACE_EVENT_SECCOMP); |
Keno Fischer | 31140d0 | 2022-04-13 22:32:52 +0000 | [diff] [blame] | 315 | } else { |
| 316 | // Restore stomped registers. |
| 317 | t->set_regs(regs); |
Keno Fischer | 3bef84d | 2021-01-13 03:46:57 -0500 | [diff] [blame] | 318 | } |
Robert O'Callahan | 955b5e0 | 2017-08-12 16:59:09 +1200 | [diff] [blame] | 319 | t->set_status(restore_wait_status); |
Keno Fischer | 42728be | 2022-04-12 00:23:09 +0000 | [diff] [blame] | 320 | if (restore_sigmask) { |
| 321 | static_cast<RecordTask*>(t)->set_sigmask(sigmask_to_restore); |
| 322 | } |
Keno Fischer | 8721ae8 | 2022-04-13 23:17:37 +0000 | [diff] [blame] | 323 | if (need_sigpending_renable) { |
| 324 | // The purpose of this PTRACE_INTERRUPT is to re-enable TIF_SIGPENDING on |
| 325 | // the tracee, without forcing any actual signals on it. Since PTRACE_INTERRUPT |
| 326 | // needs to be able to interrupt re-startable system calls, it is required |
| 327 | // to set TIF_SIGPENDING, but the fact that this works is of course a very |
| 328 | // deep implementation detail. |
Robert O'Callahan | 7039534 | 2023-08-19 15:27:44 +1200 | [diff] [blame] | 329 | // If this fails then the tracee must be dead or no longer traced, in which |
| 330 | // case we no longer care about its TIF_SIGPENDING status. |
Keno Fischer | 2510520 | 2022-06-26 23:08:20 +0000 | [diff] [blame] | 331 | t->do_ptrace_interrupt(); |
Keno Fischer | 8721ae8 | 2022-04-13 23:17:37 +0000 | [diff] [blame] | 332 | } |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 333 | } |
| 334 | |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 335 | static bool ignore_signal(Task* t) { |
| 336 | int sig = t->stop_sig(); |
| 337 | if (!sig) { |
| 338 | return false; |
| 339 | } |
| 340 | if (t->session().is_replaying()) { |
| 341 | if (ReplaySession::is_ignored_signal(sig)) { |
| 342 | return true; |
| 343 | } |
| 344 | } else if (t->session().is_recording()) { |
Kyle Huey | cd145d1 | 2019-07-07 20:07:13 -0700 | [diff] [blame] | 345 | auto rt = static_cast<RecordTask*>(t); |
| 346 | if (sig != rt->session().syscallbuf_desched_sig()) { |
| 347 | rt->stash_sig(); |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 348 | } |
| 349 | return true; |
| 350 | } |
Robert O'Callahan | 336edc3 | 2022-08-16 08:17:41 +1200 | [diff] [blame] | 351 | siginfo_t siginfo; |
Robert O'Callahan | 57d0a80 | 2023-08-19 23:05:23 +1200 | [diff] [blame] | 352 | errno = 0; |
| 353 | t->fallible_ptrace(PTRACE_GETSIGINFO, nullptr, &siginfo); |
| 354 | if (errno) { |
Robert O'Callahan | 336edc3 | 2022-08-16 08:17:41 +1200 | [diff] [blame] | 355 | ASSERT(t, false) << "Unexpected signal " << signal_name(sig); |
Robert O'Callahan | 57d0a80 | 2023-08-19 23:05:23 +1200 | [diff] [blame] | 356 | } else { |
| 357 | ASSERT(t, false) << "Unexpected signal " << siginfo; |
Robert O'Callahan | 336edc3 | 2022-08-16 08:17:41 +1200 | [diff] [blame] | 358 | } |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 359 | return false; |
| 360 | } |
| 361 | |
Robert O'Callahan | f24e09c | 2017-08-11 16:36:30 +1200 | [diff] [blame] | 362 | long AutoRemoteSyscalls::syscall_base(int syscallno, Registers& callregs) { |
Keno Fischer | 4e10088 | 2020-03-19 23:19:20 -0400 | [diff] [blame] | 363 | LOG(debug) << "syscall " << syscall_name(syscallno, t->arch()) << " " << callregs; |
Robert O'Callahan | a8eac64 | 2016-08-01 11:06:20 +1200 | [diff] [blame] | 364 | |
Robert O'Callahan | 28feb3b | 2023-08-25 22:09:52 +1200 | [diff] [blame] | 365 | if (t->seen_ptrace_exit_event()) { |
Robert O'Callahan | da7e2e8 | 2020-07-27 15:55:45 +1200 | [diff] [blame] | 366 | LOG(debug) << "Task is dying, don't try anything."; |
| 367 | return -ESRCH; |
| 368 | } |
| 369 | |
Robert O'Callahan | ed45cd6 | 2017-08-16 01:29:05 +1200 | [diff] [blame] | 370 | if ((int)callregs.arg1() == SIGTRAP && use_singlestep_path && |
| 371 | (is_sigaction_syscall(syscallno, t->arch()) || |
| 372 | is_rt_sigaction_syscall(syscallno, t->arch()) || |
| 373 | is_signal_syscall(syscallno, t->arch()))) { |
| 374 | // Don't use the fast path if we're about to set up a signal handler |
| 375 | // for SIGTRAP! |
| 376 | LOG(debug) << "Disabling singlestep path due to SIGTRAP sigaction"; |
| 377 | setup_path(false); |
| 378 | callregs.set_ip(initial_regs.ip()); |
| 379 | } |
| 380 | |
Keno Fischer | 04f22d9 | 2020-05-21 23:18:41 +0000 | [diff] [blame] | 381 | callregs.set_original_syscallno(syscallno); |
Robert O'Callahan | d070639 | 2014-09-09 12:01:23 +1200 | [diff] [blame] | 382 | callregs.set_syscallno(syscallno); |
| 383 | t->set_regs(callregs); |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 384 | |
Keno Fischer | 31140d0 | 2022-04-13 22:32:52 +0000 | [diff] [blame] | 385 | bool from_seccomp = initial_at_seccomp && t->ptrace_event() == PTRACE_EVENT_SECCOMP; |
| 386 | if (use_singlestep_path && !from_seccomp) { |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 387 | while (true) { |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 388 | if (!t->resume_execution(RESUME_SINGLESTEP, RESUME_WAIT_NO_EXIT, RESUME_NO_TICKS)) { |
| 389 | // Tracee was killed, there is nothing more we can do. |
| 390 | return -ESRCH; |
| 391 | } |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 392 | LOG(debug) << "Used singlestep path; status=" << t->status(); |
Robert O'Callahan | b143504 | 2017-08-11 18:27:49 +1200 | [diff] [blame] | 393 | // When a PTRACE_EVENT_EXIT is returned we don't update registers |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 394 | if (t->ip() != callregs.ip()) { |
| 395 | // We entered the syscall, so stop now |
| 396 | break; |
| 397 | } |
Keno Fischer | 04f22d9 | 2020-05-21 23:18:41 +0000 | [diff] [blame] | 398 | if (t->stop_sig() == SIGTRAP && t->get_siginfo().si_code == TRAP_TRACE) { |
| 399 | // On aarch64, if we were previously in a syscall-exit stop, continuing |
| 400 | // with PTRACE_SINGLESTEP will result in incurring a trap upon execution |
| 401 | // of the first instruction in userspace. Ignore such a trap. |
| 402 | continue; |
| 403 | } |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 404 | if (ignore_signal(t)) { |
| 405 | // We were interrupted by a signal before we even entered the syscall |
| 406 | continue; |
| 407 | } |
| 408 | ASSERT(t, false) << "Unexpected status " << t->status(); |
| 409 | } |
| 410 | } else { |
Keno Fischer | 31140d0 | 2022-04-13 22:32:52 +0000 | [diff] [blame] | 411 | if (from_seccomp) { |
Keno Fischer | 3bef84d | 2021-01-13 03:46:57 -0500 | [diff] [blame] | 412 | LOG(debug) << "Skipping enter_syscall - already at seccomp stop"; |
| 413 | } else { |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 414 | if (!t->enter_syscall(true)) { |
| 415 | // Tracee was killed, there is nothing more we can do. |
| 416 | // Ensure callers see the task death status. |
| 417 | return -ESRCH; |
| 418 | } |
Keno Fischer | 31140d0 | 2022-04-13 22:32:52 +0000 | [diff] [blame] | 419 | LOG(debug) << "Used enter_syscall; status=" << t->status(); |
Keno Fischer | 3bef84d | 2021-01-13 03:46:57 -0500 | [diff] [blame] | 420 | } |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 421 | if (!t->resume_execution(RESUME_SYSCALL, RESUME_WAIT_NO_EXIT, RESUME_NO_TICKS)) { |
| 422 | // Tracee was killed, there is nothing more we can do. |
| 423 | // Ensure callers see the task death status. |
Robert O'Callahan | 2c1a6d4 | 2023-08-24 01:23:28 +1200 | [diff] [blame] | 424 | return -ESRCH; |
Robert O'Callahan | 955b5e0 | 2017-08-12 16:59:09 +1200 | [diff] [blame] | 425 | } |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 426 | LOG(debug) << "syscall exit status=" << t->status(); |
| 427 | } |
| 428 | while (true) { |
Robert O'Callahan | 955b5e0 | 2017-08-12 16:59:09 +1200 | [diff] [blame] | 429 | if (t->status().is_syscall() || |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 430 | (t->stop_sig() == SIGTRAP && |
| 431 | is_kernel_trap(t->get_siginfo().si_code))) { |
| 432 | // If we got a SIGTRAP then we assume that's our singlestep and we're |
| 433 | // done. |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 434 | break; |
| 435 | } |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 436 | if (is_clone_syscall(syscallno, t->arch()) && |
Robert O'Callahan | 27d47d6 | 2017-08-15 13:59:29 +1200 | [diff] [blame] | 437 | t->clone_syscall_is_complete(&new_tid_, t->arch())) { |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 438 | if (!t->resume_execution(RESUME_SYSCALL, RESUME_WAIT_NO_EXIT, RESUME_NO_TICKS)) { |
| 439 | // Tracee was killed, there is nothing more we can do. |
| 440 | return -ESRCH; |
| 441 | } |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 442 | LOG(debug) << "got clone event; new status=" << t->status(); |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 443 | continue; |
| 444 | } |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 445 | if (ignore_signal(t)) { |
| 446 | if (t->regs().syscall_may_restart()) { |
Yichao Yu | 3e0378c | 2022-06-20 11:25:36 -0400 | [diff] [blame] | 447 | if (!t->enter_syscall(true)) { |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 448 | // Tracee was killed, there is nothing more we can do. |
| 449 | return -ESRCH; |
Yichao Yu | 3e0378c | 2022-06-20 11:25:36 -0400 | [diff] [blame] | 450 | } |
Robert O'Callahan | 955b5e0 | 2017-08-12 16:59:09 +1200 | [diff] [blame] | 451 | LOG(debug) << "signal ignored; restarting syscall, status=" |
| 452 | << t->status(); |
Robert O'Callahan | 024064f | 2023-08-23 07:34:49 +1200 | [diff] [blame] | 453 | if (!t->resume_execution(RESUME_SYSCALL, RESUME_WAIT_NO_EXIT, RESUME_NO_TICKS)) { |
| 454 | // Tracee was killed, there is nothing more we can do. |
| 455 | return -ESRCH; |
| 456 | } |
Robert O'Callahan | fa24c20 | 2017-08-12 00:46:23 +1200 | [diff] [blame] | 457 | LOG(debug) << "syscall exit status=" << t->status(); |
| 458 | continue; |
| 459 | } |
| 460 | LOG(debug) << "signal ignored"; |
| 461 | // We have been notified of a signal after a non-interruptible syscall |
| 462 | // completed. Don't continue, we're done here. |
| 463 | break; |
| 464 | } |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 465 | ASSERT(t, false) << "Unexpected status " << t->status(); |
Robert O'Callahan | f24e09c | 2017-08-11 16:36:30 +1200 | [diff] [blame] | 466 | break; |
Robert O'Callahan | 5c9348d | 2017-08-10 23:25:35 +1200 | [diff] [blame] | 467 | } |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 468 | |
Robert O'Callahan | 2c1a6d4 | 2023-08-24 01:23:28 +1200 | [diff] [blame] | 469 | LOG(debug) << "done, result=" << t->regs().syscall_result(); |
| 470 | return t->regs().syscall_result(); |
Chris Jones | c43ca32 | 2014-07-23 11:44:36 -0700 | [diff] [blame] | 471 | } |
Nathan Froyd | e5caec2 | 2014-09-11 08:48:34 -0400 | [diff] [blame] | 472 | |
Robert O'Callahan | 53bd4b3 | 2014-09-13 09:54:47 +1200 | [diff] [blame] | 473 | SupportedArch AutoRemoteSyscalls::arch() const { return t->arch(); } |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 474 | |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 475 | template <typename Arch> |
| 476 | static void write_socketcall_args(Task* t, remote_ptr<void> remote_mem, |
Robert O'Callahan | 37529cd | 2014-11-21 17:07:08 +1300 | [diff] [blame] | 477 | typename Arch::signed_long arg1, |
| 478 | typename Arch::signed_long arg2, |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 479 | typename Arch::signed_long arg3, |
| 480 | bool* ok) { |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 481 | socketcall_args<Arch> sc_args = { { arg1, arg2, arg3 } }; |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 482 | t->write_mem(remote_mem.cast<socketcall_args<Arch>>(), sc_args, ok); |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 483 | } |
| 484 | |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 485 | template <typename Arch> |
| 486 | struct fd_message { |
| 487 | // Unfortunately we need to send at least one byte of data in our |
| 488 | // message for it to work |
| 489 | char data; |
| 490 | typename Arch::iovec msgdata; |
| 491 | char cmsgbuf[Arch::cmsg_space(sizeof(int))]; |
| 492 | typename Arch::msghdr msg; |
| 493 | // XXX: Could make this conditional on Arch |
| 494 | socketcall_args<Arch> socketcall; |
| 495 | void init(remote_ptr<fd_message<Arch>> base) { |
| 496 | data = 0; |
| 497 | msgdata.iov_base = REMOTE_PTR_FIELD(base, data); |
| 498 | msgdata.iov_len = 1; |
| 499 | memset(&msg, 0, sizeof(msg)); |
| 500 | msg.msg_control = REMOTE_PTR_FIELD(base, cmsgbuf); |
| 501 | msg.msg_controllen = sizeof(cmsgbuf); |
| 502 | msg.msg_iov = REMOTE_PTR_FIELD(base, msgdata); |
| 503 | msg.msg_iovlen = 1; |
Robert O'Callahan | bc6f123 | 2017-08-07 16:14:19 +1200 | [diff] [blame] | 504 | } |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 505 | fd_message(remote_ptr<fd_message<Arch>> base) { |
| 506 | init(base); |
| 507 | } |
| 508 | fd_message() { |
| 509 | init((uintptr_t)this); |
| 510 | } |
| 511 | remote_ptr<fd_message<Arch>> remote_this() { |
| 512 | return msgdata.iov_base.rptr().as_int(); |
| 513 | } |
| 514 | remote_ptr<typename Arch::msghdr> remote_msg() { |
| 515 | return REMOTE_PTR_FIELD(remote_this(), msg); |
| 516 | } |
| 517 | remote_ptr<socketcall_args<Arch>> remote_sc_args() { |
| 518 | return REMOTE_PTR_FIELD(remote_this(), socketcall); |
| 519 | } |
| 520 | remote_ptr<int> remote_cmsgdata() { |
| 521 | return REMOTE_PTR_FIELD(remote_this(), cmsgbuf).as_int() + |
| 522 | (uintptr_t)Arch::cmsg_data(NULL); |
| 523 | } |
| 524 | }; |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 525 | |
Robert O'Callahan | 044b97f | 2016-05-26 10:43:00 +1200 | [diff] [blame] | 526 | template <typename Arch> |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 527 | static long child_sendmsg(AutoRemoteSyscalls& remote, int child_sock, int fd) { |
| 528 | AutoRestoreMem remote_buf(remote, nullptr, sizeof(fd_message<Arch>)); |
| 529 | fd_message<Arch> msg(remote_buf.get().cast<fd_message<Arch>>()); |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 530 | // Pull the puppet strings to have the child send its fd |
| 531 | // to us. Similarly to above, we DONT_WAIT on the |
| 532 | // call to finish, since it's likely not defined whether the |
| 533 | // sendmsg() may block on our recvmsg()ing what the tracee |
| 534 | // sent us (in which case we would deadlock with the tracee). |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 535 | // We call sendmsg on child socket, but first we have to prepare a lot of |
| 536 | // data. |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 537 | auto cmsg = reinterpret_cast<typename Arch::cmsghdr*>(msg.cmsgbuf); |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 538 | cmsg->cmsg_len = Arch::cmsg_len(sizeof(fd)); |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 539 | cmsg->cmsg_level = SOL_SOCKET; |
| 540 | cmsg->cmsg_type = SCM_RIGHTS; |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 541 | *static_cast<int*>(Arch::cmsg_data(cmsg)) = fd; |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 542 | |
| 543 | if (has_socketcall_syscall(Arch::arch())) { |
| 544 | socketcall_args<Arch> sc_args = { { child_sock, (typename Arch::signed_long)msg.remote_msg().as_int(), 0 } }; |
| 545 | msg.socketcall = sc_args; |
| 546 | } |
| 547 | |
| 548 | bool ok = true; |
| 549 | remote.task()->write_bytes_helper(remote_buf.get().cast<char>(), |
| 550 | sizeof(msg), &msg, &ok); |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 551 | |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 552 | if (!ok) { |
| 553 | return -ESRCH; |
| 554 | } |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 555 | if (!has_socketcall_syscall(Arch::arch())) { |
| 556 | return remote.syscall(Arch::sendmsg, child_sock, msg.remote_msg(), 0); |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 557 | } |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 558 | return remote.syscall(Arch::socketcall, SYS_SENDMSG, msg.remote_sc_args()); |
| 559 | } |
| 560 | |
| 561 | template <typename Arch> |
| 562 | static long child_recvmsg(AutoRemoteSyscalls& remote, int child_sock) { |
| 563 | AutoRestoreMem remote_buf(remote, nullptr, sizeof(fd_message<Arch>)); |
| 564 | fd_message<Arch> msg(remote_buf.get().cast<fd_message<Arch>>()); |
| 565 | bool ok = true; |
| 566 | |
| 567 | if (has_socketcall_syscall(Arch::arch())) { |
| 568 | socketcall_args<Arch> sc_args = { { child_sock, |
| 569 | (typename Arch::signed_long)msg.remote_msg().as_int(), 0 } }; |
| 570 | msg.socketcall = sc_args; |
| 571 | } |
| 572 | |
| 573 | remote.task()->write_bytes_helper(remote_buf.get().cast<char>(), |
| 574 | sizeof(msg), &msg, &ok); |
| 575 | |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 576 | if (!ok) { |
Robert O'Callahan | c88aaa7 | 2023-02-25 16:21:08 +1300 | [diff] [blame] | 577 | ASSERT(remote.task(), errno == ESRCH) << "Error writing " << remote_buf.get() |
| 578 | << " in " << remote.task()->tid; |
Robert O'Callahan | 30b72a8 | 2021-11-30 17:46:18 +1300 | [diff] [blame] | 579 | LOG(debug) << "Failed to write memory"; |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 580 | return -ESRCH; |
| 581 | } |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 582 | int ret = 0; |
Robert O'Callahan | 42cf5bb | 2020-07-30 15:28:43 +1200 | [diff] [blame] | 583 | if (has_socketcall_syscall(Arch::arch())) { |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 584 | ret = remote.syscall(Arch::socketcall, SYS_RECVMSG, msg.remote_sc_args()); |
Robert O'Callahan | 42cf5bb | 2020-07-30 15:28:43 +1200 | [diff] [blame] | 585 | } else { |
| 586 | ret = remote.syscall(Arch::recvmsg, child_sock, msg.remote_msg(), 0); |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 587 | } |
| 588 | if (ret < 0) { |
Robert O'Callahan | 30b72a8 | 2021-11-30 17:46:18 +1300 | [diff] [blame] | 589 | LOG(debug) << "Failed to recvmsg " << ret; |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 590 | return ret; |
| 591 | } |
| 592 | int their_fd = remote.task()->read_mem(msg.remote_cmsgdata(), &ok); |
| 593 | if (!ok) { |
Robert O'Callahan | 30b72a8 | 2021-11-30 17:46:18 +1300 | [diff] [blame] | 594 | ASSERT(remote.task(), errno == ESRCH); |
| 595 | LOG(debug) << "Failed to read msg"; |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 596 | return -ESRCH; |
| 597 | } |
| 598 | return their_fd; |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 599 | } |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 600 | |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 601 | #define MAX_FDS_READ 2 |
| 602 | |
| 603 | // Try to read a single-character message from `sock`. Will collect |
| 604 | // up to MAX_FDS_READ fds in an SCM_RIGHTS control message and return those |
Josh Soref | 9dd6658 | 2023-03-01 04:32:13 -0500 | [diff] [blame] | 605 | // fds. Returns an empty vector if reading the message fails. |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 606 | static vector<ScopedFd> maybe_receive_fds(ScopedFd& sock, bool blocking = true) { |
| 607 | vector<ScopedFd> ret; |
| 608 | struct msghdr msg; |
| 609 | memset(&msg, 0, sizeof(msg)); |
| 610 | char ch; |
| 611 | struct iovec iov = { &ch, 1 }; |
| 612 | msg.msg_iov = &iov; |
| 613 | msg.msg_iovlen = 1; |
| 614 | char cmsgbuf[(CMSG_SPACE(MAX_FDS_READ * sizeof(int)))]; |
| 615 | msg.msg_control = cmsgbuf; |
| 616 | msg.msg_controllen = sizeof(cmsgbuf); |
| 617 | int flags = MSG_CMSG_CLOEXEC; |
Yichao Yu | 8af63e4 | 2022-06-26 23:37:38 -0400 | [diff] [blame] | 618 | if (!blocking) { |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 619 | flags |= MSG_DONTWAIT; |
Yichao Yu | 8af63e4 | 2022-06-26 23:37:38 -0400 | [diff] [blame] | 620 | } |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 621 | if (recvmsg(sock, &msg, flags) < 0) { |
| 622 | return ret; |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 623 | } |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 624 | |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 625 | struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); |
| 626 | if (!cmsg || cmsg->cmsg_level != SOL_SOCKET || |
| 627 | cmsg->cmsg_type != SCM_RIGHTS) { |
| 628 | FATAL() << "Invalid cmsg"; |
| 629 | } |
| 630 | int num_fds = (cmsg->cmsg_len - CMSG_LEN(0))/sizeof(int); |
| 631 | for (int i = 0; i < num_fds; i++) { |
| 632 | int fd; |
| 633 | memcpy(&fd, CMSG_DATA(cmsg) + i*sizeof(int), sizeof(int)); |
| 634 | DEBUG_ASSERT(fd >= 0); |
| 635 | ret.push_back(ScopedFd(fd)); |
| 636 | } |
| 637 | return ret; |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 638 | } |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 639 | |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 640 | static void sendmsg_socket(ScopedFd& sock, int fd_to_send) |
| 641 | { |
| 642 | fd_message<NativeArch> msg; |
| 643 | |
| 644 | struct msghdr *msgp = (struct msghdr*)&msg.msg; |
| 645 | struct cmsghdr* cmsg = CMSG_FIRSTHDR(msgp); |
| 646 | cmsg->cmsg_level = SOL_SOCKET; |
| 647 | cmsg->cmsg_type = SCM_RIGHTS; |
| 648 | cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); |
| 649 | *(int*)CMSG_DATA(cmsg) = fd_to_send; |
| 650 | |
| 651 | if (0 > sendmsg(sock, msgp, 0)) { |
| 652 | FATAL() << "Failed to send fd"; |
| 653 | } |
| 654 | } |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 655 | |
Robert O'Callahan | d83c361 | 2023-01-02 20:51:14 +1300 | [diff] [blame] | 656 | static Task* thread_group_leader_for_fds(Task* t) { |
| 657 | for (Task* tt : t->fd_table()->task_set()) { |
Robert O'Callahan | 28feb3b | 2023-08-25 22:09:52 +1200 | [diff] [blame] | 658 | if (tt->tgid() == tt->rec_tid && !tt->seen_ptrace_exit_event()) { |
Robert O'Callahan | d83c361 | 2023-01-02 20:51:14 +1300 | [diff] [blame] | 659 | return tt; |
| 660 | } |
| 661 | } |
| 662 | return nullptr; |
| 663 | } |
| 664 | |
Robert O'Callahan | 3fca38a | 2014-11-21 09:58:15 +1300 | [diff] [blame] | 665 | template <typename Arch> ScopedFd AutoRemoteSyscalls::retrieve_fd_arch(int fd) { |
Robert O'Callahan | d83c361 | 2023-01-02 20:51:14 +1300 | [diff] [blame] | 666 | ScopedFd ret; |
Robert O'Callahan | d83c361 | 2023-01-02 20:51:14 +1300 | [diff] [blame] | 667 | if (!pid_fd.is_open()) { |
Robert O'Callahan | 0e37796 | 2023-07-15 22:41:21 +1200 | [diff] [blame] | 668 | // Try to use pidfd_getfd to get the fd without round-tripping to the tracee. |
| 669 | // pidfd_getfd requires a threadgroup leader, so find one if we can. |
Robert O'Callahan | d83c361 | 2023-01-02 20:51:14 +1300 | [diff] [blame] | 670 | Task* tg_leader_for_fds = thread_group_leader_for_fds(t); |
| 671 | if (tg_leader_for_fds) { |
| 672 | pid_fd = ScopedFd(::syscall(NativeArch::pidfd_open, tg_leader_for_fds->tid, 0)); |
| 673 | ASSERT(t, pid_fd.is_open() || errno == ENOSYS) |
| 674 | << "Error in pidfd_open errno=" << errno_name(errno); |
| 675 | } |
| 676 | } |
Kyle Huey | f5ab8f1 | 2023-07-12 23:52:47 -0700 | [diff] [blame] | 677 | if (pid_fd.is_open()) { |
Robert O'Callahan | d83c361 | 2023-01-02 20:51:14 +1300 | [diff] [blame] | 678 | ret = ScopedFd(::syscall(NativeArch::pidfd_getfd, pid_fd.get(), fd, 0)); |
| 679 | if (ret.is_open()) { |
| 680 | return ret; |
| 681 | } |
| 682 | ASSERT(t, errno == ENOSYS) << "Failed in pidfd_getfd errno=" << errno_name(errno); |
| 683 | } |
| 684 | |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 685 | // Clear out any pending message in the socket. |
| 686 | maybe_receive_fds(task()->session().tracee_socket_receiver_fd(), false); |
| 687 | |
Robert O'Callahan | f24e09c | 2017-08-11 16:36:30 +1200 | [diff] [blame] | 688 | long child_syscall_result = |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 689 | child_sendmsg<Arch>(*this, task()->session().tracee_fd_number(), fd); |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 690 | if (child_syscall_result == -ESRCH) { |
Robert O'Callahan | d83c361 | 2023-01-02 20:51:14 +1300 | [diff] [blame] | 691 | return ret; |
Robert O'Callahan | fd2a2c3 | 2019-03-06 16:52:18 +1300 | [diff] [blame] | 692 | } |
Robert O'Callahan | f24e09c | 2017-08-11 16:36:30 +1200 | [diff] [blame] | 693 | ASSERT(t, child_syscall_result > 0) << "Failed to sendmsg() in tracee; err=" |
| 694 | << errno_name(-child_syscall_result); |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 695 | vector<ScopedFd> fds = maybe_receive_fds(task()->session().tracee_socket_fd()); |
| 696 | ASSERT(t, !fds.empty()) << "Failed to receive fd"; |
| 697 | ASSERT(t, fds.size() == 1); |
Sidharth Kshatriya | 9dbc862 | 2023-04-21 11:25:47 +0530 | [diff] [blame] | 698 | return std::move(fds[0]); |
Robert O'Callahan | 771de35 | 2014-10-02 11:52:34 -0400 | [diff] [blame] | 699 | } |
Robert O'Callahan | c55b355 | 2014-11-20 16:53:53 +1300 | [diff] [blame] | 700 | |
| 701 | ScopedFd AutoRemoteSyscalls::retrieve_fd(int fd) { |
| 702 | RR_ARCH_FUNCTION(retrieve_fd_arch, arch(), fd); |
| 703 | } |
Robert O'Callahan | 3d5e580 | 2014-12-06 20:38:56 -0600 | [diff] [blame] | 704 | |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 705 | template <typename Arch> int AutoRemoteSyscalls::send_fd_arch(const ScopedFd &our_fd) { |
Keno Fischer | 2e59532 | 2020-04-04 02:35:45 -0400 | [diff] [blame] | 706 | if (!our_fd.is_open()) { |
| 707 | return -EBADF; |
| 708 | } |
| 709 | |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 710 | // Clear out any pending message from the socket. |
| 711 | maybe_receive_fds(task()->session().tracee_socket_receiver_fd(), false); |
| 712 | |
Keno Fischer | 2e59532 | 2020-04-04 02:35:45 -0400 | [diff] [blame] | 713 | LOG(debug) << "Sending fd " << our_fd.get() << " via socket fd " << task()->session().tracee_socket_fd().get(); |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 714 | sendmsg_socket(task()->session().tracee_socket_fd(), our_fd.get()); |
| 715 | |
| 716 | long child_syscall_result = |
| 717 | child_recvmsg<Arch>(*this, task()->session().tracee_fd_number()); |
Robert O'Callahan | 2c9833f | 2023-02-04 13:59:47 +1300 | [diff] [blame] | 718 | // If the child died before reading the message from the socket, |
| 719 | // the message will still be in the socket buffer and will be received |
| 720 | // the next time we try to send something to a tracee. That's why |
| 721 | // before using tracee_socket_receiver_fd we need to drain up to one message |
| 722 | // from it. |
| 723 | ASSERT(t, child_syscall_result >= 0 || child_syscall_result == -ESRCH) |
| 724 | << "Failed to recvmsg() in tracee; err=" << errno_name(-child_syscall_result); |
Keno Fischer | 0ec1068 | 2020-04-02 01:03:49 -0400 | [diff] [blame] | 725 | return child_syscall_result; |
| 726 | } |
| 727 | |
| 728 | int AutoRemoteSyscalls::send_fd(const ScopedFd &our_fd) { |
| 729 | RR_ARCH_FUNCTION(send_fd_arch, arch(), our_fd); |
| 730 | } |
| 731 | |
Robert O'Callahan | e917728 | 2022-03-28 11:59:09 +1300 | [diff] [blame] | 732 | void AutoRemoteSyscalls::infallible_close_syscall_if_alive(int child_fd) { |
| 733 | infallible_syscall_if_alive(syscall_number_for_close(arch()), child_fd); |
| 734 | } |
| 735 | |
Robert O'Callahan | b422fed | 2022-03-26 12:36:09 +1300 | [diff] [blame] | 736 | int AutoRemoteSyscalls::infallible_send_fd_if_alive(const ScopedFd &our_fd) { |
Robert O'Callahan | 768e348 | 2022-03-08 23:14:25 +1300 | [diff] [blame] | 737 | int child_fd = send_fd(our_fd); |
Robert O'Callahan | b422fed | 2022-03-26 12:36:09 +1300 | [diff] [blame] | 738 | ASSERT(t, child_fd >= 0 || (child_fd == -ESRCH && !t->session().is_replaying())) |
| 739 | << "Failed to send fd; err=" << errno_name(-child_fd); |
Robert O'Callahan | 768e348 | 2022-03-08 23:14:25 +1300 | [diff] [blame] | 740 | return child_fd; |
| 741 | } |
| 742 | |
Robert O'Callahan | b8566d2 | 2021-11-30 17:51:53 +1300 | [diff] [blame] | 743 | void AutoRemoteSyscalls::infallible_send_fd_dup(const ScopedFd& our_fd, int dup_to, int dup3_flags) { |
Robert O'Callahan | b422fed | 2022-03-26 12:36:09 +1300 | [diff] [blame] | 744 | int remote_fd = infallible_send_fd_if_alive(our_fd); |
| 745 | ASSERT(t, remote_fd >= 0); |
Keno Fischer | 8208c54 | 2020-05-06 22:02:22 -0400 | [diff] [blame] | 746 | if (remote_fd != dup_to) { |
| 747 | long ret = infallible_syscall(syscall_number_for_dup3(arch()), remote_fd, |
Robert O'Callahan | b8566d2 | 2021-11-30 17:51:53 +1300 | [diff] [blame] | 748 | dup_to, dup3_flags); |
Keno Fischer | 8208c54 | 2020-05-06 22:02:22 -0400 | [diff] [blame] | 749 | ASSERT(task(), ret == dup_to); |
Robert O'Callahan | e917728 | 2022-03-28 11:59:09 +1300 | [diff] [blame] | 750 | infallible_close_syscall_if_alive(remote_fd); |
Keno Fischer | 8208c54 | 2020-05-06 22:02:22 -0400 | [diff] [blame] | 751 | } |
| 752 | } |
| 753 | |
Robert O'Callahan | 4bd2467 | 2022-03-26 14:23:23 +1300 | [diff] [blame] | 754 | remote_ptr<void> AutoRemoteSyscalls::infallible_mmap_syscall_if_alive( |
Robert O'Callahan | b7e4052 | 2015-09-15 23:59:32 +1200 | [diff] [blame] | 755 | remote_ptr<void> addr, size_t length, int prot, int flags, int child_fd, |
Yichao Yu | 1b74f96 | 2022-04-13 18:27:13 -0400 | [diff] [blame] | 756 | uint64_t offset_bytes) { |
| 757 | ASSERT(t, offset_bytes % page_size() == 0) |
| 758 | << "mmap offset (" << offset_bytes << ") must be multiple of page size (" |
| 759 | << page_size() << ")"; |
Robert O'Callahan | 3ca78b9 | 2015-08-03 16:55:22 +1200 | [diff] [blame] | 760 | // The first syscall argument is called "arg 1", so |
| 761 | // our syscall-arg-index template parameter starts |
| 762 | // with "1". |
Robert O'Callahan | b7e4052 | 2015-09-15 23:59:32 +1200 | [diff] [blame] | 763 | remote_ptr<void> ret = |
| 764 | has_mmap2_syscall(arch()) |
Robert O'Callahan | 4bd2467 | 2022-03-26 14:23:23 +1300 | [diff] [blame] | 765 | ? infallible_syscall_ptr_if_alive(syscall_number_for_mmap2(arch()), addr, |
| 766 | length, prot, flags, child_fd, |
Yichao Yu | 1b74f96 | 2022-04-13 18:27:13 -0400 | [diff] [blame] | 767 | (off_t)offset_bytes / 4096) |
Robert O'Callahan | 4bd2467 | 2022-03-26 14:23:23 +1300 | [diff] [blame] | 768 | : infallible_syscall_ptr_if_alive(syscall_number_for_mmap(arch()), addr, |
| 769 | length, prot, flags, child_fd, |
Yichao Yu | 1b74f96 | 2022-04-13 18:27:13 -0400 | [diff] [blame] | 770 | offset_bytes); |
Robert O'Callahan | 7764413 | 2023-08-24 09:59:14 +1200 | [diff] [blame] | 771 | if (flags & MAP_FIXED) { |
| 772 | if (ret) { |
| 773 | ASSERT(t, addr == ret) << "MAP_FIXED at " << addr << " but got " << ret; |
| 774 | } else { |
| 775 | if (!t->vm()->has_mapping(addr)) { |
| 776 | KernelMapping km = t->vm()->read_kernel_mapping(t, addr); |
| 777 | if (km.size()) { |
| 778 | ASSERT(t, km.start() == addr && km.size() == ceil_page_size(length)); |
| 779 | // The mapping was created. Pretend this call succeeded. |
| 780 | ret = addr; |
| 781 | } |
| 782 | } |
| 783 | } |
Robert O'Callahan | 3d5e580 | 2014-12-06 20:38:56 -0600 | [diff] [blame] | 784 | } |
Robert O'Callahan | b7e4052 | 2015-09-15 23:59:32 +1200 | [diff] [blame] | 785 | return ret; |
| 786 | } |
| 787 | |
Robert O'Callahan | 7764413 | 2023-08-24 09:59:14 +1200 | [diff] [blame] | 788 | bool AutoRemoteSyscalls::infallible_munmap_syscall_if_alive( |
| 789 | remote_ptr<void> addr, size_t length) { |
| 790 | long ret = infallible_syscall_if_alive(syscall_number_for_munmap(arch()), |
| 791 | addr, length); |
| 792 | if (ret) { |
| 793 | if (t->vm()->has_mapping(addr)) { |
| 794 | KernelMapping km = t->vm()->read_kernel_mapping(t, addr); |
| 795 | if (!km.size()) { |
| 796 | // The unmap happened but the task must have died before |
| 797 | // reporting the status. |
| 798 | ret = 0; |
| 799 | } |
| 800 | } |
| 801 | } |
| 802 | return !ret; |
| 803 | } |
| 804 | |
Robert O'Callahan | 128123a | 2016-04-26 17:34:44 +1200 | [diff] [blame] | 805 | int64_t AutoRemoteSyscalls::infallible_lseek_syscall(int fd, int64_t offset, |
| 806 | int whence) { |
| 807 | switch (arch()) { |
| 808 | case x86: { |
| 809 | AutoRestoreMem mem(*this, &offset, sizeof(int64_t)); |
| 810 | infallible_syscall(syscall_number_for__llseek(arch()), fd, offset >> 32, |
| 811 | offset, mem.get(), whence); |
| 812 | return t->read_mem(mem.get().cast<int64_t>()); |
| 813 | } |
| 814 | case x86_64: |
Yichao Yu | 76991e0 | 2022-04-29 17:04:40 -0400 | [diff] [blame] | 815 | case aarch64: |
Robert O'Callahan | 128123a | 2016-04-26 17:34:44 +1200 | [diff] [blame] | 816 | return infallible_syscall(syscall_number_for_lseek(arch()), fd, offset, |
| 817 | whence); |
| 818 | default: |
Robert O'Callahan | f24e09c | 2017-08-11 16:36:30 +1200 | [diff] [blame] | 819 | ASSERT(t, false) << "Unknown arch"; |
Robert O'Callahan | 128123a | 2016-04-26 17:34:44 +1200 | [diff] [blame] | 820 | return -1; |
| 821 | } |
| 822 | } |
| 823 | |
Keno Fischer | 851c5dc | 2020-05-16 19:08:45 -0400 | [diff] [blame] | 824 | void AutoRemoteSyscalls::check_syscall_result(long ret, int syscallno, bool allow_death) { |
Robert O'Callahan | 272c2f4 | 2021-09-01 12:00:28 +1200 | [diff] [blame] | 825 | if (word_size(t->arch()) == 4) { |
| 826 | // Sign-extend ret because it can be a 32-bit negative errno |
| 827 | ret = (int)ret; |
| 828 | } |
Robert O'Callahan | e684358 | 2022-03-26 12:00:33 +1300 | [diff] [blame] | 829 | if (ret == -ESRCH && allow_death && !t->session().is_replaying()) { |
Keno Fischer | 851c5dc | 2020-05-16 19:08:45 -0400 | [diff] [blame] | 830 | return; |
| 831 | } |
Robert O'Callahan | b7e4052 | 2015-09-15 23:59:32 +1200 | [diff] [blame] | 832 | if (-4096 < ret && ret < 0) { |
| 833 | string extra_msg; |
| 834 | if (is_open_syscall(syscallno, arch())) { |
| 835 | extra_msg = " opening " + t->read_c_str(t->regs().arg1()); |
| 836 | } else if (is_openat_syscall(syscallno, arch())) { |
| 837 | extra_msg = " opening " + t->read_c_str(t->regs().arg2()); |
Robert O'Callahan | 79752d0 | 2023-08-04 14:53:08 +1200 | [diff] [blame] | 838 | } else if (is_mremap_syscall(syscallno, arch()) || |
| 839 | is_mmap_syscall(syscallno, arch())) { |
| 840 | AddressSpace::print_process_maps(t); |
Robert O'Callahan | b7e4052 | 2015-09-15 23:59:32 +1200 | [diff] [blame] | 841 | } |
| 842 | ASSERT(t, false) << "Syscall " << syscall_name(syscallno, arch()) |
Robert O'Callahan | 8f07c07 | 2023-03-14 21:15:54 +1300 | [diff] [blame] | 843 | << " failed with errno " << errno_name(-ret) << extra_msg |
| 844 | << " arg1=0x" << hex << t->regs().arg1() << " arg2=0x" << t->regs().arg2() |
| 845 | << " arg3=0x" << hex << t->regs().arg3() << " arg4=0x" << t->regs().arg4() |
| 846 | << " arg5=0x" << hex << t->regs().arg5() << " arg6=0x" << t->regs().arg6(); |
Robert O'Callahan | b7e4052 | 2015-09-15 23:59:32 +1200 | [diff] [blame] | 847 | } |
Robert O'Callahan | 3d5e580 | 2014-12-06 20:38:56 -0600 | [diff] [blame] | 848 | } |
Robert O'Callahan | 3ce49c6 | 2016-03-22 18:31:02 +1300 | [diff] [blame] | 849 | |
Keno Fischer | 114706b | 2020-04-04 02:30:59 -0400 | [diff] [blame] | 850 | void AutoRemoteSyscalls::finish_direct_mmap( |
| 851 | remote_ptr<void> rec_addr, size_t length, |
| 852 | int prot, int flags, |
| 853 | const string& backing_file_name, |
| 854 | int backing_file_open_flags, |
Yichao Yu | 1b74f96 | 2022-04-13 18:27:13 -0400 | [diff] [blame] | 855 | off64_t backing_offset_bytes, |
Keno Fischer | 114706b | 2020-04-04 02:30:59 -0400 | [diff] [blame] | 856 | struct stat& real_file, string& real_file_name) { |
| 857 | int fd; |
| 858 | |
| 859 | LOG(debug) << "directly mmap'ing " << length << " bytes of " |
Yichao Yu | 1b74f96 | 2022-04-13 18:27:13 -0400 | [diff] [blame] | 860 | << backing_file_name << " at offset " |
| 861 | << HEX(backing_offset_bytes); |
Keno Fischer | 114706b | 2020-04-04 02:30:59 -0400 | [diff] [blame] | 862 | |
| 863 | ASSERT(task(), !(flags & MAP_GROWSDOWN)); |
| 864 | |
| 865 | /* Open in the tracee the file that was mapped during |
| 866 | * recording. */ |
| 867 | { |
| 868 | AutoRestoreMem child_str(*this, backing_file_name.c_str()); |
Robert O'Callahan | 4bc3877 | 2023-05-16 23:18:03 +1200 | [diff] [blame] | 869 | if (word_size(t->arch()) == 4) { |
| 870 | backing_file_open_flags |= RR_LARGEFILE_32; |
| 871 | } |
Keno Fischer | ae5a075 | 2020-05-17 00:08:39 -0400 | [diff] [blame] | 872 | fd = infallible_syscall(syscall_number_for_openat(arch()), -1, |
Keno Fischer | 114706b | 2020-04-04 02:30:59 -0400 | [diff] [blame] | 873 | child_str.get().as_int(), |
Robert O'Callahan | 4bc3877 | 2023-05-16 23:18:03 +1200 | [diff] [blame] | 874 | backing_file_open_flags); |
Keno Fischer | 114706b | 2020-04-04 02:30:59 -0400 | [diff] [blame] | 875 | } |
| 876 | /* And mmap that file. */ |
Robert O'Callahan | 4bd2467 | 2022-03-26 14:23:23 +1300 | [diff] [blame] | 877 | infallible_mmap_syscall_if_alive(rec_addr, length, |
Keno Fischer | 114706b | 2020-04-04 02:30:59 -0400 | [diff] [blame] | 878 | /* (We let SHARED|WRITEABLE |
| 879 | * mappings go through while |
| 880 | * they're not handled properly, |
| 881 | * but we shouldn't do that.) */ |
| 882 | prot, (flags & ~MAP_SYNC) | MAP_FIXED, fd, |
| 883 | /* MAP_SYNC is used to request direct mapping |
| 884 | * (DAX) from the filesystem for persistent |
| 885 | * memory devices (requires |
| 886 | * MAP_SHARED_VALIDATE). Drop it for the |
| 887 | * backing file. */ |
Yichao Yu | 1b74f96 | 2022-04-13 18:27:13 -0400 | [diff] [blame] | 888 | backing_offset_bytes); |
Keno Fischer | 114706b | 2020-04-04 02:30:59 -0400 | [diff] [blame] | 889 | |
| 890 | // While it's open, grab the link reference. |
| 891 | real_file = task()->stat_fd(fd); |
| 892 | real_file_name = task()->file_name_of_fd(fd); |
| 893 | |
| 894 | /* Don't leak the tmp fd. The mmap doesn't need the fd to |
| 895 | * stay open. */ |
Robert O'Callahan | e917728 | 2022-03-28 11:59:09 +1300 | [diff] [blame] | 896 | infallible_close_syscall_if_alive(fd); |
Keno Fischer | 114706b | 2020-04-04 02:30:59 -0400 | [diff] [blame] | 897 | } |
| 898 | |
| 899 | |
Robert O'Callahan | 3ce49c6 | 2016-03-22 18:31:02 +1300 | [diff] [blame] | 900 | } // namespace rr |