1 /* $NetBSD: linux_time.c,v 1.42 2021/09/19 23:51:37 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Emmanuel Dreyfus, and by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.42 2021/09/19 23:51:37 thorpej Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/ucred.h> 37 #include <sys/kauth.h> 38 #include <sys/mount.h> 39 #include <sys/signal.h> 40 #include <sys/stdint.h> 41 #include <sys/time.h> 42 #include <sys/timerfd.h> 43 #include <sys/systm.h> 44 #include <sys/sched.h> 45 #include <sys/syscallargs.h> 46 #include <sys/lwp.h> 47 #include <sys/proc.h> 48 49 #include <compat/linux/common/linux_types.h> 50 #include <compat/linux/common/linux_fcntl.h> 51 #include <compat/linux/common/linux_ioctl.h> 52 #include <compat/linux/common/linux_signal.h> 53 #include <compat/linux/common/linux_sigevent.h> 54 #include <compat/linux/common/linux_machdep.h> 55 #include <compat/linux/common/linux_sched.h> 56 #include <compat/linux/common/linux_ipc.h> 57 #include <compat/linux/common/linux_sem.h> 58 59 #include <compat/linux/linux_syscallargs.h> 60 61 #include <compat/common/compat_util.h> 62 63 CTASSERT(LINUX_TIMER_ABSTIME == TIMER_ABSTIME); 64 65 /* 66 * Linux keeps track of a system timezone in the kernel. It is readen 67 * by gettimeofday and set by settimeofday. This emulates this behavior 68 * See linux/kernel/time.c 69 */ 70 struct timezone linux_sys_tz; 71 72 int 73 linux_sys_gettimeofday(struct lwp *l, const struct linux_sys_gettimeofday_args *uap, register_t *retval) 74 { 75 /* { 76 syscallarg(struct timeval50 *) tz; 77 syscallarg(struct timezone *) tzp; 78 } */ 79 int error = 0; 80 81 if (SCARG(uap, tp)) { 82 error = compat_50_sys_gettimeofday(l, (const void *)uap, retval); 83 if (error) 84 return (error); 85 } 86 87 if (SCARG(uap, tzp)) { 88 error = copyout(&linux_sys_tz, SCARG(uap, tzp), sizeof(linux_sys_tz)); 89 if (error) 90 return (error); 91 } 92 93 return (0); 94 } 95 96 int 97 linux_sys_settimeofday(struct lwp *l, const struct linux_sys_settimeofday_args *uap, register_t *retval) 98 { 99 /* { 100 syscallarg(struct timeval50 *) tp; 101 syscallarg(struct timezone *) tzp; 102 } */ 103 int error = 0; 104 105 if (SCARG(uap, tp)) { 106 error = compat_50_sys_settimeofday(l, (const void *)uap, retval); 107 if (error) 108 return (error); 109 } 110 111 if (SCARG(uap, tzp)) { 112 if (kauth_authorize_generic(kauth_cred_get(), 113 KAUTH_GENERIC_ISSUSER, NULL) != 0) 114 return (EPERM); 115 error = copyin(SCARG(uap, tzp), &linux_sys_tz, sizeof(linux_sys_tz)); 116 if (error) 117 return (error); 118 } 119 120 return (0); 121 } 122 123 void 124 native_to_linux_timespec(struct linux_timespec *ltp, const struct timespec *ntp) 125 { 126 memset(ltp, 0, sizeof(*ltp)); 127 ltp->tv_sec = ntp->tv_sec; 128 ltp->tv_nsec = ntp->tv_nsec; 129 } 130 131 void 132 linux_to_native_timespec(struct timespec *ntp, const struct linux_timespec *ltp) 133 { 134 memset(ntp, 0, sizeof(*ntp)); 135 ntp->tv_sec = ltp->tv_sec; 136 ntp->tv_nsec = ltp->tv_nsec; 137 } 138 139 void 140 native_to_linux_itimerspec(struct linux_itimerspec *litp, 141 const struct itimerspec *nitp) 142 { 143 memset(litp, 0, sizeof(*litp)); 144 native_to_linux_timespec(&litp->it_interval, &nitp->it_interval); 145 native_to_linux_timespec(&litp->it_value, &nitp->it_value); 146 } 147 148 void 149 linux_to_native_itimerspec(struct itimerspec *nitp, 150 const struct linux_itimerspec *litp) 151 { 152 memset(nitp, 0, sizeof(*nitp)); 153 linux_to_native_timespec(&nitp->it_interval, &litp->it_interval); 154 linux_to_native_timespec(&nitp->it_value, &litp->it_value); 155 } 156 157 int 158 linux_sys_nanosleep(struct lwp *l, const struct linux_sys_nanosleep_args *uap, 159 register_t *retval) 160 { 161 /* { 162 syscallarg(struct linux_timespec *) rqtp; 163 syscallarg(struct linux_timespec *) rmtp; 164 } */ 165 struct timespec rqts, rmts; 166 struct linux_timespec lrqts, lrmts; 167 int error, error1; 168 169 error = copyin(SCARG(uap, rqtp), &lrqts, sizeof(lrqts)); 170 if (error != 0) 171 return error; 172 linux_to_native_timespec(&rqts, &lrqts); 173 174 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqts, 175 SCARG(uap, rmtp) ? &rmts : NULL); 176 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 177 return error; 178 179 native_to_linux_timespec(&lrmts, &rmts); 180 error1 = copyout(&lrmts, SCARG(uap, rmtp), sizeof(lrmts)); 181 return error1 ? error1 : error; 182 } 183 184 int 185 linux_to_native_clockid(clockid_t *n, clockid_t l) 186 { 187 switch (l) { 188 case LINUX_CLOCK_REALTIME: 189 *n = CLOCK_REALTIME; 190 break; 191 case LINUX_CLOCK_MONOTONIC: 192 *n = CLOCK_MONOTONIC; 193 break; 194 case LINUX_CLOCK_PROCESS_CPUTIME_ID: 195 *n = CLOCK_PROCESS_CPUTIME_ID /* self */; 196 break; 197 case LINUX_CLOCK_THREAD_CPUTIME_ID: 198 *n = CLOCK_THREAD_CPUTIME_ID /* self */; 199 break; 200 201 case LINUX_CLOCK_MONOTONIC_RAW: 202 case LINUX_CLOCK_REALTIME_COARSE: 203 case LINUX_CLOCK_MONOTONIC_COARSE: 204 case LINUX_CLOCK_BOOTTIME: 205 case LINUX_CLOCK_BOOTTIME_ALARM: 206 case LINUX_CLOCK_REALTIME_ALARM: 207 default: 208 return ENOTSUP; 209 } 210 211 return 0; 212 } 213 214 int 215 linux_sys_clock_gettime(struct lwp *l, const struct linux_sys_clock_gettime_args *uap, register_t *retval) 216 { 217 /* { 218 syscallarg(clockid_t) which; 219 syscallarg(struct linux_timespec *)tp; 220 } */ 221 int error; 222 clockid_t id; 223 struct timespec ts; 224 struct linux_timespec lts; 225 226 error = linux_to_native_clockid(&id, SCARG(uap, which)); 227 if (error != 0) 228 return error; 229 230 error = clock_gettime1(id, &ts); 231 if (error != 0) 232 return error; 233 234 native_to_linux_timespec(<s, &ts); 235 return copyout(<s, SCARG(uap, tp), sizeof lts); 236 } 237 238 int 239 linux_sys_clock_settime(struct lwp *l, const struct linux_sys_clock_settime_args *uap, register_t *retval) 240 { 241 /* { 242 syscallarg(clockid_t) which; 243 syscallarg(struct linux_timespec *)tp; 244 } */ 245 struct timespec ts; 246 struct linux_timespec lts; 247 clockid_t id; 248 int error; 249 250 error = linux_to_native_clockid(&id, SCARG(uap, which)); 251 if (error != 0) 252 return error; 253 254 error = copyin(SCARG(uap, tp), <s, sizeof lts); 255 if (error != 0) 256 return error; 257 258 linux_to_native_timespec(&ts, <s); 259 260 return clock_settime1(l->l_proc, id, &ts, true); 261 } 262 263 int 264 linux_sys_clock_getres(struct lwp *l, const struct linux_sys_clock_getres_args *uap, register_t *retval) 265 { 266 /* { 267 syscallarg(clockid_t) which; 268 syscallarg(struct linux_timespec *)tp; 269 } */ 270 struct timespec ts; 271 struct linux_timespec lts; 272 int error; 273 clockid_t nwhich = 0; /* XXX: GCC */ 274 275 error = linux_to_native_clockid(&nwhich, SCARG(uap, which)); 276 if (error != 0 || SCARG(uap, tp) == NULL) 277 return error; 278 279 error = clock_getres1(nwhich, &ts); 280 if (error != 0) 281 return error; 282 283 native_to_linux_timespec(<s, &ts); 284 return copyout(<s, SCARG(uap, tp), sizeof lts); 285 } 286 287 int 288 linux_sys_clock_nanosleep(struct lwp *l, const struct linux_sys_clock_nanosleep_args *uap, register_t *retval) 289 { 290 /* { 291 syscallarg(clockid_t) which; 292 syscallarg(int) flags; 293 syscallarg(struct linux_timespec) *rqtp; 294 syscallarg(struct linux_timespec) *rmtp; 295 } */ 296 struct linux_timespec lrqts, lrmts; 297 struct timespec rqts, rmts; 298 int error, error1, flags; 299 clockid_t nwhich; 300 301 flags = SCARG(uap, flags); 302 if (flags & ~TIMER_ABSTIME) { 303 return EINVAL; 304 } 305 306 error = linux_to_native_clockid(&nwhich, SCARG(uap, which)); 307 if (error != 0) 308 return error; 309 310 error = copyin(SCARG(uap, rqtp), &lrqts, sizeof lrqts); 311 if (error != 0) 312 return error; 313 314 linux_to_native_timespec(&rqts, &lrqts); 315 316 error = nanosleep1(l, nwhich, flags, &rqts, 317 SCARG(uap, rmtp) ? &rmts : NULL); 318 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 319 return error; 320 321 native_to_linux_timespec(&lrmts, &rmts); 322 error1 = copyout(&lrmts, SCARG(uap, rmtp), sizeof lrmts); 323 return error1 ? error1 : error; 324 } 325 326 int 327 linux_to_native_timer_create_clockid(clockid_t *nid, clockid_t lid) 328 { 329 clockid_t id; 330 int error; 331 332 error = linux_to_native_clockid(&id, lid); 333 if (error == 0) { 334 /* 335 * We can't create a timer with every sort of clock ID 336 * that the system understands, so filter them out. 337 * 338 * Map CLOCK_PROCESS_CPUTIME_ID to CLOCK_VIRTUAL. 339 * We can't handle CLOCK_THREAD_CPUTIME_ID. 340 */ 341 switch (id) { 342 case CLOCK_REALTIME: 343 case CLOCK_MONOTONIC: 344 break; 345 346 case CLOCK_PROCESS_CPUTIME_ID: 347 id = CLOCK_VIRTUAL; 348 break; 349 350 default: 351 return ENOTSUP; 352 } 353 *nid = id; 354 } 355 356 return error; 357 } 358 359 int 360 linux_sys_timer_create(struct lwp *l, 361 const struct linux_sys_timer_create_args *uap, register_t *retval) 362 { 363 /* { 364 syscallarg(clockid_t) clockid; 365 syscallarg(struct linux_sigevent *) evp; 366 syscallarg(timer_t *) timerid; 367 } */ 368 clockid_t id; 369 int error; 370 371 error = linux_to_native_timer_create_clockid(&id, SCARG(uap, clockid)); 372 if (error == 0) { 373 error = timer_create1(SCARG(uap, timerid), id, 374 (void *)SCARG(uap, evp), linux_sigevent_copyin, l); 375 } 376 377 return error; 378 } 379 380 int 381 linux_sys_timer_settime(struct lwp *l, 382 const struct linux_sys_timer_settime_args *uap, register_t *retval) 383 { 384 /* { 385 syscallarg(timer_t) timerid; 386 syscallarg(int) flags; 387 syscallarg(const struct linux_itimerspec *) tim; 388 syscallarg(struct linux_itimerspec *) otim; 389 } */ 390 struct itimerspec value, ovalue, *ovp = NULL; 391 struct linux_itimerspec tim, otim; 392 int error; 393 394 error = copyin(SCARG(uap, tim), &tim, sizeof(tim)); 395 if (error) { 396 return error; 397 } 398 linux_to_native_itimerspec(&value, &tim); 399 400 if (SCARG(uap, otim)) { 401 ovp = &ovalue; 402 } 403 404 if (SCARG(uap, flags) & ~TIMER_ABSTIME) { 405 return EINVAL; 406 } 407 408 error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 409 SCARG(uap, flags), l->l_proc); 410 if (error) { 411 return error; 412 } 413 414 if (ovp) { 415 native_to_linux_itimerspec(&otim, ovp); 416 error = copyout(&otim, SCARG(uap, otim), sizeof(otim)); 417 } 418 419 return error; 420 } 421 422 int 423 linux_sys_timer_gettime(struct lwp *l, 424 const struct linux_sys_timer_gettime_args *uap, register_t *retval) 425 { 426 /* { 427 syscallarg(timer_t) timerid; 428 syscallarg(struct linux_itimerspec *) tim; 429 } */ 430 struct itimerspec its; 431 struct linux_itimerspec lits; 432 int error; 433 434 error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, &its); 435 if (error == 0) { 436 native_to_linux_itimerspec(&lits, &its); 437 error = copyout(&lits, SCARG(uap, tim), sizeof(lits)); 438 } 439 440 return error; 441 } 442 443 /* 444 * timer_gettoverrun(2) and timer_delete(2) are handled directly 445 * by the native calls. 446 */ 447 448 #define LINUX_TFD_TIMER_ABSTIME 0x0001 449 #define LINUX_TFD_TIMER_CANCEL_ON_SET 0x0002 450 #define LINUX_TFD_CLOEXEC LINUX_O_CLOEXEC 451 #define LINUX_TFD_NONBLOCK LINUX_O_NONBLOCK 452 453 int 454 linux_sys_timerfd_create(struct lwp *l, 455 const struct linux_sys_timerfd_create_args *uap, register_t *retval) 456 { 457 /* { 458 syscallarg(clockid_t) clock_id; 459 syscallarg(int) flags; 460 } */ 461 int nflags = 0; 462 clockid_t id; 463 int error; 464 465 error = linux_to_native_clockid(&id, SCARG(uap, clock_id)); 466 if (error) { 467 return error; 468 } 469 470 if (SCARG(uap, flags) & ~(LINUX_TFD_CLOEXEC | LINUX_TFD_NONBLOCK)) { 471 return EINVAL; 472 } 473 if (SCARG(uap, flags) & LINUX_TFD_CLOEXEC) { 474 nflags |= TFD_CLOEXEC; 475 } 476 if (SCARG(uap, flags) & LINUX_TFD_NONBLOCK) { 477 nflags |= TFD_NONBLOCK; 478 } 479 480 return do_timerfd_create(l, id, nflags, retval); 481 } 482 483 int 484 linux_sys_timerfd_gettime(struct lwp *l, 485 const struct linux_sys_timerfd_gettime_args *uap, register_t *retval) 486 { 487 /* { 488 syscallarg(int) fd; 489 syscallarg(struct linux_itimerspec *) tim; 490 } */ 491 struct itimerspec its; 492 struct linux_itimerspec lits; 493 int error; 494 495 error = do_timerfd_gettime(l, SCARG(uap, fd), &its, retval); 496 if (error == 0) { 497 native_to_linux_itimerspec(&lits, &its); 498 error = copyout(&lits, SCARG(uap, tim), sizeof(lits)); 499 } 500 501 return error; 502 } 503 504 int 505 linux_to_native_timerfd_settime_flags(int *nflagsp, int lflags) 506 { 507 int nflags = 0; 508 509 if (lflags & ~(LINUX_TFD_TIMER_ABSTIME | 510 LINUX_TFD_TIMER_CANCEL_ON_SET)) { 511 return EINVAL; 512 } 513 if (lflags & LINUX_TFD_TIMER_ABSTIME) { 514 nflags |= TFD_TIMER_ABSTIME; 515 } 516 if (lflags & LINUX_TFD_TIMER_CANCEL_ON_SET) { 517 nflags |= TFD_TIMER_CANCEL_ON_SET; 518 } 519 520 *nflagsp = nflags; 521 522 return 0; 523 } 524 525 int 526 linux_sys_timerfd_settime(struct lwp *l, 527 const struct linux_sys_timerfd_settime_args *uap, register_t *retval) 528 { 529 /* { 530 syscallarg(int) fd; 531 syscallarg(int) flags; 532 syscallarg(const struct linux_itimerspec *) tim; 533 syscallarg(struct linux_itimerspec *) otim; 534 } */ 535 struct itimerspec nits, oits, *oitsp = NULL; 536 struct linux_itimerspec lits; 537 int nflags; 538 int error; 539 540 error = copyin(SCARG(uap, tim), &lits, sizeof(lits)); 541 if (error) { 542 return error; 543 } 544 linux_to_native_itimerspec(&nits, &lits); 545 546 error = linux_to_native_timerfd_settime_flags(&nflags, 547 SCARG(uap, flags)); 548 if (error) { 549 return error; 550 } 551 552 if (SCARG(uap, otim)) { 553 oitsp = &oits; 554 } 555 556 error = do_timerfd_settime(l, SCARG(uap, fd), nflags, 557 &nits, oitsp, retval); 558 if (error == 0 && oitsp != NULL) { 559 native_to_linux_itimerspec(&lits, oitsp); 560 error = copyout(&lits, SCARG(uap, otim), sizeof(lits)); 561 } 562 563 return error; 564 } 565 566 #define LINUX_TFD_IOC_SET_TICKS _LINUX_IOW('T', 0, uint64_t) 567 568 int 569 linux_ioctl_timerfd(struct lwp *l, const struct linux_sys_ioctl_args *uap, 570 register_t *retval) 571 { 572 /* { 573 syscallarg(int) fd; 574 syscallarg(u_long) com; 575 syscallarg(void *) data; 576 } */ 577 struct sys_ioctl_args ua; 578 579 SCARG(&ua, fd) = SCARG(uap, fd); 580 SCARG(&ua, data) = SCARG(uap, data); 581 582 switch (SCARG(uap, com)) { 583 case LINUX_TFD_IOC_SET_TICKS: 584 SCARG(&ua, com) = TFD_IOC_SET_TICKS; 585 break; 586 587 default: 588 return EINVAL; 589 } 590 591 return sys_ioctl(l, (const void *)&ua, retval); 592 } 593