aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
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
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')
-rw-r--r--kernel/compat.c131
-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
6 files changed, 129 insertions, 167 deletions
diff --git a/kernel/compat.c b/kernel/compat.c
index cc9ba9d29b47..23afa26f574b 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -213,82 +213,6 @@ int compat_convert_timespec(struct timespec __user **kts,
213 return 0; 213 return 0;
214} 214}
215 215
216static long compat_nanosleep_restart(struct restart_block *restart)
217{
218 struct compat_timespec __user *rmtp;
219 struct timespec rmt;
220 mm_segment_t oldfs;
221 long ret;
222
223 restart->nanosleep.rmtp = (struct timespec __user *) &rmt;
224 oldfs = get_fs();
225 set_fs(KERNEL_DS);
226 ret = hrtimer_nanosleep_restart(restart);
227 set_fs(oldfs);
228
229 if (ret == -ERESTART_RESTARTBLOCK) {
230 rmtp = restart->nanosleep.compat_rmtp;
231
232 if (rmtp && compat_put_timespec(&rmt, rmtp))
233 return -EFAULT;
234 }
235
236 return ret;
237}
238
239COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
240 struct compat_timespec __user *, rmtp)
241{
242 struct timespec tu, rmt;
243 struct timespec64 tu64;
244 mm_segment_t oldfs;
245 long ret;
246
247 if (compat_get_timespec(&tu, rqtp))
248 return -EFAULT;
249
250 tu64 = timespec_to_timespec64(tu);
251 if (!timespec64_valid(&tu64))
252 return -EINVAL;
253
254 oldfs = get_fs();
255 set_fs(KERNEL_DS);
256 current->restart_block.nanosleep.rmtp =
257 rmtp ? (struct timespec __user *)&rmt : NULL;
258 ret = hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
259 set_fs(oldfs);
260
261 /*
262 * hrtimer_nanosleep() can only return 0 or
263 * -ERESTART_RESTARTBLOCK here because:
264 *
265 * - we call it with HRTIMER_MODE_REL and therefor exclude the
266 * -ERESTARTNOHAND return path.
267 *
268 * - we supply the rmtp argument from the task stack (due to
269 * the necessary compat conversion. So the update cannot
270 * fail, which excludes the -EFAULT return path as well. If
271 * it fails nevertheless we have a bigger problem and wont
272 * reach this place anymore.
273 *
274 * - if the return value is 0, we do not have to update rmtp
275 * because there is no remaining time.
276 *
277 * We check for -ERESTART_RESTARTBLOCK nevertheless if the
278 * core implementation decides to return random nonsense.
279 */
280 if (ret == -ERESTART_RESTARTBLOCK) {
281 struct restart_block *restart = &current->restart_block;
282
283 restart->fn = compat_nanosleep_restart;
284 restart->nanosleep.compat_rmtp = rmtp;
285
286 if (rmtp && compat_put_timespec(&rmt, rmtp))
287 return -EFAULT;
288 }
289 return ret;
290}
291
292static inline long get_compat_itimerval(struct itimerval *o, 216static inline long get_compat_itimerval(struct itimerval *o,
293 struct compat_itimerval __user *i) 217 struct compat_itimerval __user *i)
294{ 218{
@@ -821,61 +745,6 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock,
821 return err; 745 return err;
822} 746}
823 747
824static long compat_clock_nanosleep_restart(struct restart_block *restart)
825{
826 long err;
827 mm_segment_t oldfs;
828 struct timespec tu;
829 struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp;
830
831 restart->nanosleep.rmtp = (struct timespec __user *) &tu;
832 oldfs = get_fs();
833 set_fs(KERNEL_DS);
834 err = clock_nanosleep_restart(restart);
835 set_fs(oldfs);
836
837 if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
838 compat_put_timespec(&tu, rmtp))
839 return -EFAULT;
840
841 if (err == -ERESTART_RESTARTBLOCK) {
842 restart->fn = compat_clock_nanosleep_restart;
843 restart->nanosleep.compat_rmtp = rmtp;
844 }
845 return err;
846}
847
848COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
849 struct compat_timespec __user *, rqtp,
850 struct compat_timespec __user *, rmtp)
851{
852 long err;
853 mm_segment_t oldfs;
854 struct timespec in, out;
855 struct restart_block *restart;
856
857 if (compat_get_timespec(&in, rqtp))
858 return -EFAULT;
859
860 oldfs = get_fs();
861 set_fs(KERNEL_DS);
862 err = sys_clock_nanosleep(which_clock, flags,
863 (struct timespec __user *) &in,
864 (struct timespec __user *) &out);
865 set_fs(oldfs);
866
867 if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
868 compat_put_timespec(&out, rmtp))
869 return -EFAULT;
870
871 if (err == -ERESTART_RESTARTBLOCK) {
872 restart = &current->restart_block;
873 restart->fn = compat_clock_nanosleep_restart;
874 restart->nanosleep.compat_rmtp = rmtp;
875 }
876 return err;
877}
878
879/* 748/*
880 * We currently only need the following fields from the sigevent 749 * We currently only need the following fields from the sigevent
881 * structure: sigev_value, sigev_signo, sig_notify and (sometimes 750 * structure: sigev_value, sigev_signo, sig_notify and (sometimes
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,