1 /* $NetBSD: kern_time_50.c,v 1.36 2021/04/03 12:57:21 simonb 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.36 2021/04/03 12:57:21 simonb 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 tzfake.tz_minuteswest = 0; 230 tzfake.tz_dsttime = 0; 231 error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); 232 } 233 return error; 234 } 235 236 /* ARGSUSED */ 237 int 238 compat_50_sys_settimeofday(struct lwp *l, 239 const struct compat_50_sys_settimeofday_args *uap, register_t *retval) 240 { 241 /* { 242 syscallarg(const struct timeval50 *) tv; 243 syscallarg(const void *) tzp; really "const struct timezone *"; 244 } */ 245 struct timeval50 atv50; 246 struct timeval atv; 247 int error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); 248 if (error) 249 return error; 250 timeval50_to_timeval(&atv50, &atv); 251 return settimeofday1(&atv, false, SCARG(uap, tzp), l, true); 252 } 253 254 /* ARGSUSED */ 255 int 256 compat_50_sys_adjtime(struct lwp *l, 257 const struct compat_50_sys_adjtime_args *uap, register_t *retval) 258 { 259 /* { 260 syscallarg(const struct timeval50 *) delta; 261 syscallarg(struct timeval50 *) olddelta; 262 } */ 263 int error; 264 struct timeval50 delta50, olddelta50; 265 struct timeval delta, olddelta; 266 267 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, 268 KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) 269 return error; 270 271 if (SCARG(uap, delta)) { 272 error = copyin(SCARG(uap, delta), &delta50, 273 sizeof(*SCARG(uap, delta))); 274 if (error) 275 return (error); 276 timeval50_to_timeval(&delta50, &delta); 277 } 278 adjtime1(SCARG(uap, delta) ? &delta : NULL, 279 SCARG(uap, olddelta) ? &olddelta : NULL, l->l_proc); 280 if (SCARG(uap, olddelta)) { 281 timeval_to_timeval50(&olddelta, &olddelta50); 282 error = copyout(&olddelta50, SCARG(uap, olddelta), 283 sizeof(*SCARG(uap, olddelta))); 284 } 285 return error; 286 } 287 288 /* BSD routine to set/arm an interval timer. */ 289 /* ARGSUSED */ 290 int 291 compat_50_sys_getitimer(struct lwp *l, 292 const struct compat_50_sys_getitimer_args *uap, register_t *retval) 293 { 294 /* { 295 syscallarg(int) which; 296 syscallarg(struct itimerval50 *) itv; 297 } */ 298 struct proc *p = l->l_proc; 299 struct itimerval aitv; 300 struct itimerval50 aitv50; 301 int error; 302 303 error = dogetitimer(p, SCARG(uap, which), &aitv); 304 if (error) 305 return error; 306 itimerval_to_itimerval50(&aitv, &aitv50); 307 return copyout(&aitv50, SCARG(uap, itv), sizeof(*SCARG(uap, itv))); 308 } 309 310 int 311 compat_50_sys_setitimer(struct lwp *l, 312 const struct compat_50_sys_setitimer_args *uap, register_t *retval) 313 { 314 /* { 315 syscallarg(int) which; 316 syscallarg(const struct itimerval50 *) itv; 317 syscallarg(struct itimerval50 *) oitv; 318 } */ 319 struct proc *p = l->l_proc; 320 int which = SCARG(uap, which); 321 struct compat_50_sys_getitimer_args getargs; 322 const struct itimerval50 *itvp; 323 struct itimerval50 aitv50; 324 struct itimerval aitv; 325 int error; 326 327 itvp = SCARG(uap, itv); 328 if (itvp && 329 (error = copyin(itvp, &aitv50, sizeof(aitv50))) != 0) 330 return (error); 331 itimerval50_to_itimerval(&aitv50, &aitv); 332 if (SCARG(uap, oitv) != NULL) { 333 SCARG(&getargs, which) = which; 334 SCARG(&getargs, itv) = SCARG(uap, oitv); 335 if ((error = compat_50_sys_getitimer(l, &getargs, retval)) != 0) 336 return (error); 337 } 338 if (itvp == 0) 339 return (0); 340 341 return dosetitimer(p, which, &aitv); 342 } 343 344 int 345 compat_50_sys_aio_suspend(struct lwp *l, 346 const struct compat_50_sys_aio_suspend_args *uap, register_t *retval) 347 { 348 /* { 349 syscallarg(const struct aiocb *const[]) list; 350 syscallarg(int) nent; 351 syscallarg(const struct timespec50 *) timeout; 352 } */ 353 #ifdef AIO 354 struct aiocb **list; 355 struct timespec ts; 356 struct timespec50 ts50; 357 int error, nent; 358 359 nent = SCARG(uap, nent); 360 if (nent <= 0 || nent > aio_listio_max) 361 return EAGAIN; 362 363 if (SCARG(uap, timeout)) { 364 /* Convert timespec to ticks */ 365 error = copyin(SCARG(uap, timeout), &ts50, 366 sizeof(*SCARG(uap, timeout))); 367 if (error) 368 return error; 369 timespec50_to_timespec(&ts50, &ts); 370 } 371 list = kmem_alloc(nent * sizeof(*list), KM_SLEEP); 372 error = copyin(SCARG(uap, list), list, nent * sizeof(*list)); 373 if (error) 374 goto out; 375 error = aio_suspend1(l, list, nent, SCARG(uap, timeout) ? &ts : NULL); 376 out: 377 kmem_free(list, nent * sizeof(*list)); 378 return error; 379 #else 380 return ENOSYS; 381 #endif 382 } 383 384 int 385 compat_50_sys_mq_timedsend(struct lwp *l, 386 const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval) 387 { 388 /* { 389 syscallarg(mqd_t) mqdes; 390 syscallarg(const char *) msg_ptr; 391 syscallarg(size_t) msg_len; 392 syscallarg(unsigned) msg_prio; 393 syscallarg(const struct timespec50 *) abs_timeout; 394 } */ 395 #ifdef MQUEUE 396 struct timespec50 ts50; 397 struct timespec ts, *tsp; 398 int error; 399 400 /* Get and convert time value */ 401 if (SCARG(uap, abs_timeout)) { 402 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 403 if (error) 404 return error; 405 timespec50_to_timespec(&ts50, &ts); 406 tsp = &ts; 407 } else { 408 tsp = NULL; 409 } 410 411 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 412 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); 413 #else 414 return ENOSYS; 415 #endif 416 } 417 418 int 419 compat_50_sys_mq_timedreceive(struct lwp *l, 420 const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval) 421 { 422 /* { 423 syscallarg(mqd_t) mqdes; 424 syscallarg(char *) msg_ptr; 425 syscallarg(size_t) msg_len; 426 syscallarg(unsigned *) msg_prio; 427 syscallarg(const struct timespec50 *) abs_timeout; 428 } */ 429 #ifdef MQUEUE 430 struct timespec ts, *tsp; 431 struct timespec50 ts50; 432 ssize_t mlen; 433 int error; 434 435 /* Get and convert time value */ 436 if (SCARG(uap, abs_timeout)) { 437 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 438 if (error) 439 return error; 440 441 timespec50_to_timespec(&ts50, &ts); 442 tsp = &ts; 443 } else { 444 tsp = NULL; 445 } 446 447 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 448 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); 449 if (error == 0) 450 *retval = mlen; 451 452 return error; 453 #else 454 return ENOSYS; 455 #endif 456 } 457 458 void 459 rusage_to_rusage50(const struct rusage *ru, struct rusage50 *ru50) 460 { 461 (void)memcpy(&ru50->ru_first, &ru->ru_first, 462 (char *)&ru50->ru_last - (char *)&ru50->ru_first + 463 sizeof(ru50->ru_last)); 464 ru50->ru_maxrss = ru->ru_maxrss; 465 timeval_to_timeval50(&ru->ru_utime, &ru50->ru_utime); 466 timeval_to_timeval50(&ru->ru_stime, &ru50->ru_stime); 467 } 468 469 int 470 compat_50_sys_getrusage(struct lwp *l, 471 const struct compat_50_sys_getrusage_args *uap, register_t *retval) 472 { 473 /* { 474 syscallarg(int) who; 475 syscallarg(struct rusage50 *) rusage; 476 } */ 477 int error; 478 struct rusage ru; 479 struct rusage50 ru50; 480 struct proc *p = l->l_proc; 481 482 error = getrusage1(p, SCARG(uap, who), &ru); 483 if (error != 0) 484 return error; 485 486 rusage_to_rusage50(&ru, &ru50); 487 return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 488 } 489 490 491 /* Return the time remaining until a POSIX timer fires. */ 492 int 493 compat_50_sys_timer_gettime(struct lwp *l, 494 const struct compat_50_sys_timer_gettime_args *uap, register_t *retval) 495 { 496 /* { 497 syscallarg(timer_t) timerid; 498 syscallarg(struct itimerspec50 *) value; 499 } */ 500 struct itimerspec its; 501 struct itimerspec50 its50; 502 int error; 503 504 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, 505 &its)) != 0) 506 return error; 507 itimerspec_to_itimerspec50(&its, &its50); 508 509 return copyout(&its50, SCARG(uap, value), sizeof(its50)); 510 } 511 512 /* Set and arm a POSIX realtime timer */ 513 int 514 compat_50_sys_timer_settime(struct lwp *l, 515 const struct compat_50_sys_timer_settime_args *uap, register_t *retval) 516 { 517 /* { 518 syscallarg(timer_t) timerid; 519 syscallarg(int) flags; 520 syscallarg(const struct itimerspec50 *) value; 521 syscallarg(struct itimerspec50 *) ovalue; 522 } */ 523 int error; 524 struct itimerspec value, ovalue, *ovp = NULL; 525 struct itimerspec50 value50, ovalue50; 526 527 if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0) 528 return error; 529 530 itimerspec50_to_itimerspec(&value50, &value); 531 if (SCARG(uap, ovalue)) 532 ovp = &ovalue; 533 534 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 535 SCARG(uap, flags), l->l_proc)) != 0) 536 return error; 537 538 if (ovp) { 539 itimerspec_to_itimerspec50(&ovalue, &ovalue50); 540 return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50)); 541 } 542 return 0; 543 } 544 545 /* 546 * ntp_gettime() - NTP user application interface 547 */ 548 int 549 compat_50_sys___ntp_gettime30(struct lwp *l, 550 const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval) 551 { 552 if (vec_ntp_gettime == NULL) 553 return ENOSYS; /* No NTP available in kernel */ 554 555 /* { 556 syscallarg(struct ntptimeval *) ntvp; 557 } */ 558 struct ntptimeval ntv; 559 struct ntptimeval50 ntv50; 560 int error; 561 562 if (SCARG(uap, ntvp)) { 563 (*vec_ntp_gettime)(&ntv); 564 memset(&ntv50, 0, sizeof(ntv50)); 565 timespec_to_timespec50(&ntv.time, &ntv50.time); 566 ntv50.maxerror = ntv.maxerror; 567 ntv50.esterror = ntv.esterror; 568 ntv50.tai = ntv.tai; 569 ntv50.time_state = ntv.time_state; 570 571 error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50)); 572 if (error) 573 return error; 574 } 575 *retval = (*vec_ntp_timestatus)(); 576 return 0; 577 } 578 579 SYSCTL_SETUP(compat_sysctl_time, "Old system boottime") 580 { 581 struct timeval tv; 582 583 getmicroboottime(&tv); 584 timeval_to_timeval50(&tv, &boottime50); 585 586 sysctl_createv(clog, 0, NULL, NULL, 587 CTLFLAG_PERMANENT, 588 CTLTYPE_STRUCT, "oboottime", 589 SYSCTL_DESCR("System boot time"), 590 NULL, 0, &boottime50, sizeof(boottime50), 591 CTL_KERN, KERN_OBOOTTIME, CTL_EOL); 592 } 593 594 int 595 kern_time_50_init(void) 596 { 597 int error; 598 599 error = syscall_establish(NULL, kern_time_50_syscalls); 600 601 return error; 602 } 603 604 int 605 kern_time_50_fini(void) 606 { 607 int error; 608 609 error = syscall_disestablish(NULL, kern_time_50_syscalls); 610 611 return error; 612 } 613