diff --git a/include/linux/time.h b/include/linux/time.h index 4b62a2c0a661..aed74463592d 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -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, diff --git a/kernel/time/time.c b/kernel/time/time.c index df61143a54f6..ccd751e95fcb 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -853,9 +853,9 @@ 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)); @@ -863,6 +863,11 @@ int get_timespec64(struct timespec64 *ts, 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; @@ -870,12 +875,13 @@ int get_timespec64(struct timespec64 *ts, 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);