diff options
-rw-r--r-- | fs/compat.c | 41 | ||||
-rw-r--r-- | fs/timerfd.c | 85 |
2 files changed, 66 insertions, 60 deletions
diff --git a/fs/compat.c b/fs/compat.c index f9e2fe3794fa..fe40fde29111 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -1737,47 +1737,6 @@ asmlinkage long compat_sys_signalfd(int ufd, | |||
1737 | } | 1737 | } |
1738 | #endif /* CONFIG_SIGNALFD */ | 1738 | #endif /* CONFIG_SIGNALFD */ |
1739 | 1739 | ||
1740 | #ifdef CONFIG_TIMERFD | ||
1741 | |||
1742 | asmlinkage long compat_sys_timerfd_settime(int ufd, int flags, | ||
1743 | const struct compat_itimerspec __user *utmr, | ||
1744 | struct compat_itimerspec __user *otmr) | ||
1745 | { | ||
1746 | int error; | ||
1747 | struct itimerspec t; | ||
1748 | struct itimerspec __user *ut; | ||
1749 | |||
1750 | if (get_compat_itimerspec(&t, utmr)) | ||
1751 | return -EFAULT; | ||
1752 | ut = compat_alloc_user_space(2 * sizeof(struct itimerspec)); | ||
1753 | if (copy_to_user(&ut[0], &t, sizeof(t))) | ||
1754 | return -EFAULT; | ||
1755 | error = sys_timerfd_settime(ufd, flags, &ut[0], &ut[1]); | ||
1756 | if (!error && otmr) | ||
1757 | error = (copy_from_user(&t, &ut[1], sizeof(struct itimerspec)) || | ||
1758 | put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0; | ||
1759 | |||
1760 | return error; | ||
1761 | } | ||
1762 | |||
1763 | asmlinkage long compat_sys_timerfd_gettime(int ufd, | ||
1764 | struct compat_itimerspec __user *otmr) | ||
1765 | { | ||
1766 | int error; | ||
1767 | struct itimerspec t; | ||
1768 | struct itimerspec __user *ut; | ||
1769 | |||
1770 | ut = compat_alloc_user_space(sizeof(struct itimerspec)); | ||
1771 | error = sys_timerfd_gettime(ufd, ut); | ||
1772 | if (!error) | ||
1773 | error = (copy_from_user(&t, ut, sizeof(struct itimerspec)) || | ||
1774 | put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0; | ||
1775 | |||
1776 | return error; | ||
1777 | } | ||
1778 | |||
1779 | #endif /* CONFIG_TIMERFD */ | ||
1780 | |||
1781 | #ifdef CONFIG_FHANDLE | 1740 | #ifdef CONFIG_FHANDLE |
1782 | /* | 1741 | /* |
1783 | * Exactly like fs/open.c:sys_open_by_handle_at(), except that it | 1742 | * Exactly like fs/open.c:sys_open_by_handle_at(), except that it |
diff --git a/fs/timerfd.c b/fs/timerfd.c index d03822bbf190..0e606b12a59d 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/anon_inodes.h> | 22 | #include <linux/anon_inodes.h> |
23 | #include <linux/timerfd.h> | 23 | #include <linux/timerfd.h> |
24 | #include <linux/syscalls.h> | 24 | #include <linux/syscalls.h> |
25 | #include <linux/compat.h> | ||
25 | #include <linux/rcupdate.h> | 26 | #include <linux/rcupdate.h> |
26 | 27 | ||
27 | struct timerfd_ctx { | 28 | struct timerfd_ctx { |
@@ -278,21 +279,17 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) | |||
278 | return ufd; | 279 | return ufd; |
279 | } | 280 | } |
280 | 281 | ||
281 | SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, | 282 | static int do_timerfd_settime(int ufd, int flags, |
282 | const struct itimerspec __user *, utmr, | 283 | const struct itimerspec *new, |
283 | struct itimerspec __user *, otmr) | 284 | struct itimerspec *old) |
284 | { | 285 | { |
285 | struct fd f; | 286 | struct fd f; |
286 | struct timerfd_ctx *ctx; | 287 | struct timerfd_ctx *ctx; |
287 | struct itimerspec ktmr, kotmr; | ||
288 | int ret; | 288 | int ret; |
289 | 289 | ||
290 | if (copy_from_user(&ktmr, utmr, sizeof(ktmr))) | ||
291 | return -EFAULT; | ||
292 | |||
293 | if ((flags & ~TFD_SETTIME_FLAGS) || | 290 | if ((flags & ~TFD_SETTIME_FLAGS) || |
294 | !timespec_valid(&ktmr.it_value) || | 291 | !timespec_valid(&new->it_value) || |
295 | !timespec_valid(&ktmr.it_interval)) | 292 | !timespec_valid(&new->it_interval)) |
296 | return -EINVAL; | 293 | return -EINVAL; |
297 | 294 | ||
298 | ret = timerfd_fget(ufd, &f); | 295 | ret = timerfd_fget(ufd, &f); |
@@ -323,27 +320,23 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, | |||
323 | if (ctx->expired && ctx->tintv.tv64) | 320 | if (ctx->expired && ctx->tintv.tv64) |
324 | hrtimer_forward_now(&ctx->tmr, ctx->tintv); | 321 | hrtimer_forward_now(&ctx->tmr, ctx->tintv); |
325 | 322 | ||
326 | kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); | 323 | old->it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); |
327 | kotmr.it_interval = ktime_to_timespec(ctx->tintv); | 324 | old->it_interval = ktime_to_timespec(ctx->tintv); |
328 | 325 | ||
329 | /* | 326 | /* |
330 | * Re-program the timer to the new value ... | 327 | * Re-program the timer to the new value ... |
331 | */ | 328 | */ |
332 | ret = timerfd_setup(ctx, flags, &ktmr); | 329 | ret = timerfd_setup(ctx, flags, new); |
333 | 330 | ||
334 | spin_unlock_irq(&ctx->wqh.lock); | 331 | spin_unlock_irq(&ctx->wqh.lock); |
335 | fdput(f); | 332 | fdput(f); |
336 | if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr))) | ||
337 | return -EFAULT; | ||
338 | |||
339 | return ret; | 333 | return ret; |
340 | } | 334 | } |
341 | 335 | ||
342 | SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) | 336 | static int do_timerfd_gettime(int ufd, struct itimerspec *t) |
343 | { | 337 | { |
344 | struct fd f; | 338 | struct fd f; |
345 | struct timerfd_ctx *ctx; | 339 | struct timerfd_ctx *ctx; |
346 | struct itimerspec kotmr; | ||
347 | int ret = timerfd_fget(ufd, &f); | 340 | int ret = timerfd_fget(ufd, &f); |
348 | if (ret) | 341 | if (ret) |
349 | return ret; | 342 | return ret; |
@@ -356,11 +349,65 @@ SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) | |||
356 | hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1; | 349 | hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1; |
357 | hrtimer_restart(&ctx->tmr); | 350 | hrtimer_restart(&ctx->tmr); |
358 | } | 351 | } |
359 | kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); | 352 | t->it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); |
360 | kotmr.it_interval = ktime_to_timespec(ctx->tintv); | 353 | t->it_interval = ktime_to_timespec(ctx->tintv); |
361 | spin_unlock_irq(&ctx->wqh.lock); | 354 | spin_unlock_irq(&ctx->wqh.lock); |
362 | fdput(f); | 355 | fdput(f); |
356 | return 0; | ||
357 | } | ||
358 | |||
359 | SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, | ||
360 | const struct itimerspec __user *, utmr, | ||
361 | struct itimerspec __user *, otmr) | ||
362 | { | ||
363 | struct itimerspec new, old; | ||
364 | int ret; | ||
365 | |||
366 | if (copy_from_user(&new, utmr, sizeof(new))) | ||
367 | return -EFAULT; | ||
368 | ret = do_timerfd_settime(ufd, flags, &new, &old); | ||
369 | if (ret) | ||
370 | return ret; | ||
371 | if (otmr && copy_to_user(otmr, &old, sizeof(old))) | ||
372 | return -EFAULT; | ||
373 | |||
374 | return ret; | ||
375 | } | ||
363 | 376 | ||
377 | SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) | ||
378 | { | ||
379 | struct itimerspec kotmr; | ||
380 | int ret = do_timerfd_gettime(ufd, &kotmr); | ||
381 | if (ret) | ||
382 | return ret; | ||
364 | return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0; | 383 | return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0; |
365 | } | 384 | } |
366 | 385 | ||
386 | #ifdef COMPAT | ||
387 | COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, | ||
388 | const struct itimerspec __user *, utmr, | ||
389 | struct itimerspec __user *, otmr) | ||
390 | { | ||
391 | struct itimerspec new, old; | ||
392 | int ret; | ||
393 | |||
394 | if (get_compat_itimerspec(&new, utmr)) | ||
395 | return -EFAULT; | ||
396 | ret = do_timerfd_settime(ufd, flags, &new, &old); | ||
397 | if (ret) | ||
398 | return ret; | ||
399 | if (otmr && put_compat_itimerspec(otmr, &old)) | ||
400 | return -EFAULT; | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | COMPAT_SYSCALL_DEFINE2(timerfd_gettime, int, ufd, | ||
405 | struct itimerspec __user *, otmr) | ||
406 | { | ||
407 | struct itimerspec kotmr; | ||
408 | int ret = do_timerfd_gettime(ufd, &kotmr); | ||
409 | if (ret) | ||
410 | return ret; | ||
411 | return put_compat_itimerspec(otmr, &t) ? -EFAULT: 0; | ||
412 | } | ||
413 | #endif | ||