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