diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 266 |
1 files changed, 174 insertions, 92 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index ba0ae8eea6fb..6df42624e454 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -93,10 +93,8 @@ | |||
93 | int overflowuid = DEFAULT_OVERFLOWUID; | 93 | int overflowuid = DEFAULT_OVERFLOWUID; |
94 | int overflowgid = DEFAULT_OVERFLOWGID; | 94 | int overflowgid = DEFAULT_OVERFLOWGID; |
95 | 95 | ||
96 | #ifdef CONFIG_UID16 | ||
97 | EXPORT_SYMBOL(overflowuid); | 96 | EXPORT_SYMBOL(overflowuid); |
98 | EXPORT_SYMBOL(overflowgid); | 97 | EXPORT_SYMBOL(overflowgid); |
99 | #endif | ||
100 | 98 | ||
101 | /* | 99 | /* |
102 | * the same as above, but for filesystems which can only store a 16-bit | 100 | * the same as above, but for filesystems which can only store a 16-bit |
@@ -133,11 +131,10 @@ static bool set_one_prio_perm(struct task_struct *p) | |||
133 | { | 131 | { |
134 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); | 132 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); |
135 | 133 | ||
136 | if (pcred->user->user_ns == cred->user->user_ns && | 134 | if (uid_eq(pcred->uid, cred->euid) || |
137 | (pcred->uid == cred->euid || | 135 | uid_eq(pcred->euid, cred->euid)) |
138 | pcred->euid == cred->euid)) | ||
139 | return true; | 136 | return true; |
140 | if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE)) | 137 | if (ns_capable(pcred->user_ns, CAP_SYS_NICE)) |
141 | return true; | 138 | return true; |
142 | return false; | 139 | return false; |
143 | } | 140 | } |
@@ -177,6 +174,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
177 | const struct cred *cred = current_cred(); | 174 | const struct cred *cred = current_cred(); |
178 | int error = -EINVAL; | 175 | int error = -EINVAL; |
179 | struct pid *pgrp; | 176 | struct pid *pgrp; |
177 | kuid_t uid; | ||
180 | 178 | ||
181 | if (which > PRIO_USER || which < PRIO_PROCESS) | 179 | if (which > PRIO_USER || which < PRIO_PROCESS) |
182 | goto out; | 180 | goto out; |
@@ -209,18 +207,19 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
209 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 207 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
210 | break; | 208 | break; |
211 | case PRIO_USER: | 209 | case PRIO_USER: |
212 | user = (struct user_struct *) cred->user; | 210 | uid = make_kuid(cred->user_ns, who); |
211 | user = cred->user; | ||
213 | if (!who) | 212 | if (!who) |
214 | who = cred->uid; | 213 | uid = cred->uid; |
215 | else if ((who != cred->uid) && | 214 | else if (!uid_eq(uid, cred->uid) && |
216 | !(user = find_user(who))) | 215 | !(user = find_user(uid))) |
217 | goto out_unlock; /* No processes for this user */ | 216 | goto out_unlock; /* No processes for this user */ |
218 | 217 | ||
219 | do_each_thread(g, p) { | 218 | do_each_thread(g, p) { |
220 | if (__task_cred(p)->uid == who) | 219 | if (uid_eq(task_uid(p), uid)) |
221 | error = set_one_prio(p, niceval, error); | 220 | error = set_one_prio(p, niceval, error); |
222 | } while_each_thread(g, p); | 221 | } while_each_thread(g, p); |
223 | if (who != cred->uid) | 222 | if (!uid_eq(uid, cred->uid)) |
224 | free_uid(user); /* For find_user() */ | 223 | free_uid(user); /* For find_user() */ |
225 | break; | 224 | break; |
226 | } | 225 | } |
@@ -244,6 +243,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who) | |||
244 | const struct cred *cred = current_cred(); | 243 | const struct cred *cred = current_cred(); |
245 | long niceval, retval = -ESRCH; | 244 | long niceval, retval = -ESRCH; |
246 | struct pid *pgrp; | 245 | struct pid *pgrp; |
246 | kuid_t uid; | ||
247 | 247 | ||
248 | if (which > PRIO_USER || which < PRIO_PROCESS) | 248 | if (which > PRIO_USER || which < PRIO_PROCESS) |
249 | return -EINVAL; | 249 | return -EINVAL; |
@@ -274,21 +274,22 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who) | |||
274 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 274 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
275 | break; | 275 | break; |
276 | case PRIO_USER: | 276 | case PRIO_USER: |
277 | user = (struct user_struct *) cred->user; | 277 | uid = make_kuid(cred->user_ns, who); |
278 | user = cred->user; | ||
278 | if (!who) | 279 | if (!who) |
279 | who = cred->uid; | 280 | uid = cred->uid; |
280 | else if ((who != cred->uid) && | 281 | else if (!uid_eq(uid, cred->uid) && |
281 | !(user = find_user(who))) | 282 | !(user = find_user(uid))) |
282 | goto out_unlock; /* No processes for this user */ | 283 | goto out_unlock; /* No processes for this user */ |
283 | 284 | ||
284 | do_each_thread(g, p) { | 285 | do_each_thread(g, p) { |
285 | if (__task_cred(p)->uid == who) { | 286 | if (uid_eq(task_uid(p), uid)) { |
286 | niceval = 20 - task_nice(p); | 287 | niceval = 20 - task_nice(p); |
287 | if (niceval > retval) | 288 | if (niceval > retval) |
288 | retval = niceval; | 289 | retval = niceval; |
289 | } | 290 | } |
290 | } while_each_thread(g, p); | 291 | } while_each_thread(g, p); |
291 | if (who != cred->uid) | 292 | if (!uid_eq(uid, cred->uid)) |
292 | free_uid(user); /* for find_user() */ | 293 | free_uid(user); /* for find_user() */ |
293 | break; | 294 | break; |
294 | } | 295 | } |
@@ -553,9 +554,19 @@ void ctrl_alt_del(void) | |||
553 | */ | 554 | */ |
554 | SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | 555 | SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) |
555 | { | 556 | { |
557 | struct user_namespace *ns = current_user_ns(); | ||
556 | const struct cred *old; | 558 | const struct cred *old; |
557 | struct cred *new; | 559 | struct cred *new; |
558 | int retval; | 560 | int retval; |
561 | kgid_t krgid, kegid; | ||
562 | |||
563 | krgid = make_kgid(ns, rgid); | ||
564 | kegid = make_kgid(ns, egid); | ||
565 | |||
566 | if ((rgid != (gid_t) -1) && !gid_valid(krgid)) | ||
567 | return -EINVAL; | ||
568 | if ((egid != (gid_t) -1) && !gid_valid(kegid)) | ||
569 | return -EINVAL; | ||
559 | 570 | ||
560 | new = prepare_creds(); | 571 | new = prepare_creds(); |
561 | if (!new) | 572 | if (!new) |
@@ -564,25 +575,25 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
564 | 575 | ||
565 | retval = -EPERM; | 576 | retval = -EPERM; |
566 | if (rgid != (gid_t) -1) { | 577 | if (rgid != (gid_t) -1) { |
567 | if (old->gid == rgid || | 578 | if (gid_eq(old->gid, krgid) || |
568 | old->egid == rgid || | 579 | gid_eq(old->egid, krgid) || |
569 | nsown_capable(CAP_SETGID)) | 580 | nsown_capable(CAP_SETGID)) |
570 | new->gid = rgid; | 581 | new->gid = krgid; |
571 | else | 582 | else |
572 | goto error; | 583 | goto error; |
573 | } | 584 | } |
574 | if (egid != (gid_t) -1) { | 585 | if (egid != (gid_t) -1) { |
575 | if (old->gid == egid || | 586 | if (gid_eq(old->gid, kegid) || |
576 | old->egid == egid || | 587 | gid_eq(old->egid, kegid) || |
577 | old->sgid == egid || | 588 | gid_eq(old->sgid, kegid) || |
578 | nsown_capable(CAP_SETGID)) | 589 | nsown_capable(CAP_SETGID)) |
579 | new->egid = egid; | 590 | new->egid = kegid; |
580 | else | 591 | else |
581 | goto error; | 592 | goto error; |
582 | } | 593 | } |
583 | 594 | ||
584 | if (rgid != (gid_t) -1 || | 595 | if (rgid != (gid_t) -1 || |
585 | (egid != (gid_t) -1 && egid != old->gid)) | 596 | (egid != (gid_t) -1 && !gid_eq(kegid, old->gid))) |
586 | new->sgid = new->egid; | 597 | new->sgid = new->egid; |
587 | new->fsgid = new->egid; | 598 | new->fsgid = new->egid; |
588 | 599 | ||
@@ -600,9 +611,15 @@ error: | |||
600 | */ | 611 | */ |
601 | SYSCALL_DEFINE1(setgid, gid_t, gid) | 612 | SYSCALL_DEFINE1(setgid, gid_t, gid) |
602 | { | 613 | { |
614 | struct user_namespace *ns = current_user_ns(); | ||
603 | const struct cred *old; | 615 | const struct cred *old; |
604 | struct cred *new; | 616 | struct cred *new; |
605 | int retval; | 617 | int retval; |
618 | kgid_t kgid; | ||
619 | |||
620 | kgid = make_kgid(ns, gid); | ||
621 | if (!gid_valid(kgid)) | ||
622 | return -EINVAL; | ||
606 | 623 | ||
607 | new = prepare_creds(); | 624 | new = prepare_creds(); |
608 | if (!new) | 625 | if (!new) |
@@ -611,9 +628,9 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
611 | 628 | ||
612 | retval = -EPERM; | 629 | retval = -EPERM; |
613 | if (nsown_capable(CAP_SETGID)) | 630 | if (nsown_capable(CAP_SETGID)) |
614 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 631 | new->gid = new->egid = new->sgid = new->fsgid = kgid; |
615 | else if (gid == old->gid || gid == old->sgid) | 632 | else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) |
616 | new->egid = new->fsgid = gid; | 633 | new->egid = new->fsgid = kgid; |
617 | else | 634 | else |
618 | goto error; | 635 | goto error; |
619 | 636 | ||
@@ -631,7 +648,7 @@ static int set_user(struct cred *new) | |||
631 | { | 648 | { |
632 | struct user_struct *new_user; | 649 | struct user_struct *new_user; |
633 | 650 | ||
634 | new_user = alloc_uid(current_user_ns(), new->uid); | 651 | new_user = alloc_uid(new->uid); |
635 | if (!new_user) | 652 | if (!new_user) |
636 | return -EAGAIN; | 653 | return -EAGAIN; |
637 | 654 | ||
@@ -670,9 +687,19 @@ static int set_user(struct cred *new) | |||
670 | */ | 687 | */ |
671 | SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | 688 | SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) |
672 | { | 689 | { |
690 | struct user_namespace *ns = current_user_ns(); | ||
673 | const struct cred *old; | 691 | const struct cred *old; |
674 | struct cred *new; | 692 | struct cred *new; |
675 | int retval; | 693 | int retval; |
694 | kuid_t kruid, keuid; | ||
695 | |||
696 | kruid = make_kuid(ns, ruid); | ||
697 | keuid = make_kuid(ns, euid); | ||
698 | |||
699 | if ((ruid != (uid_t) -1) && !uid_valid(kruid)) | ||
700 | return -EINVAL; | ||
701 | if ((euid != (uid_t) -1) && !uid_valid(keuid)) | ||
702 | return -EINVAL; | ||
676 | 703 | ||
677 | new = prepare_creds(); | 704 | new = prepare_creds(); |
678 | if (!new) | 705 | if (!new) |
@@ -681,29 +708,29 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
681 | 708 | ||
682 | retval = -EPERM; | 709 | retval = -EPERM; |
683 | if (ruid != (uid_t) -1) { | 710 | if (ruid != (uid_t) -1) { |
684 | new->uid = ruid; | 711 | new->uid = kruid; |
685 | if (old->uid != ruid && | 712 | if (!uid_eq(old->uid, kruid) && |
686 | old->euid != ruid && | 713 | !uid_eq(old->euid, kruid) && |
687 | !nsown_capable(CAP_SETUID)) | 714 | !nsown_capable(CAP_SETUID)) |
688 | goto error; | 715 | goto error; |
689 | } | 716 | } |
690 | 717 | ||
691 | if (euid != (uid_t) -1) { | 718 | if (euid != (uid_t) -1) { |
692 | new->euid = euid; | 719 | new->euid = keuid; |
693 | if (old->uid != euid && | 720 | if (!uid_eq(old->uid, keuid) && |
694 | old->euid != euid && | 721 | !uid_eq(old->euid, keuid) && |
695 | old->suid != euid && | 722 | !uid_eq(old->suid, keuid) && |
696 | !nsown_capable(CAP_SETUID)) | 723 | !nsown_capable(CAP_SETUID)) |
697 | goto error; | 724 | goto error; |
698 | } | 725 | } |
699 | 726 | ||
700 | if (new->uid != old->uid) { | 727 | if (!uid_eq(new->uid, old->uid)) { |
701 | retval = set_user(new); | 728 | retval = set_user(new); |
702 | if (retval < 0) | 729 | if (retval < 0) |
703 | goto error; | 730 | goto error; |
704 | } | 731 | } |
705 | if (ruid != (uid_t) -1 || | 732 | if (ruid != (uid_t) -1 || |
706 | (euid != (uid_t) -1 && euid != old->uid)) | 733 | (euid != (uid_t) -1 && !uid_eq(keuid, old->uid))) |
707 | new->suid = new->euid; | 734 | new->suid = new->euid; |
708 | new->fsuid = new->euid; | 735 | new->fsuid = new->euid; |
709 | 736 | ||
@@ -731,9 +758,15 @@ error: | |||
731 | */ | 758 | */ |
732 | SYSCALL_DEFINE1(setuid, uid_t, uid) | 759 | SYSCALL_DEFINE1(setuid, uid_t, uid) |
733 | { | 760 | { |
761 | struct user_namespace *ns = current_user_ns(); | ||
734 | const struct cred *old; | 762 | const struct cred *old; |
735 | struct cred *new; | 763 | struct cred *new; |
736 | int retval; | 764 | int retval; |
765 | kuid_t kuid; | ||
766 | |||
767 | kuid = make_kuid(ns, uid); | ||
768 | if (!uid_valid(kuid)) | ||
769 | return -EINVAL; | ||
737 | 770 | ||
738 | new = prepare_creds(); | 771 | new = prepare_creds(); |
739 | if (!new) | 772 | if (!new) |
@@ -742,17 +775,17 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
742 | 775 | ||
743 | retval = -EPERM; | 776 | retval = -EPERM; |
744 | if (nsown_capable(CAP_SETUID)) { | 777 | if (nsown_capable(CAP_SETUID)) { |
745 | new->suid = new->uid = uid; | 778 | new->suid = new->uid = kuid; |
746 | if (uid != old->uid) { | 779 | if (!uid_eq(kuid, old->uid)) { |
747 | retval = set_user(new); | 780 | retval = set_user(new); |
748 | if (retval < 0) | 781 | if (retval < 0) |
749 | goto error; | 782 | goto error; |
750 | } | 783 | } |
751 | } else if (uid != old->uid && uid != new->suid) { | 784 | } else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) { |
752 | goto error; | 785 | goto error; |
753 | } | 786 | } |
754 | 787 | ||
755 | new->fsuid = new->euid = uid; | 788 | new->fsuid = new->euid = kuid; |
756 | 789 | ||
757 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); | 790 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); |
758 | if (retval < 0) | 791 | if (retval < 0) |
@@ -772,9 +805,24 @@ error: | |||
772 | */ | 805 | */ |
773 | SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | 806 | SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) |
774 | { | 807 | { |
808 | struct user_namespace *ns = current_user_ns(); | ||
775 | const struct cred *old; | 809 | const struct cred *old; |
776 | struct cred *new; | 810 | struct cred *new; |
777 | int retval; | 811 | int retval; |
812 | kuid_t kruid, keuid, ksuid; | ||
813 | |||
814 | kruid = make_kuid(ns, ruid); | ||
815 | keuid = make_kuid(ns, euid); | ||
816 | ksuid = make_kuid(ns, suid); | ||
817 | |||
818 | if ((ruid != (uid_t) -1) && !uid_valid(kruid)) | ||
819 | return -EINVAL; | ||
820 | |||
821 | if ((euid != (uid_t) -1) && !uid_valid(keuid)) | ||
822 | return -EINVAL; | ||
823 | |||
824 | if ((suid != (uid_t) -1) && !uid_valid(ksuid)) | ||
825 | return -EINVAL; | ||
778 | 826 | ||
779 | new = prepare_creds(); | 827 | new = prepare_creds(); |
780 | if (!new) | 828 | if (!new) |
@@ -784,29 +832,29 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
784 | 832 | ||
785 | retval = -EPERM; | 833 | retval = -EPERM; |
786 | if (!nsown_capable(CAP_SETUID)) { | 834 | if (!nsown_capable(CAP_SETUID)) { |
787 | if (ruid != (uid_t) -1 && ruid != old->uid && | 835 | if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && |
788 | ruid != old->euid && ruid != old->suid) | 836 | !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) |
789 | goto error; | 837 | goto error; |
790 | if (euid != (uid_t) -1 && euid != old->uid && | 838 | if (euid != (uid_t) -1 && !uid_eq(keuid, old->uid) && |
791 | euid != old->euid && euid != old->suid) | 839 | !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid)) |
792 | goto error; | 840 | goto error; |
793 | if (suid != (uid_t) -1 && suid != old->uid && | 841 | if (suid != (uid_t) -1 && !uid_eq(ksuid, old->uid) && |
794 | suid != old->euid && suid != old->suid) | 842 | !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid)) |
795 | goto error; | 843 | goto error; |
796 | } | 844 | } |
797 | 845 | ||
798 | if (ruid != (uid_t) -1) { | 846 | if (ruid != (uid_t) -1) { |
799 | new->uid = ruid; | 847 | new->uid = kruid; |
800 | if (ruid != old->uid) { | 848 | if (!uid_eq(kruid, old->uid)) { |
801 | retval = set_user(new); | 849 | retval = set_user(new); |
802 | if (retval < 0) | 850 | if (retval < 0) |
803 | goto error; | 851 | goto error; |
804 | } | 852 | } |
805 | } | 853 | } |
806 | if (euid != (uid_t) -1) | 854 | if (euid != (uid_t) -1) |
807 | new->euid = euid; | 855 | new->euid = keuid; |
808 | if (suid != (uid_t) -1) | 856 | if (suid != (uid_t) -1) |
809 | new->suid = suid; | 857 | new->suid = ksuid; |
810 | new->fsuid = new->euid; | 858 | new->fsuid = new->euid; |
811 | 859 | ||
812 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); | 860 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); |
@@ -820,14 +868,19 @@ error: | |||
820 | return retval; | 868 | return retval; |
821 | } | 869 | } |
822 | 870 | ||
823 | SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid) | 871 | SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp) |
824 | { | 872 | { |
825 | const struct cred *cred = current_cred(); | 873 | const struct cred *cred = current_cred(); |
826 | int retval; | 874 | int retval; |
875 | uid_t ruid, euid, suid; | ||
876 | |||
877 | ruid = from_kuid_munged(cred->user_ns, cred->uid); | ||
878 | euid = from_kuid_munged(cred->user_ns, cred->euid); | ||
879 | suid = from_kuid_munged(cred->user_ns, cred->suid); | ||
827 | 880 | ||
828 | if (!(retval = put_user(cred->uid, ruid)) && | 881 | if (!(retval = put_user(ruid, ruidp)) && |
829 | !(retval = put_user(cred->euid, euid))) | 882 | !(retval = put_user(euid, euidp))) |
830 | retval = put_user(cred->suid, suid); | 883 | retval = put_user(suid, suidp); |
831 | 884 | ||
832 | return retval; | 885 | return retval; |
833 | } | 886 | } |
@@ -837,9 +890,22 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __u | |||
837 | */ | 890 | */ |
838 | SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | 891 | SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) |
839 | { | 892 | { |
893 | struct user_namespace *ns = current_user_ns(); | ||
840 | const struct cred *old; | 894 | const struct cred *old; |
841 | struct cred *new; | 895 | struct cred *new; |
842 | int retval; | 896 | int retval; |
897 | kgid_t krgid, kegid, ksgid; | ||
898 | |||
899 | krgid = make_kgid(ns, rgid); | ||
900 | kegid = make_kgid(ns, egid); | ||
901 | ksgid = make_kgid(ns, sgid); | ||
902 | |||
903 | if ((rgid != (gid_t) -1) && !gid_valid(krgid)) | ||
904 | return -EINVAL; | ||
905 | if ((egid != (gid_t) -1) && !gid_valid(kegid)) | ||
906 | return -EINVAL; | ||
907 | if ((sgid != (gid_t) -1) && !gid_valid(ksgid)) | ||
908 | return -EINVAL; | ||
843 | 909 | ||
844 | new = prepare_creds(); | 910 | new = prepare_creds(); |
845 | if (!new) | 911 | if (!new) |
@@ -848,23 +914,23 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
848 | 914 | ||
849 | retval = -EPERM; | 915 | retval = -EPERM; |
850 | if (!nsown_capable(CAP_SETGID)) { | 916 | if (!nsown_capable(CAP_SETGID)) { |
851 | if (rgid != (gid_t) -1 && rgid != old->gid && | 917 | if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && |
852 | rgid != old->egid && rgid != old->sgid) | 918 | !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid)) |
853 | goto error; | 919 | goto error; |
854 | if (egid != (gid_t) -1 && egid != old->gid && | 920 | if (egid != (gid_t) -1 && !gid_eq(kegid, old->gid) && |
855 | egid != old->egid && egid != old->sgid) | 921 | !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid)) |
856 | goto error; | 922 | goto error; |
857 | if (sgid != (gid_t) -1 && sgid != old->gid && | 923 | if (sgid != (gid_t) -1 && !gid_eq(ksgid, old->gid) && |
858 | sgid != old->egid && sgid != old->sgid) | 924 | !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid)) |
859 | goto error; | 925 | goto error; |
860 | } | 926 | } |
861 | 927 | ||
862 | if (rgid != (gid_t) -1) | 928 | if (rgid != (gid_t) -1) |
863 | new->gid = rgid; | 929 | new->gid = krgid; |
864 | if (egid != (gid_t) -1) | 930 | if (egid != (gid_t) -1) |
865 | new->egid = egid; | 931 | new->egid = kegid; |
866 | if (sgid != (gid_t) -1) | 932 | if (sgid != (gid_t) -1) |
867 | new->sgid = sgid; | 933 | new->sgid = ksgid; |
868 | new->fsgid = new->egid; | 934 | new->fsgid = new->egid; |
869 | 935 | ||
870 | return commit_creds(new); | 936 | return commit_creds(new); |
@@ -874,14 +940,19 @@ error: | |||
874 | return retval; | 940 | return retval; |
875 | } | 941 | } |
876 | 942 | ||
877 | SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid) | 943 | SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp) |
878 | { | 944 | { |
879 | const struct cred *cred = current_cred(); | 945 | const struct cred *cred = current_cred(); |
880 | int retval; | 946 | int retval; |
947 | gid_t rgid, egid, sgid; | ||
948 | |||
949 | rgid = from_kgid_munged(cred->user_ns, cred->gid); | ||
950 | egid = from_kgid_munged(cred->user_ns, cred->egid); | ||
951 | sgid = from_kgid_munged(cred->user_ns, cred->sgid); | ||
881 | 952 | ||
882 | if (!(retval = put_user(cred->gid, rgid)) && | 953 | if (!(retval = put_user(rgid, rgidp)) && |
883 | !(retval = put_user(cred->egid, egid))) | 954 | !(retval = put_user(egid, egidp))) |
884 | retval = put_user(cred->sgid, sgid); | 955 | retval = put_user(sgid, sgidp); |
885 | 956 | ||
886 | return retval; | 957 | return retval; |
887 | } | 958 | } |
@@ -898,18 +969,24 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
898 | const struct cred *old; | 969 | const struct cred *old; |
899 | struct cred *new; | 970 | struct cred *new; |
900 | uid_t old_fsuid; | 971 | uid_t old_fsuid; |
972 | kuid_t kuid; | ||
973 | |||
974 | old = current_cred(); | ||
975 | old_fsuid = from_kuid_munged(old->user_ns, old->fsuid); | ||
976 | |||
977 | kuid = make_kuid(old->user_ns, uid); | ||
978 | if (!uid_valid(kuid)) | ||
979 | return old_fsuid; | ||
901 | 980 | ||
902 | new = prepare_creds(); | 981 | new = prepare_creds(); |
903 | if (!new) | 982 | if (!new) |
904 | return current_fsuid(); | 983 | return old_fsuid; |
905 | old = current_cred(); | ||
906 | old_fsuid = old->fsuid; | ||
907 | 984 | ||
908 | if (uid == old->uid || uid == old->euid || | 985 | if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || |
909 | uid == old->suid || uid == old->fsuid || | 986 | uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || |
910 | nsown_capable(CAP_SETUID)) { | 987 | nsown_capable(CAP_SETUID)) { |
911 | if (uid != old_fsuid) { | 988 | if (!uid_eq(kuid, old->fsuid)) { |
912 | new->fsuid = uid; | 989 | new->fsuid = kuid; |
913 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 990 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
914 | goto change_okay; | 991 | goto change_okay; |
915 | } | 992 | } |
@@ -931,18 +1008,24 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
931 | const struct cred *old; | 1008 | const struct cred *old; |
932 | struct cred *new; | 1009 | struct cred *new; |
933 | gid_t old_fsgid; | 1010 | gid_t old_fsgid; |
1011 | kgid_t kgid; | ||
1012 | |||
1013 | old = current_cred(); | ||
1014 | old_fsgid = from_kgid_munged(old->user_ns, old->fsgid); | ||
1015 | |||
1016 | kgid = make_kgid(old->user_ns, gid); | ||
1017 | if (!gid_valid(kgid)) | ||
1018 | return old_fsgid; | ||
934 | 1019 | ||
935 | new = prepare_creds(); | 1020 | new = prepare_creds(); |
936 | if (!new) | 1021 | if (!new) |
937 | return current_fsgid(); | 1022 | return old_fsgid; |
938 | old = current_cred(); | ||
939 | old_fsgid = old->fsgid; | ||
940 | 1023 | ||
941 | if (gid == old->gid || gid == old->egid || | 1024 | if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || |
942 | gid == old->sgid || gid == old->fsgid || | 1025 | gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || |
943 | nsown_capable(CAP_SETGID)) { | 1026 | nsown_capable(CAP_SETGID)) { |
944 | if (gid != old_fsgid) { | 1027 | if (!gid_eq(kgid, old->fsgid)) { |
945 | new->fsgid = gid; | 1028 | new->fsgid = kgid; |
946 | goto change_okay; | 1029 | goto change_okay; |
947 | } | 1030 | } |
948 | } | 1031 | } |
@@ -1498,15 +1581,14 @@ static int check_prlimit_permission(struct task_struct *task) | |||
1498 | return 0; | 1581 | return 0; |
1499 | 1582 | ||
1500 | tcred = __task_cred(task); | 1583 | tcred = __task_cred(task); |
1501 | if (cred->user->user_ns == tcred->user->user_ns && | 1584 | if (uid_eq(cred->uid, tcred->euid) && |
1502 | (cred->uid == tcred->euid && | 1585 | uid_eq(cred->uid, tcred->suid) && |
1503 | cred->uid == tcred->suid && | 1586 | uid_eq(cred->uid, tcred->uid) && |
1504 | cred->uid == tcred->uid && | 1587 | gid_eq(cred->gid, tcred->egid) && |
1505 | cred->gid == tcred->egid && | 1588 | gid_eq(cred->gid, tcred->sgid) && |
1506 | cred->gid == tcred->sgid && | 1589 | gid_eq(cred->gid, tcred->gid)) |
1507 | cred->gid == tcred->gid)) | ||
1508 | return 0; | 1590 | return 0; |
1509 | if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE)) | 1591 | if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) |
1510 | return 0; | 1592 | return 0; |
1511 | 1593 | ||
1512 | return -EPERM; | 1594 | return -EPERM; |