Commit ea3b25e1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'timers-compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull timer-related user access updates from Al Viro:
 "Continuation of timers-related stuff (there had been more, but my
  parts of that series are already merged via timers/core). This is more
  of y2038 work by Deepa Dinamani, partially disrupted by the
  unification of native and compat timers-related syscalls"

* 'timers-compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  posix_clocks: Use get_itimerspec64() and put_itimerspec64()
  timerfd: Use get_itimerspec64() and put_itimerspec64()
  nanosleep: Use get_timespec64() and put_timespec64()
  posix-timers: Use get_timespec64() and put_timespec64()
  posix-stubs: Conditionally include COMPAT_SYS_NI defines
  time: introduce {get,put}_itimerspec64
  time: add get_timespec64 and put_timespec64
parents 89fbf538 725816e8
...@@ -169,7 +169,7 @@ static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx) ...@@ -169,7 +169,7 @@ static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
} }
static int timerfd_setup(struct timerfd_ctx *ctx, int flags, static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
const struct itimerspec *ktmr) const struct itimerspec64 *ktmr)
{ {
enum hrtimer_mode htmode; enum hrtimer_mode htmode;
ktime_t texp; ktime_t texp;
...@@ -178,10 +178,10 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int flags, ...@@ -178,10 +178,10 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
htmode = (flags & TFD_TIMER_ABSTIME) ? htmode = (flags & TFD_TIMER_ABSTIME) ?
HRTIMER_MODE_ABS: HRTIMER_MODE_REL; HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
texp = timespec_to_ktime(ktmr->it_value); texp = timespec64_to_ktime(ktmr->it_value);
ctx->expired = 0; ctx->expired = 0;
ctx->ticks = 0; ctx->ticks = 0;
ctx->tintv = timespec_to_ktime(ktmr->it_interval); ctx->tintv = timespec64_to_ktime(ktmr->it_interval);
if (isalarm(ctx)) { if (isalarm(ctx)) {
alarm_init(&ctx->t.alarm, alarm_init(&ctx->t.alarm,
...@@ -432,16 +432,15 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) ...@@ -432,16 +432,15 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
} }
static int do_timerfd_settime(int ufd, int flags, static int do_timerfd_settime(int ufd, int flags,
const struct itimerspec *new, const struct itimerspec64 *new,
struct itimerspec *old) struct itimerspec64 *old)
{ {
struct fd f; struct fd f;
struct timerfd_ctx *ctx; struct timerfd_ctx *ctx;
int ret; int ret;
if ((flags & ~TFD_SETTIME_FLAGS) || if ((flags & ~TFD_SETTIME_FLAGS) ||
!timespec_valid(&new->it_value) || !itimerspec64_valid(new))
!timespec_valid(&new->it_interval))
return -EINVAL; return -EINVAL;
ret = timerfd_fget(ufd, &f); ret = timerfd_fget(ufd, &f);
...@@ -487,8 +486,8 @@ static int do_timerfd_settime(int ufd, int flags, ...@@ -487,8 +486,8 @@ static int do_timerfd_settime(int ufd, int flags,
hrtimer_forward_now(&ctx->t.tmr, ctx->tintv); hrtimer_forward_now(&ctx->t.tmr, ctx->tintv);
} }
old->it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); old->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
old->it_interval = ktime_to_timespec(ctx->tintv); old->it_interval = ktime_to_timespec64(ctx->tintv);
/* /*
* Re-program the timer to the new value ... * Re-program the timer to the new value ...
...@@ -500,7 +499,7 @@ static int do_timerfd_settime(int ufd, int flags, ...@@ -500,7 +499,7 @@ static int do_timerfd_settime(int ufd, int flags,
return ret; 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 fd f;
struct timerfd_ctx *ctx; struct timerfd_ctx *ctx;
...@@ -525,8 +524,8 @@ static int do_timerfd_gettime(int ufd, struct itimerspec *t) ...@@ -525,8 +524,8 @@ static int do_timerfd_gettime(int ufd, struct itimerspec *t)
hrtimer_restart(&ctx->t.tmr); hrtimer_restart(&ctx->t.tmr);
} }
} }
t->it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); t->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
t->it_interval = ktime_to_timespec(ctx->tintv); t->it_interval = ktime_to_timespec64(ctx->tintv);
spin_unlock_irq(&ctx->wqh.lock); spin_unlock_irq(&ctx->wqh.lock);
fdput(f); fdput(f);
return 0; return 0;
...@@ -536,15 +535,15 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, ...@@ -536,15 +535,15 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
const struct itimerspec __user *, utmr, const struct itimerspec __user *, utmr,
struct itimerspec __user *, otmr) struct itimerspec __user *, otmr)
{ {
struct itimerspec new, old; struct itimerspec64 new, old;
int ret; int ret;
if (copy_from_user(&new, utmr, sizeof(new))) if (get_itimerspec64(&new, utmr))
return -EFAULT; return -EFAULT;
ret = do_timerfd_settime(ufd, flags, &new, &old); ret = do_timerfd_settime(ufd, flags, &new, &old);
if (ret) if (ret)
return ret; return ret;
if (otmr && copy_to_user(otmr, &old, sizeof(old))) if (otmr && put_itimerspec64(&old, otmr))
return -EFAULT; return -EFAULT;
return ret; return ret;
...@@ -552,11 +551,11 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, ...@@ -552,11 +551,11 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
{ {
struct itimerspec kotmr; struct itimerspec64 kotmr;
int ret = do_timerfd_gettime(ufd, &kotmr); int ret = do_timerfd_gettime(ufd, &kotmr);
if (ret) if (ret)
return ret; return ret;
return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0; return put_itimerspec64(&kotmr, otmr) ? -EFAULT : 0;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -564,15 +563,15 @@ COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, ...@@ -564,15 +563,15 @@ COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
const struct compat_itimerspec __user *, utmr, const struct compat_itimerspec __user *, utmr,
struct compat_itimerspec __user *, otmr) struct compat_itimerspec __user *, otmr)
{ {
struct itimerspec new, old; struct itimerspec64 new, old;
int ret; int ret;
if (get_compat_itimerspec(&new, utmr)) if (get_compat_itimerspec64(&new, utmr))
return -EFAULT; return -EFAULT;
ret = do_timerfd_settime(ufd, flags, &new, &old); ret = do_timerfd_settime(ufd, flags, &new, &old);
if (ret) if (ret)
return ret; return ret;
if (otmr && put_compat_itimerspec(otmr, &old)) if (otmr && put_compat_itimerspec64(&old, otmr))
return -EFAULT; return -EFAULT;
return ret; return ret;
} }
...@@ -580,10 +579,10 @@ COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, ...@@ -580,10 +579,10 @@ COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
COMPAT_SYSCALL_DEFINE2(timerfd_gettime, int, ufd, COMPAT_SYSCALL_DEFINE2(timerfd_gettime, int, ufd,
struct compat_itimerspec __user *, otmr) struct compat_itimerspec __user *, otmr)
{ {
struct itimerspec kotmr; struct itimerspec64 kotmr;
int ret = do_timerfd_gettime(ufd, &kotmr); int ret = do_timerfd_gettime(ufd, &kotmr);
if (ret) if (ret)
return ret; return ret;
return put_compat_itimerspec(otmr, &kotmr) ? -EFAULT: 0; return put_compat_itimerspec64(&kotmr, otmr) ? -EFAULT : 0;
} }
#endif #endif
...@@ -164,6 +164,12 @@ extern int compat_get_timespec(struct timespec *, const void __user *); ...@@ -164,6 +164,12 @@ extern int compat_get_timespec(struct timespec *, const void __user *);
extern int compat_put_timespec(const struct timespec *, 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_get_timeval(struct timeval *, const void __user *);
extern int compat_put_timeval(const struct timeval *, 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 * This function convert a timespec if necessary and returns a *user
......
...@@ -453,7 +453,7 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer, ...@@ -453,7 +453,7 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer,
/* Precise sleep: */ /* 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, extern long hrtimer_nanosleep(const struct timespec64 *rqtp,
const enum hrtimer_mode mode, const enum hrtimer_mode mode,
const clockid_t clockid); const clockid_t clockid);
......
...@@ -113,5 +113,4 @@ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, ...@@ -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 update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
void posixtimer_rearm(struct siginfo *info); void posixtimer_rearm(struct siginfo *info);
#endif #endif
...@@ -8,6 +8,15 @@ ...@@ -8,6 +8,15 @@
extern struct timezone sys_tz; 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);
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) #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
static inline int timespec_equal(const struct timespec *a, static inline int timespec_equal(const struct timespec *a,
...@@ -270,4 +279,13 @@ static __always_inline void timespec_add_ns(struct timespec *a, u64 ns) ...@@ -270,4 +279,13 @@ static __always_inline void timespec_add_ns(struct timespec *a, u64 ns)
a->tv_nsec = 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 #endif
...@@ -120,6 +120,50 @@ static int __compat_put_timespec(const struct timespec *ts, struct compat_timesp ...@@ -120,6 +120,50 @@ static int __compat_put_timespec(const struct timespec *ts, struct compat_timesp
__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
} }
static int __compat_get_timespec64(struct timespec64 *ts64,
const struct compat_timespec __user *cts)
{
struct compat_timespec ts;
int ret;
ret = copy_from_user(&ts, cts, sizeof(ts));
if (ret)
return -EFAULT;
ts64->tv_sec = ts.tv_sec;
ts64->tv_nsec = ts.tv_nsec;
return 0;
}
static int __compat_put_timespec64(const struct timespec64 *ts64,
struct compat_timespec __user *cts)
{
struct compat_timespec ts = {
.tv_sec = ts64->tv_sec,
.tv_nsec = ts64->tv_nsec
};
return copy_to_user(cts, &ts, sizeof(ts)) ? -EFAULT : 0;
}
int compat_get_timespec64(struct timespec64 *ts, const void __user *uts)
{
if (COMPAT_USE_64BIT_TIME)
return copy_from_user(ts, uts, sizeof(*ts)) ? -EFAULT : 0;
else
return __compat_get_timespec64(ts, uts);
}
EXPORT_SYMBOL_GPL(compat_get_timespec64);
int compat_put_timespec64(const struct timespec64 *ts, void __user *uts)
{
if (COMPAT_USE_64BIT_TIME)
return copy_to_user(uts, ts, sizeof(*ts)) ? -EFAULT : 0;
else
return __compat_put_timespec64(ts, uts);
}
EXPORT_SYMBOL_GPL(compat_put_timespec64);
int compat_get_timeval(struct timeval *tv, const void __user *utv) int compat_get_timeval(struct timeval *tv, const void __user *utv)
{ {
if (COMPAT_USE_64BIT_TIME) if (COMPAT_USE_64BIT_TIME)
...@@ -476,6 +520,27 @@ int put_compat_itimerspec(struct compat_itimerspec __user *dst, ...@@ -476,6 +520,27 @@ int put_compat_itimerspec(struct compat_itimerspec __user *dst,
return 0; 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 * We currently only need the following fields from the sigevent
* structure: sigev_value, sigev_signo, sig_notify and (sometimes * structure: sigev_value, sigev_signo, sig_notify and (sometimes
......
...@@ -712,14 +712,14 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp, ...@@ -712,14 +712,14 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,
alarmtimer_freezerset(absexp, type); alarmtimer_freezerset(absexp, type);
restart = &current->restart_block; restart = &current->restart_block;
if (restart->nanosleep.type != TT_NONE) { if (restart->nanosleep.type != TT_NONE) {
struct timespec rmt; struct timespec64 rmt;
ktime_t rem; ktime_t rem;
rem = ktime_sub(absexp, alarm_bases[type].gettime()); rem = ktime_sub(absexp, alarm_bases[type].gettime());
if (rem <= 0) if (rem <= 0)
return 0; return 0;
rmt = ktime_to_timespec(rem); rmt = ktime_to_timespec64(rem);
return nanosleep_copyout(restart, &rmt); return nanosleep_copyout(restart, &rmt);
} }
......
...@@ -1440,17 +1440,17 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) ...@@ -1440,17 +1440,17 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
} }
EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); 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) { switch(restart->nanosleep.type) {
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
case TT_COMPAT: case TT_COMPAT:
if (compat_put_timespec(ts, restart->nanosleep.compat_rmtp)) if (compat_put_timespec64(ts, restart->nanosleep.compat_rmtp))
return -EFAULT; return -EFAULT;
break; break;
#endif #endif
case TT_NATIVE: case TT_NATIVE:
if (copy_to_user(restart->nanosleep.rmtp, ts, sizeof(struct timespec))) if (put_timespec64(ts, restart->nanosleep.rmtp))
return -EFAULT; return -EFAULT;
break; break;
default: default:
...@@ -1485,11 +1485,11 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod ...@@ -1485,11 +1485,11 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
restart = &current->restart_block; restart = &current->restart_block;
if (restart->nanosleep.type != TT_NONE) { if (restart->nanosleep.type != TT_NONE) {
ktime_t rem = hrtimer_expires_remaining(&t->timer); ktime_t rem = hrtimer_expires_remaining(&t->timer);
struct timespec rmt; struct timespec64 rmt;
if (rem <= 0) if (rem <= 0)
return 0; return 0;
rmt = ktime_to_timespec(rem); rmt = ktime_to_timespec64(rem);
return nanosleep_copyout(restart, &rmt); return nanosleep_copyout(restart, &rmt);
} }
...@@ -1546,19 +1546,17 @@ long hrtimer_nanosleep(const struct timespec64 *rqtp, ...@@ -1546,19 +1546,17 @@ long hrtimer_nanosleep(const struct timespec64 *rqtp,
SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
struct timespec __user *, rmtp) struct timespec __user *, rmtp)
{ {
struct timespec64 tu64; struct timespec64 tu;
struct timespec tu;
if (copy_from_user(&tu, rqtp, sizeof(tu))) if (get_timespec64(&tu, rqtp))
return -EFAULT; return -EFAULT;
tu64 = timespec_to_timespec64(tu); if (!timespec64_valid(&tu))
if (!timespec64_valid(&tu64))
return -EINVAL; return -EINVAL;
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
current->restart_block.nanosleep.rmtp = rmtp; 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 #ifdef CONFIG_COMPAT
...@@ -1566,19 +1564,17 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, ...@@ -1566,19 +1564,17 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
struct compat_timespec __user *, rmtp) struct compat_timespec __user *, rmtp)
{ {
struct timespec64 tu64; struct timespec64 tu;
struct timespec tu;
if (compat_get_timespec(&tu, rqtp)) if (compat_get_timespec64(&tu, rqtp))
return -EFAULT; return -EFAULT;
tu64 = timespec_to_timespec64(tu); if (!timespec64_valid(&tu))
if (!timespec64_valid(&tu64))
return -EINVAL; return -EINVAL;
current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
current->restart_block.nanosleep.compat_rmtp = rmtp; 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 #endif
......
...@@ -1318,12 +1318,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1318,12 +1318,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
*/ */
restart = &current->restart_block; restart = &current->restart_block;
restart->nanosleep.expires = expires; restart->nanosleep.expires = expires;
if (restart->nanosleep.type != TT_NONE) { if (restart->nanosleep.type != TT_NONE)
struct timespec ts; error = nanosleep_copyout(restart, &it.it_value);
ts = timespec64_to_timespec(it.it_value);
error = nanosleep_copyout(restart, &ts);
}
} }
return error; return error;
......
...@@ -41,12 +41,6 @@ SYS_NI(setitimer); ...@@ -41,12 +41,6 @@ SYS_NI(setitimer);
#ifdef __ARCH_WANT_SYS_ALARM #ifdef __ARCH_WANT_SYS_ALARM
SYS_NI(alarm); SYS_NI(alarm);
#endif #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 * We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC
...@@ -57,40 +51,52 @@ COMPAT_SYS_NI(setitimer); ...@@ -57,40 +51,52 @@ COMPAT_SYS_NI(setitimer);
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
const struct timespec __user *, tp) const struct timespec __user *, tp)
{ {
struct timespec64 new_tp64; struct timespec64 new_tp;
struct timespec new_tp;
if (which_clock != CLOCK_REALTIME) if (which_clock != CLOCK_REALTIME)
return -EINVAL; return -EINVAL;
if (copy_from_user(&new_tp, tp, sizeof (*tp))) if (get_timespec64(&new_tp, tp))
return -EFAULT; return -EFAULT;
new_tp64 = timespec_to_timespec64(new_tp); return do_sys_settimeofday64(&new_tp, NULL);
return do_sys_settimeofday64(&new_tp64, NULL);
} }
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, int do_clock_gettime(clockid_t which_clock, struct timespec64 *tp)
struct timespec __user *,tp)
{ {
struct timespec64 kernel_tp64;
struct timespec kernel_tp;
switch (which_clock) { switch (which_clock) {
case CLOCK_REALTIME: ktime_get_real_ts64(&kernel_tp64); break; case CLOCK_REALTIME:
case CLOCK_MONOTONIC: ktime_get_ts64(&kernel_tp64); break; ktime_get_real_ts64(tp);
case CLOCK_BOOTTIME: get_monotonic_boottime64(&kernel_tp64); break; break;
default: return -EINVAL; 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); return 0;
if (copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) }
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 -EFAULT;
return 0; return 0;
} }
SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __user *, tp) 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_sec = 0,
.tv_nsec = hrtimer_resolution, .tv_nsec = hrtimer_resolution,
}; };
...@@ -99,7 +105,7 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __us ...@@ -99,7 +105,7 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __us
case CLOCK_REALTIME: case CLOCK_REALTIME:
case CLOCK_MONOTONIC: case CLOCK_MONOTONIC:
case CLOCK_BOOTTIME: case CLOCK_BOOTTIME:
if (copy_to_user(tp, &rtn_tp, sizeof(rtn_tp))) if (put_timespec64(&rtn_tp, tp))
return -EFAULT; return -EFAULT;
return 0; return 0;
default: default:
...@@ -138,44 +144,45 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, ...@@ -138,44 +144,45 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
} }
#ifdef CONFIG_COMPAT #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, COMPAT_SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
struct compat_timespec __user *, tp) struct compat_timespec __user *, tp)
{ {
struct timespec64 new_tp64; struct timespec64 new_tp;
struct timespec new_tp;
if (which_clock != CLOCK_REALTIME) if (which_clock != CLOCK_REALTIME)
return -EINVAL; return -EINVAL;
if (compat_get_timespec(&new_tp, tp)) if (compat_get_timespec64(&new_tp, tp))
return -EFAULT; return -EFAULT;
new_tp64 = timespec_to_timespec64(new_tp); return do_sys_settimeofday64(&new_tp, NULL);
return do_sys_settimeofday64(&new_tp64, NULL);
} }
COMPAT_SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
struct compat_timespec __user *,tp) struct compat_timespec __user *, tp)
{ {
struct timespec64 kernel_tp64; int ret;
struct timespec kernel_tp; struct timespec64 kernel_tp;
switch (which_clock) { ret = do_clock_gettime(which_clock, &kernel_tp);
case CLOCK_REALTIME: ktime_get_real_ts64(&kernel_tp64); break; if (ret)
case CLOCK_MONOTONIC: ktime_get_ts64(&kernel_tp64); break; return ret;
case CLOCK_BOOTTIME: get_monotonic_boottime64(&kernel_tp64); break;
default: return -EINVAL;
}
kernel_tp = timespec64_to_timespec(kernel_tp64); if (compat_put_timespec64(&kernel_tp, tp))
if (compat_put_timespec(&kernel_tp, tp))
return -EFAULT; return -EFAULT;
return 0; 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 compat_timespec __user *, tp)
{ {
struct timespec rtn_tp = { struct timespec64 rtn_tp = {
.tv_sec = 0, .tv_sec = 0,
.tv_nsec = hrtimer_resolution, .tv_nsec = hrtimer_resolution,
}; };
...@@ -184,13 +191,14 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, ...@@ -184,13 +191,14 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
case CLOCK_REALTIME: case CLOCK_REALTIME:
case CLOCK_MONOTONIC: case CLOCK_MONOTONIC:
case CLOCK_BOOTTIME: case CLOCK_BOOTTIME:
if (compat_put_timespec(&rtn_tp, tp)) if (compat_put_timespec64(&rtn_tp, tp))
return -EFAULT; return -EFAULT;
return 0; return 0;
default: default:
return -EINVAL; return -EINVAL;
} }
} }
COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
struct compat_timespec __user *, rqtp, struct compat_timespec __user *, rqtp,
struct compat_timespec __user *, rmtp) struct compat_timespec __user *, rmtp)
......
...@@ -739,13 +739,11 @@ static int do_timer_gettime(timer_t timer_id, struct itimerspec64 *setting) ...@@ -739,13 +739,11 @@ static int do_timer_gettime(timer_t timer_id, struct itimerspec64 *setting)
SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
struct itimerspec __user *, setting) 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) { if (!ret) {
struct itimerspec cur_setting; if (put_itimerspec64(&cur_setting, setting))
cur_setting = itimerspec64_to_itimerspec(&cur_setting64);
if (copy_to_user(setting, &cur_setting, sizeof (cur_setting)))
ret = -EFAULT; ret = -EFAULT;
} }
return ret; return ret;
...@@ -755,13 +753,11 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, ...@@ -755,13 +753,11 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
struct compat_itimerspec __user *, setting) 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) { if (!ret) {
struct itimerspec cur_setting; if (put_compat_itimerspec64(&cur_setting, setting))
cur_setting = itimerspec64_to_itimerspec(&cur_setting64);
if (put_compat_itimerspec(setting, &cur_setting))
ret = -EFAULT; ret = -EFAULT;
} }
return ret; return ret;
...@@ -907,23 +903,19 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, ...@@ -907,23 +903,19 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
const struct itimerspec __user *, new_setting, const struct itimerspec __user *, new_setting,
struct itimerspec __user *, old_setting) struct itimerspec __user *, old_setting)
{ {
struct itimerspec64 new_spec64, old_spec64; struct itimerspec64 new_spec, old_spec;
struct itimerspec64 *rtn = old_setting ? &old_spec64 : NULL; struct itimerspec64 *rtn = old_setting ? &old_spec : NULL;
struct itimerspec new_spec;
int error = 0; int error = 0;
if (!new_setting) if (!new_setting)
return -EINVAL; return -EINVAL;
if (copy_from_user(&new_spec, new_setting, sizeof (new_spec))) if (get_itimerspec64(&new_spec, new_setting))
return -EFAULT; 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) { if (!error && old_setting) {
struct itimerspec old_spec; if (put_itimerspec64(&old_spec, old_setting))
old_spec = itimerspec64_to_itimerspec(&old_spec64);
if (copy_to_user(old_setting, &old_spec, sizeof (old_spec)))
error = -EFAULT; error = -EFAULT;
} }
return error; return error;
...@@ -934,22 +926,18 @@ COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, ...@@ -934,22 +926,18 @@ COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
struct compat_itimerspec __user *, new, struct compat_itimerspec __user *, new,
struct compat_itimerspec __user *, old) struct compat_itimerspec __user *, old)
{ {
struct itimerspec64 new_spec64, old_spec64; struct itimerspec64 new_spec, old_spec;
struct itimerspec64 *rtn = old ? &old_spec64 : NULL; struct itimerspec64 *rtn = old ? &old_spec : NULL;
struct itimerspec new_spec;
int error = 0; int error = 0;
if (!new) if (!new)
return -EINVAL; return -EINVAL;
if (get_compat_itimerspec(&new_spec, new)) if (get_compat_itimerspec64(&new_spec, new))
return -EFAULT; return -EFAULT;
new_spec64 = itimerspec_to_itimerspec64(&new_spec); error = do_timer_settime(timer_id, flags, &new_spec, rtn);
error = do_timer_settime(timer_id, flags, &new_spec64, rtn);
if (!error && old) { if (!error && old) {
struct itimerspec old_spec; if (put_compat_itimerspec64(&old_spec, old))
old_spec = itimerspec64_to_itimerspec(&old_spec64);
if (put_compat_itimerspec(old, &old_spec))
error = -EFAULT; error = -EFAULT;
} }
return error; return error;
...@@ -1049,34 +1037,30 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, ...@@ -1049,34 +1037,30 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
const struct timespec __user *, tp) const struct timespec __user *, tp)
{ {
const struct k_clock *kc = clockid_to_kclock(which_clock); const struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec64 new_tp64; struct timespec64 new_tp;
struct timespec new_tp;
if (!kc || !kc->clock_set) if (!kc || !kc->clock_set)
return -EINVAL; return -EINVAL;
if (copy_from_user(&new_tp, tp, sizeof (*tp))) if (get_timespec64(&new_tp, tp))
return -EFAULT; return -EFAULT;
new_tp64 = timespec_to_timespec64(new_tp);
return kc->clock_set(which_clock, &new_tp64); return kc->clock_set(which_clock, &new_tp);
} }
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
struct timespec __user *,tp) struct timespec __user *,tp)
{ {
const struct k_clock *kc = clockid_to_kclock(which_clock); const struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec64 kernel_tp64; struct timespec64 kernel_tp;
struct timespec kernel_tp;
int error; int error;
if (!kc) if (!kc)
return -EINVAL; return -EINVAL;
error = kc->clock_get(which_clock, &kernel_tp64); error = kc->clock_get(which_clock, &kernel_tp);
kernel_tp = timespec64_to_timespec(kernel_tp64);
if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) if (!error && put_timespec64(&kernel_tp, tp))
error = -EFAULT; error = -EFAULT;
return error; return error;
...@@ -1109,17 +1093,15 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, ...@@ -1109,17 +1093,15 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
struct timespec __user *, tp) struct timespec __user *, tp)
{ {
const struct k_clock *kc = clockid_to_kclock(which_clock); const struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec64 rtn_tp64; struct timespec64 rtn_tp;
struct timespec rtn_tp;
int error; int error;
if (!kc) if (!kc)
return -EINVAL; return -EINVAL;
error = kc->clock_getres(which_clock, &rtn_tp64); error = kc->clock_getres(which_clock, &rtn_tp);
rtn_tp = timespec64_to_timespec(rtn_tp64);
if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) if (!error && tp && put_timespec64(&rtn_tp, tp))
error = -EFAULT; error = -EFAULT;
return error; return error;
...@@ -1131,38 +1113,33 @@ COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock, ...@@ -1131,38 +1113,33 @@ COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock,
struct compat_timespec __user *, tp) struct compat_timespec __user *, tp)
{ {
const struct k_clock *kc = clockid_to_kclock(which_clock); const struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec64 new_tp64; struct timespec64 ts;
struct timespec new_tp;
if (!kc || !kc->clock_set) if (!kc || !kc->clock_set)
return -EINVAL; return -EINVAL;
if (compat_get_timespec(&new_tp, tp)) if (compat_get_timespec64(&ts, tp))
return -EFAULT; return -EFAULT;
new_tp64 = timespec_to_timespec64(new_tp); return kc->clock_set(which_clock, &ts);
return kc->clock_set(which_clock, &new_tp64);
} }
COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
struct compat_timespec __user *, tp) struct compat_timespec __user *, tp)
{ {
const struct k_clock *kc = clockid_to_kclock(which_clock); const struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec64 kernel_tp64; struct timespec64 ts;
struct timespec kernel_tp; int err;
int error;
if (!kc) if (!kc)
return -EINVAL; return -EINVAL;
error = kc->clock_get(which_clock, &kernel_tp64); err = kc->clock_get(which_clock, &ts);
kernel_tp = timespec64_to_timespec(kernel_tp64);
if (!error && compat_put_timespec(&kernel_tp, tp)) if (!err && compat_put_timespec64(&ts, tp))
error = -EFAULT; err = -EFAULT;
return error; return err;
} }
COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock,
...@@ -1193,21 +1170,19 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, ...@@ -1193,21 +1170,19 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock,
struct compat_timespec __user *, tp) struct compat_timespec __user *, tp)
{ {
const struct k_clock *kc = clockid_to_kclock(which_clock); const struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec64 rtn_tp64; struct timespec64 ts;
struct timespec rtn_tp; int err;
int error;
if (!kc) if (!kc)
return -EINVAL; return -EINVAL;
error = kc->clock_getres(which_clock, &rtn_tp64); err = kc->clock_getres(which_clock, &ts);
rtn_tp = timespec64_to_timespec(rtn_tp64); if (!err && tp && compat_put_timespec64(&ts, tp))
return -EFAULT;
if (!error && tp && compat_put_timespec(&rtn_tp, tp))
error = -EFAULT;
return error; return err;
} }
#endif #endif
/* /*
...@@ -1226,26 +1201,24 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, ...@@ -1226,26 +1201,24 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
struct timespec __user *, rmtp) struct timespec __user *, rmtp)
{ {
const struct k_clock *kc = clockid_to_kclock(which_clock); const struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec64 t64; struct timespec64 t;
struct timespec t;
if (!kc) if (!kc)
return -EINVAL; return -EINVAL;
if (!kc->nsleep) if (!kc->nsleep)
return -ENANOSLEEP_NOTSUP; return -ENANOSLEEP_NOTSUP;
if (copy_from_user(&t, rqtp, sizeof (struct timespec))) if (get_timespec64(&t, rqtp))
return -EFAULT; return -EFAULT;
t64 = timespec_to_timespec64(t); if (!timespec64_valid(&t))
if (!timespec64_valid(&t64))
return -EINVAL; return -EINVAL;
if (flags & TIMER_ABSTIME) if (flags & TIMER_ABSTIME)
rmtp = NULL; rmtp = NULL;
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
current->restart_block.nanosleep.rmtp = rmtp; current->restart_block.nanosleep.rmtp = rmtp;
return kc->nsleep(which_clock, flags, &t64); return kc->nsleep(which_clock, flags, &t);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -1254,26 +1227,24 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, ...@@ -1254,26 +1227,24 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
struct compat_timespec __user *, rmtp) struct compat_timespec __user *, rmtp)
{ {
const struct k_clock *kc = clockid_to_kclock(which_clock); const struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec64 t64; struct timespec64 t;
struct timespec t;
if (!kc) if (!kc)
return -EINVAL; return -EINVAL;
if (!kc->nsleep) if (!kc->nsleep)
return -ENANOSLEEP_NOTSUP; return -ENANOSLEEP_NOTSUP;
if (compat_get_timespec(&t, rqtp)) if (compat_get_timespec64(&t, rqtp))
return -EFAULT; return -EFAULT;
t64 = timespec_to_timespec64(t); if (!timespec64_valid(&t))
if (!timespec64_valid(&t64))
return -EINVAL; return -EINVAL;
if (flags & TIMER_ABSTIME) if (flags & TIMER_ABSTIME)
rmtp = NULL; rmtp = NULL;
current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
current->restart_block.nanosleep.compat_rmtp = rmtp; current->restart_block.nanosleep.compat_rmtp = rmtp;
return kc->nsleep(which_clock, flags, &t64); return kc->nsleep(which_clock, flags, &t);
} }
#endif #endif
......
...@@ -890,3 +890,61 @@ struct timespec64 timespec64_add_safe(const struct timespec64 lhs, ...@@ -890,3 +890,61 @@ struct timespec64 timespec64_add_safe(const struct timespec64 lhs,
return res; 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);
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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment