aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-06-07 04:42:31 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-06-13 18:00:42 -0400
commitedbeda46322fbcb15af2d2d0f2daffb0cd349a5a (patch)
treea4aa5436d4e5dcce6f4d041d13c521e1660331b7 /kernel/time
parent99e6c0e6ec349575886ca7daffc9cb7ec583176f (diff)
time/posix-timers: Move the compat copyouts to the nanosleep implementations
Turn restart_block.nanosleep.{rmtp,compat_rmtp} into a tagged union (kind = 1 -> native, kind = 2 -> compat, kind = 0 -> nothing) and make the places doing actual copyout handle compat as well as native (that will become a helper in the next commit). Result: compat wrappers, messing with reassignments, etc. are gone. [ tglx: Folded in a variant of Peter Zijlstras enum patch ] Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: John Stultz <john.stultz@linaro.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20170607084241.28657-6-viro@ZenIV.linux.org.uk
Diffstat (limited to 'kernel/time')
-rw-r--r--kernel/time/alarmtimer.c16
-rw-r--r--kernel/time/hrtimer.c42
-rw-r--r--kernel/time/posix-cpu-timers.c20
-rw-r--r--kernel/time/posix-stubs.c55
-rw-r--r--kernel/time/posix-timers.c32
5 files changed, 129 insertions, 36 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index d859a3601ddd..57bcf94ee132 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -27,6 +27,7 @@
27#include <linux/posix-timers.h> 27#include <linux/posix-timers.h>
28#include <linux/workqueue.h> 28#include <linux/workqueue.h>
29#include <linux/freezer.h> 29#include <linux/freezer.h>
30#include <linux/compat.h>
30 31
31#include "posix-timers.h" 32#include "posix-timers.h"
32 33
@@ -691,7 +692,7 @@ static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm,
691static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp, 692static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,
692 enum alarmtimer_type type) 693 enum alarmtimer_type type)
693{ 694{
694 struct timespec __user *rmtp; 695 struct restart_block *restart;
695 alarm->data = (void *)current; 696 alarm->data = (void *)current;
696 do { 697 do {
697 set_current_state(TASK_INTERRUPTIBLE); 698 set_current_state(TASK_INTERRUPTIBLE);
@@ -709,8 +710,8 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,
709 710
710 if (freezing(current)) 711 if (freezing(current))
711 alarmtimer_freezerset(absexp, type); 712 alarmtimer_freezerset(absexp, type);
712 rmtp = current->restart_block.nanosleep.rmtp; 713 restart = &current->restart_block;
713 if (rmtp) { 714 if (restart->nanosleep.type != TT_NONE) {
714 struct timespec rmt; 715 struct timespec rmt;
715 ktime_t rem; 716 ktime_t rem;
716 717
@@ -720,7 +721,14 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,
720 return 0; 721 return 0;
721 rmt = ktime_to_timespec(rem); 722 rmt = ktime_to_timespec(rem);
722 723
723 if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) 724#ifdef CONFIG_COMPAT
725 if (restart->nanosleep.type == TT_COMPAT) {
726 if (compat_put_timespec(&rmt,
727 restart->nanosleep.compat_rmtp))
728 return -EFAULT;
729 } else
730#endif
731 if (copy_to_user(restart->nanosleep.rmtp, &rmt, sizeof(rmt)))
724 return -EFAULT; 732 return -EFAULT;
725 } 733 }
726 return -ERESTART_RESTARTBLOCK; 734 return -ERESTART_RESTARTBLOCK;
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index baa7b846b6e3..5370da8fc0a4 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -51,6 +51,7 @@
51#include <linux/sched/debug.h> 51#include <linux/sched/debug.h>
52#include <linux/timer.h> 52#include <linux/timer.h>
53#include <linux/freezer.h> 53#include <linux/freezer.h>
54#include <linux/compat.h>
54 55
55#include <linux/uaccess.h> 56#include <linux/uaccess.h>
56 57
@@ -1441,7 +1442,8 @@ EXPORT_SYMBOL_GPL(hrtimer_init_sleeper);
1441 1442
1442static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) 1443static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
1443{ 1444{
1444 struct timespec __user *rmtp; 1445 struct restart_block *restart;
1446
1445 hrtimer_init_sleeper(t, current); 1447 hrtimer_init_sleeper(t, current);
1446 1448
1447 do { 1449 do {
@@ -1461,15 +1463,23 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
1461 if (!t->task) 1463 if (!t->task)
1462 return 0; 1464 return 0;
1463 1465
1464 rmtp = current->restart_block.nanosleep.rmtp; 1466 restart = &current->restart_block;
1465 if (rmtp) { 1467 if (restart->nanosleep.type != TT_NONE) {
1466 struct timespec rmt;
1467 ktime_t rem = hrtimer_expires_remaining(&t->timer); 1468 ktime_t rem = hrtimer_expires_remaining(&t->timer);
1469 struct timespec rmt;
1470
1468 if (rem <= 0) 1471 if (rem <= 0)
1469 return 0; 1472 return 0;
1470 rmt = ktime_to_timespec(rem); 1473 rmt = ktime_to_timespec(rem);
1471 1474
1472 if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) 1475#ifdef CONFIG_COMPAT
1476 if (restart->nanosleep.type == TT_COMPAT) {
1477 if (compat_put_timespec(&rmt,
1478 restart->nanosleep.compat_rmtp))
1479 return -EFAULT;
1480 } else
1481#endif
1482 if (copy_to_user(restart->nanosleep.rmtp, &rmt, sizeof(rmt)))
1473 return -EFAULT; 1483 return -EFAULT;
1474 } 1484 }
1475 return -ERESTART_RESTARTBLOCK; 1485 return -ERESTART_RESTARTBLOCK;
@@ -1535,10 +1545,32 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
1535 if (!timespec64_valid(&tu64)) 1545 if (!timespec64_valid(&tu64))
1536 return -EINVAL; 1546 return -EINVAL;
1537 1547
1548 current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
1538 current->restart_block.nanosleep.rmtp = rmtp; 1549 current->restart_block.nanosleep.rmtp = rmtp;
1539 return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC); 1550 return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
1540} 1551}
1541 1552
1553#ifdef CONFIG_COMPAT
1554
1555COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
1556 struct compat_timespec __user *, rmtp)
1557{
1558 struct timespec64 tu64;
1559 struct timespec tu;
1560
1561 if (compat_get_timespec(&tu, rqtp))
1562 return -EFAULT;
1563
1564 tu64 = timespec_to_timespec64(tu);
1565 if (!timespec64_valid(&tu64))
1566 return -EINVAL;
1567
1568 current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
1569 current->restart_block.nanosleep.compat_rmtp = rmtp;
1570 return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
1571}
1572#endif
1573
1542/* 1574/*
1543 * Functions related to boot-time initialization: 1575 * Functions related to boot-time initialization:
1544 */ 1576 */
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index ec6258c9cde5..1563ca22cf1f 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -12,6 +12,7 @@
12#include <trace/events/timer.h> 12#include <trace/events/timer.h>
13#include <linux/tick.h> 13#include <linux/tick.h>
14#include <linux/workqueue.h> 14#include <linux/workqueue.h>
15#include <linux/compat.h>
15 16
16#include "posix-timers.h" 17#include "posix-timers.h"
17 18
@@ -1243,10 +1244,9 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
1243 timer.it_process = current; 1244 timer.it_process = current;
1244 if (!error) { 1245 if (!error) {
1245 static struct itimerspec64 zero_it; 1246 static struct itimerspec64 zero_it;
1246 struct restart_block *restart = &current->restart_block; 1247 struct restart_block *restart;
1247 struct timespec __user *rmtp;
1248 1248
1249 memset(&it, 0, sizeof it); 1249 memset(&it, 0, sizeof(it));
1250 it.it_value = *rqtp; 1250 it.it_value = *rqtp;
1251 1251
1252 spin_lock_irq(&timer.it_lock); 1252 spin_lock_irq(&timer.it_lock);
@@ -1311,12 +1311,20 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
1311 /* 1311 /*
1312 * Report back to the user the time still remaining. 1312 * Report back to the user the time still remaining.
1313 */ 1313 */
1314 rmtp = restart->nanosleep.rmtp; 1314 restart = &current->restart_block;
1315 if (rmtp) { 1315 if (restart->nanosleep.type != TT_NONE) {
1316 struct timespec ts; 1316 struct timespec ts;
1317 1317
1318 ts = timespec64_to_timespec(it.it_value); 1318 ts = timespec64_to_timespec(it.it_value);
1319 if (copy_to_user(rmtp, &ts, sizeof(*rmtp))) 1319#ifdef CONFIG_COMPAT
1320 if (restart->nanosleep.type == TT_COMPAT) {
1321 if (compat_put_timespec(&ts,
1322 restart->nanosleep.compat_rmtp))
1323 return -EFAULT;
1324 } else
1325#endif
1326 if (copy_to_user(restart->nanosleep.rmtp, &ts,
1327 sizeof(ts)))
1320 return -EFAULT; 1328 return -EFAULT;
1321 } 1329 }
1322 restart->nanosleep.expires = timespec64_to_ns(rqtp); 1330 restart->nanosleep.expires = timespec64_to_ns(rqtp);
diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c
index 156a5e6f3bd2..749b76f2d757 100644
--- a/kernel/time/posix-stubs.c
+++ b/kernel/time/posix-stubs.c
@@ -17,6 +17,7 @@
17#include <linux/ktime.h> 17#include <linux/ktime.h>
18#include <linux/timekeeping.h> 18#include <linux/timekeeping.h>
19#include <linux/posix-timers.h> 19#include <linux/posix-timers.h>
20#include <linux/compat.h>
20 21
21asmlinkage long sys_ni_posix_timers(void) 22asmlinkage long sys_ni_posix_timers(void)
22{ 23{
@@ -110,25 +111,53 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
110 case CLOCK_REALTIME: 111 case CLOCK_REALTIME:
111 case CLOCK_MONOTONIC: 112 case CLOCK_MONOTONIC:
112 case CLOCK_BOOTTIME: 113 case CLOCK_BOOTTIME:
113 if (copy_from_user(&t, rqtp, sizeof (struct timespec))) 114 break;
114 return -EFAULT;
115 t64 = timespec_to_timespec64(t);
116 if (!timespec64_valid(&t64))
117 return -EINVAL;
118 if (flags & TIMER_ABSTIME)
119 rmtp = NULL;
120 current->restart_block.nanosleep.rmtp = rmtp;
121 return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ?
122 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
123 which_clock);
124 default: 115 default:
125 return -EINVAL; 116 return -EINVAL;
126 } 117 }
118
119 if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
120 return -EFAULT;
121 t64 = timespec_to_timespec64(t);
122 if (!timespec64_valid(&t64))
123 return -EINVAL;
124 if (flags & TIMER_ABSTIME)
125 rmtp = NULL;
126 current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
127 current->restart_block.nanosleep.rmtp = rmtp;
128 return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ?
129 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
130 which_clock);
127} 131}
128 132
129#ifdef CONFIG_COMPAT 133#ifdef CONFIG_COMPAT
130long clock_nanosleep_restart(struct restart_block *restart_block) 134COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
135 struct compat_timespec __user *, rqtp,
136 struct compat_timespec __user *, rmtp)
131{ 137{
132 return hrtimer_nanosleep_restart(restart_block); 138 struct timespec64 t64;
139 struct timespec t;
140
141 switch (which_clock) {
142 case CLOCK_REALTIME:
143 case CLOCK_MONOTONIC:
144 case CLOCK_BOOTTIME:
145 break;
146 default:
147 return -EINVAL;
148 }
149
150 if (compat_get_timespec(&t, rqtp))
151 return -EFAULT;
152 t64 = timespec_to_timespec64(t);
153 if (!timespec64_valid(&t64))
154 return -EINVAL;
155 if (flags & TIMER_ABSTIME)
156 rmtp = NULL;
157 current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
158 current->restart_block.nanosleep.compat_rmtp = rmtp;
159 return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ?
160 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
161 which_clock);
133} 162}
134#endif 163#endif
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index a3e5c01b430e..bec86b6b9814 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -49,6 +49,7 @@
49#include <linux/workqueue.h> 49#include <linux/workqueue.h>
50#include <linux/export.h> 50#include <linux/export.h>
51#include <linux/hashtable.h> 51#include <linux/hashtable.h>
52#include <linux/compat.h>
52 53
53#include "timekeeping.h" 54#include "timekeeping.h"
54#include "posix-timers.h" 55#include "posix-timers.h"
@@ -1069,25 +1070,40 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
1069 return -EINVAL; 1070 return -EINVAL;
1070 if (flags & TIMER_ABSTIME) 1071 if (flags & TIMER_ABSTIME)
1071 rmtp = NULL; 1072 rmtp = NULL;
1073 current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
1072 current->restart_block.nanosleep.rmtp = rmtp; 1074 current->restart_block.nanosleep.rmtp = rmtp;
1073 1075
1074 return kc->nsleep(which_clock, flags, &t64); 1076 return kc->nsleep(which_clock, flags, &t64);
1075} 1077}
1076 1078
1077/* 1079#ifdef CONFIG_COMPAT
1078 * This will restart clock_nanosleep. This is required only by 1080COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
1079 * compat_clock_nanosleep_restart for now. 1081 struct compat_timespec __user *, rqtp,
1080 */ 1082 struct compat_timespec __user *, rmtp)
1081long clock_nanosleep_restart(struct restart_block *restart_block)
1082{ 1083{
1083 clockid_t which_clock = restart_block->nanosleep.clockid;
1084 const struct k_clock *kc = clockid_to_kclock(which_clock); 1084 const struct k_clock *kc = clockid_to_kclock(which_clock);
1085 struct timespec64 t64;
1086 struct timespec t;
1085 1087
1086 if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) 1088 if (!kc)
1087 return -EINVAL; 1089 return -EINVAL;
1090 if (!kc->nsleep)
1091 return -ENANOSLEEP_NOTSUP;
1092
1093 if (compat_get_timespec(&t, rqtp))
1094 return -EFAULT;
1088 1095
1089 return kc->nsleep_restart(restart_block); 1096 t64 = timespec_to_timespec64(t);
1097 if (!timespec64_valid(&t64))
1098 return -EINVAL;
1099 if (flags & TIMER_ABSTIME)
1100 rmtp = NULL;
1101 current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
1102 current->restart_block.nanosleep.compat_rmtp = rmtp;
1103
1104 return kc->nsleep(which_clock, flags, &t64);
1090} 1105}
1106#endif
1091 1107
1092static const struct k_clock clock_realtime = { 1108static const struct k_clock clock_realtime = {
1093 .clock_getres = posix_get_hrtimer_res, 1109 .clock_getres = posix_get_hrtimer_res,