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