y2038: time: avoid timespec usage in settimeofday()
The compat_get_timeval() and timeval_valid() interfaces are deprecated and getting removed along with the definition of struct timeval itself. Change the two implementations of the settimeofday() system call to open-code these helpers and completely avoid references to timeval. The timeval_valid() call is not needed any more here, only a check to avoid overflowing tv_nsec during the multiplication, as there is another range check in do_sys_settimeofday64(). Tested-by: syzbot+dccce9b26ba09ca49966@syzkaller.appspotmail.com Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
@@ -734,7 +734,7 @@ asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct g
|
|||||||
/* kernel/time.c */
|
/* kernel/time.c */
|
||||||
asmlinkage long sys_gettimeofday(struct __kernel_old_timeval __user *tv,
|
asmlinkage long sys_gettimeofday(struct __kernel_old_timeval __user *tv,
|
||||||
struct timezone __user *tz);
|
struct timezone __user *tz);
|
||||||
asmlinkage long sys_settimeofday(struct timeval __user *tv,
|
asmlinkage long sys_settimeofday(struct __kernel_old_timeval __user *tv,
|
||||||
struct timezone __user *tz);
|
struct timezone __user *tz);
|
||||||
asmlinkage long sys_adjtimex(struct __kernel_timex __user *txc_p);
|
asmlinkage long sys_adjtimex(struct __kernel_timex __user *txc_p);
|
||||||
asmlinkage long sys_adjtimex_time32(struct old_timex32 __user *txc_p);
|
asmlinkage long sys_adjtimex_time32(struct old_timex32 __user *txc_p);
|
||||||
|
|||||||
@@ -196,22 +196,21 @@ int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv,
|
SYSCALL_DEFINE2(settimeofday, struct __kernel_old_timeval __user *, tv,
|
||||||
struct timezone __user *, tz)
|
struct timezone __user *, tz)
|
||||||
{
|
{
|
||||||
struct timespec64 new_ts;
|
struct timespec64 new_ts;
|
||||||
struct timeval user_tv;
|
|
||||||
struct timezone new_tz;
|
struct timezone new_tz;
|
||||||
|
|
||||||
if (tv) {
|
if (tv) {
|
||||||
if (copy_from_user(&user_tv, tv, sizeof(*tv)))
|
if (get_user(new_ts.tv_sec, &tv->tv_sec) ||
|
||||||
|
get_user(new_ts.tv_nsec, &tv->tv_usec))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (!timeval_valid(&user_tv))
|
if (new_ts.tv_nsec > USEC_PER_SEC || new_ts.tv_nsec < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
new_ts.tv_sec = user_tv.tv_sec;
|
new_ts.tv_nsec *= NSEC_PER_USEC;
|
||||||
new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
|
|
||||||
}
|
}
|
||||||
if (tz) {
|
if (tz) {
|
||||||
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
|
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
|
||||||
@@ -245,18 +244,17 @@ COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv,
|
|||||||
struct timezone __user *, tz)
|
struct timezone __user *, tz)
|
||||||
{
|
{
|
||||||
struct timespec64 new_ts;
|
struct timespec64 new_ts;
|
||||||
struct timeval user_tv;
|
|
||||||
struct timezone new_tz;
|
struct timezone new_tz;
|
||||||
|
|
||||||
if (tv) {
|
if (tv) {
|
||||||
if (compat_get_timeval(&user_tv, tv))
|
if (get_user(new_ts.tv_sec, &tv->tv_sec) ||
|
||||||
|
get_user(new_ts.tv_nsec, &tv->tv_usec))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (!timeval_valid(&user_tv))
|
if (new_ts.tv_nsec > USEC_PER_SEC || new_ts.tv_nsec < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
new_ts.tv_sec = user_tv.tv_sec;
|
new_ts.tv_nsec *= NSEC_PER_USEC;
|
||||||
new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
|
|
||||||
}
|
}
|
||||||
if (tz) {
|
if (tz) {
|
||||||
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
|
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
|
||||||
|
|||||||
Reference in New Issue
Block a user