Skip to content

Commit

Permalink
time: Fix get_timespec64() for y2038 safe compat interfaces
Browse files Browse the repository at this point in the history
get/put_timespec64() interfaces will eventually be used for
conversions between the new y2038 safe struct __kernel_timespec
and struct timespec64.

The new y2038 safe syscalls have a common entry for native
and compat interfaces.
On compat interfaces, the high order bits of nanoseconds
should be zeroed out. This is because the application code
or the libc do not guarantee zeroing of these. If used without
zeroing, kernel might be at risk of using timespec values
incorrectly.

Note that clearing of bits is dependent on CONFIG_64BIT_TIME
for now. This is until COMPAT_USE_64BIT_TIME has been handled
correctly. x86 will be the first architecture that will use the
CONFIG_64BIT_TIME.

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
  • Loading branch information
Deepa Dinamani authored and Arnd Bergmann committed Apr 19, 2018
1 parent acf8870 commit ea2ce8f
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 6 deletions.
4 changes: 2 additions & 2 deletions include/linux/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
extern struct timezone sys_tz;

int get_timespec64(struct timespec64 *ts,
const struct timespec __user *uts);
const struct __kernel_timespec __user *uts);
int put_timespec64(const struct timespec64 *ts,
struct timespec __user *uts);
struct __kernel_timespec __user *uts);
int get_itimerspec64(struct itimerspec64 *it,
const struct itimerspec __user *uit);
int put_itimerspec64(const struct itimerspec64 *it,
Expand Down
14 changes: 10 additions & 4 deletions kernel/time/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -853,29 +853,35 @@ struct timespec64 timespec64_add_safe(const struct timespec64 lhs,
}

int get_timespec64(struct timespec64 *ts,
const struct timespec __user *uts)
const struct __kernel_timespec __user *uts)
{
struct timespec kts;
struct __kernel_timespec kts;
int ret;

ret = copy_from_user(&kts, uts, sizeof(kts));
if (ret)
return -EFAULT;

ts->tv_sec = kts.tv_sec;

/* Zero out the padding for 32 bit systems or in compat mode */
if (IS_ENABLED(CONFIG_64BIT_TIME) && (!IS_ENABLED(CONFIG_64BIT) || in_compat_syscall()))
kts.tv_nsec &= 0xFFFFFFFFUL;

ts->tv_nsec = kts.tv_nsec;

return 0;
}
EXPORT_SYMBOL_GPL(get_timespec64);

int put_timespec64(const struct timespec64 *ts,
struct timespec __user *uts)
struct __kernel_timespec __user *uts)
{
struct timespec kts = {
struct __kernel_timespec kts = {
.tv_sec = ts->tv_sec,
.tv_nsec = ts->tv_nsec
};

return copy_to_user(uts, &kts, sizeof(kts)) ? -EFAULT : 0;
}
EXPORT_SYMBOL_GPL(put_timespec64);
Expand Down

0 comments on commit ea2ce8f

Please sign in to comment.