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