Skip to main content

starnix_registers/
x64.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{HeapRegs, RegisterStorage, RegisterStorageEnum};
6use starnix_uapi::errors::Errno;
7use starnix_uapi::restricted_aspace::RESTRICTED_ASPACE_HIGHEST_ADDRESS;
8use starnix_uapi::{__NR_restart_syscall, error, user_regs_struct};
9
10/// The size of the syscall instruction in bytes.
11const SYSCALL_INSTRUCTION_SIZE_BYTES: u64 = 2;
12
13/// The state of the task's registers when the thread of execution entered the kernel.
14/// This is a thin wrapper around [`zx::sys::zx_restricted_state_t`].
15///
16/// Implements [`std::ops::Deref`] and [`std::ops::DerefMut`] as a way to get at the underlying
17/// [`zx::sys::zx_restricted_state_t`] that this type wraps.
18#[derive(Default, Clone, Eq, PartialEq)]
19pub struct RegisterState<T: RegisterStorage> {
20    pub real_registers: T,
21
22    /// A copy of the x64 `rax` register at the time of the `syscall` instruction. This is important
23    /// to store, as the return value of a syscall overwrites `rax`, making it impossible to recover
24    /// the original syscall number in the case of syscall restart and strace output.
25    pub orig_rax: u64,
26}
27
28impl<T: RegisterStorage> RegisterState<T> {
29    pub fn to_user_regs_struct(&self) -> user_regs_struct {
30        user_regs_struct {
31            r15: self.r15,
32            r14: self.r14,
33            r13: self.r13,
34            r12: self.r12,
35            rbp: self.rbp,
36            rbx: self.rbx,
37            r11: self.r11,
38            r10: self.r10,
39            r9: self.r9,
40            r8: self.r8,
41            rax: self.rax,
42            rcx: self.rcx,
43            rdx: self.rdx,
44            rsi: self.rsi,
45            rdi: self.rdi,
46            orig_rax: self.orig_rax,
47            rip: self.ip,
48            cs: 0,
49            eflags: self.flags,
50            rsp: self.rsp,
51            ss: 0,
52            fs_base: self.fs_base,
53            gs_base: self.gs_base,
54            ds: 0,
55            es: 0,
56            fs: 0,
57            gs: 0,
58        }
59    }
60
61    pub fn to_user_regs_struct_arch32(&self) -> starnix_uapi::arch32::user_regs_struct {
62        unreachable!("arch32 not supported on x64")
63    }
64
65    pub fn from_user_regs_struct(&mut self, regs: &user_regs_struct) {
66        self.r15 = regs.r15;
67        self.r14 = regs.r14;
68        self.r13 = regs.r13;
69        self.r12 = regs.r12;
70        self.rbp = regs.rbp;
71        self.rbx = regs.rbx;
72        self.r11 = regs.r11;
73        self.r10 = regs.r10;
74        self.r9 = regs.r9;
75        self.r8 = regs.r8;
76        self.rax = regs.rax;
77        self.rcx = regs.rcx;
78        self.rdx = regs.rdx;
79        self.rsi = regs.rsi;
80        self.rdi = regs.rdi;
81        self.orig_rax = regs.orig_rax;
82        self.ip = regs.rip;
83        self.flags = regs.eflags;
84        self.rsp = regs.rsp;
85        self.fs_base = regs.fs_base;
86        self.gs_base = regs.gs_base;
87    }
88
89    pub fn from_user_regs_struct_arch32(&mut self, _regs: &starnix_uapi::arch32::user_regs_struct) {
90        unreachable!("arch32 not supported on x64")
91    }
92
93    /// Saves any register state required to restart the syscall.
94    ///
95    /// Must be called at syscall entry, before the syscall's return value is written.
96    pub fn save_registers_for_restart(&mut self) {
97        // `orig_rax` should hold the original value loaded into `rax` by the userspace process.
98        self.orig_rax = self.rax;
99
100        // The `rax` register read from the thread's state is clobbered by
101        // zircon with ZX_ERR_BAD_SYSCALL.  Similarly, Linux sets it to ENOSYS
102        // until it has determined the correct return value for the syscall; we
103        // emulate this behavior because ptrace callers expect it.
104        self.rax = -(starnix_uapi::ENOSYS as i64) as u64;
105    }
106
107    /// Custom restart, invoke restart_syscall instead of the original syscall.
108    pub fn prepare_for_custom_restart(&mut self) {
109        self.rax = __NR_restart_syscall as u64;
110    }
111
112    /// Restores `rax` to match its value before restarting.
113    pub fn restore_original_return_register(&mut self) {
114        self.rax = self.orig_rax;
115    }
116
117    /// Returns the register that indicates the single-machine-word return value from a
118    /// function call.
119    pub fn instruction_pointer_register(&self) -> u64 {
120        self.ip
121    }
122
123    /// Sets the register that indicates the single-machine-word return value from a
124    /// function call.
125    pub fn set_instruction_pointer_register(&mut self, new_ip: u64) {
126        self.ip = new_ip;
127    }
128
129    /// Rewind the the register that indicates the instruction pointer by one syscall instruction.
130    pub fn rewind_syscall_instruction(&mut self) {
131        self.ip -= SYSCALL_INSTRUCTION_SIZE_BYTES;
132    }
133
134    /// Returns the register that indicates the single-machine-word return value from a
135    /// function call.
136    pub fn return_register(&self) -> u64 {
137        self.rax
138    }
139
140    /// Sets the register that indicates the single-machine-word return value from a
141    /// function call.
142    pub fn set_return_register(&mut self, return_value: u64) {
143        self.rax = return_value;
144    }
145
146    /// Gets the register that indicates the current stack pointer.
147    pub fn stack_pointer_register(&self) -> u64 {
148        self.rsp
149    }
150
151    /// Sets the register that indicates the current stack pointer.
152    pub fn set_stack_pointer_register(&mut self, sp: u64) {
153        self.rsp = sp;
154    }
155
156    /// Sets the register that indicates the TLS.
157    pub fn set_thread_pointer_register(&mut self, tp: u64) {
158        self.fs_base = tp;
159    }
160
161    /// Sets the register that indicates the first argument to a function.
162    pub fn set_arg0_register(&mut self, rdi: u64) {
163        self.rdi = rdi;
164    }
165
166    /// Sets the register that indicates the second argument to a function.
167    pub fn set_arg1_register(&mut self, rsi: u64) {
168        self.rsi = rsi;
169    }
170
171    /// Sets the register that indicates the third argument to a function.
172    pub fn set_arg2_register(&mut self, rdx: u64) {
173        self.rdx = rdx;
174    }
175
176    /// Returns the register that contains the syscall number.
177    pub fn syscall_register(&self) -> u64 {
178        self.orig_rax
179    }
180
181    /// Resets the register that contains the application status flags.
182    pub fn reset_flags(&mut self) {
183        self.flags = 0;
184        // Clear out-of-range segment bases so that a signal handler can be entered if
185        // `zx_restricted_enter` rejected the state with `ZX_ERR_BAD_STATE`.
186        if self.fs_base as usize >= RESTRICTED_ASPACE_HIGHEST_ADDRESS {
187            self.fs_base = 0;
188        }
189        if self.gs_base as usize >= RESTRICTED_ASPACE_HIGHEST_ADDRESS {
190            self.gs_base = 0;
191        }
192    }
193
194    /// Executes the given predicate on the register.
195    pub fn apply_user_register(
196        &mut self,
197        offset: usize,
198        f: &mut dyn FnMut(&mut u64),
199    ) -> Result<(), Errno> {
200        if offset == memoffset::offset_of!(user_regs_struct, r15) {
201            f(&mut self.r15);
202        } else if offset == memoffset::offset_of!(user_regs_struct, r14) {
203            f(&mut self.r14);
204        } else if offset == memoffset::offset_of!(user_regs_struct, r13) {
205            f(&mut self.r13);
206        } else if offset == memoffset::offset_of!(user_regs_struct, r12) {
207            f(&mut self.r12);
208        } else if offset == memoffset::offset_of!(user_regs_struct, rbp) {
209            f(&mut self.rbp);
210        } else if offset == memoffset::offset_of!(user_regs_struct, rbx) {
211            f(&mut self.rbx);
212        } else if offset == memoffset::offset_of!(user_regs_struct, r11) {
213            f(&mut self.r11);
214        } else if offset == memoffset::offset_of!(user_regs_struct, r10) {
215            f(&mut self.r10);
216        } else if offset == memoffset::offset_of!(user_regs_struct, r9) {
217            f(&mut self.r9);
218        } else if offset == memoffset::offset_of!(user_regs_struct, r8) {
219            f(&mut self.r8);
220        } else if offset == memoffset::offset_of!(user_regs_struct, rax) {
221            f(&mut self.rax);
222        } else if offset == memoffset::offset_of!(user_regs_struct, rcx) {
223            f(&mut self.rcx);
224        } else if offset == memoffset::offset_of!(user_regs_struct, rdx) {
225            f(&mut self.rdx);
226        } else if offset == memoffset::offset_of!(user_regs_struct, rsi) {
227            f(&mut self.rsi);
228        } else if offset == memoffset::offset_of!(user_regs_struct, rdi) {
229            f(&mut self.rdi);
230        } else if offset == memoffset::offset_of!(user_regs_struct, orig_rax) {
231            f(&mut self.orig_rax);
232        } else if offset == memoffset::offset_of!(user_regs_struct, rip) {
233            f(&mut self.ip);
234        } else if offset == memoffset::offset_of!(user_regs_struct, cs) {
235            let mut val = 0;
236            f(&mut val);
237        } else if offset == memoffset::offset_of!(user_regs_struct, eflags) {
238            f(&mut self.flags);
239        } else if offset == memoffset::offset_of!(user_regs_struct, rsp) {
240            f(&mut self.rsp);
241        } else if offset == memoffset::offset_of!(user_regs_struct, ss) {
242            let mut val = 0;
243            f(&mut val);
244        } else if offset == memoffset::offset_of!(user_regs_struct, fs_base) {
245            f(&mut self.fs_base);
246        } else if offset == memoffset::offset_of!(user_regs_struct, gs_base) {
247            f(&mut self.gs_base);
248        } else if offset == memoffset::offset_of!(user_regs_struct, ds) {
249            let mut val = 0;
250            f(&mut val);
251        } else if offset == memoffset::offset_of!(user_regs_struct, es) {
252            let mut val = 0;
253            f(&mut val);
254        } else if offset == memoffset::offset_of!(user_regs_struct, fs) {
255            let mut val = 0;
256            f(&mut val);
257        } else if offset == memoffset::offset_of!(user_regs_struct, gs) {
258            let mut val = 0;
259            f(&mut val);
260        } else {
261            return error!(EINVAL);
262        };
263        Ok(())
264    }
265
266    pub fn load(&mut self, regs: zx::sys::zx_restricted_state_t) {
267        *self.real_registers = regs;
268    }
269
270    /// Copies the restricted state and the orig_rax bookkeeping register.
271    pub fn copy_from<O: RegisterStorage>(&mut self, other: &RegisterState<O>) {
272        self.load(*other.real_registers);
273        self.orig_rax = other.orig_rax;
274    }
275}
276
277impl<T: RegisterStorage> std::fmt::Debug for RegisterState<T> {
278    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279        f.debug_struct("RegisterState")
280            .field("real_registers", &self.real_registers)
281            .field("orig_rax", &format_args!("{:#x}", &self.orig_rax))
282            .finish()
283    }
284}
285
286impl<T: RegisterStorage> std::ops::Deref for RegisterState<T> {
287    type Target = zx::sys::zx_restricted_state_t;
288
289    fn deref(&self) -> &Self::Target {
290        &*self.real_registers
291    }
292}
293
294impl<T: RegisterStorage> std::ops::DerefMut for RegisterState<T> {
295    fn deref_mut(&mut self) -> &mut Self::Target {
296        &mut *self.real_registers
297    }
298}
299
300impl From<RegisterState<HeapRegs>> for RegisterState<RegisterStorageEnum> {
301    fn from(regs: RegisterState<HeapRegs>) -> Self {
302        Self { real_registers: regs.real_registers.into(), orig_rax: regs.orig_rax }
303    }
304}
305
306impl From<RegisterState<RegisterStorageEnum>> for RegisterState<HeapRegs> {
307    fn from(regs: RegisterState<RegisterStorageEnum>) -> Self {
308        Self { real_registers: regs.real_registers.into(), orig_rax: regs.orig_rax }
309    }
310}