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