diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-06-07 04:42:37 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2017-06-13 18:00:44 -0400 |
commit | 54ad9c46c262ce4a603dc7887e37956896a0211d (patch) | |
tree | cb056c44d5c74a913c53dcb49682c8d2b8d653bc | |
parent | b0dc12426ec404de99d7e75a12a22d9201d90914 (diff) |
itimers: Move compat itimer syscalls to native ones
get rid of set_fs(), sanitize compat copyin/copyout.
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-12-viro@ZenIV.linux.org.uk
-rw-r--r-- | include/linux/compat.h | 4 | ||||
-rw-r--r-- | kernel/compat.c | 69 | ||||
-rw-r--r-- | kernel/time/itimer.c | 38 | ||||
-rw-r--r-- | kernel/time/posix-stubs.c | 2 |
4 files changed, 60 insertions, 53 deletions
diff --git a/include/linux/compat.h b/include/linux/compat.h index ecb8dd261d36..425563c7647b 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h | |||
@@ -94,6 +94,10 @@ struct compat_itimerval { | |||
94 | struct compat_timeval it_value; | 94 | struct compat_timeval it_value; |
95 | }; | 95 | }; |
96 | 96 | ||
97 | struct itimerval; | ||
98 | int get_compat_itimerval(struct itimerval *, const struct compat_itimerval __user *); | ||
99 | int put_compat_itimerval(struct compat_itimerval __user *, const struct itimerval *); | ||
100 | |||
97 | struct compat_tms { | 101 | struct compat_tms { |
98 | compat_clock_t tms_utime; | 102 | compat_clock_t tms_utime; |
99 | compat_clock_t tms_stime; | 103 | compat_clock_t tms_stime; |
diff --git a/kernel/compat.c b/kernel/compat.c index 1fb8cf7e691e..c349417d2c40 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -217,65 +217,28 @@ int compat_convert_timespec(struct timespec __user **kts, | |||
217 | return 0; | 217 | return 0; |
218 | } | 218 | } |
219 | 219 | ||
220 | static inline long get_compat_itimerval(struct itimerval *o, | 220 | int get_compat_itimerval(struct itimerval *o, const struct compat_itimerval __user *i) |
221 | struct compat_itimerval __user *i) | ||
222 | { | 221 | { |
223 | return (!access_ok(VERIFY_READ, i, sizeof(*i)) || | 222 | struct compat_itimerval v32; |
224 | (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | | ||
225 | __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | | ||
226 | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | | ||
227 | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); | ||
228 | } | ||
229 | |||
230 | static inline long put_compat_itimerval(struct compat_itimerval __user *o, | ||
231 | struct itimerval *i) | ||
232 | { | ||
233 | return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || | ||
234 | (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | | ||
235 | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | | ||
236 | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | | ||
237 | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); | ||
238 | } | ||
239 | |||
240 | asmlinkage long sys_ni_posix_timers(void); | ||
241 | |||
242 | COMPAT_SYSCALL_DEFINE2(getitimer, int, which, | ||
243 | struct compat_itimerval __user *, it) | ||
244 | { | ||
245 | struct itimerval kit; | ||
246 | int error; | ||
247 | |||
248 | if (!IS_ENABLED(CONFIG_POSIX_TIMERS)) | ||
249 | return sys_ni_posix_timers(); | ||
250 | 223 | ||
251 | error = do_getitimer(which, &kit); | 224 | if (copy_from_user(&v32, i, sizeof(struct compat_itimerval))) |
252 | if (!error && put_compat_itimerval(it, &kit)) | 225 | return -EFAULT; |
253 | error = -EFAULT; | 226 | o->it_interval.tv_sec = v32.it_interval.tv_sec; |
254 | return error; | 227 | o->it_interval.tv_usec = v32.it_interval.tv_usec; |
228 | o->it_value.tv_sec = v32.it_value.tv_sec; | ||
229 | o->it_value.tv_usec = v32.it_value.tv_usec; | ||
230 | return 0; | ||
255 | } | 231 | } |
256 | 232 | ||
257 | COMPAT_SYSCALL_DEFINE3(setitimer, int, which, | 233 | int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerval *i) |
258 | struct compat_itimerval __user *, in, | ||
259 | struct compat_itimerval __user *, out) | ||
260 | { | 234 | { |
261 | struct itimerval kin, kout; | 235 | struct compat_itimerval v32; |
262 | int error; | ||
263 | 236 | ||
264 | if (!IS_ENABLED(CONFIG_POSIX_TIMERS)) | 237 | v32.it_interval.tv_sec = i->it_interval.tv_sec; |
265 | return sys_ni_posix_timers(); | 238 | v32.it_interval.tv_usec = i->it_interval.tv_usec; |
266 | 239 | v32.it_value.tv_sec = i->it_value.tv_sec; | |
267 | if (in) { | 240 | v32.it_value.tv_usec = i->it_value.tv_usec; |
268 | if (get_compat_itimerval(&kin, in)) | 241 | return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0; |
269 | return -EFAULT; | ||
270 | } else | ||
271 | memset(&kin, 0, sizeof(kin)); | ||
272 | |||
273 | error = do_setitimer(which, &kin, out ? &kout : NULL); | ||
274 | if (error || !out) | ||
275 | return error; | ||
276 | if (put_compat_itimerval(out, &kout)) | ||
277 | return -EFAULT; | ||
278 | return 0; | ||
279 | } | 242 | } |
280 | 243 | ||
281 | static compat_clock_t clock_t_to_compat_clock_t(clock_t x) | 244 | static compat_clock_t clock_t_to_compat_clock_t(clock_t x) |
diff --git a/kernel/time/itimer.c b/kernel/time/itimer.c index 087d6a1279b8..9dd7ff5e445a 100644 --- a/kernel/time/itimer.c +++ b/kernel/time/itimer.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/posix-timers.h> | 15 | #include <linux/posix-timers.h> |
16 | #include <linux/hrtimer.h> | 16 | #include <linux/hrtimer.h> |
17 | #include <trace/events/timer.h> | 17 | #include <trace/events/timer.h> |
18 | #include <linux/compat.h> | ||
18 | 19 | ||
19 | #include <linux/uaccess.h> | 20 | #include <linux/uaccess.h> |
20 | 21 | ||
@@ -116,6 +117,19 @@ SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value) | |||
116 | return error; | 117 | return error; |
117 | } | 118 | } |
118 | 119 | ||
120 | #ifdef CONFIG_COMPAT | ||
121 | COMPAT_SYSCALL_DEFINE2(getitimer, int, which, | ||
122 | struct compat_itimerval __user *, it) | ||
123 | { | ||
124 | struct itimerval kit; | ||
125 | int error = do_getitimer(which, &kit); | ||
126 | |||
127 | if (!error && put_compat_itimerval(it, &kit)) | ||
128 | error = -EFAULT; | ||
129 | return error; | ||
130 | } | ||
131 | #endif | ||
132 | |||
119 | 133 | ||
120 | /* | 134 | /* |
121 | * The timer is automagically restarted, when interval != 0 | 135 | * The timer is automagically restarted, when interval != 0 |
@@ -294,3 +308,27 @@ SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value, | |||
294 | return -EFAULT; | 308 | return -EFAULT; |
295 | return 0; | 309 | return 0; |
296 | } | 310 | } |
311 | |||
312 | #ifdef CONFIG_COMPAT | ||
313 | COMPAT_SYSCALL_DEFINE3(setitimer, int, which, | ||
314 | struct compat_itimerval __user *, in, | ||
315 | struct compat_itimerval __user *, out) | ||
316 | { | ||
317 | struct itimerval kin, kout; | ||
318 | int error; | ||
319 | |||
320 | if (in) { | ||
321 | if (get_compat_itimerval(&kin, in)) | ||
322 | return -EFAULT; | ||
323 | } else { | ||
324 | memset(&kin, 0, sizeof(kin)); | ||
325 | } | ||
326 | |||
327 | error = do_setitimer(which, &kin, out ? &kout : NULL); | ||
328 | if (error || !out) | ||
329 | return error; | ||
330 | if (put_compat_itimerval(out, &kout)) | ||
331 | return -EFAULT; | ||
332 | return 0; | ||
333 | } | ||
334 | #endif | ||
diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c index f4a1962d1729..7f88517461e8 100644 --- a/kernel/time/posix-stubs.c +++ b/kernel/time/posix-stubs.c | |||
@@ -44,6 +44,8 @@ SYS_NI(alarm); | |||
44 | COMPAT_SYS_NI(clock_adjtime); | 44 | COMPAT_SYS_NI(clock_adjtime); |
45 | COMPAT_SYS_NI(timer_settime); | 45 | COMPAT_SYS_NI(timer_settime); |
46 | COMPAT_SYS_NI(timer_gettime); | 46 | COMPAT_SYS_NI(timer_gettime); |
47 | COMPAT_SYS_NI(getitimer); | ||
48 | COMPAT_SYS_NI(setitimer); | ||
47 | 49 | ||
48 | /* | 50 | /* |
49 | * We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC | 51 | * We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC |