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/unistd.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21
22 #include <cerrno>
23
24 #include "berberis/base/macros.h"
25 #include "berberis/base/scoped_errno.h"
26 #include "berberis/base/struct_check.h"
27 #include "berberis/kernel_api/main_executable_real_path_emulation.h"
28 #include "berberis/kernel_api/syscall_emulation_common.h"
29 #include "berberis/kernel_api/tracing.h"
30
31 #include "epoll_emulation.h"
32 #include "guest_types.h"
33 #include "runtime_bridge.h"
34
35 namespace berberis {
36
37 namespace {
38
ConvertHostStatToGuest(const struct stat & host_stat,Guest_stat * guest_stat)39 void ConvertHostStatToGuest(const struct stat& host_stat, Guest_stat* guest_stat) {
40 guest_stat->st_dev = host_stat.st_dev;
41 guest_stat->st_ino = host_stat.st_ino;
42 guest_stat->st_mode = host_stat.st_mode;
43 guest_stat->st_nlink = host_stat.st_nlink;
44 guest_stat->st_uid = host_stat.st_uid;
45 guest_stat->st_gid = host_stat.st_gid;
46 guest_stat->st_rdev = host_stat.st_rdev;
47 guest_stat->st_size = host_stat.st_size;
48 guest_stat->st_blksize = host_stat.st_blksize;
49 guest_stat->st_blocks = host_stat.st_blocks;
50 guest_stat->st_blocks = host_stat.st_blocks;
51 guest_stat->st_atim = host_stat.st_atim;
52 guest_stat->st_mtim = host_stat.st_mtim;
53 guest_stat->st_ctim = host_stat.st_ctim;
54 }
55
FstatatForGuest(int dirfd,const char * path,struct stat * buf,int flags)56 int FstatatForGuest(int dirfd, const char* path, struct stat* buf, int flags) {
57 const char* real_path = nullptr;
58 if ((flags & AT_SYMLINK_NOFOLLOW) == 0) {
59 real_path = TryReadLinkToMainExecutableRealPath(path);
60 }
61 return syscall(__NR_newfstatat, dirfd, real_path ? real_path : path, buf, flags);
62 }
63
RunGuestSyscall___NR_execveat(long arg_1,long arg_2,long arg_3,long arg_4,long arg_5)64 long RunGuestSyscall___NR_execveat(long arg_1, long arg_2, long arg_3, long arg_4, long arg_5) {
65 UNUSED(arg_1, arg_2, arg_3, arg_4, arg_5);
66 KAPI_TRACE("unimplemented syscall __NR_execveat");
67 errno = ENOSYS;
68 return -1;
69 }
70
RunGuestSyscall___NR_fadvise64(long arg_1,long arg_2,long arg_3,long arg_4)71 long RunGuestSyscall___NR_fadvise64(long arg_1, long arg_2, long arg_3, long arg_4) {
72 // on 64-bit architectures, sys_fadvise64 and sys_fadvise64_64 are equal.
73 return syscall(__NR_fadvise64, arg_1, arg_2, arg_3, arg_4);
74 }
75
RunGuestSyscall___NR_fstat(long arg_1,long arg_2)76 long RunGuestSyscall___NR_fstat(long arg_1, long arg_2) {
77 struct stat host_stat;
78 long result = syscall(__NR_fstat, arg_1, &host_stat);
79 if (result != -1) {
80 ConvertHostStatToGuest(host_stat, bit_cast<Guest_stat*>(arg_2));
81 }
82 return result;
83 }
84
RunGuestSyscall___NR_ioctl(long arg_1,long arg_2,long arg_3)85 long RunGuestSyscall___NR_ioctl(long arg_1, long arg_2, long arg_3) {
86 // TODO(b/128614662): translate!
87 KAPI_TRACE("unimplemented ioctl 0x%lx, running host syscall as is", arg_2);
88 return syscall(__NR_ioctl, arg_1, arg_2, arg_3);
89 }
90
RunGuestSyscall___NR_newfstatat(long arg_1,long arg_2,long arg_3,long arg_4)91 long RunGuestSyscall___NR_newfstatat(long arg_1, long arg_2, long arg_3, long arg_4) {
92 struct stat host_stat;
93 int result = FstatatForGuest(static_cast<int>(arg_1), // dirfd
94 bit_cast<const char*>(arg_2), // path
95 &host_stat,
96 static_cast<int>(arg_4)); // flags
97 if (result != -1) {
98 ConvertHostStatToGuest(host_stat, bit_cast<Guest_stat*>(arg_3));
99 }
100 return result;
101 }
102
103 // RunGuestSyscallImpl.
104 #include "gen_syscall_emulation_riscv64_to_x86_64-inl.h"
105
106 } // namespace
107
RunGuestSyscall(long syscall_nr,long arg0,long arg1,long arg2,long arg3,long arg4,long arg5)108 long RunGuestSyscall(long syscall_nr,
109 long arg0,
110 long arg1,
111 long arg2,
112 long arg3,
113 long arg4,
114 long arg5) {
115 ScopedErrno scoped_errno;
116
117 // RISCV Linux takes arguments in a0-a5 and syscall number in a7.
118 long result = RunGuestSyscallImpl(syscall_nr, arg0, arg1, arg2, arg3, arg4, arg5);
119 // The result is returned in a0.
120 if (result == -1) {
121 return -errno;
122 } else {
123 return result;
124 }
125 }
126
127 } // namespace berberis
128