Home | History | Annotate | Line # | Download | only in common
      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(&lts, &ts);
    235 	return copyout(&lts, 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), &lts, sizeof lts);
    255 	if (error != 0)
    256 		return error;
    257 
    258 	linux_to_native_timespec(&ts, &lts);
    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(&lts, &ts);
    284 	return copyout(&lts, 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