Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6684ba20 authored by H. Peter Anvin's avatar H. Peter Anvin
Browse files

compat: Add helper functions to read/write struct timeval, timespec



Add helper functions to read and write struct timeval and struct
timespec from userspace.  We already had helper functions for reading
and writing struct compat_timespec; add a set of functions to do the
same with struct timeval, and add a second suite of functions which
can be sensitive to COMPAT_USE_64BIT_TIME and access either 32- or
64-bit time structures.

This also exports these helper functions to modules.

Rename the existing inlines for converting between struct
compat_timeval and native struct timespec so we can have a saner
naming convention for the exported functions.

Suggested-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent 45e87781
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -87,10 +87,26 @@ typedef struct {
	compat_sigset_word	sig[_COMPAT_NSIG_WORDS];
} compat_sigset_t;

/*
 * These functions operate strictly on struct compat_time*
 */
extern int get_compat_timespec(struct timespec *,
			       const struct compat_timespec __user *);
extern int put_compat_timespec(const struct timespec *,
			       struct compat_timespec __user *);
extern int get_compat_timeval(struct timeval *,
			      const struct compat_timeval __user *);
extern int put_compat_timeval(const struct timeval *,
			      struct compat_timeval __user *);
/*
 * These functions operate on 32- or 64-bit specs depending on
 * COMPAT_USE_64BIT_TIME, hence the void user pointer arguments and the
 * naming as compat_get/put_ rather than get/put_compat_.
 */
extern int compat_get_timespec(struct timespec *, const void __user *);
extern int compat_put_timespec(const struct timespec *, void __user *);
extern int compat_get_timeval(struct timeval *, const void __user *);
extern int compat_put_timeval(const struct timeval *, void __user *);

struct compat_iovec {
	compat_uptr_t	iov_base;
+60 −8
Original line number Diff line number Diff line
@@ -31,10 +31,9 @@
#include <asm/uaccess.h>

/*
 * Note that the native side is already converted to a timespec, because
 * that's what we want anyway.
 * Get/set struct timeval with struct timespec on the native side
 */
static int compat_get_timeval(struct timespec *o,
static int compat_get_timeval_convert(struct timespec *o,
				      struct compat_timeval __user *i)
{
	long usec;
@@ -46,7 +45,7 @@ static int compat_get_timeval(struct timespec *o,
	return 0;
}

static int compat_put_timeval(struct compat_timeval __user *o,
static int compat_put_timeval_convert(struct compat_timeval __user *o,
				      struct timeval *i)
{
	return (put_user(i->tv_sec, &o->tv_sec) ||
@@ -117,7 +116,7 @@ asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
	if (tv) {
		struct timeval ktv;
		do_gettimeofday(&ktv);
		if (compat_put_timeval(tv, &ktv))
		if (compat_put_timeval_convert(tv, &ktv))
			return -EFAULT;
	}
	if (tz) {
@@ -135,7 +134,7 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
	struct timezone ktz;

	if (tv) {
		if (compat_get_timeval(&kts, tv))
		if (compat_get_timeval_convert(&kts, tv))
			return -EFAULT;
	}
	if (tz) {
@@ -146,12 +145,29 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
}

int get_compat_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
{
	return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) ||
			__get_user(tv->tv_sec, &ctv->tv_sec) ||
			__get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
}
EXPORT_SYMBOL_GPL(get_compat_timeval);

int put_compat_timeval(const struct timeval *tv, struct compat_timeval __user *ctv)
{
	return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) ||
			__put_user(tv->tv_sec, &ctv->tv_sec) ||
			__put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
}
EXPORT_SYMBOL_GPL(put_compat_timeval);

int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
{
	return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
			__get_user(ts->tv_sec, &cts->tv_sec) ||
			__get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}
EXPORT_SYMBOL_GPL(get_compat_timespec);

int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
{
@@ -161,6 +177,42 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
}
EXPORT_SYMBOL_GPL(put_compat_timespec);

int compat_get_timeval(struct timeval *tv, const void __user *utv)
{
	if (COMPAT_USE_64BIT_TIME)
		return copy_from_user(tv, utv, sizeof *tv) ? -EFAULT : 0;
	else
		return get_compat_timeval(tv, utv);
}
EXPORT_SYMBOL_GPL(compat_get_timeval);

int compat_put_timeval(const struct timeval *tv, void __user *utv)
{
	if (COMPAT_USE_64BIT_TIME)
		return copy_to_user(utv, tv, sizeof *tv) ? -EFAULT : 0;
	else
		return put_compat_timeval(tv, utv);
}
EXPORT_SYMBOL_GPL(compat_put_timeval);

int compat_get_timespec(struct timespec *ts, const void __user *uts)
{
	if (COMPAT_USE_64BIT_TIME)
		return copy_from_user(ts, uts, sizeof *ts) ? -EFAULT : 0;
	else
		return get_compat_timespec(ts, uts);
}
EXPORT_SYMBOL_GPL(compat_get_timespec);

int compat_put_timespec(const struct timespec *ts, void __user *uts)
{
	if (COMPAT_USE_64BIT_TIME)
		return copy_to_user(uts, ts, sizeof *ts) ? -EFAULT : 0;
	else
		return put_compat_timespec(ts, uts);
}
EXPORT_SYMBOL_GPL(compat_put_timespec);

static long compat_nanosleep_restart(struct restart_block *restart)
{
	struct compat_timespec __user *rmtp;