1 /* $NetBSD: kern_time_50.c,v 1.37 2021/09/07 11:43:02 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 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 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: kern_time_50.c,v 1.37 2021/09/07 11:43:02 riastradh Exp $"); 33 34 #ifdef _KERNEL_OPT 35 #include "opt_compat_netbsd.h" 36 #include "opt_aio.h" 37 #include "opt_ntp.h" 38 #include "opt_mqueue.h" 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/conf.h> 43 #include <sys/systm.h> 44 #include <sys/namei.h> 45 #include <sys/filedesc.h> 46 #include <sys/kernel.h> 47 #include <sys/file.h> 48 #include <sys/stat.h> 49 #include <sys/socketvar.h> 50 #include <sys/vnode.h> 51 #include <sys/proc.h> 52 #include <sys/uio.h> 53 #include <sys/dirent.h> 54 #include <sys/kauth.h> 55 #include <sys/time.h> 56 #include <sys/timex.h> 57 #include <sys/clockctl.h> 58 #include <sys/aio.h> 59 #include <sys/poll.h> 60 #include <sys/syscall.h> 61 #include <sys/syscallargs.h> 62 #include <sys/syscallvar.h> 63 #include <sys/sysctl.h> 64 #include <sys/resource.h> 65 #include <sys/compat_stub.h> 66 67 #include <compat/common/compat_util.h> 68 #include <compat/common/compat_mod.h> 69 #include <compat/sys/time.h> 70 #include <compat/sys/timex.h> 71 #include <compat/sys/resource.h> 72 #include <compat/sys/clockctl.h> 73 74 struct timeval50 boottime50; 75 76 static const struct syscall_package kern_time_50_syscalls[] = { 77 { SYS_compat_50_clock_gettime, 0, 78 (sy_call_t *)compat_50_sys_clock_gettime }, 79 { SYS_compat_50_clock_settime, 0, 80 (sy_call_t *)compat_50_sys_clock_settime }, 81 { SYS_compat_50_clock_getres, 0, 82 (sy_call_t *)compat_50_sys_clock_getres}, 83 { SYS_compat_50_nanosleep, 0, (sy_call_t *)compat_50_sys_nanosleep }, 84 { SYS_compat_50_gettimeofday, 0, 85 (sy_call_t *)compat_50_sys_gettimeofday }, 86 { SYS_compat_50_settimeofday, 0, 87 (sy_call_t *)compat_50_sys_settimeofday }, 88 { SYS_compat_50_adjtime, 0, (sy_call_t *)compat_50_sys_adjtime }, 89 { SYS_compat_50_setitimer, 0, (sy_call_t *)compat_50_sys_setitimer }, 90 { SYS_compat_50_getitimer, 0, (sy_call_t *)compat_50_sys_getitimer }, 91 { SYS_compat_50_aio_suspend, 0, 92 (sy_call_t *)compat_50_sys_aio_suspend }, 93 { SYS_compat_50_mq_timedsend, 0, 94 (sy_call_t *)compat_50_sys_mq_timedsend }, 95 { SYS_compat_50_mq_timedreceive, 0, 96 (sy_call_t *)compat_50_sys_mq_timedreceive }, 97 { SYS_compat_50_getrusage, 0, (sy_call_t *)compat_50_sys_getrusage }, 98 { SYS_compat_50_timer_settime, 0, 99 (sy_call_t *)compat_50_sys_timer_settime }, 100 { SYS_compat_50_timer_gettime, 0, 101 (sy_call_t *)compat_50_sys_timer_gettime }, 102 { SYS_compat_50___ntp_gettime30, 0, 103 (sy_call_t *)compat_50_sys___ntp_gettime30 }, 104 { 0, 0, NULL } 105 }; 106 107 int 108 compat_50_sys_clock_gettime(struct lwp *l, 109 const struct compat_50_sys_clock_gettime_args *uap, register_t *retval) 110 { 111 /* { 112 syscallarg(clockid_t) clock_id; 113 syscallarg(struct timespec50 *) tp; 114 } */ 115 int error; 116 struct timespec ats; 117 struct timespec50 ats50; 118 119 error = clock_gettime1(SCARG(uap, clock_id), &ats); 120 if (error != 0) 121 return error; 122 123 timespec_to_timespec50(&ats, &ats50); 124 125 return copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 126 } 127 128 /* ARGSUSED */ 129 int 130 compat_50_sys_clock_settime(struct lwp *l, 131 const struct compat_50_sys_clock_settime_args *uap, register_t *retval) 132 { 133 /* { 134 syscallarg(clockid_t) clock_id; 135 syscallarg(const struct timespec50 *) tp; 136 } */ 137 int error; 138 struct timespec ats; 139 struct timespec50 ats50; 140 141 error = copyin(SCARG(uap, tp), &ats50, sizeof(ats50)); 142 if (error) 143 return error; 144 timespec50_to_timespec(&ats50, &ats); 145 146 return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, 147 true); 148 } 149 150 151 int 152 compat_50_sys_clock_getres(struct lwp *l, 153 const struct compat_50_sys_clock_getres_args *uap, register_t *retval) 154 { 155 /* { 156 syscallarg(clockid_t) clock_id; 157 syscallarg(struct timespec50 *) tp; 158 } */ 159 struct timespec50 ats50; 160 struct timespec ats; 161 int error; 162 163 error = clock_getres1(SCARG(uap, clock_id), &ats); 164 if (error != 0) 165 return error; 166 167 if (SCARG(uap, tp)) { 168 timespec_to_timespec50(&ats, &ats50); 169 error = copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 170 } 171 172 return error; 173 } 174 175 /* ARGSUSED */ 176 int 177 compat_50_sys_nanosleep(struct lwp *l, 178 const struct compat_50_sys_nanosleep_args *uap, register_t *retval) 179 { 180 /* { 181 syscallarg(struct timespec50 *) rqtp; 182 syscallarg(struct timespec50 *) rmtp; 183 } */ 184 struct timespec rmt, rqt; 185 struct timespec50 rmt50, rqt50; 186 int error, error1; 187 188 error = copyin(SCARG(uap, rqtp), &rqt50, sizeof(rqt50)); 189 if (error) 190 return error; 191 timespec50_to_timespec(&rqt50, &rqt); 192 193 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, 194 SCARG(uap, rmtp) ? &rmt : NULL); 195 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 196 return error; 197 198 timespec_to_timespec50(&rmt, &rmt50); 199 error1 = copyout(&rmt50, SCARG(uap, rmtp), sizeof(*SCARG(uap, rmtp))); 200 return error1 ? error1 : error; 201 } 202 203 /* ARGSUSED */ 204 int 205 compat_50_sys_gettimeofday(struct lwp *l, 206 const struct compat_50_sys_gettimeofday_args *uap, register_t *retval) 207 { 208 /* { 209 syscallarg(struct timeval50 *) tp; 210 syscallarg(void *) tzp; really "struct timezone *"; 211 } */ 212 struct timeval atv; 213 struct timeval50 atv50; 214 int error = 0; 215 struct timezone tzfake; 216 217 if (SCARG(uap, tp)) { 218 microtime(&atv); 219 timeval_to_timeval50(&atv, &atv50); 220 error = copyout(&atv50, SCARG(uap, tp), sizeof(*SCARG(uap, tp))); 221 if (error) 222 return error; 223 } 224 if (SCARG(uap, tzp)) { 225 /* 226 * NetBSD has no kernel notion of time zone, so we just 227 * fake up a timezone struct and return it if demanded. 228 */ 229 memset(&tzfake, 0, sizeof(tzfake)); 230 tzfake.tz_minuteswest = 0; 231 tzfake.tz_dsttime = 0; 232 error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); 233 } 234 return error; 235 } 236 237 /* ARGSUSED */ 238 int 239 compat_50_sys_settimeofday(struct lwp *l, 240 const struct compat_50_sys_settimeofday_args *uap, register_t *retval) 241 { 242 /* { 243 syscallarg(const struct timeval50 *) tv; 244 syscallarg(const void *) tzp; really "const struct timezone *"; 245 } */ 246 struct timeval50 atv50; 247 struct timeval atv; 248 int error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); 249 if (error) 250 return error; 251 timeval50_to_timeval(&atv50, &atv); 252 return settimeofday1(&atv, false, SCARG(uap, tzp), l, true); 253 } 254 255 /* ARGSUSED */ 256 int 257 compat_50_sys_adjtime(struct lwp *l, 258 const struct compat_50_sys_adjtime_args *uap, register_t *retval) 259 { 260 /* { 261 syscallarg(const struct timeval50 *) delta; 262 syscallarg(struct timeval50 *) olddelta; 263 } */ 264 int error; 265 struct timeval50 delta50, olddelta50; 266 struct timeval delta, olddelta; 267 268 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, 269 KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) 270 return error; 271 272 if (SCARG(uap, delta)) { 273 error = copyin(SCARG(uap, delta), &delta50, 274 sizeof(*SCARG(uap, delta))); 275 if (error) 276 return (error); 277 timeval50_to_timeval(&delta50, &delta); 278 } 279 adjtime1(SCARG(uap, delta) ? &delta : NULL, 280 SCARG(uap, olddelta) ? &olddelta : NULL, l->l_proc); 281 if (SCARG(uap, olddelta)) { 282 timeval_to_timeval50(&olddelta, &olddelta50); 283 error = copyout(&olddelta50, SCARG(uap, olddelta), 284 sizeof(*SCARG(uap, olddelta))); 285 } 286 return error; 287 } 288 289 /* BSD routine to set/arm an interval timer. */ 290 /* ARGSUSED */ 291 int 292 compat_50_sys_getitimer(struct lwp *l, 293 const struct compat_50_sys_getitimer_args *uap, register_t *retval) 294 { 295 /* { 296 syscallarg(int) which; 297 syscallarg(struct itimerval50 *) itv; 298 } */ 299 struct proc *p = l->l_proc; 300 struct itimerval aitv; 301 struct itimerval50 aitv50; 302 int error; 303 304 error = dogetitimer(p, SCARG(uap, which), &aitv); 305 if (error) 306 return error; 307 itimerval_to_itimerval50(&aitv, &aitv50); 308 return copyout(&aitv50, SCARG(uap, itv), sizeof(*SCARG(uap, itv))); 309 } 310 311 int 312 compat_50_sys_setitimer(struct lwp *l, 313 const struct compat_50_sys_setitimer_args *uap, register_t *retval) 314 { 315 /* { 316 syscallarg(int) which; 317 syscallarg(const struct itimerval50 *) itv; 318 syscallarg(struct itimerval50 *) oitv; 319 } */ 320 struct proc *p = l->l_proc; 321 int which = SCARG(uap, which); 322 struct compat_50_sys_getitimer_args getargs; 323 const struct itimerval50 *itvp; 324 struct itimerval50 aitv50; 325 struct itimerval aitv; 326 int error; 327 328 itvp = SCARG(uap, itv); 329 if (itvp && 330 (error = copyin(itvp, &aitv50, sizeof(aitv50))) != 0) 331 return (error); 332 itimerval50_to_itimerval(&aitv50, &aitv); 333 if (SCARG(uap, oitv) != NULL) { 334 SCARG(&getargs, which) = which; 335 SCARG(&getargs, itv) = SCARG(uap, oitv); 336 if ((error = compat_50_sys_getitimer(l, &getargs, retval)) != 0) 337 return (error); 338 } 339 if (itvp == 0) 340 return (0); 341 342 return dosetitimer(p, which, &aitv); 343 } 344 345 int 346 compat_50_sys_aio_suspend(struct lwp *l, 347 const struct compat_50_sys_aio_suspend_args *uap, register_t *retval) 348 { 349 /* { 350 syscallarg(const struct aiocb *const[]) list; 351 syscallarg(int) nent; 352 syscallarg(const struct timespec50 *) timeout; 353 } */ 354 #ifdef AIO 355 struct aiocb **list; 356 struct timespec ts; 357 struct timespec50 ts50; 358 int error, nent; 359 360 nent = SCARG(uap, nent); 361 if (nent <= 0 || nent > aio_listio_max) 362 return EAGAIN; 363 364 if (SCARG(uap, timeout)) { 365 /* Convert timespec to ticks */ 366 error = copyin(SCARG(uap, timeout), &ts50, 367 sizeof(*SCARG(uap, timeout))); 368 if (error) 369 return error; 370 timespec50_to_timespec(&ts50, &ts); 371 } 372 list = kmem_alloc(nent * sizeof(*list), KM_SLEEP); 373 error = copyin(SCARG(uap, list), list, nent * sizeof(*list)); 374 if (error) 375 goto out; 376 error = aio_suspend1(l, list, nent, SCARG(uap, timeout) ? &ts : NULL); 377 out: 378 kmem_free(list, nent * sizeof(*list)); 379 return error; 380 #else 381 return ENOSYS; 382 #endif 383 } 384 385 int 386 compat_50_sys_mq_timedsend(struct lwp *l, 387 const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval) 388 { 389 /* { 390 syscallarg(mqd_t) mqdes; 391 syscallarg(const char *) msg_ptr; 392 syscallarg(size_t) msg_len; 393 syscallarg(unsigned) msg_prio; 394 syscallarg(const struct timespec50 *) abs_timeout; 395 } */ 396 #ifdef MQUEUE 397 struct timespec50 ts50; 398 struct timespec ts, *tsp; 399 int error; 400 401 /* Get and convert time value */ 402 if (SCARG(uap, abs_timeout)) { 403 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 404 if (error) 405 return error; 406 timespec50_to_timespec(&ts50, &ts); 407 tsp = &ts; 408 } else { 409 tsp = NULL; 410 } 411 412 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 413 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); 414 #else 415 return ENOSYS; 416 #endif 417 } 418 419 int 420 compat_50_sys_mq_timedreceive(struct lwp *l, 421 const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval) 422 { 423 /* { 424 syscallarg(mqd_t) mqdes; 425 syscallarg(char *) msg_ptr; 426 syscallarg(size_t) msg_len; 427 syscallarg(unsigned *) msg_prio; 428 syscallarg(const struct timespec50 *) abs_timeout; 429 } */ 430 #ifdef MQUEUE 431 struct timespec ts, *tsp; 432 struct timespec50 ts50; 433 ssize_t mlen; 434 int error; 435 436 /* Get and convert time value */ 437 if (SCARG(uap, abs_timeout)) { 438 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 439 if (error) 440 return error; 441 442 timespec50_to_timespec(&ts50, &ts); 443 tsp = &ts; 444 } else { 445 tsp = NULL; 446 } 447 448 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 449 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); 450 if (error == 0) 451 *retval = mlen; 452 453 return error; 454 #else 455 return ENOSYS; 456 #endif 457 } 458 459 void 460 rusage_to_rusage50(const struct rusage *ru, struct rusage50 *ru50) 461 { 462 memset(ru50, 0, sizeof(*ru50)); 463 (void)memcpy(&ru50->ru_first, &ru->ru_first, 464 (char *)&ru50->ru_last - (char *)&ru50->ru_first + 465 sizeof(ru50->ru_last)); 466 ru50->ru_maxrss = ru->ru_maxrss; 467 timeval_to_timeval50(&ru->ru_utime, &ru50->ru_utime); 468 timeval_to_timeval50(&ru->ru_stime, &ru50->ru_stime); 469 } 470 471 int 472 compat_50_sys_getrusage(struct lwp *l, 473 const struct compat_50_sys_getrusage_args *uap, register_t *retval) 474 { 475 /* { 476 syscallarg(int) who; 477 syscallarg(struct rusage50 *) rusage; 478 } */ 479 int error; 480 struct rusage ru; 481 struct rusage50 ru50; 482 struct proc *p = l->l_proc; 483 484 error = getrusage1(p, SCARG(uap, who), &ru); 485 if (error != 0) 486 return error; 487 488 rusage_to_rusage50(&ru, &ru50); 489 return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 490 } 491 492 493 /* Return the time remaining until a POSIX timer fires. */ 494 int 495 compat_50_sys_timer_gettime(struct lwp *l, 496 const struct compat_50_sys_timer_gettime_args *uap, register_t *retval) 497 { 498 /* { 499 syscallarg(timer_t) timerid; 500 syscallarg(struct itimerspec50 *) value; 501 } */ 502 struct itimerspec its; 503 struct itimerspec50 its50; 504 int error; 505 506 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, 507 &its)) != 0) 508 return error; 509 itimerspec_to_itimerspec50(&its, &its50); 510 511 return copyout(&its50, SCARG(uap, value), sizeof(its50)); 512 } 513 514 /* Set and arm a POSIX realtime timer */ 515 int 516 compat_50_sys_timer_settime(struct lwp *l, 517 const struct compat_50_sys_timer_settime_args *uap, register_t *retval) 518 { 519 /* { 520 syscallarg(timer_t) timerid; 521 syscallarg(int) flags; 522 syscallarg(const struct itimerspec50 *) value; 523 syscallarg(struct itimerspec50 *) ovalue; 524 } */ 525 int error; 526 struct itimerspec value, ovalue, *ovp = NULL; 527 struct itimerspec50 value50, ovalue50; 528 529 if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0) 530 return error; 531 532 itimerspec50_to_itimerspec(&value50, &value); 533 if (SCARG(uap, ovalue)) 534 ovp = &ovalue; 535 536 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 537 SCARG(uap, flags), l->l_proc)) != 0) 538 return error; 539 540 if (ovp) { 541 itimerspec_to_itimerspec50(&ovalue, &ovalue50); 542 return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50)); 543 } 544 return 0; 545 } 546 547 /* 548 * ntp_gettime() - NTP user application interface 549 */ 550 int 551 compat_50_sys___ntp_gettime30(struct lwp *l, 552 const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval) 553 { 554 if (vec_ntp_gettime == NULL) 555 return ENOSYS; /* No NTP available in kernel */ 556 557 /* { 558 syscallarg(struct ntptimeval *) ntvp; 559 } */ 560 struct ntptimeval ntv; 561 struct ntptimeval50 ntv50; 562 int error; 563 564 if (SCARG(uap, ntvp)) { 565 (*vec_ntp_gettime)(&ntv); 566 memset(&ntv50, 0, sizeof(ntv50)); 567 timespec_to_timespec50(&ntv.time, &ntv50.time); 568 ntv50.maxerror = ntv.maxerror; 569 ntv50.esterror = ntv.esterror; 570 ntv50.tai = ntv.tai; 571 ntv50.time_state = ntv.time_state; 572 573 error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50)); 574 if (error) 575 return error; 576 } 577 *retval = (*vec_ntp_timestatus)(); 578 return 0; 579 } 580 581 SYSCTL_SETUP(compat_sysctl_time, "Old system boottime") 582 { 583 struct timeval tv; 584 585 getmicroboottime(&tv); 586 timeval_to_timeval50(&tv, &boottime50); 587 588 sysctl_createv(clog, 0, NULL, NULL, 589 CTLFLAG_PERMANENT, 590 CTLTYPE_STRUCT, "oboottime", 591 SYSCTL_DESCR("System boot time"), 592 NULL, 0, &boottime50, sizeof(boottime50), 593 CTL_KERN, KERN_OBOOTTIME, CTL_EOL); 594 } 595 596 int 597 kern_time_50_init(void) 598 { 599 int error; 600 601 error = syscall_establish(NULL, kern_time_50_syscalls); 602 603 return error; 604 } 605 606 int 607 kern_time_50_fini(void) 608 { 609 int error; 610 611 error = syscall_disestablish(NULL, kern_time_50_syscalls); 612 613 return error; 614 } 615