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
This commit is contained in:
commit
ea3b25e132
43
fs/timerfd.c
43
fs/timerfd.c
|
@ -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 && copy_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
|
||||
|
|
|
@ -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_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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -8,6 +8,15 @@
|
|||
|
||||
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)
|
||||
|
||||
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)
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (COMPAT_USE_64BIT_TIME)
|
||||
|
@ -476,6 +520,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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 @@ out:
|
|||
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -41,12 +41,6 @@ SYS_NI(setitimer);
|
|||
#ifdef __ARCH_WANT_SYS_ALARM
|
||||
SYS_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
|
||||
|
@ -57,40 +51,52 @@ COMPAT_SYS_NI(setitimer);
|
|||
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,
|
||||
};
|
||||
|
@ -99,7 +105,7 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __us
|
|||
case 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:
|
||||
|
@ -138,44 +144,45 @@ 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)
|
||||
{
|
||||
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,
|
||||
};
|
||||
|
@ -184,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)
|
||||
|
|
|
@ -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;
|
||||
|
@ -1049,34 +1037,30 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
|
|||
const struct timespec __user *, tp)
|
||||
{
|
||||
const struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
struct timespec64 new_tp64;
|
||||
struct timespec new_tp;
|
||||
struct timespec64 new_tp;
|
||||
|
||||
if (!kc || !kc->clock_set)
|
||||
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 kc->clock_set(which_clock, &new_tp64);
|
||||
return kc->clock_set(which_clock, &new_tp);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
|
||||
struct timespec __user *,tp)
|
||||
{
|
||||
const struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
struct timespec64 kernel_tp64;
|
||||
struct timespec kernel_tp;
|
||||
struct timespec64 kernel_tp;
|
||||
int error;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
error = kc->clock_get(which_clock, &kernel_tp64);
|
||||
kernel_tp = timespec64_to_timespec(kernel_tp64);
|
||||
error = kc->clock_get(which_clock, &kernel_tp);
|
||||
|
||||
if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp)))
|
||||
if (!error && put_timespec64(&kernel_tp, tp))
|
||||
error = -EFAULT;
|
||||
|
||||
return error;
|
||||
|
@ -1109,17 +1093,15 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
|
|||
struct timespec __user *, tp)
|
||||
{
|
||||
const struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
struct timespec64 rtn_tp64;
|
||||
struct timespec rtn_tp;
|
||||
struct timespec64 rtn_tp;
|
||||
int error;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
error = kc->clock_getres(which_clock, &rtn_tp64);
|
||||
rtn_tp = timespec64_to_timespec(rtn_tp64);
|
||||
error = kc->clock_getres(which_clock, &rtn_tp);
|
||||
|
||||
if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp)))
|
||||
if (!error && tp && put_timespec64(&rtn_tp, tp))
|
||||
error = -EFAULT;
|
||||
|
||||
return error;
|
||||
|
@ -1131,38 +1113,33 @@ COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock,
|
|||
struct compat_timespec __user *, tp)
|
||||
{
|
||||
const struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
struct timespec64 new_tp64;
|
||||
struct timespec new_tp;
|
||||
struct timespec64 ts;
|
||||
|
||||
if (!kc || !kc->clock_set)
|
||||
return -EINVAL;
|
||||
|
||||
if (compat_get_timespec(&new_tp, tp))
|
||||
if (compat_get_timespec64(&ts, tp))
|
||||
return -EFAULT;
|
||||
|
||||
new_tp64 = timespec_to_timespec64(new_tp);
|
||||
|
||||
return kc->clock_set(which_clock, &new_tp64);
|
||||
return kc->clock_set(which_clock, &ts);
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
|
||||
struct compat_timespec __user *, tp)
|
||||
{
|
||||
const struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
struct timespec64 kernel_tp64;
|
||||
struct timespec kernel_tp;
|
||||
int error;
|
||||
struct timespec64 ts;
|
||||
int err;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
error = kc->clock_get(which_clock, &kernel_tp64);
|
||||
kernel_tp = timespec64_to_timespec(kernel_tp64);
|
||||
err = kc->clock_get(which_clock, &ts);
|
||||
|
||||
if (!error && compat_put_timespec(&kernel_tp, tp))
|
||||
error = -EFAULT;
|
||||
if (!err && compat_put_timespec64(&ts, tp))
|
||||
err = -EFAULT;
|
||||
|
||||
return error;
|
||||
return err;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock,
|
||||
|
@ -1193,21 +1170,19 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock,
|
|||
struct compat_timespec __user *, tp)
|
||||
{
|
||||
const struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
struct timespec64 rtn_tp64;
|
||||
struct timespec rtn_tp;
|
||||
int error;
|
||||
struct timespec64 ts;
|
||||
int err;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
error = kc->clock_getres(which_clock, &rtn_tp64);
|
||||
rtn_tp = timespec64_to_timespec(rtn_tp64);
|
||||
err = kc->clock_getres(which_clock, &ts);
|
||||
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
|
||||
|
||||
/*
|
||||
|
@ -1226,26 +1201,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
|
||||
|
@ -1254,26 +1227,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
|
||||
|
||||
|
|
|
@ -890,3 +890,61 @@ 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);
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue