Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Feb 2017 07:56:42 +1100 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Dmitry Chagin <dchagin@freebsd.org>
Cc:        src-committers@freebsd.org, svn-src-all@freebsd.org,  svn-src-head@freebsd.org
Subject:   Re: svn commit: r314293 - head/sys/compat/linux
Message-ID:  <20170227070338.X992@besplex.bde.org>
In-Reply-To: <201702260940.v1Q9egOq029307@repo.freebsd.org>
References:  <201702260940.v1Q9egOq029307@repo.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 26 Feb 2017, Dmitry Chagin wrote:

> Log:
>  Return EOVERFLOW error in case then the size of tv_sec field of struct timespec
>  in COMPAT_LINUX32 Linuxulator's not equal to the size of native tv_sec.

This has several bugs, and it is silly to check the range of times (where
overflow can't happen occurs for normal times) while blindly truncating
security-related things like uids (where overflow happens for normal uids).

> Modified: head/sys/compat/linux/linux_time.c
> ==============================================================================
> --- head/sys/compat/linux/linux_time.c	Sun Feb 26 09:37:25 2017	(r314292)
> +++ head/sys/compat/linux/linux_time.c	Sun Feb 26 09:40:42 2017	(r314293)
> ...
> -void
> +int
> native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
> {
>
> 	LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp);
> -
> +#ifdef COMPAT_LINUX32
> +	if (ntp->tv_sec > INT_MAX &&

This doesn't use the parametrization that l_time_t is l_long = int32_t
when COMPAT_LINUX32, but uses an ugly ifdef, then assumes than
int == int32_t.

> +	    sizeof(ltp->tv_sec) != sizeof(ntp->tv_sec))
> +		return (EOVERFLOW);
> +#endif

Negative values are not checked for, so overflow can still occur.  Sometimes
negative values overlow to a positive value(e.g., bit pattern
0x8000000000000001 -> 1 in 2's complement.  Other times they overflow to
a negative value (e.g., 0x8000000080000001 -> 0x80000001 in 2's complement).

Overflowing values are very unlikely, and the check doesn't prevent them.
E.g., even COMPAT_32 APIs might set a time to 0x7fffffff.  The time overflows
to INT32_MIN 1 second later on 32-bit kernels.  The kernel shouldn't allow
setting such times, but does.  It is left to the user to avoid this foot-
shooting.  Since setting critical times is privileged, the user usually
doesn't do this.  On 64-bit kernels, setting such times works and no
overflow occurs for native times, but unsuspecting 32-bit applications
are broken, so again it is left to privileged users to avoid this foot-
shooting (now for 32-bit feet).

Similarly for negative times.  They are even less useful than times after
32-bit time_t overflows, but in some cases they are not errors so must
not be rejected or blindly truncated by conversion functions.

Overflow of tv_nsec is not checked for.  It really can't happen, since
although native time_t is required to be long by historical mistakes,
and long might tbe 64 bits or larger, on values between 0 and 10**9-1
are valid for it, and these are representable by 32-bit long.  This
depends on the conversion function only being from native times which
are presumably already active so have been checked for validity.

uids overflow routinely.  E.g., the error uid is (uid_t)-1 = 0xffffffff
and blind truncation of this in linux_uid16.c overflows to 0xffff which
is the 16-bit error uid (uid16_t)-1.  But 0xffff = 65535 is a valid
native uid.  The valid native uid 0x10000 overflows to 0 (root).
The valid native uid 0xfffffffe (nobody for nfs) overflows to 0xfffe
(nobody).

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20170227070338.X992>