1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_KERNEL_API_SYSCALL_EMULATION_COMMON_H_
18 #define BERBERIS_KERNEL_API_SYSCALL_EMULATION_COMMON_H_
19 
20 #include <sys/stat.h>
21 #include <sys/syscall.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 
25 #include <cerrno>
26 
27 #include "berberis/base/bit_util.h"
28 #include "berberis/base/macros.h"
29 #include "berberis/base/tracing.h"
30 #include "berberis/guest_state/guest_addr.h"
31 #include "berberis/kernel_api/exec_emulation.h"
32 #include "berberis/kernel_api/fcntl_emulation.h"
33 #include "berberis/kernel_api/open_emulation.h"
34 #include "berberis/kernel_api/sys_prctl_emulation.h"
35 #include "berberis/kernel_api/sys_ptrace_emulation.h"
36 #include "berberis/kernel_api/unistd_emulation.h"
37 
38 namespace berberis {
39 
40 void ConvertHostStatToGuestArch(const struct stat& host_stat, GuestAddr guest_stat);
41 
RunGuestSyscall___NR_clone3(long arg_1,long arg_2)42 inline long RunGuestSyscall___NR_clone3(long arg_1, long arg_2) {
43   UNUSED(arg_1, arg_2);
44   TRACE("unimplemented syscall __NR_clone3");
45   errno = ENOSYS;
46   return -1;
47 }
48 
RunGuestSyscall___NR_close(long arg_1)49 inline long RunGuestSyscall___NR_close(long arg_1) {
50   // TODO(b/346604197): Enable on arm64 once guest_os_primitives is ported.
51 #ifdef __aarch64__
52   UNUSED(arg_1);
53   TRACE("unimplemented syscall __NR_close");
54   errno = ENOSYS;
55   return -1;
56 #else
57   CloseEmulatedProcSelfMapsFileDescriptor(arg_1);
58   return syscall(__NR_close, arg_1);
59 #endif
60 }
61 
RunGuestSyscall___NR_execve(long arg_1,long arg_2,long arg_3)62 inline long RunGuestSyscall___NR_execve(long arg_1, long arg_2, long arg_3) {
63   return static_cast<long>(ExecveForGuest(bit_cast<const char*>(arg_1),     // filename
64                                           bit_cast<char* const*>(arg_2),    // argv
65                                           bit_cast<char* const*>(arg_3)));  // envp
66 }
67 
RunGuestSyscall___NR_faccessat(long arg_1,long arg_2,long arg_3)68 inline long RunGuestSyscall___NR_faccessat(long arg_1, long arg_2, long arg_3) {
69   // TODO(b/128614662): translate!
70   TRACE("unimplemented syscall __NR_faccessat, running host syscall as is");
71   return syscall(__NR_faccessat, arg_1, arg_2, arg_3);
72 }
73 
RunGuestSyscall___NR_fstat(long arg_1,long arg_2)74 inline long RunGuestSyscall___NR_fstat(long arg_1, long arg_2) {
75   // TODO(b/346604197): Enable on arm64 once guest_os_primitives is ported.
76 #ifdef __aarch64__
77   UNUSED(arg_1, arg_2);
78   TRACE("unimplemented syscall __NR_fstat");
79   errno = ENOSYS;
80   return -1;
81 #else
82   // We are including this structure from library headers (sys/stat.h) and assume
83   // that it matches kernel's layout.
84   // TODO(b/232598137): Add a check for this. It seems like this is an issue for 32-bit
85   // guest syscall, since compiled with bionic this declares `struct stat64` while
86   // the syscall will expect `struct stat`
87   struct stat host_stat;
88   long result;
89   if (IsFileDescriptorEmulatedProcSelfMaps(arg_1)) {
90     TRACE("Emulating fstat for /proc/self/maps");
91 #if defined(__LP64__)
92     result = syscall(__NR_newfstatat, AT_FDCWD, "/proc/self/maps", &host_stat, 0);
93 #else
94     result = syscall(__NR_fstatat64, AT_FDCWD, "/proc/self/maps", &host_stat, 0);
95 #endif
96   } else {
97     result = syscall(__NR_fstat, arg_1, &host_stat);
98   }
99   if (result != -1) {
100     ConvertHostStatToGuestArch(host_stat, bit_cast<GuestAddr>(arg_2));
101   }
102   return result;
103 #endif
104 }
105 
RunGuestSyscall___NR_fstatfs(long arg_1,long arg_2)106 inline long RunGuestSyscall___NR_fstatfs(long arg_1, long arg_2) {
107   // TODO(b/346604197): Enable on arm64 once guest_os_primitives is ported.
108 #ifdef __aarch64__
109   UNUSED(arg_1, arg_2);
110   TRACE("unimplemented syscall __NR_fstatfs");
111   errno = ENOSYS;
112   return -1;
113 #else
114   if (IsFileDescriptorEmulatedProcSelfMaps(arg_1)) {
115     TRACE("Emulating fstatfs for /proc/self/maps");
116     // arg_2 (struct statfs*) has kernel expected layout, which is different from
117     // what libc may expect. E.g. this happens for 32-bit bionic where the library call
118     // expects struct statfs64. Thus ensure we invoke syscall, not library call.
119     return syscall(__NR_statfs, "/proc/self/maps", arg_2);
120   }
121   return syscall(__NR_fstatfs, arg_1, arg_2);
122 #endif
123 }
124 
RunGuestSyscall___NR_fcntl(long arg_1,long arg_2,long arg_3)125 inline long RunGuestSyscall___NR_fcntl(long arg_1, long arg_2, long arg_3) {
126   return GuestFcntl(arg_1, arg_2, arg_3);
127 }
128 
RunGuestSyscall___NR_openat(long arg_1,long arg_2,long arg_3,long arg_4)129 inline long RunGuestSyscall___NR_openat(long arg_1, long arg_2, long arg_3, long arg_4) {
130   // TODO(b/346604197): Enable on arm64 once guest_os_primitives is ported.
131 #ifdef __aarch64__
132   UNUSED(arg_1, arg_2, arg_3, arg_4);
133   TRACE("unimplemented syscall __NR_openat");
134   errno = ENOSYS;
135   return -1;
136 #else
137   return static_cast<long>(OpenatForGuest(static_cast<int>(arg_1),       // dirfd
138                                           bit_cast<const char*>(arg_2),  // path
139                                           static_cast<int>(arg_3),       // flags
140                                           static_cast<mode_t>(arg_4)));  // mode
141 #endif
142 }
143 
RunGuestSyscall___NR_prctl(long arg_1,long arg_2,long arg_3,long arg_4,long arg_5)144 inline long RunGuestSyscall___NR_prctl(long arg_1, long arg_2, long arg_3, long arg_4, long arg_5) {
145   // TODO(b/346604197): Enable on arm64 once guest_os_primitives is ported.
146 #ifdef __aarch64__
147   UNUSED(arg_1, arg_2, arg_3, arg_4, arg_5);
148   TRACE("unimplemented syscall __NR_prctl");
149   errno = ENOSYS;
150   return -1;
151 #else
152   return PrctlForGuest(arg_1, arg_2, arg_3, arg_4, arg_5);
153 #endif
154 }
155 
RunGuestSyscall___NR_ptrace(long arg_1,long arg_2,long arg_3,long arg_4)156 inline long RunGuestSyscall___NR_ptrace(long arg_1, long arg_2, long arg_3, long arg_4) {
157   return static_cast<long>(PtraceForGuest(static_cast<int>(arg_1),    // request
158                                           static_cast<pid_t>(arg_2),  // pid
159                                           bit_cast<void*>(arg_3),     // addr
160                                           bit_cast<void*>(arg_4)));   // data
161 }
162 
RunGuestSyscall___NR_readlinkat(long arg_1,long arg_2,long arg_3,long arg_4)163 inline long RunGuestSyscall___NR_readlinkat(long arg_1, long arg_2, long arg_3, long arg_4) {
164   return static_cast<long>(ReadLinkAtForGuest(static_cast<int>(arg_1),       // dirfd
165                                               bit_cast<const char*>(arg_2),  // path
166                                               bit_cast<char*>(arg_3),        // buf
167                                               bit_cast<size_t>(arg_4)));     // buf_size
168 }
169 
RunGuestSyscall___NR_rt_sigreturn(long)170 inline long RunGuestSyscall___NR_rt_sigreturn(long) {
171   TRACE("unsupported syscall __NR_rt_sigaction");
172   errno = ENOSYS;
173   return -1;
174 }
175 
RunGuestSyscall___NR_statx(long arg_1,long arg_2,long arg_3,long arg_4,long arg_5)176 inline long RunGuestSyscall___NR_statx(long arg_1, long arg_2, long arg_3, long arg_4, long arg_5) {
177 #if defined(__NR_statx)
178   // TODO(b/128614662): add struct statx layout checkers.
179   return syscall(__NR_statx, arg_1, arg_2, arg_3, arg_4, arg_5);
180 #else
181   UNUSED(arg_1, arg_2, arg_3, arg_4, arg_5);
182   errno = ENOSYS;
183   return -1;
184 #endif
185 }
186 
RunUnknownGuestSyscall(long guest_nr,long arg_1,long arg_2,long arg_3,long arg_4,long arg_5,long arg_6)187 long RunUnknownGuestSyscall(long guest_nr,
188                             long arg_1,
189                             long arg_2,
190                             long arg_3,
191                             long arg_4,
192                             long arg_5,
193                             long arg_6) {
194   UNUSED(arg_1, arg_2, arg_3, arg_4, arg_5, arg_6);
195   TRACE("unknown syscall %ld", guest_nr);
196   errno = ENOSYS;
197   return -1;
198 }
199 
200 }  // namespace berberis
201 
202 #endif  // BERBERIS_KERNEL_API_SYSCALL_EMULATION_COMMON_H_
203