xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/regs.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Implementation of the sandbox2::Regs class.
16 
17 #include "sandboxed_api/sandbox2/regs.h"
18 
19 #include <elf.h>  // IWYU pragma: keep // used for NT_PRSTATUS inside an ifdef
20 #include <sys/ptrace.h>
21 #include <sys/uio.h>  // IWYU pragma: keep // used for iovec
22 
23 #include <cerrno>
24 #include <cstdint>
25 
26 #include "absl/base/optimization.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/str_cat.h"
29 #include "sandboxed_api/config.h"
30 
31 namespace sandbox2 {
32 
33 #ifndef NT_ARM_SYSTEM_CALL
34 #define NT_ARM_SYSTEM_CALL 0x404
35 #endif
36 
Fetch()37 absl::Status Regs::Fetch() {
38 #ifdef SAPI_X86_64
39   if (ptrace(PTRACE_GETREGS, pid_, 0, &user_regs_) == -1L) {
40     return absl::ErrnoToStatus(
41         errno, absl::StrCat("ptrace(PTRACE_GETREGS, pid=", pid_, ") failed"));
42   }
43 #endif
44   if constexpr (sapi::host_cpu::IsPPC64LE() || sapi::host_cpu::IsArm64() ||
45                 sapi::host_cpu::IsArm()) {
46     iovec pt_iov = {&user_regs_, sizeof(user_regs_)};
47 
48     if (ptrace(PTRACE_GETREGSET, pid_, NT_PRSTATUS, &pt_iov) == -1L) {
49       return absl::ErrnoToStatus(
50           errno,
51           absl::StrCat("ptrace(PTRACE_GETREGSET, pid=", pid_, ") failed"));
52     }
53     if (pt_iov.iov_len != sizeof(user_regs_)) {
54       return absl::InternalError(absl::StrCat(
55           "ptrace(PTRACE_GETREGSET, pid=", pid_,
56           ") size returned: ", pt_iov.iov_len,
57           " different than sizeof(user_regs_): ", sizeof(user_regs_)));
58     }
59 
60     // On AArch64, we are not done yet. Read the syscall number.
61     if constexpr (sapi::host_cpu::IsArm64()) {
62       iovec sys_iov = {&syscall_number_, sizeof(syscall_number_)};
63 
64       if (ptrace(PTRACE_GETREGSET, pid_, NT_ARM_SYSTEM_CALL, &sys_iov) == -1L) {
65         return absl::ErrnoToStatus(
66             errno, absl::StrCat("ptrace(PTRACE_GETREGSET, pid=", pid_,
67                                 ", NT_ARM_SYSTEM_CALL)"));
68       }
69       if (sys_iov.iov_len != sizeof(syscall_number_)) {
70         return absl::InternalError(absl::StrCat(
71             "ptrace(PTRACE_GETREGSET, pid=", pid_,
72             ", NT_ARM_SYSTEM_CALL) size returned: ", sys_iov.iov_len,
73             " different than sizeof(syscall_number_): ",
74             sizeof(syscall_number_)));
75       }
76     }
77   }
78   return absl::OkStatus();
79 }
80 
Store()81 absl::Status Regs::Store() {
82 #ifdef SAPI_X86_64
83   if (ptrace(PTRACE_SETREGS, pid_, 0, &user_regs_) == -1) {
84     return absl::ErrnoToStatus(
85         errno, absl::StrCat("ptrace(PTRACE_SETREGS, pid=", pid_, ")"));
86   }
87 #endif
88   if constexpr (sapi::host_cpu::IsPPC64LE() || sapi::host_cpu::IsArm64() ||
89                 sapi::host_cpu::IsArm()) {
90     iovec pt_iov = {&user_regs_, sizeof(user_regs_)};
91 
92     if (ptrace(PTRACE_SETREGSET, pid_, NT_PRSTATUS, &pt_iov) == -1L) {
93       return absl::ErrnoToStatus(
94           errno,
95           absl::StrCat("ptrace(PTRACE_SETREGSET, pid=", pid_, ") failed"));
96     }
97 
98     // Store syscall number on AArch64.
99     if constexpr (sapi::host_cpu::IsArm64()) {
100       iovec sys_iov = {&syscall_number_, sizeof(syscall_number_)};
101 
102       if (ptrace(PTRACE_SETREGSET, pid_, NT_ARM_SYSTEM_CALL, &sys_iov) == -1L) {
103         return absl::ErrnoToStatus(
104             errno, absl::StrCat("ptrace(PTRACE_SETREGSET, pid=", pid_,
105                                 ", NT_ARM_SYSTEM_CALL) failed"));
106       }
107     }
108   }
109   return absl::OkStatus();
110 }
111 
SkipSyscallReturnValue(uintptr_t value)112 absl::Status Regs::SkipSyscallReturnValue(uintptr_t value) {
113 #if defined(SAPI_X86_64)
114   user_regs_.orig_rax = -1;
115   user_regs_.rax = value;
116 #elif defined(SAPI_PPC64_LE)
117   user_regs_.gpr[0] = -1;
118   user_regs_.gpr[3] = value;
119 #elif defined(SAPI_ARM64)
120   syscall_number_ = -1;
121   user_regs_.regs[0] = value;
122 #elif defined(SAPI_ARM)
123   user_regs_.orig_x0 = -1;
124   user_regs_.regs[7] = value;
125 #endif
126   return Store();
127 }
128 
ToSyscall(sapi::cpu::Architecture syscall_arch) const129 Syscall Regs::ToSyscall(sapi::cpu::Architecture syscall_arch) const {
130 #if defined(SAPI_X86_64)
131   if (ABSL_PREDICT_TRUE(syscall_arch == sapi::cpu::kX8664)) {
132     auto syscall = user_regs_.orig_rax;
133     Syscall::Args args = {user_regs_.rdi, user_regs_.rsi, user_regs_.rdx,
134                           user_regs_.r10, user_regs_.r8,  user_regs_.r9};
135     auto sp = user_regs_.rsp;
136     auto ip = user_regs_.rip;
137     return Syscall(syscall_arch, syscall, args, pid_, sp, ip);
138   }
139   if (syscall_arch == sapi::cpu::kX86) {
140     auto syscall = user_regs_.orig_rax & 0xFFFFFFFF;
141     Syscall::Args args = {
142         user_regs_.rbx & 0xFFFFFFFF, user_regs_.rcx & 0xFFFFFFFF,
143         user_regs_.rdx & 0xFFFFFFFF, user_regs_.rsi & 0xFFFFFFFF,
144         user_regs_.rdi & 0xFFFFFFFF, user_regs_.rbp & 0xFFFFFFFF};
145     auto sp = user_regs_.rsp & 0xFFFFFFFF;
146     auto ip = user_regs_.rip & 0xFFFFFFFF;
147     return Syscall(syscall_arch, syscall, args, pid_, sp, ip);
148   }
149 #elif defined(SAPI_PPC64_LE)
150   if (ABSL_PREDICT_TRUE(syscall_arch == sapi::cpu::kPPC64LE)) {
151     auto syscall = user_regs_.gpr[0];
152     Syscall::Args args = {user_regs_.orig_gpr3, user_regs_.gpr[4],
153                           user_regs_.gpr[5],    user_regs_.gpr[6],
154                           user_regs_.gpr[7],    user_regs_.gpr[8]};
155     auto sp = user_regs_.gpr[1];
156     auto ip = user_regs_.nip;
157     return Syscall(syscall_arch, syscall, args, pid_, sp, ip);
158   }
159 #elif defined(SAPI_ARM64)
160   if (ABSL_PREDICT_TRUE(syscall_arch == sapi::cpu::kArm64)) {
161     Syscall::Args args = {
162         // First argument should be orig_x0, which is not available to ptrace on
163         // AArch64 (see
164         // https://undo.io/resources/arm64-vs-arm32-whats-different-linux-programmers/),
165         // as it will have been overwritten. For our use case, though, using
166         // regs[0] is fine, as we are always called on syscall entry and never
167         // on exit.
168         user_regs_.regs[0], user_regs_.regs[1], user_regs_.regs[2],
169         user_regs_.regs[3], user_regs_.regs[4], user_regs_.regs[5],
170     };
171     auto sp = user_regs_.sp;
172     auto ip = user_regs_.pc;
173     return Syscall(syscall_arch, syscall_number_, args, pid_, sp, ip);
174   }
175 #elif defined(SAPI_ARM)
176   if (ABSL_PREDICT_TRUE(syscall_arch == sapi::cpu::kArm)) {
177     Syscall::Args args = {
178         user_regs_.orig_x0, user_regs_.regs[1], user_regs_.regs[2],
179         user_regs_.regs[3], user_regs_.regs[4], user_regs_.regs[5],
180     };
181     auto sp = user_regs_.regs[13];
182     auto ip = user_regs_.pc;
183     return Syscall(syscall_arch, user_regs_.regs[7], args, pid_, sp, ip);
184   }
185 #endif
186   return Syscall(pid_);
187 }
188 
GetReturnValue(sapi::cpu::Architecture syscall_arch) const189 int64_t Regs::GetReturnValue(sapi::cpu::Architecture syscall_arch) const {
190 #if defined(SAPI_X86_64)
191   if (ABSL_PREDICT_TRUE(syscall_arch == sapi::cpu::kX8664)) {
192     return static_cast<int64_t>(user_regs_.rax);
193   }
194   if (syscall_arch == sapi::cpu::kX86) {
195     return static_cast<int32_t>(user_regs_.rax & 0xFFFFFFFF);
196   }
197 #elif defined(SAPI_PPC64_LE)
198   if (ABSL_PREDICT_TRUE(syscall_arch == sapi::cpu::kPPC64LE)) {
199     return static_cast<int64_t>(user_regs_.gpr[3]);
200   }
201 #elif defined(SAPI_ARM64)
202   if (ABSL_PREDICT_TRUE(syscall_arch == sapi::cpu::kArm64)) {
203     return static_cast<int64_t>(user_regs_.regs[0]);
204   }
205 #elif defined(SAPI_ARM)
206   if (ABSL_PREDICT_TRUE(syscall_arch == sapi::cpu::kArm)) {
207     return static_cast<int32_t>(user_regs_.regs[0]);
208   }
209 #endif
210   return -1;
211 }
212 
StoreRegisterValuesInProtobuf(RegisterValues * values) const213 void Regs::StoreRegisterValuesInProtobuf(RegisterValues* values) const {
214 #if defined(SAPI_X86_64)
215   RegisterX8664* regs = values->mutable_register_x86_64();
216   regs->set_r15(user_regs_.r15);
217   regs->set_r14(user_regs_.r14);
218   regs->set_r13(user_regs_.r13);
219   regs->set_r12(user_regs_.r12);
220   regs->set_rbp(user_regs_.rbp);
221   regs->set_rbx(user_regs_.rbx);
222   regs->set_r11(user_regs_.r11);
223   regs->set_r10(user_regs_.r10);
224   regs->set_r9(user_regs_.r9);
225   regs->set_r8(user_regs_.r8);
226   regs->set_rax(user_regs_.rax);
227   regs->set_rcx(user_regs_.rcx);
228   regs->set_rdx(user_regs_.rdx);
229   regs->set_rsi(user_regs_.rsi);
230   regs->set_rdi(user_regs_.rdi);
231   regs->set_orig_rax(user_regs_.orig_rax);
232   regs->set_rip(user_regs_.rip);
233   regs->set_cs(user_regs_.cs);
234   regs->set_eflags(user_regs_.eflags);
235   regs->set_rsp(user_regs_.rsp);
236   regs->set_ss(user_regs_.ss);
237   regs->set_fs_base(user_regs_.fs_base);
238   regs->set_gs_base(user_regs_.gs_base);
239   regs->set_ds(user_regs_.ds);
240   regs->set_es(user_regs_.es);
241   regs->set_fs(user_regs_.fs);
242   regs->set_gs(user_regs_.gs);
243 #elif defined(SAPI_PPC64_LE)
244   RegisterPowerpc64* regs = values->mutable_register_powerpc64();
245   for (int i = 0; i < ABSL_ARRAYSIZE(user_regs_.gpr); ++i) {
246     regs->add_gpr(user_regs_.gpr[i]);
247   }
248   regs->set_nip(user_regs_.nip);
249   regs->set_msr(user_regs_.msr);
250   regs->set_orig_gpr3(user_regs_.orig_gpr3);
251   regs->set_ctr(user_regs_.ctr);
252   regs->set_link(user_regs_.link);
253   regs->set_xer(user_regs_.xer);
254   regs->set_ccr(user_regs_.ccr);
255   regs->set_softe(user_regs_.softe);
256   regs->set_trap(user_regs_.trap);
257   regs->set_dar(user_regs_.dar);
258   regs->set_dsisr(user_regs_.dsisr);
259   regs->set_result(user_regs_.result);
260   regs->set_zero0(user_regs_.zero0);
261   regs->set_zero1(user_regs_.zero1);
262   regs->set_zero2(user_regs_.zero2);
263   regs->set_zero3(user_regs_.zero3);
264 #elif defined(SAPI_ARM64)
265   RegisterAarch64* regs = values->mutable_register_aarch64();
266   for (int i = 0; i < ABSL_ARRAYSIZE(user_regs_.regs); ++i) {
267     regs->add_regs(user_regs_.regs[i]);
268   }
269   regs->set_sp(user_regs_.sp);
270   regs->set_pc(user_regs_.pc);
271   regs->set_pstate(user_regs_.pstate);
272 #elif defined(SAPI_ARM)
273   RegisterArm* regs = values->mutable_register_arm();
274   for (int i = 0; i < ABSL_ARRAYSIZE(user_regs_.regs); ++i) {
275     regs->add_regs(user_regs_.regs[i]);
276   }
277   regs->set_pc(user_regs_.pc);
278   regs->set_cpsr(user_regs_.cpsr);
279   regs->set_orig_x0(user_regs_.orig_x0);
280 #endif
281 }
282 
283 }  // namespace sandbox2
284