1 /* $NetBSD: linux32_misc.c,v 1.33 2021/09/20 02:20:03 thorpej 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.33 2021/09/20 02:20:03 thorpej 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 #include <sys/futex.h> 47 48 #include <compat/netbsd32/netbsd32.h> 49 #include <compat/netbsd32/netbsd32_syscallargs.h> 50 51 #include <compat/linux/common/linux_types.h> 52 53 #include <compat/linux32/common/linux32_types.h> 54 #include <compat/linux32/common/linux32_signal.h> 55 #include <compat/linux32/common/linux32_sched.h> 56 #include <compat/linux32/linux32_syscallargs.h> 57 58 #include <compat/linux/common/linux_ptrace.h> 59 #include <compat/linux/common/linux_emuldata.h> 60 #include <compat/linux/common/linux_signal.h> 61 #include <compat/linux/common/linux_misc.h> 62 #include <compat/linux/common/linux_statfs.h> 63 #include <compat/linux/common/linux_ipc.h> 64 #include <compat/linux/common/linux_sem.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 /* 71 * Implement the fs stat functions. Straightforward. 72 */ 73 int 74 linux32_sys_statfs(struct lwp *l, const struct linux32_sys_statfs_args *uap, register_t *retval) 75 { 76 /* { 77 syscallarg(const netbsd32_charp char) path; 78 syscallarg(linux32_statfsp) sp; 79 } */ 80 struct statvfs *sb; 81 struct linux_statfs ltmp; 82 int error; 83 84 sb = STATVFSBUF_GET(); 85 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 86 if (error == 0) { 87 bsd_to_linux_statfs(sb, <mp); 88 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 89 } 90 91 STATVFSBUF_PUT(sb); 92 return error; 93 } 94 95 int 96 linux32_sys_fstatfs(struct lwp *l, const struct linux32_sys_fstatfs_args *uap, register_t *retval) 97 { 98 /* { 99 syscallarg(int) fd; 100 syscallarg(linux32_statfsp) sp; 101 } */ 102 struct statvfs *sb; 103 struct linux_statfs ltmp; 104 int error; 105 106 sb = STATVFSBUF_GET(); 107 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 108 if (error == 0) { 109 bsd_to_linux_statfs(sb, <mp); 110 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 111 } 112 STATVFSBUF_PUT(sb); 113 114 return error; 115 } 116 117 int 118 linux32_sys_statfs64(struct lwp *l, const struct linux32_sys_statfs64_args *uap, register_t *retval) 119 { 120 /* { 121 syscallarg(const netbsd32_charp char) path; 122 syscallarg(linux32_statfs64p) sp; 123 } */ 124 struct statvfs *sb; 125 struct linux_statfs64 ltmp; 126 int error; 127 128 sb = STATVFSBUF_GET(); 129 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 130 if (error == 0) { 131 bsd_to_linux_statfs64(sb, <mp); 132 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 133 } 134 135 STATVFSBUF_PUT(sb); 136 return error; 137 } 138 139 int 140 linux32_sys_fstatfs64(struct lwp *l, const struct linux32_sys_fstatfs64_args *uap, register_t *retval) 141 { 142 /* { 143 syscallarg(int) fd; 144 syscallarg(linux32_statfs64p) sp; 145 } */ 146 struct statvfs *sb; 147 struct linux_statfs64 ltmp; 148 int error; 149 150 sb = STATVFSBUF_GET(); 151 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 152 if (error == 0) { 153 bsd_to_linux_statfs64(sb, <mp); 154 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 155 } 156 STATVFSBUF_PUT(sb); 157 158 return error; 159 } 160 161 extern const int linux_ptrace_request_map[]; 162 163 int 164 linux32_sys_ptrace(struct lwp *l, const struct linux32_sys_ptrace_args *uap, register_t *retval) 165 { 166 /* { 167 i386, m68k, powerpc: T=int 168 alpha, amd64: T=long 169 syscallarg(T) request; 170 syscallarg(T) pid; 171 syscallarg(T) addr; 172 syscallarg(T) data; 173 } */ 174 const int *ptr; 175 int request; 176 int error; 177 178 ptr = linux_ptrace_request_map; 179 request = SCARG(uap, request); 180 while (*ptr != -1) 181 if (*ptr++ == request) { 182 struct sys_ptrace_args pta; 183 184 SCARG(&pta, req) = *ptr; 185 SCARG(&pta, pid) = SCARG(uap, pid); 186 SCARG(&pta, addr) = NETBSD32IPTR64(SCARG(uap, addr)); 187 SCARG(&pta, data) = SCARG(uap, data); 188 189 /* 190 * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually 191 * to continue where the process left off previously. 192 * The same thing is achieved by addr == (void *) 1 193 * on NetBSD, so rewrite 'addr' appropriately. 194 */ 195 if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0) 196 SCARG(&pta, addr) = (void *) 1; 197 198 error = sysent[SYS_ptrace].sy_call(l, &pta, retval); 199 if (error) 200 return error; 201 switch (request) { 202 case LINUX_PTRACE_PEEKTEXT: 203 case LINUX_PTRACE_PEEKDATA: 204 error = copyout (retval, 205 NETBSD32IPTR64(SCARG(uap, data)), 206 sizeof *retval); 207 *retval = SCARG(uap, data); 208 break; 209 default: 210 break; 211 } 212 return error; 213 } 214 else 215 ptr++; 216 217 return EIO; 218 } 219 220 int 221 linux32_sys_personality(struct lwp *l, const struct linux32_sys_personality_args *uap, register_t *retval) 222 { 223 /* { 224 syscallarg(netbsd32_u_long) per; 225 } */ 226 struct linux_sys_personality_args ua; 227 228 NETBSD32TOX_UAP(per, long); 229 return linux_sys_personality(l, &ua, retval); 230 } 231 232 int 233 linux32_sys_futex(struct lwp *l, 234 const struct linux32_sys_futex_args *uap, register_t *retval) 235 { 236 /* { 237 syscallarg(linux32_intp_t) uaddr; 238 syscallarg(int) op; 239 syscallarg(int) val; 240 syscallarg(linux32_timespecp_t) timeout; 241 syscallarg(linux32_intp_t) uaddr2; 242 syscallarg(int) val3; 243 } */ 244 struct linux32_timespec lts; 245 struct timespec ts, *tsp = NULL; 246 int val2 = 0; 247 int error; 248 249 /* 250 * Linux overlays the "timeout" field and the "val2" field. 251 * "timeout" is only valid for FUTEX_WAIT and FUTEX_WAIT_BITSET 252 * on Linux. 253 */ 254 const int op = (SCARG(uap, op) & FUTEX_CMD_MASK); 255 if ((op == FUTEX_WAIT || op == FUTEX_WAIT_BITSET) && 256 SCARG_P32(uap, timeout) != NULL) { 257 if ((error = copyin(SCARG_P32(uap, timeout), 258 <s, sizeof(lts))) != 0) { 259 return error; 260 } 261 linux32_to_native_timespec(&ts, <s); 262 tsp = &ts; 263 } else { 264 val2 = (int)(uintptr_t)SCARG_P32(uap, timeout); 265 } 266 267 return linux_do_futex(SCARG_P32(uap, uaddr), SCARG(uap, op), 268 SCARG(uap, val), tsp, SCARG_P32(uap, uaddr2), val2, 269 SCARG(uap, val3), retval); 270 } 271 272 int 273 linux32_sys_truncate64(struct lwp *l, const struct linux32_sys_truncate64_args *uap, register_t *retval) 274 { 275 /* { 276 syscallarg(netbsd32_charp) path; 277 syscallarg(off_t) length; 278 } */ 279 struct sys_truncate_args ua; 280 281 /* Linux doesn't have the 'pad' pseudo-parameter */ 282 NETBSD32TOP_UAP(path, const char *); 283 SCARG(&ua, PAD) = 0; 284 SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); 285 return sys_truncate(l, &ua, retval); 286 } 287 288 int 289 linux32_sys_ftruncate64(struct lwp *l, const struct linux32_sys_ftruncate64_args *uap, register_t *retval) 290 { 291 /* { 292 syscallarg(unsigned int) fd; 293 syscallarg(off_t) length; 294 } */ 295 struct sys_ftruncate_args ua; 296 297 /* Linux doesn't have the 'pad' pseudo-parameter */ 298 NETBSD32TO64_UAP(fd); 299 SCARG(&ua, PAD) = 0; 300 SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); 301 return sys_ftruncate(l, &ua, retval); 302 } 303 304 int 305 linux32_sys_setdomainname(struct lwp *l, const struct linux32_sys_setdomainname_args *uap, register_t *retval) 306 { 307 /* { 308 syscallarg(netbsd32_charp) domainname; 309 syscallarg(int) len; 310 } */ 311 struct linux_sys_setdomainname_args ua; 312 313 NETBSD32TOP_UAP(domainname, char); 314 NETBSD32TO64_UAP(len); 315 return linux_sys_setdomainname(l, &ua, retval); 316 } 317 318 int 319 linux32_sys_ppoll(struct lwp *l, const struct linux32_sys_ppoll_args *uap, 320 register_t *retval) 321 { 322 /* { 323 syscallarg(netbsd32_pollfdp_t) fds; 324 syscallarg(u_int) nfds; 325 syscallarg(linux32_timespecp_t) timeout; 326 syscallarg(linux32_sigsetp_t) sigset; 327 } */ 328 struct linux32_timespec lts0, *lts; 329 struct timespec ts0, *ts = NULL; 330 linux32_sigset_t lsigmask0, *lsigmask; 331 sigset_t sigmask0, *sigmask = NULL; 332 int error; 333 334 lts = SCARG_P32(uap, timeout); 335 if (lts) { 336 if ((error = copyin(lts, <s0, sizeof(lts0))) != 0) 337 return error; 338 linux32_to_native_timespec(&ts0, <s0); 339 ts = &ts0; 340 } 341 342 lsigmask = SCARG_P32(uap, sigset); 343 if (lsigmask) { 344 if ((error = copyin(lsigmask, &lsigmask0, sizeof(lsigmask0)))) 345 return error; 346 linux32_to_native_sigset(&sigmask0, &lsigmask0); 347 sigmask = &sigmask0; 348 } 349 350 return pollcommon(retval, SCARG_P32(uap, fds), SCARG(uap, nfds), 351 ts, sigmask); 352 } 353 354 int 355 linux32_sys_eventfd(struct lwp *l, const struct linux32_sys_eventfd_args *uap, 356 register_t *retval) 357 { 358 /* { 359 syscallarg(unsigned int) initval; 360 } */ 361 struct linux_sys_eventfd_args ua; 362 363 NETBSD32TO64_UAP(initval); 364 365 return linux_sys_eventfd(l, &ua, retval); 366 } 367 368 int 369 linux32_sys_eventfd2(struct lwp *l, const struct linux32_sys_eventfd2_args *uap, 370 register_t *retval) 371 { 372 /* { 373 syscallarg(unsigned int) initval; 374 syscallarg(int) flags; 375 } */ 376 struct linux_sys_eventfd2_args ua; 377 378 NETBSD32TO64_UAP(initval); 379 NETBSD32TO64_UAP(flags); 380 381 return linux_sys_eventfd2(l, &ua, retval); 382 } 383 384 static inline off_t 385 linux32_hilo_to_off_t(unsigned long hi, unsigned long lo) 386 { 387 return (((off_t)hi) << 32) | lo; 388 } 389 390 int 391 linux32_sys_preadv(struct lwp *l, const struct linux32_sys_preadv_args *uap, 392 register_t *retval) 393 { 394 /* { 395 syscallarg(int) fd; 396 syscallarg(const netbsd32_iovecp_t) iovp; 397 syscallarg(int) iovcnt; 398 syscallarg(netbsd32_u_long) off_lo; 399 syscallarg(netbsd32_u_long) off_hi; 400 } */ 401 struct netbsd32_preadv_args ua; 402 403 SCARG(&ua, fd) = SCARG(uap, fd); 404 SCARG(&ua, iovp) = SCARG(uap, iovp); 405 SCARG(&ua, iovcnt) = SCARG(uap, iovcnt); 406 SCARG(&ua, PAD) = 0; 407 SCARG(&ua, offset) = linux32_hilo_to_off_t(SCARG(uap, off_hi), 408 SCARG(uap, off_lo)); 409 return netbsd32_preadv(l, &ua, retval); 410 } 411 412 int 413 linux32_sys_pwritev(struct lwp *l, const struct linux32_sys_pwritev_args *uap, 414 register_t *retval) 415 { 416 /* { 417 syscallarg(int) fd; 418 syscallarg(const netbsd32_iovecp_t) iovp; 419 syscallarg(int) iovcnt; 420 syscallarg(netbsd32_u_long) off_lo; 421 syscallarg(netbsd32_u_long) off_hi; 422 } */ 423 struct netbsd32_pwritev_args ua; 424 425 SCARG(&ua, fd) = SCARG(uap, fd); 426 SCARG(&ua, iovp) = SCARG(uap, iovp); 427 SCARG(&ua, iovcnt) = SCARG(uap, iovcnt); 428 SCARG(&ua, PAD) = 0; 429 SCARG(&ua, offset) = linux32_hilo_to_off_t(SCARG(uap, off_hi), 430 SCARG(uap, off_lo)); 431 return netbsd32_pwritev(l, &ua, retval); 432 } 433