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(<s, &ts);
235 return copyout(<s, 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), <s, sizeof lts);
255 if (error != 0)
256 return error;
257
258 linux_to_native_timespec(&ts, <s);
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(<s, &ts);
284 return copyout(<s, 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