Hi,

This sets EINVAL on non-normal input for adjtime(2), clock_settime(2),
and settimeofday(2).

clock_settime and settimeofday take absolute times as input, and adjtime
is explicitly allowed to be a negative relative time, so timespecfix() is
inapplicable.

POSIX specifies that clock_settime(2) set EINVAL for non-normal input,
and we document this but don't actually do the check.  FreeBSD, NetBSD,
illumos, and Linux all check and set EINVAL.

Although adjtime(2) and settimeofday(2) are non-standard, the timeval
struct itself *is* specified by POSIX, and (almost?) every standard
system call using a timeval or a timespec is specified to set EINVAL
for non-normal input.  FreeBSD, illumos, and Linux set EINVAL for
adjtime(2) and settimeofday(2).

Maybe of note is that illumos sets EINVAL for adjtime(2) but that their
valid range for tv_usec is (-1000000, 1000000), which seems off: I'm
pretty sure you can represent all relevant absolute subseconds while
constraining tv_usec to [0, 1000000), the valid range used effectively
everywhere else.

If anything, consistent behavior is good, and most system calls validate
timeval/timespec inputs, so I think we ought to do the same for these.

ok?

--
Scott Cheloha

jmc:    Is past tense preferred in ERRORS?

        i.e. "<arg> specified" vs. "<arg> specifies"

Index: lib/libc/sys/adjtime.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/adjtime.2,v
retrieving revision 1.22
diff -u -p -r1.22 adjtime.2
--- lib/libc/sys/adjtime.2      10 Sep 2015 17:55:21 -0000      1.22
+++ lib/libc/sys/adjtime.2      10 May 2018 14:12:42 -0000
@@ -87,6 +87,11 @@ will fail if:
 .Bl -tag -width Er
 .It Bq Er EFAULT
 Either of the arguments point outside the process's allocated address space.
+.It Bq Er EINVAL
+The
+.Fn delta
+argument specifies a microsecond value less than zero or
+greater than or equal to 1 million.
 .It Bq Er EPERM
 The
 .Fn delta
Index: lib/libc/sys/clock_gettime.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/clock_gettime.2,v
retrieving revision 1.29
diff -u -p -r1.29 clock_gettime.2
--- lib/libc/sys/clock_gettime.2        18 Dec 2017 07:15:15 -0000      1.29
+++ lib/libc/sys/clock_gettime.2        10 May 2018 14:12:42 -0000
@@ -139,7 +139,8 @@ A user other than the superuser attempte
 .Fa clock_id
 specifies a clock that isn't settable,
 .Fa tp
-specifies a nanosecond value less than zero or greater than 1000 million,
+specifies a nanosecond value less than zero or
+greater than or equal to 1000 million,
 or a value outside the range of the specified clock.
 .El
 .Sh SEE ALSO
Index: lib/libc/sys/gettimeofday.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/gettimeofday.2,v
retrieving revision 1.29
diff -u -p -r1.29 gettimeofday.2
--- lib/libc/sys/gettimeofday.2 10 Sep 2015 17:55:21 -0000      1.29
+++ lib/libc/sys/gettimeofday.2 10 May 2018 14:12:42 -0000
@@ -118,8 +118,12 @@ An argument address referenced invalid m
 .Pp
 In addition,
 .Fn settimeofday
-may return the following error:
+may return the following errors:
 .Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa tp
+specified a microsecond value less than zero or
+greater than or equal to 1 million.
 .It Bq Er EPERM
 A user other than the superuser attempted to set the time.
 .El
Index: sys/kern/kern_time.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_time.c,v
retrieving revision 1.101
diff -u -p -r1.101 kern_time.c
--- sys/kern/kern_time.c        19 Feb 2018 08:59:52 -0000      1.101
+++ sys/kern/kern_time.c        10 May 2018 14:12:42 -0000
@@ -197,6 +197,8 @@ sys_clock_settime(struct proc *p, void *
        clock_id = SCARG(uap, clock_id);
        switch (clock_id) {
        case CLOCK_REALTIME:
+               if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000)
+                       return (EINVAL);
                if ((error = settime(&ats)) != 0)
                        return (error);
                break;
@@ -381,6 +383,8 @@ sys_settimeofday(struct proc *p, void *v
        if (tv) {
                struct timespec ts;
 
+               if (atv.tv_usec < 0 || atv.tv_usec >= 1000000)
+                       return (EINVAL);
                TIMEVAL_TO_TIMESPEC(&atv, &ts);
                if ((error = settime(&ts)) != 0)
                        return (error);
@@ -453,6 +457,8 @@ sys_adjtime(struct proc *p, void *v, reg
 
                if ((error = copyin(delta, &atv, sizeof(struct timeval))))
                        return (error);
+               if (atv.tv_usec < 0 || atv.tv_usec >= 1000000)
+                       return (EINVAL);
 
                /* XXX Check for overflow? */
                adjtimedelta = (int64_t)atv.tv_sec * 1000000 + atv.tv_usec;

Reply via email to