diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2017-06-07 04:42:31 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2017-06-13 18:00:42 -0400 |
| commit | edbeda46322fbcb15af2d2d0f2daffb0cd349a5a (patch) | |
| tree | a4aa5436d4e5dcce6f4d041d13c521e1660331b7 /kernel/time | |
| parent | 99e6c0e6ec349575886ca7daffc9cb7ec583176f (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.c | 16 | ||||
| -rw-r--r-- | kernel/time/hrtimer.c | 42 | ||||
| -rw-r--r-- | kernel/time/posix-cpu-timers.c | 20 | ||||
| -rw-r--r-- | kernel/time/posix-stubs.c | 55 | ||||
| -rw-r--r-- | kernel/time/posix-timers.c | 32 |
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, | |||
| 691 | static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp, | 692 | static 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 = ¤t->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 | ||
| 1442 | static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) | 1443 | static 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 = ¤t->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 | |||
| 1555 | COMPAT_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 = ¤t->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 = ¤t->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 | ||
| 21 | asmlinkage long sys_ni_posix_timers(void) | 22 | asmlinkage 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 |
| 130 | long clock_nanosleep_restart(struct restart_block *restart_block) | 134 | COMPAT_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 | 1080 | COMPAT_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) |
| 1081 | long 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 | ||
| 1092 | static const struct k_clock clock_realtime = { | 1108 | static const struct k_clock clock_realtime = { |
| 1093 | .clock_getres = posix_get_hrtimer_res, | 1109 | .clock_getres = posix_get_hrtimer_res, |
