diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 450 |
1 files changed, 245 insertions, 205 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index ccc9eb736d35..ab735040468a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -180,7 +180,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) | |||
180 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 180 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
181 | break; | 181 | break; |
182 | case PRIO_USER: | 182 | case PRIO_USER: |
183 | user = cred->user; | 183 | user = (struct user_struct *) cred->user; |
184 | if (!who) | 184 | if (!who) |
185 | who = cred->uid; | 185 | who = cred->uid; |
186 | else if ((who != cred->uid) && | 186 | else if ((who != cred->uid) && |
@@ -479,47 +479,48 @@ void ctrl_alt_del(void) | |||
479 | */ | 479 | */ |
480 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | 480 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) |
481 | { | 481 | { |
482 | struct cred *cred = current->cred; | 482 | const struct cred *old; |
483 | int old_rgid = cred->gid; | 483 | struct cred *new; |
484 | int old_egid = cred->egid; | ||
485 | int new_rgid = old_rgid; | ||
486 | int new_egid = old_egid; | ||
487 | int retval; | 484 | int retval; |
488 | 485 | ||
486 | new = prepare_creds(); | ||
487 | if (!new) | ||
488 | return -ENOMEM; | ||
489 | old = current_cred(); | ||
490 | |||
489 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); | 491 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); |
490 | if (retval) | 492 | if (retval) |
491 | return retval; | 493 | goto error; |
492 | 494 | ||
495 | retval = -EPERM; | ||
493 | if (rgid != (gid_t) -1) { | 496 | if (rgid != (gid_t) -1) { |
494 | if ((old_rgid == rgid) || | 497 | if (old->gid == rgid || |
495 | (cred->egid == rgid) || | 498 | old->egid == rgid || |
496 | capable(CAP_SETGID)) | 499 | capable(CAP_SETGID)) |
497 | new_rgid = rgid; | 500 | new->gid = rgid; |
498 | else | 501 | else |
499 | return -EPERM; | 502 | goto error; |
500 | } | 503 | } |
501 | if (egid != (gid_t) -1) { | 504 | if (egid != (gid_t) -1) { |
502 | if ((old_rgid == egid) || | 505 | if (old->gid == egid || |
503 | (cred->egid == egid) || | 506 | old->egid == egid || |
504 | (cred->sgid == egid) || | 507 | old->sgid == egid || |
505 | capable(CAP_SETGID)) | 508 | capable(CAP_SETGID)) |
506 | new_egid = egid; | 509 | new->egid = egid; |
507 | else | 510 | else |
508 | return -EPERM; | 511 | goto error; |
509 | } | ||
510 | if (new_egid != old_egid) { | ||
511 | set_dumpable(current->mm, suid_dumpable); | ||
512 | smp_wmb(); | ||
513 | } | 512 | } |
513 | |||
514 | if (rgid != (gid_t) -1 || | 514 | if (rgid != (gid_t) -1 || |
515 | (egid != (gid_t) -1 && egid != old_rgid)) | 515 | (egid != (gid_t) -1 && egid != old->gid)) |
516 | cred->sgid = new_egid; | 516 | new->sgid = new->egid; |
517 | cred->fsgid = new_egid; | 517 | new->fsgid = new->egid; |
518 | cred->egid = new_egid; | 518 | |
519 | cred->gid = new_rgid; | 519 | return commit_creds(new); |
520 | key_fsgid_changed(current); | 520 | |
521 | proc_id_connector(current, PROC_EVENT_GID); | 521 | error: |
522 | return 0; | 522 | abort_creds(new); |
523 | return retval; | ||
523 | } | 524 | } |
524 | 525 | ||
525 | /* | 526 | /* |
@@ -529,40 +530,42 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | |||
529 | */ | 530 | */ |
530 | asmlinkage long sys_setgid(gid_t gid) | 531 | asmlinkage long sys_setgid(gid_t gid) |
531 | { | 532 | { |
532 | struct cred *cred = current->cred; | 533 | const struct cred *old; |
533 | int old_egid = cred->egid; | 534 | struct cred *new; |
534 | int retval; | 535 | int retval; |
535 | 536 | ||
537 | new = prepare_creds(); | ||
538 | if (!new) | ||
539 | return -ENOMEM; | ||
540 | old = current_cred(); | ||
541 | |||
536 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); | 542 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); |
537 | if (retval) | 543 | if (retval) |
538 | return retval; | 544 | goto error; |
539 | 545 | ||
540 | if (capable(CAP_SETGID)) { | 546 | retval = -EPERM; |
541 | if (old_egid != gid) { | 547 | if (capable(CAP_SETGID)) |
542 | set_dumpable(current->mm, suid_dumpable); | 548 | new->gid = new->egid = new->sgid = new->fsgid = gid; |
543 | smp_wmb(); | 549 | else if (gid == old->gid || gid == old->sgid) |
544 | } | 550 | new->egid = new->fsgid = gid; |
545 | cred->gid = cred->egid = cred->sgid = cred->fsgid = gid; | ||
546 | } else if ((gid == cred->gid) || (gid == cred->sgid)) { | ||
547 | if (old_egid != gid) { | ||
548 | set_dumpable(current->mm, suid_dumpable); | ||
549 | smp_wmb(); | ||
550 | } | ||
551 | cred->egid = cred->fsgid = gid; | ||
552 | } | ||
553 | else | 551 | else |
554 | return -EPERM; | 552 | goto error; |
555 | 553 | ||
556 | key_fsgid_changed(current); | 554 | return commit_creds(new); |
557 | proc_id_connector(current, PROC_EVENT_GID); | 555 | |
558 | return 0; | 556 | error: |
557 | abort_creds(new); | ||
558 | return retval; | ||
559 | } | 559 | } |
560 | 560 | ||
561 | static int set_user(uid_t new_ruid, int dumpclear) | 561 | /* |
562 | * change the user struct in a credentials set to match the new UID | ||
563 | */ | ||
564 | static int set_user(struct cred *new) | ||
562 | { | 565 | { |
563 | struct user_struct *new_user; | 566 | struct user_struct *new_user; |
564 | 567 | ||
565 | new_user = alloc_uid(current->nsproxy->user_ns, new_ruid); | 568 | new_user = alloc_uid(current->nsproxy->user_ns, new->uid); |
566 | if (!new_user) | 569 | if (!new_user) |
567 | return -EAGAIN; | 570 | return -EAGAIN; |
568 | 571 | ||
@@ -573,13 +576,8 @@ static int set_user(uid_t new_ruid, int dumpclear) | |||
573 | return -EAGAIN; | 576 | return -EAGAIN; |
574 | } | 577 | } |
575 | 578 | ||
576 | switch_uid(new_user); | 579 | free_uid(new->user); |
577 | 580 | new->user = new_user; | |
578 | if (dumpclear) { | ||
579 | set_dumpable(current->mm, suid_dumpable); | ||
580 | smp_wmb(); | ||
581 | } | ||
582 | current->cred->uid = new_ruid; | ||
583 | return 0; | 581 | return 0; |
584 | } | 582 | } |
585 | 583 | ||
@@ -600,55 +598,56 @@ static int set_user(uid_t new_ruid, int dumpclear) | |||
600 | */ | 598 | */ |
601 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | 599 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) |
602 | { | 600 | { |
603 | struct cred *cred = current->cred; | 601 | const struct cred *old; |
604 | int old_ruid, old_euid, old_suid, new_ruid, new_euid; | 602 | struct cred *new; |
605 | int retval; | 603 | int retval; |
606 | 604 | ||
605 | new = prepare_creds(); | ||
606 | if (!new) | ||
607 | return -ENOMEM; | ||
608 | old = current_cred(); | ||
609 | |||
607 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); | 610 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); |
608 | if (retval) | 611 | if (retval) |
609 | return retval; | 612 | goto error; |
610 | |||
611 | new_ruid = old_ruid = cred->uid; | ||
612 | new_euid = old_euid = cred->euid; | ||
613 | old_suid = cred->suid; | ||
614 | 613 | ||
614 | retval = -EPERM; | ||
615 | if (ruid != (uid_t) -1) { | 615 | if (ruid != (uid_t) -1) { |
616 | new_ruid = ruid; | 616 | new->uid = ruid; |
617 | if ((old_ruid != ruid) && | 617 | if (old->uid != ruid && |
618 | (cred->euid != ruid) && | 618 | old->euid != ruid && |
619 | !capable(CAP_SETUID)) | 619 | !capable(CAP_SETUID)) |
620 | return -EPERM; | 620 | goto error; |
621 | } | 621 | } |
622 | 622 | ||
623 | if (euid != (uid_t) -1) { | 623 | if (euid != (uid_t) -1) { |
624 | new_euid = euid; | 624 | new->euid = euid; |
625 | if ((old_ruid != euid) && | 625 | if (old->uid != euid && |
626 | (cred->euid != euid) && | 626 | old->euid != euid && |
627 | (cred->suid != euid) && | 627 | old->suid != euid && |
628 | !capable(CAP_SETUID)) | 628 | !capable(CAP_SETUID)) |
629 | return -EPERM; | 629 | goto error; |
630 | } | 630 | } |
631 | 631 | ||
632 | if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) | 632 | retval = -EAGAIN; |
633 | return -EAGAIN; | 633 | if (new->uid != old->uid && set_user(new) < 0) |
634 | goto error; | ||
634 | 635 | ||
635 | if (new_euid != old_euid) { | ||
636 | set_dumpable(current->mm, suid_dumpable); | ||
637 | smp_wmb(); | ||
638 | } | ||
639 | cred->fsuid = cred->euid = new_euid; | ||
640 | if (ruid != (uid_t) -1 || | 636 | if (ruid != (uid_t) -1 || |
641 | (euid != (uid_t) -1 && euid != old_ruid)) | 637 | (euid != (uid_t) -1 && euid != old->uid)) |
642 | cred->suid = cred->euid; | 638 | new->suid = new->euid; |
643 | cred->fsuid = cred->euid; | 639 | new->fsuid = new->euid; |
644 | |||
645 | key_fsuid_changed(current); | ||
646 | proc_id_connector(current, PROC_EVENT_UID); | ||
647 | 640 | ||
648 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); | 641 | retval = security_task_fix_setuid(new, old, LSM_SETID_RE); |
649 | } | 642 | if (retval < 0) |
643 | goto error; | ||
650 | 644 | ||
645 | return commit_creds(new); | ||
651 | 646 | ||
647 | error: | ||
648 | abort_creds(new); | ||
649 | return retval; | ||
650 | } | ||
652 | 651 | ||
653 | /* | 652 | /* |
654 | * setuid() is implemented like SysV with SAVED_IDS | 653 | * setuid() is implemented like SysV with SAVED_IDS |
@@ -663,37 +662,41 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | |||
663 | */ | 662 | */ |
664 | asmlinkage long sys_setuid(uid_t uid) | 663 | asmlinkage long sys_setuid(uid_t uid) |
665 | { | 664 | { |
666 | struct cred *cred = current->cred; | 665 | const struct cred *old; |
667 | int old_euid = cred->euid; | 666 | struct cred *new; |
668 | int old_ruid, old_suid, new_suid; | ||
669 | int retval; | 667 | int retval; |
670 | 668 | ||
669 | new = prepare_creds(); | ||
670 | if (!new) | ||
671 | return -ENOMEM; | ||
672 | old = current_cred(); | ||
673 | |||
671 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); | 674 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); |
672 | if (retval) | 675 | if (retval) |
673 | return retval; | 676 | goto error; |
674 | 677 | ||
675 | old_ruid = cred->uid; | 678 | retval = -EPERM; |
676 | old_suid = cred->suid; | ||
677 | new_suid = old_suid; | ||
678 | |||
679 | if (capable(CAP_SETUID)) { | 679 | if (capable(CAP_SETUID)) { |
680 | if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) | 680 | new->suid = new->uid = uid; |
681 | return -EAGAIN; | 681 | if (uid != old->uid && set_user(new) < 0) { |
682 | new_suid = uid; | 682 | retval = -EAGAIN; |
683 | } else if ((uid != cred->uid) && (uid != new_suid)) | 683 | goto error; |
684 | return -EPERM; | 684 | } |
685 | 685 | } else if (uid != old->uid && uid != new->suid) { | |
686 | if (old_euid != uid) { | 686 | goto error; |
687 | set_dumpable(current->mm, suid_dumpable); | ||
688 | smp_wmb(); | ||
689 | } | 687 | } |
690 | cred->fsuid = cred->euid = uid; | ||
691 | cred->suid = new_suid; | ||
692 | 688 | ||
693 | key_fsuid_changed(current); | 689 | new->fsuid = new->euid = uid; |
694 | proc_id_connector(current, PROC_EVENT_UID); | 690 | |
691 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); | ||
692 | if (retval < 0) | ||
693 | goto error; | ||
694 | |||
695 | return commit_creds(new); | ||
695 | 696 | ||
696 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); | 697 | error: |
698 | abort_creds(new); | ||
699 | return retval; | ||
697 | } | 700 | } |
698 | 701 | ||
699 | 702 | ||
@@ -703,47 +706,53 @@ asmlinkage long sys_setuid(uid_t uid) | |||
703 | */ | 706 | */ |
704 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) | 707 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) |
705 | { | 708 | { |
706 | struct cred *cred = current->cred; | 709 | const struct cred *old; |
707 | int old_ruid = cred->uid; | 710 | struct cred *new; |
708 | int old_euid = cred->euid; | ||
709 | int old_suid = cred->suid; | ||
710 | int retval; | 711 | int retval; |
711 | 712 | ||
713 | new = prepare_creds(); | ||
714 | if (!new) | ||
715 | return -ENOMEM; | ||
716 | |||
712 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); | 717 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); |
713 | if (retval) | 718 | if (retval) |
714 | return retval; | 719 | goto error; |
720 | old = current_cred(); | ||
715 | 721 | ||
722 | retval = -EPERM; | ||
716 | if (!capable(CAP_SETUID)) { | 723 | if (!capable(CAP_SETUID)) { |
717 | if ((ruid != (uid_t) -1) && (ruid != cred->uid) && | 724 | if (ruid != (uid_t) -1 && ruid != old->uid && |
718 | (ruid != cred->euid) && (ruid != cred->suid)) | 725 | ruid != old->euid && ruid != old->suid) |
719 | return -EPERM; | 726 | goto error; |
720 | if ((euid != (uid_t) -1) && (euid != cred->uid) && | 727 | if (euid != (uid_t) -1 && euid != old->uid && |
721 | (euid != cred->euid) && (euid != cred->suid)) | 728 | euid != old->euid && euid != old->suid) |
722 | return -EPERM; | 729 | goto error; |
723 | if ((suid != (uid_t) -1) && (suid != cred->uid) && | 730 | if (suid != (uid_t) -1 && suid != old->uid && |
724 | (suid != cred->euid) && (suid != cred->suid)) | 731 | suid != old->euid && suid != old->suid) |
725 | return -EPERM; | 732 | goto error; |
726 | } | 733 | } |
734 | |||
735 | retval = -EAGAIN; | ||
727 | if (ruid != (uid_t) -1) { | 736 | if (ruid != (uid_t) -1) { |
728 | if (ruid != cred->uid && | 737 | new->uid = ruid; |
729 | set_user(ruid, euid != cred->euid) < 0) | 738 | if (ruid != old->uid && set_user(new) < 0) |
730 | return -EAGAIN; | 739 | goto error; |
731 | } | 740 | } |
732 | if (euid != (uid_t) -1) { | 741 | if (euid != (uid_t) -1) |
733 | if (euid != cred->euid) { | 742 | new->euid = euid; |
734 | set_dumpable(current->mm, suid_dumpable); | ||
735 | smp_wmb(); | ||
736 | } | ||
737 | cred->euid = euid; | ||
738 | } | ||
739 | cred->fsuid = cred->euid; | ||
740 | if (suid != (uid_t) -1) | 743 | if (suid != (uid_t) -1) |
741 | cred->suid = suid; | 744 | new->suid = suid; |
745 | new->fsuid = new->euid; | ||
742 | 746 | ||
743 | key_fsuid_changed(current); | 747 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); |
744 | proc_id_connector(current, PROC_EVENT_UID); | 748 | if (retval < 0) |
749 | goto error; | ||
745 | 750 | ||
746 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); | 751 | return commit_creds(new); |
752 | |||
753 | error: | ||
754 | abort_creds(new); | ||
755 | return retval; | ||
747 | } | 756 | } |
748 | 757 | ||
749 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) | 758 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) |
@@ -763,40 +772,45 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us | |||
763 | */ | 772 | */ |
764 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) | 773 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) |
765 | { | 774 | { |
766 | struct cred *cred = current->cred; | 775 | const struct cred *old; |
776 | struct cred *new; | ||
767 | int retval; | 777 | int retval; |
768 | 778 | ||
779 | new = prepare_creds(); | ||
780 | if (!new) | ||
781 | return -ENOMEM; | ||
782 | old = current_cred(); | ||
783 | |||
769 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); | 784 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); |
770 | if (retval) | 785 | if (retval) |
771 | return retval; | 786 | goto error; |
772 | 787 | ||
788 | retval = -EPERM; | ||
773 | if (!capable(CAP_SETGID)) { | 789 | if (!capable(CAP_SETGID)) { |
774 | if ((rgid != (gid_t) -1) && (rgid != cred->gid) && | 790 | if (rgid != (gid_t) -1 && rgid != old->gid && |
775 | (rgid != cred->egid) && (rgid != cred->sgid)) | 791 | rgid != old->egid && rgid != old->sgid) |
776 | return -EPERM; | 792 | goto error; |
777 | if ((egid != (gid_t) -1) && (egid != cred->gid) && | 793 | if (egid != (gid_t) -1 && egid != old->gid && |
778 | (egid != cred->egid) && (egid != cred->sgid)) | 794 | egid != old->egid && egid != old->sgid) |
779 | return -EPERM; | 795 | goto error; |
780 | if ((sgid != (gid_t) -1) && (sgid != cred->gid) && | 796 | if (sgid != (gid_t) -1 && sgid != old->gid && |
781 | (sgid != cred->egid) && (sgid != cred->sgid)) | 797 | sgid != old->egid && sgid != old->sgid) |
782 | return -EPERM; | 798 | goto error; |
783 | } | 799 | } |
784 | if (egid != (gid_t) -1) { | 800 | |
785 | if (egid != cred->egid) { | ||
786 | set_dumpable(current->mm, suid_dumpable); | ||
787 | smp_wmb(); | ||
788 | } | ||
789 | cred->egid = egid; | ||
790 | } | ||
791 | cred->fsgid = cred->egid; | ||
792 | if (rgid != (gid_t) -1) | 801 | if (rgid != (gid_t) -1) |
793 | cred->gid = rgid; | 802 | new->gid = rgid; |
803 | if (egid != (gid_t) -1) | ||
804 | new->egid = egid; | ||
794 | if (sgid != (gid_t) -1) | 805 | if (sgid != (gid_t) -1) |
795 | cred->sgid = sgid; | 806 | new->sgid = sgid; |
807 | new->fsgid = new->egid; | ||
796 | 808 | ||
797 | key_fsgid_changed(current); | 809 | return commit_creds(new); |
798 | proc_id_connector(current, PROC_EVENT_GID); | 810 | |
799 | return 0; | 811 | error: |
812 | abort_creds(new); | ||
813 | return retval; | ||
800 | } | 814 | } |
801 | 815 | ||
802 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) | 816 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) |
@@ -820,28 +834,35 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us | |||
820 | */ | 834 | */ |
821 | asmlinkage long sys_setfsuid(uid_t uid) | 835 | asmlinkage long sys_setfsuid(uid_t uid) |
822 | { | 836 | { |
823 | struct cred *cred = current->cred; | 837 | const struct cred *old; |
824 | int old_fsuid; | 838 | struct cred *new; |
839 | uid_t old_fsuid; | ||
840 | |||
841 | new = prepare_creds(); | ||
842 | if (!new) | ||
843 | return current_fsuid(); | ||
844 | old = current_cred(); | ||
845 | old_fsuid = old->fsuid; | ||
825 | 846 | ||
826 | old_fsuid = cred->fsuid; | 847 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0) |
827 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) | 848 | goto error; |
828 | return old_fsuid; | ||
829 | 849 | ||
830 | if (uid == cred->uid || uid == cred->euid || | 850 | if (uid == old->uid || uid == old->euid || |
831 | uid == cred->suid || uid == cred->fsuid || | 851 | uid == old->suid || uid == old->fsuid || |
832 | capable(CAP_SETUID)) { | 852 | capable(CAP_SETUID)) { |
833 | if (uid != old_fsuid) { | 853 | if (uid != old_fsuid) { |
834 | set_dumpable(current->mm, suid_dumpable); | 854 | new->fsuid = uid; |
835 | smp_wmb(); | 855 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
856 | goto change_okay; | ||
836 | } | 857 | } |
837 | cred->fsuid = uid; | ||
838 | } | 858 | } |
839 | 859 | ||
840 | key_fsuid_changed(current); | 860 | error: |
841 | proc_id_connector(current, PROC_EVENT_UID); | 861 | abort_creds(new); |
842 | 862 | return old_fsuid; | |
843 | security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); | ||
844 | 863 | ||
864 | change_okay: | ||
865 | commit_creds(new); | ||
845 | return old_fsuid; | 866 | return old_fsuid; |
846 | } | 867 | } |
847 | 868 | ||
@@ -850,24 +871,34 @@ asmlinkage long sys_setfsuid(uid_t uid) | |||
850 | */ | 871 | */ |
851 | asmlinkage long sys_setfsgid(gid_t gid) | 872 | asmlinkage long sys_setfsgid(gid_t gid) |
852 | { | 873 | { |
853 | struct cred *cred = current->cred; | 874 | const struct cred *old; |
854 | int old_fsgid; | 875 | struct cred *new; |
876 | gid_t old_fsgid; | ||
877 | |||
878 | new = prepare_creds(); | ||
879 | if (!new) | ||
880 | return current_fsgid(); | ||
881 | old = current_cred(); | ||
882 | old_fsgid = old->fsgid; | ||
855 | 883 | ||
856 | old_fsgid = cred->fsgid; | ||
857 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) | 884 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) |
858 | return old_fsgid; | 885 | goto error; |
859 | 886 | ||
860 | if (gid == cred->gid || gid == cred->egid || | 887 | if (gid == old->gid || gid == old->egid || |
861 | gid == cred->sgid || gid == cred->fsgid || | 888 | gid == old->sgid || gid == old->fsgid || |
862 | capable(CAP_SETGID)) { | 889 | capable(CAP_SETGID)) { |
863 | if (gid != old_fsgid) { | 890 | if (gid != old_fsgid) { |
864 | set_dumpable(current->mm, suid_dumpable); | 891 | new->fsgid = gid; |
865 | smp_wmb(); | 892 | goto change_okay; |
866 | } | 893 | } |
867 | cred->fsgid = gid; | ||
868 | key_fsgid_changed(current); | ||
869 | proc_id_connector(current, PROC_EVENT_GID); | ||
870 | } | 894 | } |
895 | |||
896 | error: | ||
897 | abort_creds(new); | ||
898 | return old_fsgid; | ||
899 | |||
900 | change_okay: | ||
901 | commit_creds(new); | ||
871 | return old_fsgid; | 902 | return old_fsgid; |
872 | } | 903 | } |
873 | 904 | ||
@@ -1136,7 +1167,7 @@ EXPORT_SYMBOL(groups_free); | |||
1136 | 1167 | ||
1137 | /* export the group_info to a user-space array */ | 1168 | /* export the group_info to a user-space array */ |
1138 | static int groups_to_user(gid_t __user *grouplist, | 1169 | static int groups_to_user(gid_t __user *grouplist, |
1139 | struct group_info *group_info) | 1170 | const struct group_info *group_info) |
1140 | { | 1171 | { |
1141 | int i; | 1172 | int i; |
1142 | unsigned int count = group_info->ngroups; | 1173 | unsigned int count = group_info->ngroups; |
@@ -1227,31 +1258,25 @@ int groups_search(const struct group_info *group_info, gid_t grp) | |||
1227 | } | 1258 | } |
1228 | 1259 | ||
1229 | /** | 1260 | /** |
1230 | * set_groups - Change a group subscription in a security record | 1261 | * set_groups - Change a group subscription in a set of credentials |
1231 | * @sec: The security record to alter | 1262 | * @new: The newly prepared set of credentials to alter |
1232 | * @group_info: The group list to impose | 1263 | * @group_info: The group list to install |
1233 | * | 1264 | * |
1234 | * Validate a group subscription and, if valid, impose it upon a task security | 1265 | * Validate a group subscription and, if valid, insert it into a set |
1235 | * record. | 1266 | * of credentials. |
1236 | */ | 1267 | */ |
1237 | int set_groups(struct cred *cred, struct group_info *group_info) | 1268 | int set_groups(struct cred *new, struct group_info *group_info) |
1238 | { | 1269 | { |
1239 | int retval; | 1270 | int retval; |
1240 | struct group_info *old_info; | ||
1241 | 1271 | ||
1242 | retval = security_task_setgroups(group_info); | 1272 | retval = security_task_setgroups(group_info); |
1243 | if (retval) | 1273 | if (retval) |
1244 | return retval; | 1274 | return retval; |
1245 | 1275 | ||
1276 | put_group_info(new->group_info); | ||
1246 | groups_sort(group_info); | 1277 | groups_sort(group_info); |
1247 | get_group_info(group_info); | 1278 | get_group_info(group_info); |
1248 | 1279 | new->group_info = group_info; | |
1249 | spin_lock(&cred->lock); | ||
1250 | old_info = cred->group_info; | ||
1251 | cred->group_info = group_info; | ||
1252 | spin_unlock(&cred->lock); | ||
1253 | |||
1254 | put_group_info(old_info); | ||
1255 | return 0; | 1280 | return 0; |
1256 | } | 1281 | } |
1257 | 1282 | ||
@@ -1266,7 +1291,20 @@ EXPORT_SYMBOL(set_groups); | |||
1266 | */ | 1291 | */ |
1267 | int set_current_groups(struct group_info *group_info) | 1292 | int set_current_groups(struct group_info *group_info) |
1268 | { | 1293 | { |
1269 | return set_groups(current->cred, group_info); | 1294 | struct cred *new; |
1295 | int ret; | ||
1296 | |||
1297 | new = prepare_creds(); | ||
1298 | if (!new) | ||
1299 | return -ENOMEM; | ||
1300 | |||
1301 | ret = set_groups(new, group_info); | ||
1302 | if (ret < 0) { | ||
1303 | abort_creds(new); | ||
1304 | return ret; | ||
1305 | } | ||
1306 | |||
1307 | return commit_creds(new); | ||
1270 | } | 1308 | } |
1271 | 1309 | ||
1272 | EXPORT_SYMBOL(set_current_groups); | 1310 | EXPORT_SYMBOL(set_current_groups); |
@@ -1666,9 +1704,11 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1666 | unsigned char comm[sizeof(me->comm)]; | 1704 | unsigned char comm[sizeof(me->comm)]; |
1667 | long error; | 1705 | long error; |
1668 | 1706 | ||
1669 | if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error)) | 1707 | error = security_task_prctl(option, arg2, arg3, arg4, arg5); |
1708 | if (error != -ENOSYS) | ||
1670 | return error; | 1709 | return error; |
1671 | 1710 | ||
1711 | error = 0; | ||
1672 | switch (option) { | 1712 | switch (option) { |
1673 | case PR_SET_PDEATHSIG: | 1713 | case PR_SET_PDEATHSIG: |
1674 | if (!valid_signal(arg2)) { | 1714 | if (!valid_signal(arg2)) { |