1 /*
2  * Copyright (C) 2018 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 #include <fcntl.h>  // AT_FDCWD, AT_SYMLINK_NOFOLLOW
18 #include <linux/sched.h>
19 #include <linux/unistd.h>
20 #include <sys/stat.h>
21 #include <sys/sysinfo.h>
22 #include <sys/types.h>
23 
24 #include <cerrno>
25 
26 #include "berberis/base/macros.h"
27 #include "berberis/base/scoped_errno.h"
28 #include "berberis/base/tracing.h"
29 #include "berberis/guest_state/guest_addr.h"
30 #include "berberis/guest_state/guest_state.h"
31 #include "berberis/instrument/syscall.h"
32 #include "berberis/kernel_api/main_executable_real_path_emulation.h"
33 #include "berberis/kernel_api/runtime_bridge.h"
34 #include "berberis/kernel_api/syscall_emulation_common.h"
35 
36 // TODO(b/346604197): Enable on arm64 once these modules are ported.
37 #ifdef __x86_64__
38 #include "berberis/guest_os_primitives/scoped_pending_signals.h"
39 #include "berberis/runtime_primitives/runtime_library.h"
40 #endif
41 
42 #include "epoll_emulation.h"
43 #include "guest_types.h"
44 
45 namespace berberis {
46 
47 namespace {
48 
FstatatForGuest(int dirfd,const char * path,struct stat * buf,int flags)49 int FstatatForGuest(int dirfd, const char* path, struct stat* buf, int flags) {
50   const char* real_path = nullptr;
51   if ((flags & AT_SYMLINK_NOFOLLOW) == 0) {
52     real_path = TryReadLinkToMainExecutableRealPath(path);
53   }
54   return syscall(__NR_newfstatat, dirfd, real_path ? real_path : path, buf, flags);
55 }
56 
Hwprobe(Guest_riscv_hwprobe & pair)57 void Hwprobe(Guest_riscv_hwprobe& pair) {
58   switch (pair.key) {
59     case RISCV_HWPROBE_KEY_MVENDORID:
60       pair.value = 0;
61       break;
62     case RISCV_HWPROBE_KEY_MARCHID:
63       pair.value = 0;
64       break;
65     case RISCV_HWPROBE_KEY_MIMPID:
66       pair.value = 0;
67       break;
68     case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
69       pair.value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
70       break;
71     case RISCV_HWPROBE_KEY_IMA_EXT_0:
72       pair.value = RISCV_HWPROBE_IMA_FD | RISCV_HWPROBE_IMA_C | RISCV_HWPROBE_IMA_V |
73                    RISCV_HWPROBE_EXT_ZBA | RISCV_HWPROBE_EXT_ZBB | RISCV_HWPROBE_EXT_ZBS;
74       break;
75     case RISCV_HWPROBE_KEY_CPUPERF_0:
76       pair.value = RISCV_HWPROBE_MISALIGNED_FAST;
77       break;
78     default:
79       TRACE("unsupported __riscv_hwprobe capability key: %ld", pair.key);
80       pair.key = -1;
81       pair.value = 0;
82       break;
83   }
84 }
85 
RunGuestSyscall___NR_execveat(long arg_1,long arg_2,long arg_3,long arg_4,long arg_5)86 long RunGuestSyscall___NR_execveat(long arg_1, long arg_2, long arg_3, long arg_4, long arg_5) {
87   UNUSED(arg_1, arg_2, arg_3, arg_4, arg_5);
88   TRACE("unimplemented syscall __NR_execveat");
89   errno = ENOSYS;
90   return -1;
91 }
92 
93 // sys_fadvise64 has a different entry-point symbol name between riscv64 and x86_64.
94 #ifdef __x86_64__
RunGuestSyscall___NR_fadvise64(long arg_1,long arg_2,long arg_3,long arg_4)95 long RunGuestSyscall___NR_fadvise64(long arg_1, long arg_2, long arg_3, long arg_4) {
96   // on 64-bit architectures, sys_fadvise64 and sys_fadvise64_64 are equal.
97   return syscall(__NR_fadvise64, arg_1, arg_2, arg_3, arg_4);
98 }
99 #endif
100 
RunGuestSyscall___NR_ioctl(long arg_1,long arg_2,long arg_3)101 long RunGuestSyscall___NR_ioctl(long arg_1, long arg_2, long arg_3) {
102   // TODO(b/128614662): translate!
103   TRACE("unimplemented ioctl 0x%lx, running host syscall as is", arg_2);
104   return syscall(__NR_ioctl, arg_1, arg_2, arg_3);
105 }
106 
RunGuestSyscall___NR_newfstatat(long arg_1,long arg_2,long arg_3,long arg_4)107 long RunGuestSyscall___NR_newfstatat(long arg_1, long arg_2, long arg_3, long arg_4) {
108   struct stat host_stat;
109   int result = FstatatForGuest(static_cast<int>(arg_1),       // dirfd
110                                bit_cast<const char*>(arg_2),  // path
111                                &host_stat,
112                                static_cast<int>(arg_4));  // flags
113   if (result != -1) {
114     ConvertHostStatToGuestArch(host_stat, bit_cast<GuestAddr>(arg_3));
115   }
116   return result;
117 }
118 
RunGuestSyscall___NR_riscv_hwprobe(long arg_1,long arg_2,long arg_3,long arg_4,long arg_5)119 long RunGuestSyscall___NR_riscv_hwprobe(long arg_1,
120                                         long arg_2,
121                                         long arg_3,
122                                         long arg_4,
123                                         long arg_5) {
124   UNUSED(arg_3, arg_4);  // cpu_count, cpus_in
125 
126   // There are currently no flags defined by the kernel. This may change in the future.
127   static constexpr unsigned int kFlagsAll = 0;
128 
129   auto pairs = bit_cast<Guest_riscv_hwprobe*>(arg_1);
130   auto pair_count = bit_cast<size_t>(arg_2);
131   auto flags = static_cast<unsigned int>(bit_cast<unsigned long>(arg_5));
132   if ((flags & ~kFlagsAll) != 0) {
133     return -EINVAL;
134   }
135 
136   for (size_t i = 0; i < pair_count; ++i) {
137     Hwprobe(pairs[i]);
138   }
139   return 0;
140 }
141 
RunGuestSyscall___NR_riscv_flush_icache(long arg_1,long arg_2,long arg_3)142 long RunGuestSyscall___NR_riscv_flush_icache(long arg_1, long arg_2, long arg_3) {
143 // TODO(b/346604197): Enable on arm64 once runtime_primitives are ready.
144 #ifdef __x86_64__
145   static constexpr uint64_t kFlagsLocal = 1UL;
146   static constexpr uint64_t kFlagsAll = kFlagsLocal;
147 
148   // ATTENTION: On RISC-V, arg_2 is the address range end, not the address range size.
149   auto start = bit_cast<GuestAddr>(arg_1);
150   auto end = bit_cast<GuestAddr>(arg_2);
151   auto flags = bit_cast<uint64_t>(arg_3);
152   if (end < start || (flags & ~kFlagsAll) != 0) {
153     errno = EINVAL;
154     return -1;
155   }
156 
157   // Ignore kFlagsLocal because we do not have a per-thread cache to clear.
158   TRACE("icache flush: [0x%lx, 0x%lx)", start, end);
159   InvalidateGuestRange(start, end);
160   return 0;
161 #else
162   UNUSED(arg_1, arg_2, arg_3);
163   TRACE("unimplemented syscall __NR_riscv_flush_icache");
164   errno = ENOSYS;
165   return -1;
166 #endif
167 }
168 
169 // RunGuestSyscallImpl.
170 #if defined(__aarch64__)
171 #include "gen_syscall_emulation_riscv64_to_arm64-inl.h"
172 #elif defined(__x86_64__)
173 #include "gen_syscall_emulation_riscv64_to_x86_64-inl.h"
174 #else
175 #error "Unsupported host arch"
176 #endif
177 
178 }  // namespace
179 
RunGuestSyscall(ThreadState * state)180 void RunGuestSyscall(ThreadState* state) {
181 #ifdef __x86_64__
182   // ATTENTION: run guest signal handlers instantly!
183   // If signal arrives while in a syscall, syscall should immediately return with EINTR.
184   // In this case pending signals are OK, as guest handlers will run on return from syscall.
185   // BUT, if signal action has SA_RESTART, certain syscalls will restart instead of returning.
186   // In this case, pending signals will never run...
187   ScopedPendingSignalsDisabler scoped_pending_signals_disabler(state->thread);
188 #else
189   // TODO(b/346604197): Enable on arm64 once guest_os_primitives is ported.
190   TRACE("ScopedPendingSignalsDisabler is not available on this arch");
191 #endif
192   ScopedErrno scoped_errno;
193 
194   long guest_nr = state->cpu.x[A7];
195   if (kInstrumentSyscalls) {
196     OnSyscall(state, guest_nr);
197   }
198 
199   // RISCV Linux takes arguments in a0-a5 and syscall number in a7.
200   // TODO(b/161722184): if syscall is interrupted by signal, signal handler might overwrite the
201   // return value, so setting A0 here might be incorrect. Investigate!
202   long result = RunGuestSyscallImpl(guest_nr,
203                                     state->cpu.x[A0],
204                                     state->cpu.x[A1],
205                                     state->cpu.x[A2],
206                                     state->cpu.x[A3],
207                                     state->cpu.x[A4],
208                                     state->cpu.x[A5]);
209   if (result == -1) {
210     state->cpu.x[A0] = -errno;
211   } else {
212     state->cpu.x[A0] = result;
213   }
214 
215   if (kInstrumentSyscalls) {
216     OnSyscallReturn(state, guest_nr);
217   }
218 }
219 
220 }  // namespace berberis
221