As we change the user space type for the timerfd and posix timer functions to newer data types, we need some form of conversion helpers to avoid duplicating that logic. Suggested-by: Arnd Bergmann <arnd@xxxxxxxx> Signed-off-by: Deepa Dinamani <deepa.kernel@xxxxxxxxx> --- include/linux/compat.h | 4 ++++ include/linux/posix-timers.h | 1 - include/linux/time.h | 13 +++++++++++++ kernel/compat.c | 21 +++++++++++++++++++++ kernel/time/time.c | 30 ++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/include/linux/compat.h b/include/linux/compat.h index 3eb04016ffa9..2ed54020ace0 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -166,6 +166,10 @@ extern int compat_get_timeval(struct timeval *, const void __user *); extern int compat_put_timeval(const struct timeval *, void __user *); extern int compat_get_timespec64(struct timespec64 *, const void __user *); extern int compat_put_timespec64(const struct timespec64 *, void __user *); +extern int get_compat_itimerspec64(struct itimerspec64 *its, + const struct compat_itimerspec __user *uits); +extern int put_compat_itimerspec64(const struct itimerspec64 *its, + struct compat_itimerspec __user *uits); /* * This function convert a timespec if necessary and returns a *user diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 29f1b7f09ced..62839fd04dce 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -113,5 +113,4 @@ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new); void posixtimer_rearm(struct siginfo *info); - #endif diff --git a/include/linux/time.h b/include/linux/time.h index 36afb579495f..f9858d7e6361 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -12,6 +12,10 @@ int get_timespec64(struct timespec64 *ts, const struct timespec __user *uts); int put_timespec64(const struct timespec64 *ts, struct timespec __user *uts); +int get_itimerspec64(struct itimerspec64 *it, + const struct itimerspec __user *uit); +int put_itimerspec64(const struct itimerspec64 *it, + struct itimerspec __user *uit); #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) @@ -275,4 +279,13 @@ static __always_inline void timespec_add_ns(struct timespec *a, u64 ns) a->tv_nsec = ns; } +static inline bool itimerspec64_valid(const struct itimerspec64 *its) +{ + if (!timespec64_valid(&(its->it_interval)) || + !timespec64_valid(&(its->it_value))) + return false; + + return true; +} + #endif diff --git a/kernel/compat.c b/kernel/compat.c index 73f26ba44a8a..a350deda503a 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -586,6 +586,27 @@ int put_compat_itimerspec(struct compat_itimerspec __user *dst, return 0; } +int get_compat_itimerspec64(struct itimerspec64 *its, + const struct compat_itimerspec __user *uits) +{ + + if (__compat_get_timespec64(&its->it_interval, &uits->it_interval) || + __compat_get_timespec64(&its->it_value, &uits->it_value)) + return -EFAULT; + return 0; +} +EXPORT_SYMBOL_GPL(get_compat_itimerspec64); + +int put_compat_itimerspec64(const struct itimerspec64 *its, + struct compat_itimerspec __user *uits) +{ + if (__compat_put_timespec64(&its->it_interval, &uits->it_interval) || + __compat_put_timespec64(&its->it_value, &uits->it_value)) + return -EFAULT; + return 0; +} +EXPORT_SYMBOL_GPL(put_compat_itimerspec64); + /* * We currently only need the following fields from the sigevent * structure: sigev_value, sigev_signo, sig_notify and (sometimes diff --git a/kernel/time/time.c b/kernel/time/time.c index adb9853ca6b0..44a8c1402133 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -918,3 +918,33 @@ int put_timespec64(const struct timespec64 *ts, return copy_to_user(uts, &kts, sizeof(kts)) ? -EFAULT : 0; } EXPORT_SYMBOL_GPL(put_timespec64); + +int get_itimerspec64(struct itimerspec64 *it, + const struct itimerspec __user *uit) +{ + int ret; + + ret = get_timespec64(&it->it_interval, &uit->it_interval); + if (ret) + return ret; + + ret = get_timespec64(&it->it_value, &uit->it_value); + + return ret; +} +EXPORT_SYMBOL_GPL(get_itimerspec64); + +int put_itimerspec64(const struct itimerspec64 *it, + struct itimerspec __user *uit) +{ + int ret; + + ret = put_timespec64(&it->it_interval, &uit->it_interval); + if (ret) + return ret; + + ret = put_timespec64(&it->it_value, &uit->it_value); + + return ret; +} +EXPORT_SYMBOL_GPL(put_itimerspec64); -- 2.11.0