1 /* $NetBSD: linux32_misc.c,v 1.27 2019/08/23 13:49:12 maxv Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe 9 * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center; 10 * by Edgar Fu\ss, Mathematisches Institut der Uni Bonn. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.27 2019/08/23 13:49:12 maxv Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/proc.h> 39 #include <sys/time.h> 40 #include <sys/types.h> 41 #include <sys/fstypes.h> 42 #include <sys/vfs_syscalls.h> 43 #include <sys/ptrace.h> 44 #include <sys/syscall.h> 45 #include <sys/poll.h> 46 47 #include <compat/netbsd32/netbsd32.h> 48 #include <compat/netbsd32/netbsd32_syscallargs.h> 49 50 #include <compat/linux/common/linux_types.h> 51 52 #include <compat/linux32/common/linux32_types.h> 53 #include <compat/linux32/common/linux32_signal.h> 54 #include <compat/linux32/common/linux32_sched.h> 55 #include <compat/linux32/linux32_syscallargs.h> 56 57 #include <compat/linux/common/linux_ptrace.h> 58 #include <compat/linux/common/linux_emuldata.h> 59 #include <compat/linux/common/linux_signal.h> 60 #include <compat/linux/common/linux_misc.h> 61 #include <compat/linux/common/linux_statfs.h> 62 #include <compat/linux/common/linux_ipc.h> 63 #include <compat/linux/common/linux_sem.h> 64 #include <compat/linux/common/linux_futex.h> 65 #include <compat/linux/linux_syscallargs.h> 66 67 extern const struct linux_mnttypes linux_fstypes[]; 68 extern const int linux_fstypes_cnt; 69 70 void linux32_to_native_timespec(struct timespec *, struct linux32_timespec *); 71 72 /* 73 * Implement the fs stat functions. Straightforward. 74 */ 75 int 76 linux32_sys_statfs(struct lwp *l, const struct linux32_sys_statfs_args *uap, register_t *retval) 77 { 78 /* { 79 syscallarg(const netbsd32_charp char) path; 80 syscallarg(linux32_statfsp) sp; 81 } */ 82 struct statvfs *sb; 83 struct linux_statfs ltmp; 84 int error; 85 86 sb = STATVFSBUF_GET(); 87 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 88 if (error == 0) { 89 bsd_to_linux_statfs(sb, <mp); 90 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 91 } 92 93 STATVFSBUF_PUT(sb); 94 return error; 95 } 96 97 int 98 linux32_sys_fstatfs(struct lwp *l, const struct linux32_sys_fstatfs_args *uap, register_t *retval) 99 { 100 /* { 101 syscallarg(int) fd; 102 syscallarg(linux32_statfsp) sp; 103 } */ 104 struct statvfs *sb; 105 struct linux_statfs ltmp; 106 int error; 107 108 sb = STATVFSBUF_GET(); 109 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 110 if (error == 0) { 111 bsd_to_linux_statfs(sb, <mp); 112 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 113 } 114 STATVFSBUF_PUT(sb); 115 116 return error; 117 } 118 119 int 120 linux32_sys_statfs64(struct lwp *l, const struct linux32_sys_statfs64_args *uap, register_t *retval) 121 { 122 /* { 123 syscallarg(const netbsd32_charp char) path; 124 syscallarg(linux32_statfs64p) sp; 125 } */ 126 struct statvfs *sb; 127 struct linux_statfs64 ltmp; 128 int error; 129 130 sb = STATVFSBUF_GET(); 131 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 132 if (error == 0) { 133 bsd_to_linux_statfs64(sb, <mp); 134 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 135 } 136 137 STATVFSBUF_PUT(sb); 138 return error; 139 } 140 141 int 142 linux32_sys_fstatfs64(struct lwp *l, const struct linux32_sys_fstatfs64_args *uap, register_t *retval) 143 { 144 /* { 145 syscallarg(int) fd; 146 syscallarg(linux32_statfs64p) sp; 147 } */ 148 struct statvfs *sb; 149 struct linux_statfs64 ltmp; 150 int error; 151 152 sb = STATVFSBUF_GET(); 153 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 154 if (error == 0) { 155 bsd_to_linux_statfs64(sb, <mp); 156 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 157 } 158 STATVFSBUF_PUT(sb); 159 160 return error; 161 } 162 163 extern const int linux_ptrace_request_map[]; 164 165 int 166 linux32_sys_ptrace(struct lwp *l, const struct linux32_sys_ptrace_args *uap, register_t *retval) 167 { 168 /* { 169 i386, m68k, powerpc: T=int 170 alpha, amd64: T=long 171 syscallarg(T) request; 172 syscallarg(T) pid; 173 syscallarg(T) addr; 174 syscallarg(T) data; 175 } */ 176 const int *ptr; 177 int request; 178 int error; 179 180 ptr = linux_ptrace_request_map; 181 request = SCARG(uap, request); 182 while (*ptr != -1) 183 if (*ptr++ == request) { 184 struct sys_ptrace_args pta; 185 186 SCARG(&pta, req) = *ptr; 187 SCARG(&pta, pid) = SCARG(uap, pid); 188 SCARG(&pta, addr) = NETBSD32IPTR64(SCARG(uap, addr)); 189 SCARG(&pta, data) = SCARG(uap, data); 190 191 /* 192 * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually 193 * to continue where the process left off previously. 194 * The same thing is achieved by addr == (void *) 1 195 * on NetBSD, so rewrite 'addr' appropriately. 196 */ 197 if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0) 198 SCARG(&pta, addr) = (void *) 1; 199 200 error = sysent[SYS_ptrace].sy_call(l, &pta, retval); 201 if (error) 202 return error; 203 switch (request) { 204 case LINUX_PTRACE_PEEKTEXT: 205 case LINUX_PTRACE_PEEKDATA: 206 error = copyout (retval, 207 NETBSD32IPTR64(SCARG(uap, data)), 208 sizeof *retval); 209 *retval = SCARG(uap, data); 210 break; 211 default: 212 break; 213 } 214 return error; 215 } 216 else 217 ptr++; 218 219 return EIO; 220 } 221 222 int 223 linux32_sys_personality(struct lwp *l, const struct linux32_sys_personality_args *uap, register_t *retval) 224 { 225 /* { 226 syscallarg(netbsd32_u_long) per; 227 } */ 228 struct linux_sys_personality_args ua; 229 230 NETBSD32TOX_UAP(per, long); 231 return linux_sys_personality(l, &ua, retval); 232 } 233 234 int 235 linux32_sys_futex(struct lwp *l, 236 const struct linux32_sys_futex_args *uap, register_t *retval) 237 { 238 /* { 239 syscallarg(linux32_intp_t) uaddr; 240 syscallarg(int) op; 241 syscallarg(int) val; 242 syscallarg(linux32_timespecp_t) timeout; 243 syscallarg(linux32_intp_t) uaddr2; 244 syscallarg(int) val3; 245 } */ 246 struct linux_sys_futex_args ua; 247 struct linux32_timespec lts; 248 struct timespec ts = { 0, 0 }; 249 int error; 250 251 NETBSD32TOP_UAP(uaddr, int); 252 NETBSD32TO64_UAP(op); 253 NETBSD32TO64_UAP(val); 254 NETBSD32TOP_UAP(timeout, struct linux_timespec); 255 NETBSD32TOP_UAP(uaddr2, int); 256 NETBSD32TO64_UAP(val3); 257 if ((SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) == LINUX_FUTEX_WAIT && 258 SCARG_P32(uap, timeout) != NULL) { 259 if ((error = copyin((void *)SCARG_P32(uap, timeout), 260 <s, sizeof(lts))) != 0) { 261 return error; 262 } 263 linux32_to_native_timespec(&ts, <s); 264 } 265 return linux_do_futex(l, &ua, &ts, retval); 266 } 267 268 int 269 linux32_sys_set_robust_list(struct lwp *l, 270 const struct linux32_sys_set_robust_list_args *uap, register_t *retval) 271 { 272 /* { 273 syscallarg(linux32_robust_list_headp_t) head; 274 syscallarg(linux32_size_t) len; 275 } */ 276 struct linux_sys_set_robust_list_args ua; 277 struct linux_emuldata *led; 278 279 if (SCARG(uap, len) != 12) 280 return EINVAL; 281 282 NETBSD32TOP_UAP(head, struct robust_list_head); 283 NETBSD32TOX64_UAP(len, size_t); 284 285 led = l->l_emuldata; 286 led->led_robust_head = SCARG(&ua, head); 287 *retval = 0; 288 return 0; 289 } 290 291 int 292 linux32_sys_get_robust_list(struct lwp *l, 293 const struct linux32_sys_get_robust_list_args *uap, register_t *retval) 294 { 295 /* { 296 syscallarg(linux32_pid_t) pid; 297 syscallarg(linux32_robust_list_headpp_t) head; 298 syscallarg(linux32_sizep_t) len; 299 } */ 300 struct linux_sys_get_robust_list_args ua; 301 302 NETBSD32TOX_UAP(pid, int); 303 NETBSD32TOP_UAP(head, struct robust_list_head *); 304 NETBSD32TOP_UAP(len, size_t *); 305 return linux_sys_get_robust_list(l, &ua, retval); 306 } 307 308 int 309 linux32_sys_truncate64(struct lwp *l, const struct linux32_sys_truncate64_args *uap, register_t *retval) 310 { 311 /* { 312 syscallarg(netbsd32_charp) path; 313 syscallarg(off_t) length; 314 } */ 315 struct sys_truncate_args ua; 316 317 /* Linux doesn't have the 'pad' pseudo-parameter */ 318 NETBSD32TOP_UAP(path, const char *); 319 SCARG(&ua, PAD) = 0; 320 SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); 321 return sys_truncate(l, &ua, retval); 322 } 323 324 int 325 linux32_sys_ftruncate64(struct lwp *l, const struct linux32_sys_ftruncate64_args *uap, register_t *retval) 326 { 327 /* { 328 syscallarg(unsigned int) fd; 329 syscallarg(off_t) length; 330 } */ 331 struct sys_ftruncate_args ua; 332 333 /* Linux doesn't have the 'pad' pseudo-parameter */ 334 NETBSD32TO64_UAP(fd); 335 SCARG(&ua, PAD) = 0; 336 SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); 337 return sys_ftruncate(l, &ua, retval); 338 } 339 340 int 341 linux32_sys_setdomainname(struct lwp *l, const struct linux32_sys_setdomainname_args *uap, register_t *retval) 342 { 343 /* { 344 syscallarg(netbsd32_charp) domainname; 345 syscallarg(int) len; 346 } */ 347 struct linux_sys_setdomainname_args ua; 348 349 NETBSD32TOP_UAP(domainname, char); 350 NETBSD32TO64_UAP(len); 351 return linux_sys_setdomainname(l, &ua, retval); 352 } 353 354 int 355 linux32_sys_ppoll(struct lwp *l, const struct linux32_sys_ppoll_args *uap, 356 register_t *retval) 357 { 358 /* { 359 syscallarg(netbsd32_pollfdp_t) fds; 360 syscallarg(u_int) nfds; 361 syscallarg(linux32_timespecp_t) timeout; 362 syscallarg(linux32_sigsetp_t) sigset; 363 } */ 364 struct linux32_timespec lts0, *lts; 365 struct timespec ts0, *ts = NULL; 366 linux32_sigset_t lsigmask0, *lsigmask; 367 sigset_t sigmask0, *sigmask = NULL; 368 int error; 369 370 lts = SCARG_P32(uap, timeout); 371 if (lts) { 372 if ((error = copyin(lts, <s0, sizeof(lts0))) != 0) 373 return error; 374 linux32_to_native_timespec(&ts0, <s0); 375 ts = &ts0; 376 } 377 378 lsigmask = SCARG_P32(uap, sigset); 379 if (lsigmask) { 380 if ((error = copyin(lsigmask, &lsigmask0, sizeof(lsigmask0)))) 381 return error; 382 linux32_to_native_sigset(&sigmask0, &lsigmask0); 383 sigmask = &sigmask0; 384 } 385 386 return pollcommon(retval, SCARG_P32(uap, fds), SCARG(uap, nfds), 387 ts, sigmask); 388 } 389