diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 592 |
1 files changed, 337 insertions, 255 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 31deba8f7d16..763c3c17ded3 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/task_io_accounting_ops.h> | 33 | #include <linux/task_io_accounting_ops.h> |
34 | #include <linux/seccomp.h> | 34 | #include <linux/seccomp.h> |
35 | #include <linux/cpu.h> | 35 | #include <linux/cpu.h> |
36 | #include <linux/ptrace.h> | ||
36 | 37 | ||
37 | #include <linux/compat.h> | 38 | #include <linux/compat.h> |
38 | #include <linux/syscalls.h> | 39 | #include <linux/syscalls.h> |
@@ -112,12 +113,17 @@ EXPORT_SYMBOL(cad_pid); | |||
112 | 113 | ||
113 | void (*pm_power_off_prepare)(void); | 114 | void (*pm_power_off_prepare)(void); |
114 | 115 | ||
116 | /* | ||
117 | * set the priority of a task | ||
118 | * - the caller must hold the RCU read lock | ||
119 | */ | ||
115 | static int set_one_prio(struct task_struct *p, int niceval, int error) | 120 | static int set_one_prio(struct task_struct *p, int niceval, int error) |
116 | { | 121 | { |
122 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); | ||
117 | int no_nice; | 123 | int no_nice; |
118 | 124 | ||
119 | if (p->uid != current->euid && | 125 | if (pcred->uid != cred->euid && |
120 | p->euid != current->euid && !capable(CAP_SYS_NICE)) { | 126 | pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) { |
121 | error = -EPERM; | 127 | error = -EPERM; |
122 | goto out; | 128 | goto out; |
123 | } | 129 | } |
@@ -141,6 +147,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) | |||
141 | { | 147 | { |
142 | struct task_struct *g, *p; | 148 | struct task_struct *g, *p; |
143 | struct user_struct *user; | 149 | struct user_struct *user; |
150 | const struct cred *cred = current_cred(); | ||
144 | int error = -EINVAL; | 151 | int error = -EINVAL; |
145 | struct pid *pgrp; | 152 | struct pid *pgrp; |
146 | 153 | ||
@@ -174,18 +181,18 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) | |||
174 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 181 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
175 | break; | 182 | break; |
176 | case PRIO_USER: | 183 | case PRIO_USER: |
177 | user = current->user; | 184 | user = (struct user_struct *) cred->user; |
178 | if (!who) | 185 | if (!who) |
179 | who = current->uid; | 186 | who = cred->uid; |
180 | else | 187 | else if ((who != cred->uid) && |
181 | if ((who != current->uid) && !(user = find_user(who))) | 188 | !(user = find_user(who))) |
182 | goto out_unlock; /* No processes for this user */ | 189 | goto out_unlock; /* No processes for this user */ |
183 | 190 | ||
184 | do_each_thread(g, p) | 191 | do_each_thread(g, p) |
185 | if (p->uid == who) | 192 | if (__task_cred(p)->uid == who) |
186 | error = set_one_prio(p, niceval, error); | 193 | error = set_one_prio(p, niceval, error); |
187 | while_each_thread(g, p); | 194 | while_each_thread(g, p); |
188 | if (who != current->uid) | 195 | if (who != cred->uid) |
189 | free_uid(user); /* For find_user() */ | 196 | free_uid(user); /* For find_user() */ |
190 | break; | 197 | break; |
191 | } | 198 | } |
@@ -205,6 +212,7 @@ asmlinkage long sys_getpriority(int which, int who) | |||
205 | { | 212 | { |
206 | struct task_struct *g, *p; | 213 | struct task_struct *g, *p; |
207 | struct user_struct *user; | 214 | struct user_struct *user; |
215 | const struct cred *cred = current_cred(); | ||
208 | long niceval, retval = -ESRCH; | 216 | long niceval, retval = -ESRCH; |
209 | struct pid *pgrp; | 217 | struct pid *pgrp; |
210 | 218 | ||
@@ -236,21 +244,21 @@ asmlinkage long sys_getpriority(int which, int who) | |||
236 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 244 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
237 | break; | 245 | break; |
238 | case PRIO_USER: | 246 | case PRIO_USER: |
239 | user = current->user; | 247 | user = (struct user_struct *) cred->user; |
240 | if (!who) | 248 | if (!who) |
241 | who = current->uid; | 249 | who = cred->uid; |
242 | else | 250 | else if ((who != cred->uid) && |
243 | if ((who != current->uid) && !(user = find_user(who))) | 251 | !(user = find_user(who))) |
244 | goto out_unlock; /* No processes for this user */ | 252 | goto out_unlock; /* No processes for this user */ |
245 | 253 | ||
246 | do_each_thread(g, p) | 254 | do_each_thread(g, p) |
247 | if (p->uid == who) { | 255 | if (__task_cred(p)->uid == who) { |
248 | niceval = 20 - task_nice(p); | 256 | niceval = 20 - task_nice(p); |
249 | if (niceval > retval) | 257 | if (niceval > retval) |
250 | retval = niceval; | 258 | retval = niceval; |
251 | } | 259 | } |
252 | while_each_thread(g, p); | 260 | while_each_thread(g, p); |
253 | if (who != current->uid) | 261 | if (who != cred->uid) |
254 | free_uid(user); /* for find_user() */ | 262 | free_uid(user); /* for find_user() */ |
255 | break; | 263 | break; |
256 | } | 264 | } |
@@ -472,46 +480,48 @@ void ctrl_alt_del(void) | |||
472 | */ | 480 | */ |
473 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | 481 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) |
474 | { | 482 | { |
475 | int old_rgid = current->gid; | 483 | const struct cred *old; |
476 | int old_egid = current->egid; | 484 | struct cred *new; |
477 | int new_rgid = old_rgid; | ||
478 | int new_egid = old_egid; | ||
479 | int retval; | 485 | int retval; |
480 | 486 | ||
487 | new = prepare_creds(); | ||
488 | if (!new) | ||
489 | return -ENOMEM; | ||
490 | old = current_cred(); | ||
491 | |||
481 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); | 492 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); |
482 | if (retval) | 493 | if (retval) |
483 | return retval; | 494 | goto error; |
484 | 495 | ||
496 | retval = -EPERM; | ||
485 | if (rgid != (gid_t) -1) { | 497 | if (rgid != (gid_t) -1) { |
486 | if ((old_rgid == rgid) || | 498 | if (old->gid == rgid || |
487 | (current->egid==rgid) || | 499 | old->egid == rgid || |
488 | capable(CAP_SETGID)) | 500 | capable(CAP_SETGID)) |
489 | new_rgid = rgid; | 501 | new->gid = rgid; |
490 | else | 502 | else |
491 | return -EPERM; | 503 | goto error; |
492 | } | 504 | } |
493 | if (egid != (gid_t) -1) { | 505 | if (egid != (gid_t) -1) { |
494 | if ((old_rgid == egid) || | 506 | if (old->gid == egid || |
495 | (current->egid == egid) || | 507 | old->egid == egid || |
496 | (current->sgid == egid) || | 508 | old->sgid == egid || |
497 | capable(CAP_SETGID)) | 509 | capable(CAP_SETGID)) |
498 | new_egid = egid; | 510 | new->egid = egid; |
499 | else | 511 | else |
500 | return -EPERM; | 512 | goto error; |
501 | } | ||
502 | if (new_egid != old_egid) { | ||
503 | set_dumpable(current->mm, suid_dumpable); | ||
504 | smp_wmb(); | ||
505 | } | 513 | } |
514 | |||
506 | if (rgid != (gid_t) -1 || | 515 | if (rgid != (gid_t) -1 || |
507 | (egid != (gid_t) -1 && egid != old_rgid)) | 516 | (egid != (gid_t) -1 && egid != old->gid)) |
508 | current->sgid = new_egid; | 517 | new->sgid = new->egid; |
509 | current->fsgid = new_egid; | 518 | new->fsgid = new->egid; |
510 | current->egid = new_egid; | 519 | |
511 | current->gid = new_rgid; | 520 | return commit_creds(new); |
512 | key_fsgid_changed(current); | 521 | |
513 | proc_id_connector(current, PROC_EVENT_GID); | 522 | error: |
514 | return 0; | 523 | abort_creds(new); |
524 | return retval; | ||
515 | } | 525 | } |
516 | 526 | ||
517 | /* | 527 | /* |
@@ -521,56 +531,54 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | |||
521 | */ | 531 | */ |
522 | asmlinkage long sys_setgid(gid_t gid) | 532 | asmlinkage long sys_setgid(gid_t gid) |
523 | { | 533 | { |
524 | int old_egid = current->egid; | 534 | const struct cred *old; |
535 | struct cred *new; | ||
525 | int retval; | 536 | int retval; |
526 | 537 | ||
538 | new = prepare_creds(); | ||
539 | if (!new) | ||
540 | return -ENOMEM; | ||
541 | old = current_cred(); | ||
542 | |||
527 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); | 543 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); |
528 | if (retval) | 544 | if (retval) |
529 | return retval; | 545 | goto error; |
530 | 546 | ||
531 | if (capable(CAP_SETGID)) { | 547 | retval = -EPERM; |
532 | if (old_egid != gid) { | 548 | if (capable(CAP_SETGID)) |
533 | set_dumpable(current->mm, suid_dumpable); | 549 | new->gid = new->egid = new->sgid = new->fsgid = gid; |
534 | smp_wmb(); | 550 | else if (gid == old->gid || gid == old->sgid) |
535 | } | 551 | new->egid = new->fsgid = gid; |
536 | current->gid = current->egid = current->sgid = current->fsgid = gid; | ||
537 | } else if ((gid == current->gid) || (gid == current->sgid)) { | ||
538 | if (old_egid != gid) { | ||
539 | set_dumpable(current->mm, suid_dumpable); | ||
540 | smp_wmb(); | ||
541 | } | ||
542 | current->egid = current->fsgid = gid; | ||
543 | } | ||
544 | else | 552 | else |
545 | return -EPERM; | 553 | goto error; |
546 | 554 | ||
547 | key_fsgid_changed(current); | 555 | return commit_creds(new); |
548 | proc_id_connector(current, PROC_EVENT_GID); | 556 | |
549 | return 0; | 557 | error: |
558 | abort_creds(new); | ||
559 | return retval; | ||
550 | } | 560 | } |
551 | 561 | ||
552 | static int set_user(uid_t new_ruid, int dumpclear) | 562 | /* |
563 | * change the user struct in a credentials set to match the new UID | ||
564 | */ | ||
565 | static int set_user(struct cred *new) | ||
553 | { | 566 | { |
554 | struct user_struct *new_user; | 567 | struct user_struct *new_user; |
555 | 568 | ||
556 | new_user = alloc_uid(current->nsproxy->user_ns, new_ruid); | 569 | new_user = alloc_uid(current_user_ns(), new->uid); |
557 | if (!new_user) | 570 | if (!new_user) |
558 | return -EAGAIN; | 571 | return -EAGAIN; |
559 | 572 | ||
560 | if (atomic_read(&new_user->processes) >= | 573 | if (atomic_read(&new_user->processes) >= |
561 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && | 574 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && |
562 | new_user != current->nsproxy->user_ns->root_user) { | 575 | new_user != INIT_USER) { |
563 | free_uid(new_user); | 576 | free_uid(new_user); |
564 | return -EAGAIN; | 577 | return -EAGAIN; |
565 | } | 578 | } |
566 | 579 | ||
567 | switch_uid(new_user); | 580 | free_uid(new->user); |
568 | 581 | new->user = new_user; | |
569 | if (dumpclear) { | ||
570 | set_dumpable(current->mm, suid_dumpable); | ||
571 | smp_wmb(); | ||
572 | } | ||
573 | current->uid = new_ruid; | ||
574 | return 0; | 582 | return 0; |
575 | } | 583 | } |
576 | 584 | ||
@@ -591,54 +599,56 @@ static int set_user(uid_t new_ruid, int dumpclear) | |||
591 | */ | 599 | */ |
592 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | 600 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) |
593 | { | 601 | { |
594 | int old_ruid, old_euid, old_suid, new_ruid, new_euid; | 602 | const struct cred *old; |
603 | struct cred *new; | ||
595 | int retval; | 604 | int retval; |
596 | 605 | ||
606 | new = prepare_creds(); | ||
607 | if (!new) | ||
608 | return -ENOMEM; | ||
609 | old = current_cred(); | ||
610 | |||
597 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); | 611 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); |
598 | if (retval) | 612 | if (retval) |
599 | return retval; | 613 | goto error; |
600 | |||
601 | new_ruid = old_ruid = current->uid; | ||
602 | new_euid = old_euid = current->euid; | ||
603 | old_suid = current->suid; | ||
604 | 614 | ||
615 | retval = -EPERM; | ||
605 | if (ruid != (uid_t) -1) { | 616 | if (ruid != (uid_t) -1) { |
606 | new_ruid = ruid; | 617 | new->uid = ruid; |
607 | if ((old_ruid != ruid) && | 618 | if (old->uid != ruid && |
608 | (current->euid != ruid) && | 619 | old->euid != ruid && |
609 | !capable(CAP_SETUID)) | 620 | !capable(CAP_SETUID)) |
610 | return -EPERM; | 621 | goto error; |
611 | } | 622 | } |
612 | 623 | ||
613 | if (euid != (uid_t) -1) { | 624 | if (euid != (uid_t) -1) { |
614 | new_euid = euid; | 625 | new->euid = euid; |
615 | if ((old_ruid != euid) && | 626 | if (old->uid != euid && |
616 | (current->euid != euid) && | 627 | old->euid != euid && |
617 | (current->suid != euid) && | 628 | old->suid != euid && |
618 | !capable(CAP_SETUID)) | 629 | !capable(CAP_SETUID)) |
619 | return -EPERM; | 630 | goto error; |
620 | } | 631 | } |
621 | 632 | ||
622 | if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) | 633 | retval = -EAGAIN; |
623 | return -EAGAIN; | 634 | if (new->uid != old->uid && set_user(new) < 0) |
635 | goto error; | ||
624 | 636 | ||
625 | if (new_euid != old_euid) { | ||
626 | set_dumpable(current->mm, suid_dumpable); | ||
627 | smp_wmb(); | ||
628 | } | ||
629 | current->fsuid = current->euid = new_euid; | ||
630 | if (ruid != (uid_t) -1 || | 637 | if (ruid != (uid_t) -1 || |
631 | (euid != (uid_t) -1 && euid != old_ruid)) | 638 | (euid != (uid_t) -1 && euid != old->uid)) |
632 | current->suid = current->euid; | 639 | new->suid = new->euid; |
633 | current->fsuid = current->euid; | 640 | new->fsuid = new->euid; |
634 | 641 | ||
635 | key_fsuid_changed(current); | 642 | retval = security_task_fix_setuid(new, old, LSM_SETID_RE); |
636 | proc_id_connector(current, PROC_EVENT_UID); | 643 | if (retval < 0) |
637 | 644 | goto error; | |
638 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); | ||
639 | } | ||
640 | 645 | ||
646 | return commit_creds(new); | ||
641 | 647 | ||
648 | error: | ||
649 | abort_creds(new); | ||
650 | return retval; | ||
651 | } | ||
642 | 652 | ||
643 | /* | 653 | /* |
644 | * setuid() is implemented like SysV with SAVED_IDS | 654 | * setuid() is implemented like SysV with SAVED_IDS |
@@ -653,36 +663,41 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | |||
653 | */ | 663 | */ |
654 | asmlinkage long sys_setuid(uid_t uid) | 664 | asmlinkage long sys_setuid(uid_t uid) |
655 | { | 665 | { |
656 | int old_euid = current->euid; | 666 | const struct cred *old; |
657 | int old_ruid, old_suid, new_suid; | 667 | struct cred *new; |
658 | int retval; | 668 | int retval; |
659 | 669 | ||
670 | new = prepare_creds(); | ||
671 | if (!new) | ||
672 | return -ENOMEM; | ||
673 | old = current_cred(); | ||
674 | |||
660 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); | 675 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); |
661 | if (retval) | 676 | if (retval) |
662 | return retval; | 677 | goto error; |
663 | 678 | ||
664 | old_ruid = current->uid; | 679 | retval = -EPERM; |
665 | old_suid = current->suid; | ||
666 | new_suid = old_suid; | ||
667 | |||
668 | if (capable(CAP_SETUID)) { | 680 | if (capable(CAP_SETUID)) { |
669 | if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) | 681 | new->suid = new->uid = uid; |
670 | return -EAGAIN; | 682 | if (uid != old->uid && set_user(new) < 0) { |
671 | new_suid = uid; | 683 | retval = -EAGAIN; |
672 | } else if ((uid != current->uid) && (uid != new_suid)) | 684 | goto error; |
673 | return -EPERM; | 685 | } |
674 | 686 | } else if (uid != old->uid && uid != new->suid) { | |
675 | if (old_euid != uid) { | 687 | goto error; |
676 | set_dumpable(current->mm, suid_dumpable); | ||
677 | smp_wmb(); | ||
678 | } | 688 | } |
679 | current->fsuid = current->euid = uid; | ||
680 | current->suid = new_suid; | ||
681 | 689 | ||
682 | key_fsuid_changed(current); | 690 | new->fsuid = new->euid = uid; |
683 | proc_id_connector(current, PROC_EVENT_UID); | 691 | |
692 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); | ||
693 | if (retval < 0) | ||
694 | goto error; | ||
684 | 695 | ||
685 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); | 696 | return commit_creds(new); |
697 | |||
698 | error: | ||
699 | abort_creds(new); | ||
700 | return retval; | ||
686 | } | 701 | } |
687 | 702 | ||
688 | 703 | ||
@@ -692,54 +707,63 @@ asmlinkage long sys_setuid(uid_t uid) | |||
692 | */ | 707 | */ |
693 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) | 708 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) |
694 | { | 709 | { |
695 | int old_ruid = current->uid; | 710 | const struct cred *old; |
696 | int old_euid = current->euid; | 711 | struct cred *new; |
697 | int old_suid = current->suid; | ||
698 | int retval; | 712 | int retval; |
699 | 713 | ||
714 | new = prepare_creds(); | ||
715 | if (!new) | ||
716 | return -ENOMEM; | ||
717 | |||
700 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); | 718 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); |
701 | if (retval) | 719 | if (retval) |
702 | return retval; | 720 | goto error; |
721 | old = current_cred(); | ||
703 | 722 | ||
723 | retval = -EPERM; | ||
704 | if (!capable(CAP_SETUID)) { | 724 | if (!capable(CAP_SETUID)) { |
705 | if ((ruid != (uid_t) -1) && (ruid != current->uid) && | 725 | if (ruid != (uid_t) -1 && ruid != old->uid && |
706 | (ruid != current->euid) && (ruid != current->suid)) | 726 | ruid != old->euid && ruid != old->suid) |
707 | return -EPERM; | 727 | goto error; |
708 | if ((euid != (uid_t) -1) && (euid != current->uid) && | 728 | if (euid != (uid_t) -1 && euid != old->uid && |
709 | (euid != current->euid) && (euid != current->suid)) | 729 | euid != old->euid && euid != old->suid) |
710 | return -EPERM; | 730 | goto error; |
711 | if ((suid != (uid_t) -1) && (suid != current->uid) && | 731 | if (suid != (uid_t) -1 && suid != old->uid && |
712 | (suid != current->euid) && (suid != current->suid)) | 732 | suid != old->euid && suid != old->suid) |
713 | return -EPERM; | 733 | goto error; |
714 | } | 734 | } |
735 | |||
736 | retval = -EAGAIN; | ||
715 | if (ruid != (uid_t) -1) { | 737 | if (ruid != (uid_t) -1) { |
716 | if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) | 738 | new->uid = ruid; |
717 | return -EAGAIN; | 739 | if (ruid != old->uid && set_user(new) < 0) |
740 | goto error; | ||
718 | } | 741 | } |
719 | if (euid != (uid_t) -1) { | 742 | if (euid != (uid_t) -1) |
720 | if (euid != current->euid) { | 743 | new->euid = euid; |
721 | set_dumpable(current->mm, suid_dumpable); | ||
722 | smp_wmb(); | ||
723 | } | ||
724 | current->euid = euid; | ||
725 | } | ||
726 | current->fsuid = current->euid; | ||
727 | if (suid != (uid_t) -1) | 744 | if (suid != (uid_t) -1) |
728 | current->suid = suid; | 745 | new->suid = suid; |
746 | new->fsuid = new->euid; | ||
747 | |||
748 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); | ||
749 | if (retval < 0) | ||
750 | goto error; | ||
729 | 751 | ||
730 | key_fsuid_changed(current); | 752 | return commit_creds(new); |
731 | proc_id_connector(current, PROC_EVENT_UID); | ||
732 | 753 | ||
733 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); | 754 | error: |
755 | abort_creds(new); | ||
756 | return retval; | ||
734 | } | 757 | } |
735 | 758 | ||
736 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) | 759 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) |
737 | { | 760 | { |
761 | const struct cred *cred = current_cred(); | ||
738 | int retval; | 762 | int retval; |
739 | 763 | ||
740 | if (!(retval = put_user(current->uid, ruid)) && | 764 | if (!(retval = put_user(cred->uid, ruid)) && |
741 | !(retval = put_user(current->euid, euid))) | 765 | !(retval = put_user(cred->euid, euid))) |
742 | retval = put_user(current->suid, suid); | 766 | retval = put_user(cred->suid, suid); |
743 | 767 | ||
744 | return retval; | 768 | return retval; |
745 | } | 769 | } |
@@ -749,48 +773,55 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us | |||
749 | */ | 773 | */ |
750 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) | 774 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) |
751 | { | 775 | { |
776 | const struct cred *old; | ||
777 | struct cred *new; | ||
752 | int retval; | 778 | int retval; |
753 | 779 | ||
780 | new = prepare_creds(); | ||
781 | if (!new) | ||
782 | return -ENOMEM; | ||
783 | old = current_cred(); | ||
784 | |||
754 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); | 785 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); |
755 | if (retval) | 786 | if (retval) |
756 | return retval; | 787 | goto error; |
757 | 788 | ||
789 | retval = -EPERM; | ||
758 | if (!capable(CAP_SETGID)) { | 790 | if (!capable(CAP_SETGID)) { |
759 | if ((rgid != (gid_t) -1) && (rgid != current->gid) && | 791 | if (rgid != (gid_t) -1 && rgid != old->gid && |
760 | (rgid != current->egid) && (rgid != current->sgid)) | 792 | rgid != old->egid && rgid != old->sgid) |
761 | return -EPERM; | 793 | goto error; |
762 | if ((egid != (gid_t) -1) && (egid != current->gid) && | 794 | if (egid != (gid_t) -1 && egid != old->gid && |
763 | (egid != current->egid) && (egid != current->sgid)) | 795 | egid != old->egid && egid != old->sgid) |
764 | return -EPERM; | 796 | goto error; |
765 | if ((sgid != (gid_t) -1) && (sgid != current->gid) && | 797 | if (sgid != (gid_t) -1 && sgid != old->gid && |
766 | (sgid != current->egid) && (sgid != current->sgid)) | 798 | sgid != old->egid && sgid != old->sgid) |
767 | return -EPERM; | 799 | goto error; |
768 | } | ||
769 | if (egid != (gid_t) -1) { | ||
770 | if (egid != current->egid) { | ||
771 | set_dumpable(current->mm, suid_dumpable); | ||
772 | smp_wmb(); | ||
773 | } | ||
774 | current->egid = egid; | ||
775 | } | 800 | } |
776 | current->fsgid = current->egid; | 801 | |
777 | if (rgid != (gid_t) -1) | 802 | if (rgid != (gid_t) -1) |
778 | current->gid = rgid; | 803 | new->gid = rgid; |
804 | if (egid != (gid_t) -1) | ||
805 | new->egid = egid; | ||
779 | if (sgid != (gid_t) -1) | 806 | if (sgid != (gid_t) -1) |
780 | current->sgid = sgid; | 807 | new->sgid = sgid; |
808 | new->fsgid = new->egid; | ||
781 | 809 | ||
782 | key_fsgid_changed(current); | 810 | return commit_creds(new); |
783 | proc_id_connector(current, PROC_EVENT_GID); | 811 | |
784 | return 0; | 812 | error: |
813 | abort_creds(new); | ||
814 | return retval; | ||
785 | } | 815 | } |
786 | 816 | ||
787 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) | 817 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) |
788 | { | 818 | { |
819 | const struct cred *cred = current_cred(); | ||
789 | int retval; | 820 | int retval; |
790 | 821 | ||
791 | if (!(retval = put_user(current->gid, rgid)) && | 822 | if (!(retval = put_user(cred->gid, rgid)) && |
792 | !(retval = put_user(current->egid, egid))) | 823 | !(retval = put_user(cred->egid, egid))) |
793 | retval = put_user(current->sgid, sgid); | 824 | retval = put_user(cred->sgid, sgid); |
794 | 825 | ||
795 | return retval; | 826 | return retval; |
796 | } | 827 | } |
@@ -804,27 +835,35 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us | |||
804 | */ | 835 | */ |
805 | asmlinkage long sys_setfsuid(uid_t uid) | 836 | asmlinkage long sys_setfsuid(uid_t uid) |
806 | { | 837 | { |
807 | int old_fsuid; | 838 | const struct cred *old; |
839 | struct cred *new; | ||
840 | uid_t old_fsuid; | ||
841 | |||
842 | new = prepare_creds(); | ||
843 | if (!new) | ||
844 | return current_fsuid(); | ||
845 | old = current_cred(); | ||
846 | old_fsuid = old->fsuid; | ||
808 | 847 | ||
809 | old_fsuid = current->fsuid; | 848 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0) |
810 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) | 849 | goto error; |
811 | return old_fsuid; | ||
812 | 850 | ||
813 | if (uid == current->uid || uid == current->euid || | 851 | if (uid == old->uid || uid == old->euid || |
814 | uid == current->suid || uid == current->fsuid || | 852 | uid == old->suid || uid == old->fsuid || |
815 | capable(CAP_SETUID)) { | 853 | capable(CAP_SETUID)) { |
816 | if (uid != old_fsuid) { | 854 | if (uid != old_fsuid) { |
817 | set_dumpable(current->mm, suid_dumpable); | 855 | new->fsuid = uid; |
818 | smp_wmb(); | 856 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
857 | goto change_okay; | ||
819 | } | 858 | } |
820 | current->fsuid = uid; | ||
821 | } | 859 | } |
822 | 860 | ||
823 | key_fsuid_changed(current); | 861 | error: |
824 | proc_id_connector(current, PROC_EVENT_UID); | 862 | abort_creds(new); |
825 | 863 | return old_fsuid; | |
826 | security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); | ||
827 | 864 | ||
865 | change_okay: | ||
866 | commit_creds(new); | ||
828 | return old_fsuid; | 867 | return old_fsuid; |
829 | } | 868 | } |
830 | 869 | ||
@@ -833,23 +872,34 @@ asmlinkage long sys_setfsuid(uid_t uid) | |||
833 | */ | 872 | */ |
834 | asmlinkage long sys_setfsgid(gid_t gid) | 873 | asmlinkage long sys_setfsgid(gid_t gid) |
835 | { | 874 | { |
836 | int old_fsgid; | 875 | const struct cred *old; |
876 | struct cred *new; | ||
877 | gid_t old_fsgid; | ||
878 | |||
879 | new = prepare_creds(); | ||
880 | if (!new) | ||
881 | return current_fsgid(); | ||
882 | old = current_cred(); | ||
883 | old_fsgid = old->fsgid; | ||
837 | 884 | ||
838 | old_fsgid = current->fsgid; | ||
839 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) | 885 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) |
840 | return old_fsgid; | 886 | goto error; |
841 | 887 | ||
842 | if (gid == current->gid || gid == current->egid || | 888 | if (gid == old->gid || gid == old->egid || |
843 | gid == current->sgid || gid == current->fsgid || | 889 | gid == old->sgid || gid == old->fsgid || |
844 | capable(CAP_SETGID)) { | 890 | capable(CAP_SETGID)) { |
845 | if (gid != old_fsgid) { | 891 | if (gid != old_fsgid) { |
846 | set_dumpable(current->mm, suid_dumpable); | 892 | new->fsgid = gid; |
847 | smp_wmb(); | 893 | goto change_okay; |
848 | } | 894 | } |
849 | current->fsgid = gid; | ||
850 | key_fsgid_changed(current); | ||
851 | proc_id_connector(current, PROC_EVENT_GID); | ||
852 | } | 895 | } |
896 | |||
897 | error: | ||
898 | abort_creds(new); | ||
899 | return old_fsgid; | ||
900 | |||
901 | change_okay: | ||
902 | commit_creds(new); | ||
853 | return old_fsgid; | 903 | return old_fsgid; |
854 | } | 904 | } |
855 | 905 | ||
@@ -858,8 +908,8 @@ void do_sys_times(struct tms *tms) | |||
858 | struct task_cputime cputime; | 908 | struct task_cputime cputime; |
859 | cputime_t cutime, cstime; | 909 | cputime_t cutime, cstime; |
860 | 910 | ||
861 | spin_lock_irq(¤t->sighand->siglock); | ||
862 | thread_group_cputime(current, &cputime); | 911 | thread_group_cputime(current, &cputime); |
912 | spin_lock_irq(¤t->sighand->siglock); | ||
863 | cutime = current->signal->cutime; | 913 | cutime = current->signal->cutime; |
864 | cstime = current->signal->cstime; | 914 | cstime = current->signal->cstime; |
865 | spin_unlock_irq(¤t->sighand->siglock); | 915 | spin_unlock_irq(¤t->sighand->siglock); |
@@ -878,6 +928,7 @@ asmlinkage long sys_times(struct tms __user * tbuf) | |||
878 | if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) | 928 | if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) |
879 | return -EFAULT; | 929 | return -EFAULT; |
880 | } | 930 | } |
931 | force_successful_syscall_return(); | ||
881 | return (long) jiffies_64_to_clock_t(get_jiffies_64()); | 932 | return (long) jiffies_64_to_clock_t(get_jiffies_64()); |
882 | } | 933 | } |
883 | 934 | ||
@@ -1118,7 +1169,7 @@ EXPORT_SYMBOL(groups_free); | |||
1118 | 1169 | ||
1119 | /* export the group_info to a user-space array */ | 1170 | /* export the group_info to a user-space array */ |
1120 | static int groups_to_user(gid_t __user *grouplist, | 1171 | static int groups_to_user(gid_t __user *grouplist, |
1121 | struct group_info *group_info) | 1172 | const struct group_info *group_info) |
1122 | { | 1173 | { |
1123 | int i; | 1174 | int i; |
1124 | unsigned int count = group_info->ngroups; | 1175 | unsigned int count = group_info->ngroups; |
@@ -1186,7 +1237,7 @@ static void groups_sort(struct group_info *group_info) | |||
1186 | } | 1237 | } |
1187 | 1238 | ||
1188 | /* a simple bsearch */ | 1239 | /* a simple bsearch */ |
1189 | int groups_search(struct group_info *group_info, gid_t grp) | 1240 | int groups_search(const struct group_info *group_info, gid_t grp) |
1190 | { | 1241 | { |
1191 | unsigned int left, right; | 1242 | unsigned int left, right; |
1192 | 1243 | ||
@@ -1208,51 +1259,74 @@ int groups_search(struct group_info *group_info, gid_t grp) | |||
1208 | return 0; | 1259 | return 0; |
1209 | } | 1260 | } |
1210 | 1261 | ||
1211 | /* validate and set current->group_info */ | 1262 | /** |
1212 | int set_current_groups(struct group_info *group_info) | 1263 | * set_groups - Change a group subscription in a set of credentials |
1264 | * @new: The newly prepared set of credentials to alter | ||
1265 | * @group_info: The group list to install | ||
1266 | * | ||
1267 | * Validate a group subscription and, if valid, insert it into a set | ||
1268 | * of credentials. | ||
1269 | */ | ||
1270 | int set_groups(struct cred *new, struct group_info *group_info) | ||
1213 | { | 1271 | { |
1214 | int retval; | 1272 | int retval; |
1215 | struct group_info *old_info; | ||
1216 | 1273 | ||
1217 | retval = security_task_setgroups(group_info); | 1274 | retval = security_task_setgroups(group_info); |
1218 | if (retval) | 1275 | if (retval) |
1219 | return retval; | 1276 | return retval; |
1220 | 1277 | ||
1278 | put_group_info(new->group_info); | ||
1221 | groups_sort(group_info); | 1279 | groups_sort(group_info); |
1222 | get_group_info(group_info); | 1280 | get_group_info(group_info); |
1281 | new->group_info = group_info; | ||
1282 | return 0; | ||
1283 | } | ||
1223 | 1284 | ||
1224 | task_lock(current); | 1285 | EXPORT_SYMBOL(set_groups); |
1225 | old_info = current->group_info; | ||
1226 | current->group_info = group_info; | ||
1227 | task_unlock(current); | ||
1228 | 1286 | ||
1229 | put_group_info(old_info); | 1287 | /** |
1288 | * set_current_groups - Change current's group subscription | ||
1289 | * @group_info: The group list to impose | ||
1290 | * | ||
1291 | * Validate a group subscription and, if valid, impose it upon current's task | ||
1292 | * security record. | ||
1293 | */ | ||
1294 | int set_current_groups(struct group_info *group_info) | ||
1295 | { | ||
1296 | struct cred *new; | ||
1297 | int ret; | ||
1230 | 1298 | ||
1231 | return 0; | 1299 | new = prepare_creds(); |
1300 | if (!new) | ||
1301 | return -ENOMEM; | ||
1302 | |||
1303 | ret = set_groups(new, group_info); | ||
1304 | if (ret < 0) { | ||
1305 | abort_creds(new); | ||
1306 | return ret; | ||
1307 | } | ||
1308 | |||
1309 | return commit_creds(new); | ||
1232 | } | 1310 | } |
1233 | 1311 | ||
1234 | EXPORT_SYMBOL(set_current_groups); | 1312 | EXPORT_SYMBOL(set_current_groups); |
1235 | 1313 | ||
1236 | asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist) | 1314 | asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist) |
1237 | { | 1315 | { |
1238 | int i = 0; | 1316 | const struct cred *cred = current_cred(); |
1239 | 1317 | int i; | |
1240 | /* | ||
1241 | * SMP: Nobody else can change our grouplist. Thus we are | ||
1242 | * safe. | ||
1243 | */ | ||
1244 | 1318 | ||
1245 | if (gidsetsize < 0) | 1319 | if (gidsetsize < 0) |
1246 | return -EINVAL; | 1320 | return -EINVAL; |
1247 | 1321 | ||
1248 | /* no need to grab task_lock here; it cannot change */ | 1322 | /* no need to grab task_lock here; it cannot change */ |
1249 | i = current->group_info->ngroups; | 1323 | i = cred->group_info->ngroups; |
1250 | if (gidsetsize) { | 1324 | if (gidsetsize) { |
1251 | if (i > gidsetsize) { | 1325 | if (i > gidsetsize) { |
1252 | i = -EINVAL; | 1326 | i = -EINVAL; |
1253 | goto out; | 1327 | goto out; |
1254 | } | 1328 | } |
1255 | if (groups_to_user(grouplist, current->group_info)) { | 1329 | if (groups_to_user(grouplist, cred->group_info)) { |
1256 | i = -EFAULT; | 1330 | i = -EFAULT; |
1257 | goto out; | 1331 | goto out; |
1258 | } | 1332 | } |
@@ -1296,9 +1370,11 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist) | |||
1296 | */ | 1370 | */ |
1297 | int in_group_p(gid_t grp) | 1371 | int in_group_p(gid_t grp) |
1298 | { | 1372 | { |
1373 | const struct cred *cred = current_cred(); | ||
1299 | int retval = 1; | 1374 | int retval = 1; |
1300 | if (grp != current->fsgid) | 1375 | |
1301 | retval = groups_search(current->group_info, grp); | 1376 | if (grp != cred->fsgid) |
1377 | retval = groups_search(cred->group_info, grp); | ||
1302 | return retval; | 1378 | return retval; |
1303 | } | 1379 | } |
1304 | 1380 | ||
@@ -1306,9 +1382,11 @@ EXPORT_SYMBOL(in_group_p); | |||
1306 | 1382 | ||
1307 | int in_egroup_p(gid_t grp) | 1383 | int in_egroup_p(gid_t grp) |
1308 | { | 1384 | { |
1385 | const struct cred *cred = current_cred(); | ||
1309 | int retval = 1; | 1386 | int retval = 1; |
1310 | if (grp != current->egid) | 1387 | |
1311 | retval = groups_search(current->group_info, grp); | 1388 | if (grp != cred->egid) |
1389 | retval = groups_search(cred->group_info, grp); | ||
1312 | return retval; | 1390 | return retval; |
1313 | } | 1391 | } |
1314 | 1392 | ||
@@ -1551,6 +1629,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1551 | utime = stime = cputime_zero; | 1629 | utime = stime = cputime_zero; |
1552 | 1630 | ||
1553 | if (who == RUSAGE_THREAD) { | 1631 | if (who == RUSAGE_THREAD) { |
1632 | utime = task_utime(current); | ||
1633 | stime = task_stime(current); | ||
1554 | accumulate_thread_rusage(p, r); | 1634 | accumulate_thread_rusage(p, r); |
1555 | goto out; | 1635 | goto out; |
1556 | } | 1636 | } |
@@ -1624,50 +1704,56 @@ asmlinkage long sys_umask(int mask) | |||
1624 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | 1704 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, |
1625 | unsigned long arg4, unsigned long arg5) | 1705 | unsigned long arg4, unsigned long arg5) |
1626 | { | 1706 | { |
1627 | long error = 0; | 1707 | struct task_struct *me = current; |
1708 | unsigned char comm[sizeof(me->comm)]; | ||
1709 | long error; | ||
1628 | 1710 | ||
1629 | if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error)) | 1711 | error = security_task_prctl(option, arg2, arg3, arg4, arg5); |
1712 | if (error != -ENOSYS) | ||
1630 | return error; | 1713 | return error; |
1631 | 1714 | ||
1715 | error = 0; | ||
1632 | switch (option) { | 1716 | switch (option) { |
1633 | case PR_SET_PDEATHSIG: | 1717 | case PR_SET_PDEATHSIG: |
1634 | if (!valid_signal(arg2)) { | 1718 | if (!valid_signal(arg2)) { |
1635 | error = -EINVAL; | 1719 | error = -EINVAL; |
1636 | break; | 1720 | break; |
1637 | } | 1721 | } |
1638 | current->pdeath_signal = arg2; | 1722 | me->pdeath_signal = arg2; |
1723 | error = 0; | ||
1639 | break; | 1724 | break; |
1640 | case PR_GET_PDEATHSIG: | 1725 | case PR_GET_PDEATHSIG: |
1641 | error = put_user(current->pdeath_signal, (int __user *)arg2); | 1726 | error = put_user(me->pdeath_signal, (int __user *)arg2); |
1642 | break; | 1727 | break; |
1643 | case PR_GET_DUMPABLE: | 1728 | case PR_GET_DUMPABLE: |
1644 | error = get_dumpable(current->mm); | 1729 | error = get_dumpable(me->mm); |
1645 | break; | 1730 | break; |
1646 | case PR_SET_DUMPABLE: | 1731 | case PR_SET_DUMPABLE: |
1647 | if (arg2 < 0 || arg2 > 1) { | 1732 | if (arg2 < 0 || arg2 > 1) { |
1648 | error = -EINVAL; | 1733 | error = -EINVAL; |
1649 | break; | 1734 | break; |
1650 | } | 1735 | } |
1651 | set_dumpable(current->mm, arg2); | 1736 | set_dumpable(me->mm, arg2); |
1737 | error = 0; | ||
1652 | break; | 1738 | break; |
1653 | 1739 | ||
1654 | case PR_SET_UNALIGN: | 1740 | case PR_SET_UNALIGN: |
1655 | error = SET_UNALIGN_CTL(current, arg2); | 1741 | error = SET_UNALIGN_CTL(me, arg2); |
1656 | break; | 1742 | break; |
1657 | case PR_GET_UNALIGN: | 1743 | case PR_GET_UNALIGN: |
1658 | error = GET_UNALIGN_CTL(current, arg2); | 1744 | error = GET_UNALIGN_CTL(me, arg2); |
1659 | break; | 1745 | break; |
1660 | case PR_SET_FPEMU: | 1746 | case PR_SET_FPEMU: |
1661 | error = SET_FPEMU_CTL(current, arg2); | 1747 | error = SET_FPEMU_CTL(me, arg2); |
1662 | break; | 1748 | break; |
1663 | case PR_GET_FPEMU: | 1749 | case PR_GET_FPEMU: |
1664 | error = GET_FPEMU_CTL(current, arg2); | 1750 | error = GET_FPEMU_CTL(me, arg2); |
1665 | break; | 1751 | break; |
1666 | case PR_SET_FPEXC: | 1752 | case PR_SET_FPEXC: |
1667 | error = SET_FPEXC_CTL(current, arg2); | 1753 | error = SET_FPEXC_CTL(me, arg2); |
1668 | break; | 1754 | break; |
1669 | case PR_GET_FPEXC: | 1755 | case PR_GET_FPEXC: |
1670 | error = GET_FPEXC_CTL(current, arg2); | 1756 | error = GET_FPEXC_CTL(me, arg2); |
1671 | break; | 1757 | break; |
1672 | case PR_GET_TIMING: | 1758 | case PR_GET_TIMING: |
1673 | error = PR_TIMING_STATISTICAL; | 1759 | error = PR_TIMING_STATISTICAL; |
@@ -1675,33 +1761,28 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1675 | case PR_SET_TIMING: | 1761 | case PR_SET_TIMING: |
1676 | if (arg2 != PR_TIMING_STATISTICAL) | 1762 | if (arg2 != PR_TIMING_STATISTICAL) |
1677 | error = -EINVAL; | 1763 | error = -EINVAL; |
1764 | else | ||
1765 | error = 0; | ||
1678 | break; | 1766 | break; |
1679 | 1767 | ||
1680 | case PR_SET_NAME: { | 1768 | case PR_SET_NAME: |
1681 | struct task_struct *me = current; | 1769 | comm[sizeof(me->comm)-1] = 0; |
1682 | unsigned char ncomm[sizeof(me->comm)]; | 1770 | if (strncpy_from_user(comm, (char __user *)arg2, |
1683 | 1771 | sizeof(me->comm) - 1) < 0) | |
1684 | ncomm[sizeof(me->comm)-1] = 0; | ||
1685 | if (strncpy_from_user(ncomm, (char __user *)arg2, | ||
1686 | sizeof(me->comm)-1) < 0) | ||
1687 | return -EFAULT; | 1772 | return -EFAULT; |
1688 | set_task_comm(me, ncomm); | 1773 | set_task_comm(me, comm); |
1689 | return 0; | 1774 | return 0; |
1690 | } | 1775 | case PR_GET_NAME: |
1691 | case PR_GET_NAME: { | 1776 | get_task_comm(comm, me); |
1692 | struct task_struct *me = current; | 1777 | if (copy_to_user((char __user *)arg2, comm, |
1693 | unsigned char tcomm[sizeof(me->comm)]; | 1778 | sizeof(comm))) |
1694 | |||
1695 | get_task_comm(tcomm, me); | ||
1696 | if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm))) | ||
1697 | return -EFAULT; | 1779 | return -EFAULT; |
1698 | return 0; | 1780 | return 0; |
1699 | } | ||
1700 | case PR_GET_ENDIAN: | 1781 | case PR_GET_ENDIAN: |
1701 | error = GET_ENDIAN(current, arg2); | 1782 | error = GET_ENDIAN(me, arg2); |
1702 | break; | 1783 | break; |
1703 | case PR_SET_ENDIAN: | 1784 | case PR_SET_ENDIAN: |
1704 | error = SET_ENDIAN(current, arg2); | 1785 | error = SET_ENDIAN(me, arg2); |
1705 | break; | 1786 | break; |
1706 | 1787 | ||
1707 | case PR_GET_SECCOMP: | 1788 | case PR_GET_SECCOMP: |
@@ -1725,6 +1806,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1725 | current->default_timer_slack_ns; | 1806 | current->default_timer_slack_ns; |
1726 | else | 1807 | else |
1727 | current->timer_slack_ns = arg2; | 1808 | current->timer_slack_ns = arg2; |
1809 | error = 0; | ||
1728 | break; | 1810 | break; |
1729 | default: | 1811 | default: |
1730 | error = -EINVAL; | 1812 | error = -EINVAL; |