Isolate time_t data types for clock/timer syscalls
Subsystems (6)
v3 cover Isolate time_t data types for clock/timer syscalls
The series aims at isolating data conversions of time_t based structures:
struct timespec and struct itimerspec at user space boundaries. This helps to later change the underlying types to handle y2038 changes to these.
The series is an update to Arnd Bergmann's previous series:
http://sourceware.org/ml/libc-alpha/2015-05/msg00070.html
Changes since v1:
* Rebased and removed common code paths on the tip linux-next. Changes since v2:
* Removed accidental inclusion of wrong version of patch 3/7.
Deepa Dinamani (7):
time: add get_timespec64 and put_timespec64
time: introduce {get,put}_itimerspec64
posix-stubs: Conditionally include COMPAT_SYS_NI defines
posix-timers: Use get_timepsec64() and put_timespec64()
nanosleep: Use get_timepsec64() and put_timespec64()
timerfd: Use get_itimerspec64() and put_itimerspec64()
posix_clocks: Use get_itimerspec64() and put_itimerspec64()
fs/timerfd.c | 43 +++++++------ include/linux/compat.h | 6 ++ include/linux/hrtimer.h | 2 +- include/linux/posix-timers.h | 1 - include/linux/time.h | 18 ++++++ kernel/compat.c | 65 ++++++++++++++++++++ kernel/time/alarmtimer.c | 4 +- kernel/time/hrtimer.c | 30 ++++------ kernel/time/posix-cpu-timers.c | 8 +-- kernel/time/posix-stubs.c | 96 +++++++++++++++-------------- kernel/time/posix-timers.c | 133 +++++++++++++++-------------------------- kernel/time/time.c | 58 ++++++++++++++++++ 12 files changed, 287 insertions(+), 177 deletions(-)
Signature · 1 line
2.11.0
PATCH v3 1/7 time: add get_timespec64 and put_timespec64
Add helper functions to convert between struct timespec64 and struct timespec at userspace boundaries.
This is a preparatory patch to use timespec64 as the basic type internally in the kernel as timespec is not y2038 safe on 32 bit systems. The patch helps the cause by containing all data conversions at the userspace boundaries within these functions.
--- include/linux/compat.h | 2 ++ include/linux/time.h | 5 +++++ kernel/compat.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ kernel/time/time.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+)
include/linux/compat.h +2 -0
@@ -164,6 +164,8 @@ extern int compat_get_timespec(struct timespec *, const void __user *);extern int compat_put_timespec (const struct timespec *,void __user *);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 *);/* * This function convert a timespec if necessary and returns a *user
include/linux/time.h +5 -0
@@ -8,6 +8,11 @@extern struct timezone sys_tz; +int get_timespec64 (struct timespec64 *ts, +const struct timespec __user *uts); +int put_timespec64 (const struct timespec64 *ts, +struct timespec __user *uts); +#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) static inline int timespec_equal(const struct timespec *a,
kernel/compat.c +44 -0
50 lines not on this page · raw message
kernel/time/time.c +28 -0
@@ -890,3 +890,31 @@ struct timespec64 timespec64_add_safe(const struct timespec64 lhs,return res; } + +int get_timespec64 (struct timespec64 *ts, +const struct timespec __user *uts) +{ +struct timespec kts; +int ret; + + ret =copy_from_user (&kts, uts,sizeof (kts)); +if (ret) +return -EFAULT ; + + ts->tv_sec = kts.tv_sec; + 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 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);
Signature · 1 line
2.11.0
PATCH v3 2/7 time: introduce {get,put}_itimerspec64
In reply to Deepa DinamaniAs 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.
--- 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(-)
include/linux/compat.h +4 -0
@@ -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
include/linux/posix-timers.h +0 -1
@@ -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
include/linux/time.h +13 -0
@@ -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
kernel/compat.c +21 -0
@@ -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
kernel/time/time.c +30 -0
@@ -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);
Signature · 1 line
2.11.0
PATCH v3 3/7 posix-stubs: Conditionally include COMPAT_SYS_NI defines
In reply to Deepa DinamaniThese apis only need to be defined if CONFIG_COMPAT is enabled.
--- kernel/time/posix-stubs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
kernel/time/posix-stubs.c +7 -6
@@ -41,12 +41,6 @@ SYS_NI(setitimer);#ifdef __ARCH_WANT_SYS_ALARMSYS_NI (alarm);#endif -COMPAT_SYS_NI (timer_create); -COMPAT_SYS_NI (clock_adjtime); -COMPAT_SYS_NI (timer_settime); -COMPAT_SYS_NI (timer_gettime); -COMPAT_SYS_NI (getitimer); -COMPAT_SYS_NI (setitimer);/* * We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC
@@ -138,6 +132,13 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, }#ifdef CONFIG_COMPAT +COMPAT_SYS_NI (timer_create); +COMPAT_SYS_NI (clock_adjtime); +COMPAT_SYS_NI (timer_settime); +COMPAT_SYS_NI (timer_gettime); +COMPAT_SYS_NI (getitimer); +COMPAT_SYS_NI (setitimer); + COMPAT_SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, struct compat_timespec __user *, tp) {
Signature · 1 line
2.11.0
PATCH v3 4/7 posix-timers: Use get_timepsec64() and put_timespec64()
In reply to Deepa DinamaniUsage of these apis and their compat versions makes the syscalls: clock_gettime, clock_settime, clock_getres and their compat implementations simpler.
This is a preparatory patch to isolate data conversions to struct timespec64 at userspace boundaries. This helps contain the changes needed to transition to new y2038 safe types.
--- kernel/time/posix-stubs.c | 83 +++++++++++++++++++++++++--------------------- kernel/time/posix-timers.c | 69 ++++++++++++++------------------------ 2 files changed, 70 insertions(+), 82 deletions(-)
kernel/time/posix-stubs.c +45 -38
@@ -51,40 +51,52 @@ SYS_NI(alarm); SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, const struct timespec __user *, tp) { -struct timespec64 new_tp64; -struct timespec new_tp; +struct timespec64 new_tp;if (which_clock !=CLOCK_REALTIME )return -EINVAL ; -if (copy_from_user (&new_tp, tp,sizeof (*tp))) +if (get_timespec64 (&new_tp, tp))return -EFAULT ; - new_tp64 =timespec_to_timespec64 (new_tp); -return do_sys_settimeofday64 (&new_tp64,NULL ); +return do_sys_settimeofday64 (&new_tp,NULL ); } -SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, - struct timespec __user *,tp) +int do_clock_gettime (clockid_t which_clock,struct timespec64 *tp) { -struct timespec64 kernel_tp64; -struct timespec kernel_tp; -switch (which_clock) { -case CLOCK_REALTIME :ktime_get_real_ts64 (&kernel_tp64);break ; -case CLOCK_MONOTONIC :ktime_get_ts64 (&kernel_tp64);break ; -case CLOCK_BOOTTIME :get_monotonic_boottime64 (&kernel_tp64);break ; -default :return -EINVAL ; +case CLOCK_REALTIME : +ktime_get_real_ts64 (tp); +break ; +case CLOCK_MONOTONIC : +ktime_get_ts64 (tp); +break ; +case CLOCK_BOOTTIME : +get_monotonic_boottime64 (tp); +break ; +default : +return -EINVAL ; } - kernel_tp =timespec64_to_timespec (kernel_tp64); -if (copy_to_user (tp, &kernel_tp,sizeof (kernel_tp))) +return 0 ; +} +SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, + struct timespec __user *, tp) +{ +int ret; +struct timespec64 kernel_tp; + + ret =do_clock_gettime (which_clock, &kernel_tp); +if (ret) +return ret; + +if (put_timespec64 (&kernel_tp, tp))return -EFAULT ;return 0 ; } SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __user *, tp) { -struct timespec rtn_tp = { +struct timespec64 rtn_tp = { .tv_sec =0 , .tv_nsec = hrtimer_resolution, };
@@ -93,7 +105,7 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __uscase CLOCK_REALTIME :case CLOCK_MONOTONIC :case CLOCK_BOOTTIME : -if (copy_to_user (tp, &rtn_tp,sizeof (rtn_tp))) +if (put_timespec64 (&rtn_tp, tp))return -EFAULT ;return 0 ;default :
@@ -142,41 +154,35 @@ COMPAT_SYS_NI(setitimer); COMPAT_SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, struct compat_timespec __user *, tp) { -struct timespec64 new_tp64; -struct timespec new_tp; +struct timespec64 new_tp;if (which_clock !=CLOCK_REALTIME )return -EINVAL ; -if (compat_get_timespec (&new_tp, tp)) +if (compat_get_timespec64 (&new_tp, tp))return -EFAULT ; - new_tp64 =timespec_to_timespec64 (new_tp); -return do_sys_settimeofday64 (&new_tp64,NULL ); +return do_sys_settimeofday64 (&new_tp,NULL ); } -COMPAT_SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, - struct compat_timespec __user *,tp) +COMPAT_SYSCALL_DEFINE2 (clock_gettime, clockid_t, which_clock, + struct compat_timespec __user *, tp) { -struct timespec64 kernel_tp64; -struct timespec kernel_tp; +int ret; +struct timespec64 kernel_tp; -switch (which_clock) { -case CLOCK_REALTIME :ktime_get_real_ts64 (&kernel_tp64);break ; -case CLOCK_MONOTONIC :ktime_get_ts64 (&kernel_tp64);break ; -case CLOCK_BOOTTIME :get_monotonic_boottime64 (&kernel_tp64);break ; -default :return -EINVAL ; - } + ret =do_clock_gettime (which_clock, &kernel_tp); +if (ret) +return ret; - kernel_tp =timespec64_to_timespec (kernel_tp64); -if (compat_put_timespec (&kernel_tp, tp)) +if (compat_put_timespec64 (&kernel_tp, tp))return -EFAULT ;return 0 ; } -COMPAT_SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, +COMPAT_SYSCALL_DEFINE2 (clock_getres, clockid_t, which_clock, struct compat_timespec __user *, tp) { -struct timespec rtn_tp = { +struct timespec64 rtn_tp = { .tv_sec =0 , .tv_nsec = hrtimer_resolution, };
@@ -185,13 +191,14 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,case CLOCK_REALTIME :case CLOCK_MONOTONIC :case CLOCK_BOOTTIME : -if (compat_put_timespec (&rtn_tp, tp)) +if (compat_put_timespec64 (&rtn_tp, tp))return -EFAULT ;return 0 ;default :return -EINVAL ; } } +COMPAT_SYSCALL_DEFINE4 (clock_nanosleep, clockid_t, which_clock, int, flags, struct compat_timespec __user *, rqtp, struct compat_timespec __user *, rmtp)
kernel/time/posix-timers.c +25 -44
135 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH v3 5/7 nanosleep: Use get_timepsec64() and put_timespec64()
In reply to Deepa DinamaniUsage of these apis and their compat versions makes the syscalls: clock_nanosleep and nanosleep and their compat implementations simpler.
This is a preparatory patch to isolate data conversions to struct timespec64 at userspace boundaries. This helps contain the changes needed to transition to new y2038 safe types.
--- include/linux/hrtimer.h | 2 +- kernel/time/alarmtimer.c | 4 ++-- kernel/time/hrtimer.c | 30 +++++++++++++----------------- kernel/time/posix-cpu-timers.c | 8 ++------ kernel/time/posix-timers.c | 20 ++++++++------------ 5 files changed, 26 insertions(+), 38 deletions(-)
include/linux/hrtimer.h +1 -1
@@ -453,7 +453,7 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer,/* Precise sleep: */ -extern int nanosleep_copyout (struct restart_block *,struct timespec *); +extern int nanosleep_copyout (struct restart_block *,struct timespec64 *);extern long hrtimer_nanosleep (const struct timespec64 *rqtp,const enum hrtimer_mode mode,const clockid_t clockid);
kernel/time/alarmtimer.c +2 -2
@@ -712,14 +712,14 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,alarmtimer_freezerset (absexp, type); restart = ¤t->restart_block;if (restart->nanosleep.type !=TT_NONE ) { -struct timespec rmt; +struct timespec64 rmt;ktime_t rem; rem =ktime_sub (absexp, alarm_bases[type].gettime ());if (rem <=0 )return 0 ; - rmt =ktime_to_timespec (rem); + rmt =ktime_to_timespec64 (rem);return nanosleep_copyout (restart, &rmt); }
kernel/time/hrtimer.c +13 -17
@@ -1440,17 +1440,17 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) }EXPORT_SYMBOL_GPL (hrtimer_init_sleeper); -int nanosleep_copyout (struct restart_block *restart,struct timespec *ts) +int nanosleep_copyout (struct restart_block *restart,struct timespec64 *ts) {switch (restart->nanosleep.type) {#ifdef CONFIG_COMPAT case TT_COMPAT : -if (compat_put_timespec (ts, restart->nanosleep.compat_rmtp)) +if (compat_put_timespec64 (ts, restart->nanosleep.compat_rmtp))return -EFAULT ;break ;#endif case TT_NATIVE : -if (copy_to_user (restart->nanosleep.rmtp, ts,sizeof (struct timespec ))) +if (put_timespec64 (ts, restart->nanosleep.rmtp))return -EFAULT ;break ;default :
@@ -1485,11 +1485,11 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod restart = ¤t->restart_block;if (restart->nanosleep.type !=TT_NONE ) {ktime_t rem =hrtimer_expires_remaining (&t->timer); -struct timespec rmt; +struct timespec64 rmt;if (rem <=0 )return 0 ; - rmt =ktime_to_timespec (rem); + rmt =ktime_to_timespec64 (rem);return nanosleep_copyout (restart, &rmt); }
@@ -1546,19 +1546,17 @@ long hrtimer_nanosleep(const struct timespec64 *rqtp, SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, struct timespec __user *, rmtp) { -struct timespec64 tu64; -struct timespec tu; +struct timespec64 tu; -if (copy_from_user (&tu, rqtp,sizeof (tu))) +if (get_timespec64 (&tu, rqtp))return -EFAULT ; - tu64 =timespec_to_timespec64 (tu); -if (!timespec64_valid (&tu64)) +if (!timespec64_valid (&tu))return -EINVAL ; current->restart_block.nanosleep.type = rmtp ?TT_NATIVE :TT_NONE ; current->restart_block.nanosleep.rmtp = rmtp; -return hrtimer_nanosleep (&tu64,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); +return hrtimer_nanosleep (&tu,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); }#ifdef CONFIG_COMPAT
@@ -1566,19 +1564,17 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, struct compat_timespec __user *, rmtp) { -struct timespec64 tu64; -struct timespec tu; +struct timespec64 tu; -if (compat_get_timespec (&tu, rqtp)) +if (compat_get_timespec64 (&tu, rqtp))return -EFAULT ; - tu64 =timespec_to_timespec64 (tu); -if (!timespec64_valid (&tu64)) +if (!timespec64_valid (&tu))return -EINVAL ; current->restart_block.nanosleep.type = rmtp ?TT_COMPAT :TT_NONE ; current->restart_block.nanosleep.compat_rmtp = rmtp; -return hrtimer_nanosleep (&tu64,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); +return hrtimer_nanosleep (&tu,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); }#endif
kernel/time/posix-cpu-timers.c +2 -6
@@ -1318,12 +1318,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,*/ restart = ¤t->restart_block; restart->nanosleep.expires = expires; -if (restart->nanosleep.type !=TT_NONE ) { -struct timespec ts; - - ts =timespec64_to_timespec (it.it_value); - error =nanosleep_copyout (restart, &ts); - } +if (restart->nanosleep.type !=TT_NONE ) + error =nanosleep_copyout (restart, &it.it_value); }return error;
kernel/time/posix-timers.c +8 -12
@@ -1207,26 +1207,24 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, struct timespec __user *, rmtp) {const struct k_clock *kc =clockid_to_kclock (which_clock); -struct timespec64 t64; -struct timespec t; +struct timespec64 t;if (!kc)return -EINVAL ;if (!kc->nsleep)return -ENANOSLEEP_NOTSUP ; -if (copy_from_user (&t, rqtp,sizeof (struct timespec ))) +if (get_timespec64 (&t, rqtp))return -EFAULT ; - t64 =timespec_to_timespec64 (t); -if (!timespec64_valid (&t64)) +if (!timespec64_valid (&t))return -EINVAL ;if (flags &TIMER_ABSTIME ) rmtp =NULL ; current->restart_block.nanosleep.type = rmtp ?TT_NATIVE :TT_NONE ; current->restart_block.nanosleep.rmtp = rmtp; -return kc->nsleep (which_clock, flags, &t64); +return kc->nsleep (which_clock, flags, &t); }#ifdef CONFIG_COMPAT
@@ -1235,26 +1233,24 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, struct compat_timespec __user *, rmtp) {const struct k_clock *kc =clockid_to_kclock (which_clock); -struct timespec64 t64; -struct timespec t; +struct timespec64 t;if (!kc)return -EINVAL ;if (!kc->nsleep)return -ENANOSLEEP_NOTSUP ; -if (compat_get_timespec (&t, rqtp)) +if (compat_get_timespec64 (&t, rqtp))return -EFAULT ; - t64 =timespec_to_timespec64 (t); -if (!timespec64_valid (&t64)) +if (!timespec64_valid (&t))return -EINVAL ;if (flags &TIMER_ABSTIME ) rmtp =NULL ; current->restart_block.nanosleep.type = rmtp ?TT_COMPAT :TT_NONE ; current->restart_block.nanosleep.compat_rmtp = rmtp; -return kc->nsleep (which_clock, flags, &t64); +return kc->nsleep (which_clock, flags, &t); }#endif
Signature · 1 line
2.11.0
PATCH v3 6/7 timerfd: Use get_itimerspec64() and put_itimerspec64()
In reply to Deepa DinamaniUsage of these apis and their compat versions makes the syscalls: timerfd_settime and timerfd_gettime and their compat implementations simpler.
This patch also serves as a preparatory patch for changing syscalls to use new time_t data types to support the y2038 effort by isolating the processing of user pointers through these apis.
--- fs/timerfd.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-)
fs/timerfd.c +21 -22
@@ -169,7 +169,7 @@ static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx) }static int timerfd_setup (struct timerfd_ctx *ctx,int flags, -const struct itimerspec *ktmr) +const struct itimerspec64 *ktmr) {enum hrtimer_mode htmode;ktime_t texp;
@@ -178,10 +178,10 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int flags, htmode = (flags &TFD_TIMER_ABSTIME ) ?HRTIMER_MODE_ABS :HRTIMER_MODE_REL ; - texp =timespec_to_ktime (ktmr->it_value); + texp =timespec64_to_ktime (ktmr->it_value); ctx->expired =0 ; ctx->ticks =0 ; - ctx->tintv =timespec_to_ktime (ktmr->it_interval); + ctx->tintv =timespec64_to_ktime (ktmr->it_interval);if (isalarm (ctx)) { alarm_init(&ctx->t.alarm,
@@ -432,16 +432,15 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) }static int do_timerfd_settime (int ufd,int flags, -const struct itimerspec *new, -struct itimerspec *old) +const struct itimerspec64 *new, +struct itimerspec64 *old) {struct fd f;struct timerfd_ctx *ctx;int ret;if ((flags & ~TFD_SETTIME_FLAGS ) || - !timespec_valid (&new->it_value) || - !timespec_valid (&new->it_interval)) + !itimerspec64_valid (new))return -EINVAL ; ret =timerfd_fget (ufd, &f);
@@ -487,8 +486,8 @@ static int do_timerfd_settime(int ufd, int flags,hrtimer_forward_now (&ctx->t.tmr, ctx->tintv); } - old->it_value =ktime_to_timespec (timerfd_get_remaining (ctx)); - old->it_interval =ktime_to_timespec (ctx->tintv); + old->it_value =ktime_to_timespec64 (timerfd_get_remaining (ctx)); + old->it_interval =ktime_to_timespec64 (ctx->tintv);/* * Re-program the timer to the new value ...
@@ -500,7 +499,7 @@ static int do_timerfd_settime(int ufd, int flags,return ret; } -static int do_timerfd_gettime (int ufd,struct itimerspec *t) +static int do_timerfd_gettime (int ufd,struct itimerspec64 *t) {struct fd f;struct timerfd_ctx *ctx;
@@ -525,8 +524,8 @@ static int do_timerfd_gettime(int ufd, struct itimerspec *t)hrtimer_restart (&ctx->t.tmr); } } - t->it_value =ktime_to_timespec (timerfd_get_remaining (ctx)); - t->it_interval =ktime_to_timespec (ctx->tintv); + t->it_value =ktime_to_timespec64 (timerfd_get_remaining (ctx)); + t->it_interval =ktime_to_timespec64 (ctx->tintv);spin_unlock_irq (&ctx->wqh.lock);fdput (f);return 0 ;
@@ -536,15 +535,15 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, const struct itimerspec __user *, utmr, struct itimerspec __user *, otmr) { - struct itimerspec new, old; + struct itimerspec64 new, old;int ret; -if (copy_from_user (&new, utmr,sizeof (new))) +if (get_itimerspec64 (&new, utmr))return -EFAULT ; ret =do_timerfd_settime (ufd, flags, &new, &old);if (ret)return ret; -if (otmr &©_to_user (otmr, &old,sizeof (old))) +if (otmr &&put_itimerspec64 (&old, otmr))return -EFAULT ;return ret;
@@ -552,11 +551,11 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) { -struct itimerspec kotmr; +struct itimerspec64 kotmr;int ret =do_timerfd_gettime (ufd, &kotmr);if (ret)return ret; -return copy_to_user (otmr, &kotmr,sizeof (kotmr)) ? -EFAULT :0 ; +return put_itimerspec64 (&kotmr, otmr) ? -EFAULT :0 ; }#ifdef CONFIG_COMPAT
@@ -564,15 +563,15 @@ COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, const struct compat_itimerspec __user *, utmr, struct compat_itimerspec __user *, otmr) { - struct itimerspec new, old; + struct itimerspec64 new, old;int ret; -if (get_compat_itimerspec (&new, utmr)) +if (get_compat_itimerspec64 (&new, utmr))return -EFAULT ; ret =do_timerfd_settime (ufd, flags, &new, &old);if (ret)return ret; -if (otmr &&put_compat_itimerspec (otmr, &old)) +if (otmr &&put_compat_itimerspec64 (&old, otmr))return -EFAULT ;return ret; }
@@ -580,10 +579,10 @@ COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,COMPAT_SYSCALL_DEFINE2 (timerfd_gettime, int, ufd, struct compat_itimerspec __user *, otmr) { -struct itimerspec kotmr; +struct itimerspec64 kotmr;int ret =do_timerfd_gettime (ufd, &kotmr);if (ret)return ret; -return put_compat_itimerspec (otmr, &kotmr) ? -EFAULT :0 ; +return put_compat_itimerspec64 (&kotmr, otmr) ? -EFAULT :0 ; }#endif
Signature · 1 line
2.11.0
PATCH v3 7/7 posix_clocks: Use get_itimerspec64() and put_itimerspec64()
In reply to Deepa DinamaniUsage of these apis and their compat versions makes the syscalls: timer_settime and timer_gettime and their compat implementations simpler.
This patch also serves as a preparatory patch for changing syscalls to use new time_t data types to support the y2038 effort by isolating the processing of user pointers through these apis.
--- kernel/time/posix-timers.c | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-)
kernel/time/posix-timers.c +16 -28
@@ -739,13 +739,11 @@ static int do_timer_gettime(timer_t timer_id, struct itimerspec64 *setting)SYSCALL_DEFINE2 (timer_gettime, timer_t, timer_id, struct itimerspec __user *, setting) { -struct itimerspec64 cur_setting64; +struct itimerspec64 cur_setting; -int ret =do_timer_gettime (timer_id, &cur_setting64); +int ret =do_timer_gettime (timer_id, &cur_setting);if (!ret) { -struct itimerspec cur_setting; - cur_setting =itimerspec64_to_itimerspec (&cur_setting64); -if (copy_to_user (setting, &cur_setting,sizeof (cur_setting))) +if (put_itimerspec64 (&cur_setting, setting)) ret = -EFAULT ; }return ret;
@@ -755,13 +753,11 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,COMPAT_SYSCALL_DEFINE2 (timer_gettime, timer_t, timer_id, struct compat_itimerspec __user *, setting) { -struct itimerspec64 cur_setting64; +struct itimerspec64 cur_setting; -int ret =do_timer_gettime (timer_id, &cur_setting64); +int ret =do_timer_gettime (timer_id, &cur_setting);if (!ret) { -struct itimerspec cur_setting; - cur_setting =itimerspec64_to_itimerspec (&cur_setting64); -if (put_compat_itimerspec (setting, &cur_setting)) +if (put_compat_itimerspec64 (&cur_setting, setting)) ret = -EFAULT ; }return ret;
@@ -907,23 +903,19 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, const struct itimerspec __user *, new_setting, struct itimerspec __user *, old_setting) { - struct itimerspec64 new_spec64, old_spec64; -struct itimerspec64 *rtn = old_setting ? &old_spec64 :NULL ; -struct itimerspec new_spec; + struct itimerspec64 new_spec, old_spec; +struct itimerspec64 *rtn = old_setting ? &old_spec :NULL ;int error =0 ;if (!new_setting)return -EINVAL ; -if (copy_from_user (&new_spec, new_setting,sizeof (new_spec))) +if (get_itimerspec64 (&new_spec, new_setting))return -EFAULT ; - new_spec64 =itimerspec_to_itimerspec64 (&new_spec); - error =do_timer_settime (timer_id, flags, &new_spec64, rtn); + error =do_timer_settime (timer_id, flags, &new_spec, rtn);if (!error && old_setting) { -struct itimerspec old_spec; - old_spec =itimerspec64_to_itimerspec (&old_spec64); -if (copy_to_user (old_setting, &old_spec,sizeof (old_spec))) +if (put_itimerspec64 (&old_spec, old_setting)) error = -EFAULT ; }return error;
@@ -934,22 +926,18 @@ COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, struct compat_itimerspec __user *, new, struct compat_itimerspec __user *, old) { - struct itimerspec64 new_spec64, old_spec64; -struct itimerspec64 *rtn = old ? &old_spec64 :NULL ; -struct itimerspec new_spec; + struct itimerspec64 new_spec, old_spec; +struct itimerspec64 *rtn = old ? &old_spec :NULL ;int error =0 ;if (!new)return -EINVAL ; -if (get_compat_itimerspec (&new_spec, new)) +if (get_compat_itimerspec64 (&new_spec, new))return -EFAULT ; - new_spec64 =itimerspec_to_itimerspec64 (&new_spec); - error =do_timer_settime (timer_id, flags, &new_spec64, rtn); + error =do_timer_settime (timer_id, flags, &new_spec, rtn);if (!error && old) { -struct itimerspec old_spec; - old_spec =itimerspec64_to_itimerspec (&old_spec64); -if (put_compat_itimerspec (old, &old_spec)) +if (put_compat_itimerspec64 (&old_spec, old)) error = -EFAULT ; }return error;
Signature · 1 line
2.11.0
Al Viro
maintainerQuoted 4 lines · Deepa Dinamani
The series aims at isolating data conversions of
time_tbased structures:
struct timespec and struct itimerspec at user space boundaries. This helps to later change the underlying types to handle y2038 changes to these.
Nice... A few questions:
* what about setitimer(2)? Right now that's the only remaining user of get_compat_itimerval(); similar for getitimer(2) and put_compat_itimerval().
* you have two callers of get_compat_itimerspec64(); one is followed by itimerspec64_valid(), another - by its open-coded analogue. The same goes for get_itimerspec64(); wouldn't it be better to have both check the validity immediately and simply fail with -EINVAL? Matter of taste, but...
* should __sys_recvmmsg() switch to timespec64?
Al Viro
maintainerQuoted 11 lines · Al Viro
Quoted 4 lines · Deepa Dinamani
The series aims at isolating data conversions of
time_tbased structures:
struct timespec and struct itimerspec at user space boundaries. This helps to later change the underlying types to handle y2038 changes to these.Nice... A few questions:
* what about setitimer(2)? Right now that's the only remaining user of
get_compat_itimerval(); similar for getitimer(2) andput_compat_itimerval().
Quoted 7 lines
* you have two callers of
get_compat_itimerspec64(); one is followed byitimerspec64_valid(), another - by its open-coded analogue. The same goes forget_itimerspec64(); wouldn't it be better to have both check the validity immediately and simply fail with-EINVAL? Matter of taste, but...* should
__sys_recvmmsg()switch to timespec64?
While we are at it - do we need any locking for accesses of ->sk_stamp?
* ax25, ipx, netrom, qrtr: sock_get_timestamp() done under lock_sock().
* bluetooth: without (and case next door in the same switch is
grabbing/dropping lock_sock, so it's not held by caller either)
* ipv4, ipv6, packet, can: without
* irda: without, checks for NULL sock->sk for some reason (other
cases do not, so if we ever get there with NULL ->sk, we are fucked). Incidentally, TIOCINQ in there looks fishy - what's to prevent us from losing CPU just as skb_peek() returns, with skb getting freed by the time we regain it and go looking at skb->len? Don't we need at least to hold ->lock on queue we are peeking into?
* rose: without, and TIOCINQ there looks similar to irda one
* x25: without, with the same odd check for NULL sock->sk
* atm: without, apparently. Same unprotected skb_peek() on
TIOCINQ...
* atalk: ditto.
Quoted 10 lines · Al Viro
Quoted 4 lines · Deepa Dinamani
The series aims at isolating data conversions of
time_tbased structures:
struct timespec and struct itimerspec at user space boundaries. This helps to later change the underlying types to handle y2038 changes to these.Nice... A few questions:
* what about setitimer(2)? Right now that's the only remaining user of
get_compat_itimerval(); similar for getitimer(2) andput_compat_itimerval().
We do not plan to support these beyond y2038 on 32 bit systems. timer_settime() and timer_gettime() are considered to be replacements for these, respectively.
There is also going to be a cleanup of timeval/ timespec/ time_t data types and apis after the new syscalls are ready.
At that time I might choose to get rid of these itimerval apis. I'm not sure yet.
Quoted 5 lines
* you have two callers of
get_compat_itimerspec64(); one is followed byitimerspec64_valid(), another - by its open-coded analogue. The same goes forget_itimerspec64(); wouldn't it be better to have both check the validity immediately and simply fail with-EINVAL? Matter of taste, but...
This is what I thought also. And, in fact this is how I had it in one of the earlier version of my series.
But, the utimensat(2) is what I consider provides a counter example of why this is a bad idea.
There is no reason you should not be able to read the itimerspec64 and not check for validity soon after. Meaning there can be special markers like UTIME_NOW and UTIME_OMIT in the nanosecond field which will make the validity check fail. But, is perfectly normal for the syscall under consideration.
Quoted 1 line
* should
__sys_recvmmsg()switch to timespec64?
Socket timestamps will be handled in a different series. These could be done a few ways like adding a new flag to recv syscall variants or defining new timestamp types. The above call will be changed at that time.
-Deepa
Quoted 12 lines · Deepa Dinamani
Quoted 10 lines · Al Viro
Quoted 4 lines · Deepa Dinamani
The series aims at isolating data conversions of
time_tbased structures:
struct timespec and struct itimerspec at user space boundaries. This helps to later change the underlying types to handle y2038 changes to these.Nice... A few questions:
* what about setitimer(2)? Right now that's the only remaining user of
get_compat_itimerval(); similar for getitimer(2) andput_compat_itimerval().
Quoted 8 lines
We do not plan to support these beyond y2038 on 32 bit systems.
timer_settime()andtimer_gettime()are considered to be replacements for these, respectively.There is also going to be a cleanup of timeval/ timespec/
time_tdata types and apis after the new syscalls are ready.
At that time I might choose to get rid of these itimerval apis. I'm not sure yet.
I see that internally, alarm/getitimer/setitimer all use ktime_t, so one possible solution would be to push down the use of ktime_t into the callers and do both the conversion and range check in the user copy function.
Quoted 6 lines
Quoted 5 lines
* you have two callers of
get_compat_itimerspec64(); one is followed byitimerspec64_valid(), another - by its open-coded analogue. The same goes forget_itimerspec64(); wouldn't it be better to have both check the validity immediately and simply fail with-EINVAL? Matter of taste, but...
Quoted 9 lines
This is what I thought also. And, in fact this is how I had it in one of the earlier version of my series.
But, the utimensat(2) is what I consider provides a counter example of why this is a bad idea.
There is no reason you should not be able to read the itimerspec64 and not check for validity soon after. Meaning there can be special markers likeUTIME_NOWandUTIME_OMITin the nanosecond field which will make the validity check fail. But, is perfectly normal for the syscall under consideration.
If this is the only case we find, we could create another get_utimes_arg() (and compat_get_utimes_arg()) helper just for this one, which then copies both timespec structures at once and does the appropriate checks.
Another problem might be interfaces that don't have a range check today with existing users that may pass invalid data and expect it to succeed (or fail in a particular way). We probably want to add range checks here in most cases, but having the option of not doing the checking in some cases may be useful. Maybe I'm just overly cautious here though.
Arnd
Quoted 19 lines
Quoted 10 lines
Quoted 9 lines
Quoted 4 lines
The series aims at isolating data conversions of
time_tbased structures:
struct timespec and struct itimerspec at user space boundaries. This helps to later change the underlying types to handle y2038 changes to these.Nice... A few questions:
* what about setitimer(2)? Right now that's the only remaining user of
get_compat_itimerval(); similar for getitimer(2) andput_compat_itimerval().Quoted 8 lines
We do not plan to support these beyond y2038 on 32 bit systems.
timer_settime()andtimer_gettime()are considered to be replacements for these, respectively.There is also going to be a cleanup of timeval/ timespec/
time_tdata types and apis after the new syscalls are ready.
At that time I might choose to get rid of these itimerval apis. I'm not sure yet.
Quoted 4 lines
I see that internally, alarm/getitimer/setitimer all use
ktime_t, so one possible solution would be to push down the use ofktime_tinto the callers and do both the conversion and range check in the user copy function.
Right. This is one way of doing it. I was asking if you guys are okay with doing this as a cleanup series later or would you like for it to be part of the current series?
-Deepa
Quoted 22 lines · Arnd Bergmann
Quoted 12 lines · Deepa Dinamani
Quoted 10 lines · Al Viro
Quoted 4 lines · Deepa Dinamani
The series aims at isolating data conversions of
time_tbased structures:
struct timespec and struct itimerspec at user space boundaries. This helps to later change the underlying types to handle y2038 changes to these.Nice... A few questions:
* what about setitimer(2)? Right now that's the only remaining user of
get_compat_itimerval(); similar for getitimer(2) andput_compat_itimerval().Quoted 8 lines
We do not plan to support these beyond y2038 on 32 bit systems.
timer_settime()andtimer_gettime()are considered to be replacements for these, respectively.There is also going to be a cleanup of timeval/ timespec/
time_tdata types and apis after the new syscalls are ready.
At that time I might choose to get rid of these itimerval apis. I'm not sure yet.
Quoted 4 lines
I see that internally, alarm/getitimer/setitimer all use
ktime_t, so one possible solution would be to push down the use ofktime_tinto the callers and do both the conversion and range check in the user copy function.
We still can decide to not support the itimer API with the new y2038 ready syscalls.
Actually there is no real need to do so because the itimer interfaces are relative and never absolute. Keeping relative time limited to 68 years from now should be good enough :)
Thanks,
tglx
Quoted 28 lines · Thomas Gleixner
Quoted 22 lines · Arnd Bergmann
Quoted 12 lines · Deepa Dinamani
Quoted 10 lines · Al Viro
Quoted 4 lines · Deepa Dinamani
The series aims at isolating data conversions of
time_tbased structures:
struct timespec and struct itimerspec at user space boundaries. This helps to later change the underlying types to handle y2038 changes to these.Nice... A few questions:
* what about setitimer(2)? Right now that's the only remaining user of
get_compat_itimerval(); similar for getitimer(2) andput_compat_itimerval().Quoted 8 lines
We do not plan to support these beyond y2038 on 32 bit systems.
timer_settime()andtimer_gettime()are considered to be replacements for these, respectively.There is also going to be a cleanup of timeval/ timespec/
time_tdata types and apis after the new syscalls are ready.
At that time I might choose to get rid of these itimerval apis. I'm not sure yet.Quoted 4 lines
I see that internally, alarm/getitimer/setitimer all use
ktime_t, so one possible solution would be to push down the use ofktime_tinto the callers and do both the conversion and range check in the user copy function.
Quoted 6 lines
We still can decide to not support the itimer API with the new y2038 ready syscalls.
Actually there is no real need to do so because the itimer interfaces are relative and never absolute. Keeping relative time limited to 68 years from now should be good enough :)
I really want to have all syscalls to use 64-bit time_t for the new API, otherwise
we get into the really silly state where even for future architectures, glibc has to convert the 64-bit time_t coming from an application into a 32-bit timeval to pass it to the kernel, which then converts it back to an internal type (64-bit time_t or ktime_t).
In case of the itimer interfaces, this is really no question though, as Deepa said, since glibc can simply implement the new version by calling timer_create/timer_settime instead of calling the 32-bit setitimer. timer_settime() needs to take 64-bit arguments anyway because it can use either relative or absolute arguments.
Arnd