diff options
Diffstat (limited to 'kernel/compat.c')
-rw-r--r-- | kernel/compat.c | 117 |
1 files changed, 41 insertions, 76 deletions
diff --git a/kernel/compat.c b/kernel/compat.c index 3bae3742c2aa..42a1ed4b61b1 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -40,62 +40,27 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user | |||
40 | __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; | 40 | __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; |
41 | } | 41 | } |
42 | 42 | ||
43 | static long compat_nanosleep_restart(struct restart_block *restart) | ||
44 | { | ||
45 | unsigned long expire = restart->arg0, now = jiffies; | ||
46 | struct compat_timespec __user *rmtp; | ||
47 | |||
48 | /* Did it expire while we handled signals? */ | ||
49 | if (!time_after(expire, now)) | ||
50 | return 0; | ||
51 | |||
52 | expire = schedule_timeout_interruptible(expire - now); | ||
53 | if (expire == 0) | ||
54 | return 0; | ||
55 | |||
56 | rmtp = (struct compat_timespec __user *)restart->arg1; | ||
57 | if (rmtp) { | ||
58 | struct compat_timespec ct; | ||
59 | struct timespec t; | ||
60 | |||
61 | jiffies_to_timespec(expire, &t); | ||
62 | ct.tv_sec = t.tv_sec; | ||
63 | ct.tv_nsec = t.tv_nsec; | ||
64 | if (copy_to_user(rmtp, &ct, sizeof(ct))) | ||
65 | return -EFAULT; | ||
66 | } | ||
67 | /* The 'restart' block is already filled in */ | ||
68 | return -ERESTART_RESTARTBLOCK; | ||
69 | } | ||
70 | |||
71 | asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, | 43 | asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, |
72 | struct compat_timespec __user *rmtp) | 44 | struct compat_timespec __user *rmtp) |
73 | { | 45 | { |
74 | struct timespec t; | 46 | struct timespec tu, rmt; |
75 | struct restart_block *restart; | 47 | long ret; |
76 | unsigned long expire; | ||
77 | 48 | ||
78 | if (get_compat_timespec(&t, rqtp)) | 49 | if (get_compat_timespec(&tu, rqtp)) |
79 | return -EFAULT; | 50 | return -EFAULT; |
80 | 51 | ||
81 | if ((t.tv_nsec >= 1000000000L) || (t.tv_nsec < 0) || (t.tv_sec < 0)) | 52 | if (!timespec_valid(&tu)) |
82 | return -EINVAL; | 53 | return -EINVAL; |
83 | 54 | ||
84 | expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); | 55 | ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, |
85 | expire = schedule_timeout_interruptible(expire); | 56 | CLOCK_MONOTONIC); |
86 | if (expire == 0) | ||
87 | return 0; | ||
88 | 57 | ||
89 | if (rmtp) { | 58 | if (ret && rmtp) { |
90 | jiffies_to_timespec(expire, &t); | 59 | if (put_compat_timespec(&rmt, rmtp)) |
91 | if (put_compat_timespec(&t, rmtp)) | ||
92 | return -EFAULT; | 60 | return -EFAULT; |
93 | } | 61 | } |
94 | restart = ¤t_thread_info()->restart_block; | 62 | |
95 | restart->fn = compat_nanosleep_restart; | 63 | return ret; |
96 | restart->arg0 = jiffies + expire; | ||
97 | restart->arg1 = (unsigned long) rmtp; | ||
98 | return -ERESTART_RESTARTBLOCK; | ||
99 | } | 64 | } |
100 | 65 | ||
101 | static inline long get_compat_itimerval(struct itimerval *o, | 66 | static inline long get_compat_itimerval(struct itimerval *o, |
@@ -247,8 +212,8 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource, | |||
247 | int ret; | 212 | int ret; |
248 | mm_segment_t old_fs = get_fs (); | 213 | mm_segment_t old_fs = get_fs (); |
249 | 214 | ||
250 | if (resource >= RLIM_NLIMITS) | 215 | if (resource >= RLIM_NLIMITS) |
251 | return -EINVAL; | 216 | return -EINVAL; |
252 | 217 | ||
253 | if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) || | 218 | if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) || |
254 | __get_user(r.rlim_cur, &rlim->rlim_cur) || | 219 | __get_user(r.rlim_cur, &rlim->rlim_cur) || |
@@ -477,21 +442,21 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, | |||
477 | 442 | ||
478 | int get_compat_itimerspec(struct itimerspec *dst, | 443 | int get_compat_itimerspec(struct itimerspec *dst, |
479 | const struct compat_itimerspec __user *src) | 444 | const struct compat_itimerspec __user *src) |
480 | { | 445 | { |
481 | if (get_compat_timespec(&dst->it_interval, &src->it_interval) || | 446 | if (get_compat_timespec(&dst->it_interval, &src->it_interval) || |
482 | get_compat_timespec(&dst->it_value, &src->it_value)) | 447 | get_compat_timespec(&dst->it_value, &src->it_value)) |
483 | return -EFAULT; | 448 | return -EFAULT; |
484 | return 0; | 449 | return 0; |
485 | } | 450 | } |
486 | 451 | ||
487 | int put_compat_itimerspec(struct compat_itimerspec __user *dst, | 452 | int put_compat_itimerspec(struct compat_itimerspec __user *dst, |
488 | const struct itimerspec *src) | 453 | const struct itimerspec *src) |
489 | { | 454 | { |
490 | if (put_compat_timespec(&src->it_interval, &dst->it_interval) || | 455 | if (put_compat_timespec(&src->it_interval, &dst->it_interval) || |
491 | put_compat_timespec(&src->it_value, &dst->it_value)) | 456 | put_compat_timespec(&src->it_value, &dst->it_value)) |
492 | return -EFAULT; | 457 | return -EFAULT; |
493 | return 0; | 458 | return 0; |
494 | } | 459 | } |
495 | 460 | ||
496 | long compat_sys_timer_create(clockid_t which_clock, | 461 | long compat_sys_timer_create(clockid_t which_clock, |
497 | struct compat_sigevent __user *timer_event_spec, | 462 | struct compat_sigevent __user *timer_event_spec, |
@@ -512,9 +477,9 @@ long compat_sys_timer_create(clockid_t which_clock, | |||
512 | } | 477 | } |
513 | 478 | ||
514 | long compat_sys_timer_settime(timer_t timer_id, int flags, | 479 | long compat_sys_timer_settime(timer_t timer_id, int flags, |
515 | struct compat_itimerspec __user *new, | 480 | struct compat_itimerspec __user *new, |
516 | struct compat_itimerspec __user *old) | 481 | struct compat_itimerspec __user *old) |
517 | { | 482 | { |
518 | long err; | 483 | long err; |
519 | mm_segment_t oldfs; | 484 | mm_segment_t oldfs; |
520 | struct itimerspec newts, oldts; | 485 | struct itimerspec newts, oldts; |
@@ -522,58 +487,58 @@ long compat_sys_timer_settime(timer_t timer_id, int flags, | |||
522 | if (!new) | 487 | if (!new) |
523 | return -EINVAL; | 488 | return -EINVAL; |
524 | if (get_compat_itimerspec(&newts, new)) | 489 | if (get_compat_itimerspec(&newts, new)) |
525 | return -EFAULT; | 490 | return -EFAULT; |
526 | oldfs = get_fs(); | 491 | oldfs = get_fs(); |
527 | set_fs(KERNEL_DS); | 492 | set_fs(KERNEL_DS); |
528 | err = sys_timer_settime(timer_id, flags, | 493 | err = sys_timer_settime(timer_id, flags, |
529 | (struct itimerspec __user *) &newts, | 494 | (struct itimerspec __user *) &newts, |
530 | (struct itimerspec __user *) &oldts); | 495 | (struct itimerspec __user *) &oldts); |
531 | set_fs(oldfs); | 496 | set_fs(oldfs); |
532 | if (!err && old && put_compat_itimerspec(old, &oldts)) | 497 | if (!err && old && put_compat_itimerspec(old, &oldts)) |
533 | return -EFAULT; | 498 | return -EFAULT; |
534 | return err; | 499 | return err; |
535 | } | 500 | } |
536 | 501 | ||
537 | long compat_sys_timer_gettime(timer_t timer_id, | 502 | long compat_sys_timer_gettime(timer_t timer_id, |
538 | struct compat_itimerspec __user *setting) | 503 | struct compat_itimerspec __user *setting) |
539 | { | 504 | { |
540 | long err; | 505 | long err; |
541 | mm_segment_t oldfs; | 506 | mm_segment_t oldfs; |
542 | struct itimerspec ts; | 507 | struct itimerspec ts; |
543 | 508 | ||
544 | oldfs = get_fs(); | 509 | oldfs = get_fs(); |
545 | set_fs(KERNEL_DS); | 510 | set_fs(KERNEL_DS); |
546 | err = sys_timer_gettime(timer_id, | 511 | err = sys_timer_gettime(timer_id, |
547 | (struct itimerspec __user *) &ts); | 512 | (struct itimerspec __user *) &ts); |
548 | set_fs(oldfs); | 513 | set_fs(oldfs); |
549 | if (!err && put_compat_itimerspec(setting, &ts)) | 514 | if (!err && put_compat_itimerspec(setting, &ts)) |
550 | return -EFAULT; | 515 | return -EFAULT; |
551 | return err; | 516 | return err; |
552 | } | 517 | } |
553 | 518 | ||
554 | long compat_sys_clock_settime(clockid_t which_clock, | 519 | long compat_sys_clock_settime(clockid_t which_clock, |
555 | struct compat_timespec __user *tp) | 520 | struct compat_timespec __user *tp) |
556 | { | 521 | { |
557 | long err; | 522 | long err; |
558 | mm_segment_t oldfs; | 523 | mm_segment_t oldfs; |
559 | struct timespec ts; | 524 | struct timespec ts; |
560 | 525 | ||
561 | if (get_compat_timespec(&ts, tp)) | 526 | if (get_compat_timespec(&ts, tp)) |
562 | return -EFAULT; | 527 | return -EFAULT; |
563 | oldfs = get_fs(); | 528 | oldfs = get_fs(); |
564 | set_fs(KERNEL_DS); | 529 | set_fs(KERNEL_DS); |
565 | err = sys_clock_settime(which_clock, | 530 | err = sys_clock_settime(which_clock, |
566 | (struct timespec __user *) &ts); | 531 | (struct timespec __user *) &ts); |
567 | set_fs(oldfs); | 532 | set_fs(oldfs); |
568 | return err; | 533 | return err; |
569 | } | 534 | } |
570 | 535 | ||
571 | long compat_sys_clock_gettime(clockid_t which_clock, | 536 | long compat_sys_clock_gettime(clockid_t which_clock, |
572 | struct compat_timespec __user *tp) | 537 | struct compat_timespec __user *tp) |
573 | { | 538 | { |
574 | long err; | 539 | long err; |
575 | mm_segment_t oldfs; | 540 | mm_segment_t oldfs; |
576 | struct timespec ts; | 541 | struct timespec ts; |
577 | 542 | ||
578 | oldfs = get_fs(); | 543 | oldfs = get_fs(); |
579 | set_fs(KERNEL_DS); | 544 | set_fs(KERNEL_DS); |
@@ -581,16 +546,16 @@ long compat_sys_clock_gettime(clockid_t which_clock, | |||
581 | (struct timespec __user *) &ts); | 546 | (struct timespec __user *) &ts); |
582 | set_fs(oldfs); | 547 | set_fs(oldfs); |
583 | if (!err && put_compat_timespec(&ts, tp)) | 548 | if (!err && put_compat_timespec(&ts, tp)) |
584 | return -EFAULT; | 549 | return -EFAULT; |
585 | return err; | 550 | return err; |
586 | } | 551 | } |
587 | 552 | ||
588 | long compat_sys_clock_getres(clockid_t which_clock, | 553 | long compat_sys_clock_getres(clockid_t which_clock, |
589 | struct compat_timespec __user *tp) | 554 | struct compat_timespec __user *tp) |
590 | { | 555 | { |
591 | long err; | 556 | long err; |
592 | mm_segment_t oldfs; | 557 | mm_segment_t oldfs; |
593 | struct timespec ts; | 558 | struct timespec ts; |
594 | 559 | ||
595 | oldfs = get_fs(); | 560 | oldfs = get_fs(); |
596 | set_fs(KERNEL_DS); | 561 | set_fs(KERNEL_DS); |
@@ -598,9 +563,9 @@ long compat_sys_clock_getres(clockid_t which_clock, | |||
598 | (struct timespec __user *) &ts); | 563 | (struct timespec __user *) &ts); |
599 | set_fs(oldfs); | 564 | set_fs(oldfs); |
600 | if (!err && tp && put_compat_timespec(&ts, tp)) | 565 | if (!err && tp && put_compat_timespec(&ts, tp)) |
601 | return -EFAULT; | 566 | return -EFAULT; |
602 | return err; | 567 | return err; |
603 | } | 568 | } |
604 | 569 | ||
605 | static long compat_clock_nanosleep_restart(struct restart_block *restart) | 570 | static long compat_clock_nanosleep_restart(struct restart_block *restart) |
606 | { | 571 | { |
@@ -632,10 +597,10 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, | |||
632 | { | 597 | { |
633 | long err; | 598 | long err; |
634 | mm_segment_t oldfs; | 599 | mm_segment_t oldfs; |
635 | struct timespec in, out; | 600 | struct timespec in, out; |
636 | struct restart_block *restart; | 601 | struct restart_block *restart; |
637 | 602 | ||
638 | if (get_compat_timespec(&in, rqtp)) | 603 | if (get_compat_timespec(&in, rqtp)) |
639 | return -EFAULT; | 604 | return -EFAULT; |
640 | 605 | ||
641 | oldfs = get_fs(); | 606 | oldfs = get_fs(); |
@@ -654,8 +619,8 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, | |||
654 | restart->fn = compat_clock_nanosleep_restart; | 619 | restart->fn = compat_clock_nanosleep_restart; |
655 | restart->arg1 = (unsigned long) rmtp; | 620 | restart->arg1 = (unsigned long) rmtp; |
656 | } | 621 | } |
657 | return err; | 622 | return err; |
658 | } | 623 | } |
659 | 624 | ||
660 | /* | 625 | /* |
661 | * We currently only need the following fields from the sigevent | 626 | * We currently only need the following fields from the sigevent |