Skip to content

Commit

Permalink
compat: Get rid of (get|put)_compat_time(val|spec)
Browse files Browse the repository at this point in the history
We have two APIs for compatiblity timespec/val, with confusingly
similar names.  compat_(get|put)_time(val|spec) *do* handle the case
where COMPAT_USE_64BIT_TIME is set, whereas
(get|put)_compat_time(val|spec) do not.  This is an accident waiting
to happen.

Clean it up by favoring the full-service version; the limited version
is replaced with double-underscore versions static to kernel/compat.c.

A common pattern is to convert a struct timespec to kernel format in
an allocation on the user stack.  Unfortunately it is open-coded in
several places.  Since this allocation isn't actually needed if
COMPAT_USE_64BIT_TIME is true (since user format == kernel format)
encapsulate that whole pattern into the function
compat_convert_timespec().  An equivalent function should be written
for struct timeval if it is needed in the future.

Finally, get rid of compat_(get|put)_timeval_convert(): each was only
used once, and the latter was not even doing what the function said
(no conversion actually was being done.)  Moving the conversion into
compat_sys_settimeofday() itself makes the code much more similar to
sys_settimeofday() itself.

v3: Remove unused compat_convert_timeval().

v2: Drop bogus "const" in the destination argument for
    compat_convert_time*().

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: Alexander Viro <[email protected]>
Cc: Hans Verkuil <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Manfred Spraul <[email protected]>
Cc: Mateusz Guzik <[email protected]>
Cc: Rafael Aquini <[email protected]>
Cc: Davidlohr Bueso <[email protected]>
Cc: Stephen Rothwell <[email protected]>
Cc: Dan Carpenter <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Tested-by: H.J. Lu <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
  • Loading branch information
H. Peter Anvin committed Feb 2, 2014
1 parent 5cb480f commit 81993e8
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 97 deletions.
2 changes: 1 addition & 1 deletion drivers/media/v4l2-core/v4l2-compat-ioctl32.c
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u
copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
put_user(kp->pending, &up->pending) ||
put_user(kp->sequence, &up->sequence) ||
put_compat_timespec(&kp->timestamp, &up->timestamp) ||
compat_put_timespec(&kp->timestamp, &up->timestamp) ||
put_user(kp->id, &up->id) ||
copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
return -EFAULT;
Expand Down
6 changes: 3 additions & 3 deletions fs/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filena
struct timespec tv[2];

if (t) {
if (get_compat_timespec(&tv[0], &t[0]) ||
get_compat_timespec(&tv[1], &t[1]))
if (compat_get_timespec(&tv[0], &t[0]) ||
compat_get_timespec(&tv[1], &t[1]))
return -EFAULT;

if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
Expand Down Expand Up @@ -512,7 +512,7 @@ compat_sys_io_getevents(aio_context_t ctx_id,
nr * sizeof(struct io_event))))
goto out;
if (timeout) {
if (get_compat_timespec(&t, timeout))
if (compat_get_timespec(&t, timeout))
goto out;

ut = compat_alloc_user_space(sizeof(*ut));
Expand Down
23 changes: 10 additions & 13 deletions include/linux/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,27 +140,24 @@ struct compat_sigaction {
compat_sigset_t sa_mask __packed;
};

/*
* 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_.
* COMPAT_USE_64BIT_TIME, hence the void user pointer arguments.
*/
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 *);

/*
* This function convert a timespec if necessary and returns a *user
* space* pointer. If no conversion is necessary, it returns the
* initial pointer. NULL is a legitimate argument and will always
* output NULL.
*/
extern int compat_convert_timespec(struct timespec __user **,
const void __user *);

struct compat_iovec {
compat_uptr_t iov_base;
compat_size_t iov_len;
Expand Down
12 changes: 3 additions & 9 deletions ipc/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,14 +752,8 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
unsigned nsops, const struct compat_timespec __user *timeout)
{
struct timespec __user *ts64 = NULL;
if (timeout) {
struct timespec ts;
ts64 = compat_alloc_user_space(sizeof(*ts64));
if (get_compat_timespec(&ts, timeout))
return -EFAULT;
if (copy_to_user(ts64, &ts, sizeof(ts)))
return -EFAULT;
}
struct timespec __user *ts64;
if (compat_convert_timespec(&ts64, timeout))
return -EFAULT;
return sys_semtimedop(semid, tsems, nsops, ts64);
}
19 changes: 3 additions & 16 deletions ipc/compat_mq.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,14 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name,
return sys_mq_open(u_name, oflag, mode, p);
}

static int compat_prepare_timeout(struct timespec __user **p,
const struct compat_timespec __user *u)
{
struct timespec ts;
if (!u) {
*p = NULL;
return 0;
}
*p = compat_alloc_user_space(sizeof(ts));
if (get_compat_timespec(&ts, u) || copy_to_user(*p, &ts, sizeof(ts)))
return -EFAULT;
return 0;
}

asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
const char __user *u_msg_ptr,
size_t msg_len, unsigned int msg_prio,
const struct compat_timespec __user *u_abs_timeout)
{
struct timespec __user *u_ts;

if (compat_prepare_timeout(&u_ts, u_abs_timeout))
if (compat_convert_timespec(&u_ts, u_abs_timeout))
return -EFAULT;

return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
Expand All @@ -98,7 +84,8 @@ asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
const struct compat_timespec __user *u_abs_timeout)
{
struct timespec __user *u_ts;
if (compat_prepare_timeout(&u_ts, u_abs_timeout))

if (compat_convert_timespec(&u_ts, u_abs_timeout))
return -EFAULT;

return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
Expand Down
Loading

0 comments on commit 81993e8

Please sign in to comment.