xref: /netbsd/sys/compat/linux/common/linux_time.c (revision 5390d158)
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
linux_sys_gettimeofday(struct lwp * l,const struct linux_sys_gettimeofday_args * uap,register_t * retval)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
linux_sys_settimeofday(struct lwp * l,const struct linux_sys_settimeofday_args * uap,register_t * retval)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
native_to_linux_timespec(struct linux_timespec * ltp,const struct timespec * ntp)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
linux_to_native_timespec(struct timespec * ntp,const struct linux_timespec * ltp)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
native_to_linux_itimerspec(struct linux_itimerspec * litp,const struct itimerspec * nitp)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
linux_to_native_itimerspec(struct itimerspec * nitp,const struct linux_itimerspec * litp)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
linux_sys_nanosleep(struct lwp * l,const struct linux_sys_nanosleep_args * uap,register_t * retval)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
linux_to_native_clockid(clockid_t * n,clockid_t l)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
linux_sys_clock_gettime(struct lwp * l,const struct linux_sys_clock_gettime_args * uap,register_t * retval)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
linux_sys_clock_settime(struct lwp * l,const struct linux_sys_clock_settime_args * uap,register_t * retval)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
linux_sys_clock_getres(struct lwp * l,const struct linux_sys_clock_getres_args * uap,register_t * retval)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
linux_sys_clock_nanosleep(struct lwp * l,const struct linux_sys_clock_nanosleep_args * uap,register_t * retval)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
linux_to_native_timer_create_clockid(clockid_t * nid,clockid_t lid)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
linux_sys_timer_create(struct lwp * l,const struct linux_sys_timer_create_args * uap,register_t * retval)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
linux_sys_timer_settime(struct lwp * l,const struct linux_sys_timer_settime_args * uap,register_t * retval)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
linux_sys_timer_gettime(struct lwp * l,const struct linux_sys_timer_gettime_args * uap,register_t * retval)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
linux_sys_timerfd_create(struct lwp * l,const struct linux_sys_timerfd_create_args * uap,register_t * retval)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
linux_sys_timerfd_gettime(struct lwp * l,const struct linux_sys_timerfd_gettime_args * uap,register_t * retval)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
linux_to_native_timerfd_settime_flags(int * nflagsp,int lflags)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
linux_sys_timerfd_settime(struct lwp * l,const struct linux_sys_timerfd_settime_args * uap,register_t * retval)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
linux_ioctl_timerfd(struct lwp * l,const struct linux_sys_ioctl_args * uap,register_t * retval)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