From f103a11a3713360e9f0551c5200f64381913c9f0 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 5 Aug 2023 03:14:38 -0400 Subject: [PATCH] aarch64: Save/Restore PAC keys Should fix #3568. --- src/Task.cc | 43 +++++++++++++++++++++++++++++++++++++++++++ src/Task.h | 10 ++++++++++ src/TraceStream.cc | 5 +++++ src/TraceTaskEvent.h | 9 +++++++++ src/kernel_abi.h | 11 +++++++++++ src/record_syscall.cc | 1 + src/replay_syscall.cc | 3 +++ src/rr_trace.capnp | 6 ++++++ 8 files changed, 88 insertions(+) diff --git a/src/Task.cc b/src/Task.cc index 728668133b8..b7b811fd5cb 100644 --- a/src/Task.cc +++ b/src/Task.cc @@ -1278,7 +1278,50 @@ bool Task::get_aarch64_debug_regs(int which, ARM64Arch::user_hwdebug_state *regs fallible_ptrace(PTRACE_GETREGSET, which, (void*)&iov); return errno == 0; } +std::vector Task::pac_keys(bool *ok) +{ + std::vector pac_data( + sizeof(ARM64Arch::user_pac_address_keys) + + sizeof(ARM64Arch::user_pac_generic_keys)); + struct iovec vec = { pac_data.data(), sizeof(ARM64Arch::user_pac_address_keys) }; + if (fallible_ptrace(PTRACE_GETREGSET, NT_ARM_PACA_KEYS, &vec)) { + if (ok) { + *ok = false; + } + return std::vector{}; + } + vec = { pac_data.data() + sizeof(ARM64Arch::user_pac_address_keys), + sizeof(ARM64Arch::user_pac_generic_keys) }; + if (fallible_ptrace(PTRACE_GETREGSET, NT_ARM_PACG_KEYS, &vec)) { + if (ok) { + *ok = false; + } + return std::vector{}; + } + return pac_data; +} +bool Task::set_pac_keys(const std::vector &pac_data) +{ + if (pac_data.empty()) { + return true; + } + struct iovec vec = { (void*)pac_data.data(), sizeof(ARM64Arch::user_pac_address_keys) }; + if (fallible_ptrace(PTRACE_SETREGSET, NT_ARM_PACA_KEYS, &vec)) { + return false; + } + vec = { (void*)(pac_data.data() + sizeof(ARM64Arch::user_pac_address_keys)), + sizeof(ARM64Arch::user_pac_generic_keys) }; + return !fallible_ptrace(PTRACE_SETREGSET, NT_ARM_PACG_KEYS, &vec); +} #else +std::vector Task::pac_keys(bool *ok) +{ + return std::vector{}; +} +bool Task::set_pac_keys(const std::vector &pac_data) +{ + return true; +} bool Task::set_aarch64_debug_regs(int, ARM64Arch::user_hwdebug_state *, size_t) { FATAL() << "Reached aarch64 code path on non-aarch64 system"; return false; diff --git a/src/Task.h b/src/Task.h index 0705cb98404..21a86e80658 100644 --- a/src/Task.h +++ b/src/Task.h @@ -528,6 +528,16 @@ class Task { */ void set_x86_debug_status(uintptr_t status); + /** + * Read the (architecture-specific) pointer authentication keys of the current task + */ + std::vector pac_keys(bool *ok = nullptr); + + /** + * Set the (architecture-specific) pointer authentication keys for the current task + */ + bool set_pac_keys(const std::vector &data); + /** * Determine why a SIGTRAP occurred. On x86, uses x86_debug_status() but doesn't * consume it. diff --git a/src/TraceStream.cc b/src/TraceStream.cc index 4b3d67d2a40..ed312b7bc34 100644 --- a/src/TraceStream.cc +++ b/src/TraceStream.cc @@ -778,6 +778,9 @@ void TraceWriter::write_task_event(const TraceTaskEvent& event) { exec.setExeBase(event.exe_base().as_int()); exec.setInterpBase(event.interp_base().as_int()); exec.setInterpName(str_to_data(event.interp_name()));; + auto pac_data = exec.initPacData(); + std::vector pac_data_vec = event.pac_data(); + pac_data.setRaw(Data::Reader(pac_data_vec.data(), pac_data_vec.size())); break; } case TraceTaskEvent::EXIT: @@ -840,6 +843,8 @@ TraceTaskEvent TraceReader::read_task_event(FrameTime* time) { r.exe_base_ = exec.getExeBase(); r.interp_base_ = exec.getInterpBase(); r.interp_name_ = data_to_str(exec.getInterpName()); + auto pac_data = exec.getPacData().getRaw(); + r.pac_data_ = std::vector(pac_data.begin(), pac_data.end()); break; } case trace::TaskEvent::Which::EXIT: diff --git a/src/TraceTaskEvent.h b/src/TraceTaskEvent.h index d3ecd27f4cb..251fcaa874d 100644 --- a/src/TraceTaskEvent.h +++ b/src/TraceTaskEvent.h @@ -105,6 +105,14 @@ class TraceTaskEvent { DEBUG_ASSERT(type() == EXEC); interp_name_ = name; } + std::vector pac_data() const { + DEBUG_ASSERT(type() == EXEC); + return pac_data_; + } + void set_pac_data(std::vector data) { + DEBUG_ASSERT(type() == EXEC); + pac_data_ = data; + } WaitStatus exit_status() const { DEBUG_ASSERT(type() == EXIT); return exit_status_; @@ -124,6 +132,7 @@ class TraceTaskEvent { remote_ptr exe_base_; // EXEC only remote_ptr interp_base_; // EXEC only std::string interp_name_; // EXEC only + std::vector pac_data_; // EXEC only WaitStatus exit_status_; // EXIT only }; diff --git a/src/kernel_abi.h b/src/kernel_abi.h index a990fbfd6ff..c2e8de34950 100644 --- a/src/kernel_abi.h +++ b/src/kernel_abi.h @@ -2560,6 +2560,17 @@ struct ARM64Arch : public GenericArch { uint32_t rule_locs[0]; }; RR_VERIFY_TYPE_ARCH(SupportedArch::aarch64, struct ::ethtool_rxnfc, struct ethtool_rxnfc); + + struct user_pac_address_keys { + __uint128_t apiakey; + __uint128_t apibkey; + __uint128_t apdakey; + __uint128_t apdbkey; + }; + + struct user_pac_generic_keys { + __uint128_t apgakey; + }; }; #define RR_ARCH_FUNCTION(f, arch, args...) \ diff --git a/src/record_syscall.cc b/src/record_syscall.cc index b22b47380f0..4817818e9dc 100644 --- a/src/record_syscall.cc +++ b/src/record_syscall.cc @@ -5772,6 +5772,7 @@ static void process_execve(RecordTask* t, TaskSyscallState& syscall_state) { } } + syscall_state.exec_saved_event->set_pac_data(t->pac_keys()); t->session().trace_writer().write_task_event(*syscall_state.exec_saved_event); { diff --git a/src/replay_syscall.cc b/src/replay_syscall.cc index 4bdc192eaf7..6a102497cfa 100644 --- a/src/replay_syscall.cc +++ b/src/replay_syscall.cc @@ -450,6 +450,9 @@ static void process_execve(ReplayTask* t, const TraceFrame& trace_frame, t->post_exec_syscall(exe_name, kms[exe_km].fsname()); t->vm()->set_interp_base(tte.interp_base()); t->vm()->set_interp_name(tte.interp_name()); + if (!t->set_pac_keys(tte.pac_data())) { + LOG(warn) << "Failed to restore PAC keys. Replay may fail."; + } t->fd_table()->close_after_exec( t, t->current_trace_frame().event().Syscall().exec_fds_to_close); diff --git a/src/rr_trace.capnp b/src/rr_trace.capnp index bb74cd8a1ff..a575f2f4375 100644 --- a/src/rr_trace.capnp +++ b/src/rr_trace.capnp @@ -218,6 +218,7 @@ struct TaskEvent { interpBase @10 :RemotePtr; # Not a Path since it is only meaningful during recording interpName @11 :CString; + pacData @12 :PACData; } # Most frame 'exit' events generate one of these, but these are not # generated if rr ends abnormally so the tasks did not in fact exit during @@ -261,6 +262,11 @@ struct ExtraRegisters { raw @0 :Data; } +struct PACData { + # Formay determined by Frame::arch + raw @0 :Data; +} + enum SyscallState { enteringPtrace @0; entering @1;