aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeepa Dinamani <deepa.kernel@gmail.com>2018-03-14 00:03:31 -0400
committerArnd Bergmann <arnd@arndb.de>2018-04-19 07:31:39 -0400
commitea2ce8f3514e2074a1910d8d721842d7341d5c81 (patch)
tree6cd2f49fc736fa05993aaec0f6827c31aba9a617
parentacf8870a62afd4f1b3c0b695aaa619df355c0851 (diff)
time: Fix get_timespec64() for y2038 safe compat interfaces
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>
-rw-r--r--include/linux/time.h4
-rw-r--r--kernel/time/time.c14
2 files changed, 12 insertions, 6 deletions
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 @@
10extern struct timezone sys_tz; 10extern struct timezone sys_tz;
11 11
12int get_timespec64(struct timespec64 *ts, 12int get_timespec64(struct timespec64 *ts,
13 const struct timespec __user *uts); 13 const struct __kernel_timespec __user *uts);
14int put_timespec64(const struct timespec64 *ts, 14int put_timespec64(const struct timespec64 *ts,
15 struct timespec __user *uts); 15 struct __kernel_timespec __user *uts);
16int get_itimerspec64(struct itimerspec64 *it, 16int get_itimerspec64(struct itimerspec64 *it,
17 const struct itimerspec __user *uit); 17 const struct itimerspec __user *uit);
18int put_itimerspec64(const struct itimerspec64 *it, 18int 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,
853} 853}
854 854
855int get_timespec64(struct timespec64 *ts, 855int get_timespec64(struct timespec64 *ts,
856 const struct timespec __user *uts) 856 const struct __kernel_timespec __user *uts)
857{ 857{
858 struct timespec kts; 858 struct __kernel_timespec kts;
859 int ret; 859 int ret;
860 860
861 ret = copy_from_user(&kts, uts, sizeof(kts)); 861 ret = copy_from_user(&kts, uts, sizeof(kts));
@@ -863,6 +863,11 @@ int get_timespec64(struct timespec64 *ts,
863 return -EFAULT; 863 return -EFAULT;
864 864
865 ts->tv_sec = kts.tv_sec; 865 ts->tv_sec = kts.tv_sec;
866
867 /* Zero out the padding for 32 bit systems or in compat mode */
868 if (IS_ENABLED(CONFIG_64BIT_TIME) && (!IS_ENABLED(CONFIG_64BIT) || in_compat_syscall()))
869 kts.tv_nsec &= 0xFFFFFFFFUL;
870
866 ts->tv_nsec = kts.tv_nsec; 871 ts->tv_nsec = kts.tv_nsec;
867 872
868 return 0; 873 return 0;
@@ -870,12 +875,13 @@ int get_timespec64(struct timespec64 *ts,
870EXPORT_SYMBOL_GPL(get_timespec64); 875EXPORT_SYMBOL_GPL(get_timespec64);
871 876
872int put_timespec64(const struct timespec64 *ts, 877int put_timespec64(const struct timespec64 *ts,
873 struct timespec __user *uts) 878 struct __kernel_timespec __user *uts)
874{ 879{
875 struct timespec kts = { 880 struct __kernel_timespec kts = {
876 .tv_sec = ts->tv_sec, 881 .tv_sec = ts->tv_sec,
877 .tv_nsec = ts->tv_nsec 882 .tv_nsec = ts->tv_nsec
878 }; 883 };
884
879 return copy_to_user(uts, &kts, sizeof(kts)) ? -EFAULT : 0; 885 return copy_to_user(uts, &kts, sizeof(kts)) ? -EFAULT : 0;
880} 886}
881EXPORT_SYMBOL_GPL(put_timespec64); 887EXPORT_SYMBOL_GPL(put_timespec64);