diff options
Diffstat (limited to 'kernel/sys.c')
| -rw-r--r-- | kernel/sys.c | 491 |
1 files changed, 334 insertions, 157 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index e7006eb6c1e4..9ff89cb9657a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -36,6 +36,8 @@ | |||
| 36 | #include <linux/personality.h> | 36 | #include <linux/personality.h> |
| 37 | #include <linux/ptrace.h> | 37 | #include <linux/ptrace.h> |
| 38 | #include <linux/fs_struct.h> | 38 | #include <linux/fs_struct.h> |
| 39 | #include <linux/file.h> | ||
| 40 | #include <linux/mount.h> | ||
| 39 | #include <linux/gfp.h> | 41 | #include <linux/gfp.h> |
| 40 | #include <linux/syscore_ops.h> | 42 | #include <linux/syscore_ops.h> |
| 41 | #include <linux/version.h> | 43 | #include <linux/version.h> |
| @@ -93,10 +95,8 @@ | |||
| 93 | int overflowuid = DEFAULT_OVERFLOWUID; | 95 | int overflowuid = DEFAULT_OVERFLOWUID; |
| 94 | int overflowgid = DEFAULT_OVERFLOWGID; | 96 | int overflowgid = DEFAULT_OVERFLOWGID; |
| 95 | 97 | ||
| 96 | #ifdef CONFIG_UID16 | ||
| 97 | EXPORT_SYMBOL(overflowuid); | 98 | EXPORT_SYMBOL(overflowuid); |
| 98 | EXPORT_SYMBOL(overflowgid); | 99 | EXPORT_SYMBOL(overflowgid); |
| 99 | #endif | ||
| 100 | 100 | ||
| 101 | /* | 101 | /* |
| 102 | * the same as above, but for filesystems which can only store a 16-bit | 102 | * the same as above, but for filesystems which can only store a 16-bit |
| @@ -133,11 +133,10 @@ static bool set_one_prio_perm(struct task_struct *p) | |||
| 133 | { | 133 | { |
| 134 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); | 134 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); |
| 135 | 135 | ||
| 136 | if (pcred->user->user_ns == cred->user->user_ns && | 136 | if (uid_eq(pcred->uid, cred->euid) || |
| 137 | (pcred->uid == cred->euid || | 137 | uid_eq(pcred->euid, cred->euid)) |
| 138 | pcred->euid == cred->euid)) | ||
| 139 | return true; | 138 | return true; |
| 140 | if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE)) | 139 | if (ns_capable(pcred->user_ns, CAP_SYS_NICE)) |
| 141 | return true; | 140 | return true; |
| 142 | return false; | 141 | return false; |
| 143 | } | 142 | } |
| @@ -177,6 +176,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
| 177 | const struct cred *cred = current_cred(); | 176 | const struct cred *cred = current_cred(); |
| 178 | int error = -EINVAL; | 177 | int error = -EINVAL; |
| 179 | struct pid *pgrp; | 178 | struct pid *pgrp; |
| 179 | kuid_t uid; | ||
| 180 | 180 | ||
| 181 | if (which > PRIO_USER || which < PRIO_PROCESS) | 181 | if (which > PRIO_USER || which < PRIO_PROCESS) |
| 182 | goto out; | 182 | goto out; |
| @@ -209,18 +209,19 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
| 209 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 209 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
| 210 | break; | 210 | break; |
| 211 | case PRIO_USER: | 211 | case PRIO_USER: |
| 212 | user = (struct user_struct *) cred->user; | 212 | uid = make_kuid(cred->user_ns, who); |
| 213 | user = cred->user; | ||
| 213 | if (!who) | 214 | if (!who) |
| 214 | who = cred->uid; | 215 | uid = cred->uid; |
| 215 | else if ((who != cred->uid) && | 216 | else if (!uid_eq(uid, cred->uid) && |
| 216 | !(user = find_user(who))) | 217 | !(user = find_user(uid))) |
| 217 | goto out_unlock; /* No processes for this user */ | 218 | goto out_unlock; /* No processes for this user */ |
| 218 | 219 | ||
| 219 | do_each_thread(g, p) { | 220 | do_each_thread(g, p) { |
| 220 | if (__task_cred(p)->uid == who) | 221 | if (uid_eq(task_uid(p), uid)) |
| 221 | error = set_one_prio(p, niceval, error); | 222 | error = set_one_prio(p, niceval, error); |
| 222 | } while_each_thread(g, p); | 223 | } while_each_thread(g, p); |
| 223 | if (who != cred->uid) | 224 | if (!uid_eq(uid, cred->uid)) |
| 224 | free_uid(user); /* For find_user() */ | 225 | free_uid(user); /* For find_user() */ |
| 225 | break; | 226 | break; |
| 226 | } | 227 | } |
| @@ -244,6 +245,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who) | |||
| 244 | const struct cred *cred = current_cred(); | 245 | const struct cred *cred = current_cred(); |
| 245 | long niceval, retval = -ESRCH; | 246 | long niceval, retval = -ESRCH; |
| 246 | struct pid *pgrp; | 247 | struct pid *pgrp; |
| 248 | kuid_t uid; | ||
| 247 | 249 | ||
| 248 | if (which > PRIO_USER || which < PRIO_PROCESS) | 250 | if (which > PRIO_USER || which < PRIO_PROCESS) |
| 249 | return -EINVAL; | 251 | return -EINVAL; |
| @@ -274,21 +276,22 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who) | |||
| 274 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 276 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
| 275 | break; | 277 | break; |
| 276 | case PRIO_USER: | 278 | case PRIO_USER: |
| 277 | user = (struct user_struct *) cred->user; | 279 | uid = make_kuid(cred->user_ns, who); |
| 280 | user = cred->user; | ||
| 278 | if (!who) | 281 | if (!who) |
| 279 | who = cred->uid; | 282 | uid = cred->uid; |
| 280 | else if ((who != cred->uid) && | 283 | else if (!uid_eq(uid, cred->uid) && |
| 281 | !(user = find_user(who))) | 284 | !(user = find_user(uid))) |
| 282 | goto out_unlock; /* No processes for this user */ | 285 | goto out_unlock; /* No processes for this user */ |
| 283 | 286 | ||
| 284 | do_each_thread(g, p) { | 287 | do_each_thread(g, p) { |
| 285 | if (__task_cred(p)->uid == who) { | 288 | if (uid_eq(task_uid(p), uid)) { |
| 286 | niceval = 20 - task_nice(p); | 289 | niceval = 20 - task_nice(p); |
| 287 | if (niceval > retval) | 290 | if (niceval > retval) |
| 288 | retval = niceval; | 291 | retval = niceval; |
| 289 | } | 292 | } |
| 290 | } while_each_thread(g, p); | 293 | } while_each_thread(g, p); |
| 291 | if (who != cred->uid) | 294 | if (!uid_eq(uid, cred->uid)) |
| 292 | free_uid(user); /* for find_user() */ | 295 | free_uid(user); /* for find_user() */ |
| 293 | break; | 296 | break; |
| 294 | } | 297 | } |
| @@ -553,9 +556,19 @@ void ctrl_alt_del(void) | |||
| 553 | */ | 556 | */ |
| 554 | SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | 557 | SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) |
| 555 | { | 558 | { |
| 559 | struct user_namespace *ns = current_user_ns(); | ||
| 556 | const struct cred *old; | 560 | const struct cred *old; |
| 557 | struct cred *new; | 561 | struct cred *new; |
| 558 | int retval; | 562 | int retval; |
| 563 | kgid_t krgid, kegid; | ||
| 564 | |||
| 565 | krgid = make_kgid(ns, rgid); | ||
| 566 | kegid = make_kgid(ns, egid); | ||
| 567 | |||
| 568 | if ((rgid != (gid_t) -1) && !gid_valid(krgid)) | ||
| 569 | return -EINVAL; | ||
| 570 | if ((egid != (gid_t) -1) && !gid_valid(kegid)) | ||
| 571 | return -EINVAL; | ||
| 559 | 572 | ||
| 560 | new = prepare_creds(); | 573 | new = prepare_creds(); |
| 561 | if (!new) | 574 | if (!new) |
| @@ -564,25 +577,25 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
| 564 | 577 | ||
| 565 | retval = -EPERM; | 578 | retval = -EPERM; |
| 566 | if (rgid != (gid_t) -1) { | 579 | if (rgid != (gid_t) -1) { |
| 567 | if (old->gid == rgid || | 580 | if (gid_eq(old->gid, krgid) || |
| 568 | old->egid == rgid || | 581 | gid_eq(old->egid, krgid) || |
| 569 | nsown_capable(CAP_SETGID)) | 582 | nsown_capable(CAP_SETGID)) |
| 570 | new->gid = rgid; | 583 | new->gid = krgid; |
| 571 | else | 584 | else |
| 572 | goto error; | 585 | goto error; |
| 573 | } | 586 | } |
| 574 | if (egid != (gid_t) -1) { | 587 | if (egid != (gid_t) -1) { |
| 575 | if (old->gid == egid || | 588 | if (gid_eq(old->gid, kegid) || |
| 576 | old->egid == egid || | 589 | gid_eq(old->egid, kegid) || |
| 577 | old->sgid == egid || | 590 | gid_eq(old->sgid, kegid) || |
| 578 | nsown_capable(CAP_SETGID)) | 591 | nsown_capable(CAP_SETGID)) |
| 579 | new->egid = egid; | 592 | new->egid = kegid; |
| 580 | else | 593 | else |
| 581 | goto error; | 594 | goto error; |
| 582 | } | 595 | } |
| 583 | 596 | ||
| 584 | if (rgid != (gid_t) -1 || | 597 | if (rgid != (gid_t) -1 || |
| 585 | (egid != (gid_t) -1 && egid != old->gid)) | 598 | (egid != (gid_t) -1 && !gid_eq(kegid, old->gid))) |
| 586 | new->sgid = new->egid; | 599 | new->sgid = new->egid; |
| 587 | new->fsgid = new->egid; | 600 | new->fsgid = new->egid; |
| 588 | 601 | ||
| @@ -600,9 +613,15 @@ error: | |||
| 600 | */ | 613 | */ |
| 601 | SYSCALL_DEFINE1(setgid, gid_t, gid) | 614 | SYSCALL_DEFINE1(setgid, gid_t, gid) |
| 602 | { | 615 | { |
| 616 | struct user_namespace *ns = current_user_ns(); | ||
| 603 | const struct cred *old; | 617 | const struct cred *old; |
| 604 | struct cred *new; | 618 | struct cred *new; |
| 605 | int retval; | 619 | int retval; |
| 620 | kgid_t kgid; | ||
| 621 | |||
| 622 | kgid = make_kgid(ns, gid); | ||
| 623 | if (!gid_valid(kgid)) | ||
| 624 | return -EINVAL; | ||
| 606 | 625 | ||
| 607 | new = prepare_creds(); | 626 | new = prepare_creds(); |
| 608 | if (!new) | 627 | if (!new) |
| @@ -611,9 +630,9 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
| 611 | 630 | ||
| 612 | retval = -EPERM; | 631 | retval = -EPERM; |
| 613 | if (nsown_capable(CAP_SETGID)) | 632 | if (nsown_capable(CAP_SETGID)) |
| 614 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 633 | new->gid = new->egid = new->sgid = new->fsgid = kgid; |
| 615 | else if (gid == old->gid || gid == old->sgid) | 634 | else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) |
| 616 | new->egid = new->fsgid = gid; | 635 | new->egid = new->fsgid = kgid; |
| 617 | else | 636 | else |
| 618 | goto error; | 637 | goto error; |
| 619 | 638 | ||
| @@ -631,7 +650,7 @@ static int set_user(struct cred *new) | |||
| 631 | { | 650 | { |
| 632 | struct user_struct *new_user; | 651 | struct user_struct *new_user; |
| 633 | 652 | ||
| 634 | new_user = alloc_uid(current_user_ns(), new->uid); | 653 | new_user = alloc_uid(new->uid); |
| 635 | if (!new_user) | 654 | if (!new_user) |
| 636 | return -EAGAIN; | 655 | return -EAGAIN; |
| 637 | 656 | ||
| @@ -670,9 +689,19 @@ static int set_user(struct cred *new) | |||
| 670 | */ | 689 | */ |
| 671 | SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | 690 | SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) |
| 672 | { | 691 | { |
| 692 | struct user_namespace *ns = current_user_ns(); | ||
| 673 | const struct cred *old; | 693 | const struct cred *old; |
| 674 | struct cred *new; | 694 | struct cred *new; |
| 675 | int retval; | 695 | int retval; |
| 696 | kuid_t kruid, keuid; | ||
| 697 | |||
| 698 | kruid = make_kuid(ns, ruid); | ||
| 699 | keuid = make_kuid(ns, euid); | ||
| 700 | |||
| 701 | if ((ruid != (uid_t) -1) && !uid_valid(kruid)) | ||
| 702 | return -EINVAL; | ||
| 703 | if ((euid != (uid_t) -1) && !uid_valid(keuid)) | ||
| 704 | return -EINVAL; | ||
| 676 | 705 | ||
| 677 | new = prepare_creds(); | 706 | new = prepare_creds(); |
| 678 | if (!new) | 707 | if (!new) |
| @@ -681,29 +710,29 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
| 681 | 710 | ||
| 682 | retval = -EPERM; | 711 | retval = -EPERM; |
| 683 | if (ruid != (uid_t) -1) { | 712 | if (ruid != (uid_t) -1) { |
| 684 | new->uid = ruid; | 713 | new->uid = kruid; |
| 685 | if (old->uid != ruid && | 714 | if (!uid_eq(old->uid, kruid) && |
| 686 | old->euid != ruid && | 715 | !uid_eq(old->euid, kruid) && |
| 687 | !nsown_capable(CAP_SETUID)) | 716 | !nsown_capable(CAP_SETUID)) |
| 688 | goto error; | 717 | goto error; |
| 689 | } | 718 | } |
| 690 | 719 | ||
| 691 | if (euid != (uid_t) -1) { | 720 | if (euid != (uid_t) -1) { |
| 692 | new->euid = euid; | 721 | new->euid = keuid; |
| 693 | if (old->uid != euid && | 722 | if (!uid_eq(old->uid, keuid) && |
| 694 | old->euid != euid && | 723 | !uid_eq(old->euid, keuid) && |
| 695 | old->suid != euid && | 724 | !uid_eq(old->suid, keuid) && |
| 696 | !nsown_capable(CAP_SETUID)) | 725 | !nsown_capable(CAP_SETUID)) |
| 697 | goto error; | 726 | goto error; |
| 698 | } | 727 | } |
| 699 | 728 | ||
| 700 | if (new->uid != old->uid) { | 729 | if (!uid_eq(new->uid, old->uid)) { |
| 701 | retval = set_user(new); | 730 | retval = set_user(new); |
| 702 | if (retval < 0) | 731 | if (retval < 0) |
| 703 | goto error; | 732 | goto error; |
| 704 | } | 733 | } |
| 705 | if (ruid != (uid_t) -1 || | 734 | if (ruid != (uid_t) -1 || |
| 706 | (euid != (uid_t) -1 && euid != old->uid)) | 735 | (euid != (uid_t) -1 && !uid_eq(keuid, old->uid))) |
| 707 | new->suid = new->euid; | 736 | new->suid = new->euid; |
| 708 | new->fsuid = new->euid; | 737 | new->fsuid = new->euid; |
| 709 | 738 | ||
| @@ -731,9 +760,15 @@ error: | |||
| 731 | */ | 760 | */ |
| 732 | SYSCALL_DEFINE1(setuid, uid_t, uid) | 761 | SYSCALL_DEFINE1(setuid, uid_t, uid) |
| 733 | { | 762 | { |
| 763 | struct user_namespace *ns = current_user_ns(); | ||
| 734 | const struct cred *old; | 764 | const struct cred *old; |
| 735 | struct cred *new; | 765 | struct cred *new; |
| 736 | int retval; | 766 | int retval; |
| 767 | kuid_t kuid; | ||
| 768 | |||
| 769 | kuid = make_kuid(ns, uid); | ||
| 770 | if (!uid_valid(kuid)) | ||
| 771 | return -EINVAL; | ||
| 737 | 772 | ||
| 738 | new = prepare_creds(); | 773 | new = prepare_creds(); |
| 739 | if (!new) | 774 | if (!new) |
| @@ -742,17 +777,17 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
| 742 | 777 | ||
| 743 | retval = -EPERM; | 778 | retval = -EPERM; |
| 744 | if (nsown_capable(CAP_SETUID)) { | 779 | if (nsown_capable(CAP_SETUID)) { |
| 745 | new->suid = new->uid = uid; | 780 | new->suid = new->uid = kuid; |
| 746 | if (uid != old->uid) { | 781 | if (!uid_eq(kuid, old->uid)) { |
| 747 | retval = set_user(new); | 782 | retval = set_user(new); |
| 748 | if (retval < 0) | 783 | if (retval < 0) |
| 749 | goto error; | 784 | goto error; |
| 750 | } | 785 | } |
| 751 | } else if (uid != old->uid && uid != new->suid) { | 786 | } else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) { |
| 752 | goto error; | 787 | goto error; |
| 753 | } | 788 | } |
| 754 | 789 | ||
| 755 | new->fsuid = new->euid = uid; | 790 | new->fsuid = new->euid = kuid; |
| 756 | 791 | ||
| 757 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); | 792 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); |
| 758 | if (retval < 0) | 793 | if (retval < 0) |
| @@ -772,9 +807,24 @@ error: | |||
| 772 | */ | 807 | */ |
| 773 | SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | 808 | SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) |
| 774 | { | 809 | { |
| 810 | struct user_namespace *ns = current_user_ns(); | ||
| 775 | const struct cred *old; | 811 | const struct cred *old; |
| 776 | struct cred *new; | 812 | struct cred *new; |
| 777 | int retval; | 813 | int retval; |
| 814 | kuid_t kruid, keuid, ksuid; | ||
| 815 | |||
| 816 | kruid = make_kuid(ns, ruid); | ||
| 817 | keuid = make_kuid(ns, euid); | ||
| 818 | ksuid = make_kuid(ns, suid); | ||
| 819 | |||
| 820 | if ((ruid != (uid_t) -1) && !uid_valid(kruid)) | ||
| 821 | return -EINVAL; | ||
| 822 | |||
| 823 | if ((euid != (uid_t) -1) && !uid_valid(keuid)) | ||
| 824 | return -EINVAL; | ||
| 825 | |||
| 826 | if ((suid != (uid_t) -1) && !uid_valid(ksuid)) | ||
| 827 | return -EINVAL; | ||
| 778 | 828 | ||
| 779 | new = prepare_creds(); | 829 | new = prepare_creds(); |
| 780 | if (!new) | 830 | if (!new) |
| @@ -784,29 +834,29 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
| 784 | 834 | ||
| 785 | retval = -EPERM; | 835 | retval = -EPERM; |
| 786 | if (!nsown_capable(CAP_SETUID)) { | 836 | if (!nsown_capable(CAP_SETUID)) { |
| 787 | if (ruid != (uid_t) -1 && ruid != old->uid && | 837 | if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && |
| 788 | ruid != old->euid && ruid != old->suid) | 838 | !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) |
| 789 | goto error; | 839 | goto error; |
| 790 | if (euid != (uid_t) -1 && euid != old->uid && | 840 | if (euid != (uid_t) -1 && !uid_eq(keuid, old->uid) && |
| 791 | euid != old->euid && euid != old->suid) | 841 | !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid)) |
| 792 | goto error; | 842 | goto error; |
| 793 | if (suid != (uid_t) -1 && suid != old->uid && | 843 | if (suid != (uid_t) -1 && !uid_eq(ksuid, old->uid) && |
| 794 | suid != old->euid && suid != old->suid) | 844 | !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid)) |
| 795 | goto error; | 845 | goto error; |
| 796 | } | 846 | } |
| 797 | 847 | ||
| 798 | if (ruid != (uid_t) -1) { | 848 | if (ruid != (uid_t) -1) { |
| 799 | new->uid = ruid; | 849 | new->uid = kruid; |
| 800 | if (ruid != old->uid) { | 850 | if (!uid_eq(kruid, old->uid)) { |
| 801 | retval = set_user(new); | 851 | retval = set_user(new); |
| 802 | if (retval < 0) | 852 | if (retval < 0) |
| 803 | goto error; | 853 | goto error; |
| 804 | } | 854 | } |
| 805 | } | 855 | } |
| 806 | if (euid != (uid_t) -1) | 856 | if (euid != (uid_t) -1) |
| 807 | new->euid = euid; | 857 | new->euid = keuid; |
| 808 | if (suid != (uid_t) -1) | 858 | if (suid != (uid_t) -1) |
| 809 | new->suid = suid; | 859 | new->suid = ksuid; |
| 810 | new->fsuid = new->euid; | 860 | new->fsuid = new->euid; |
| 811 | 861 | ||
| 812 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); | 862 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); |
| @@ -820,14 +870,19 @@ error: | |||
| 820 | return retval; | 870 | return retval; |
| 821 | } | 871 | } |
| 822 | 872 | ||
| 823 | SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid) | 873 | SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp) |
| 824 | { | 874 | { |
| 825 | const struct cred *cred = current_cred(); | 875 | const struct cred *cred = current_cred(); |
| 826 | int retval; | 876 | int retval; |
| 877 | uid_t ruid, euid, suid; | ||
| 827 | 878 | ||
| 828 | if (!(retval = put_user(cred->uid, ruid)) && | 879 | ruid = from_kuid_munged(cred->user_ns, cred->uid); |
| 829 | !(retval = put_user(cred->euid, euid))) | 880 | euid = from_kuid_munged(cred->user_ns, cred->euid); |
| 830 | retval = put_user(cred->suid, suid); | 881 | suid = from_kuid_munged(cred->user_ns, cred->suid); |
| 882 | |||
| 883 | if (!(retval = put_user(ruid, ruidp)) && | ||
| 884 | !(retval = put_user(euid, euidp))) | ||
| 885 | retval = put_user(suid, suidp); | ||
| 831 | 886 | ||
| 832 | return retval; | 887 | return retval; |
| 833 | } | 888 | } |
| @@ -837,9 +892,22 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __u | |||
| 837 | */ | 892 | */ |
| 838 | SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | 893 | SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) |
| 839 | { | 894 | { |
| 895 | struct user_namespace *ns = current_user_ns(); | ||
| 840 | const struct cred *old; | 896 | const struct cred *old; |
| 841 | struct cred *new; | 897 | struct cred *new; |
| 842 | int retval; | 898 | int retval; |
| 899 | kgid_t krgid, kegid, ksgid; | ||
| 900 | |||
| 901 | krgid = make_kgid(ns, rgid); | ||
| 902 | kegid = make_kgid(ns, egid); | ||
| 903 | ksgid = make_kgid(ns, sgid); | ||
| 904 | |||
| 905 | if ((rgid != (gid_t) -1) && !gid_valid(krgid)) | ||
| 906 | return -EINVAL; | ||
| 907 | if ((egid != (gid_t) -1) && !gid_valid(kegid)) | ||
| 908 | return -EINVAL; | ||
| 909 | if ((sgid != (gid_t) -1) && !gid_valid(ksgid)) | ||
| 910 | return -EINVAL; | ||
| 843 | 911 | ||
| 844 | new = prepare_creds(); | 912 | new = prepare_creds(); |
| 845 | if (!new) | 913 | if (!new) |
| @@ -848,23 +916,23 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
| 848 | 916 | ||
| 849 | retval = -EPERM; | 917 | retval = -EPERM; |
| 850 | if (!nsown_capable(CAP_SETGID)) { | 918 | if (!nsown_capable(CAP_SETGID)) { |
| 851 | if (rgid != (gid_t) -1 && rgid != old->gid && | 919 | if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && |
| 852 | rgid != old->egid && rgid != old->sgid) | 920 | !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid)) |
| 853 | goto error; | 921 | goto error; |
| 854 | if (egid != (gid_t) -1 && egid != old->gid && | 922 | if (egid != (gid_t) -1 && !gid_eq(kegid, old->gid) && |
| 855 | egid != old->egid && egid != old->sgid) | 923 | !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid)) |
| 856 | goto error; | 924 | goto error; |
| 857 | if (sgid != (gid_t) -1 && sgid != old->gid && | 925 | if (sgid != (gid_t) -1 && !gid_eq(ksgid, old->gid) && |
| 858 | sgid != old->egid && sgid != old->sgid) | 926 | !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid)) |
| 859 | goto error; | 927 | goto error; |
| 860 | } | 928 | } |
| 861 | 929 | ||
| 862 | if (rgid != (gid_t) -1) | 930 | if (rgid != (gid_t) -1) |
| 863 | new->gid = rgid; | 931 | new->gid = krgid; |
| 864 | if (egid != (gid_t) -1) | 932 | if (egid != (gid_t) -1) |
| 865 | new->egid = egid; | 933 | new->egid = kegid; |
| 866 | if (sgid != (gid_t) -1) | 934 | if (sgid != (gid_t) -1) |
| 867 | new->sgid = sgid; | 935 | new->sgid = ksgid; |
| 868 | new->fsgid = new->egid; | 936 | new->fsgid = new->egid; |
| 869 | 937 | ||
| 870 | return commit_creds(new); | 938 | return commit_creds(new); |
| @@ -874,14 +942,19 @@ error: | |||
| 874 | return retval; | 942 | return retval; |
| 875 | } | 943 | } |
| 876 | 944 | ||
| 877 | SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid) | 945 | SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp) |
| 878 | { | 946 | { |
| 879 | const struct cred *cred = current_cred(); | 947 | const struct cred *cred = current_cred(); |
| 880 | int retval; | 948 | int retval; |
| 949 | gid_t rgid, egid, sgid; | ||
| 881 | 950 | ||
| 882 | if (!(retval = put_user(cred->gid, rgid)) && | 951 | rgid = from_kgid_munged(cred->user_ns, cred->gid); |
| 883 | !(retval = put_user(cred->egid, egid))) | 952 | egid = from_kgid_munged(cred->user_ns, cred->egid); |
| 884 | retval = put_user(cred->sgid, sgid); | 953 | sgid = from_kgid_munged(cred->user_ns, cred->sgid); |
| 954 | |||
| 955 | if (!(retval = put_user(rgid, rgidp)) && | ||
| 956 | !(retval = put_user(egid, egidp))) | ||
| 957 | retval = put_user(sgid, sgidp); | ||
| 885 | 958 | ||
| 886 | return retval; | 959 | return retval; |
| 887 | } | 960 | } |
| @@ -898,18 +971,24 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
| 898 | const struct cred *old; | 971 | const struct cred *old; |
| 899 | struct cred *new; | 972 | struct cred *new; |
| 900 | uid_t old_fsuid; | 973 | uid_t old_fsuid; |
| 974 | kuid_t kuid; | ||
| 975 | |||
| 976 | old = current_cred(); | ||
| 977 | old_fsuid = from_kuid_munged(old->user_ns, old->fsuid); | ||
| 978 | |||
| 979 | kuid = make_kuid(old->user_ns, uid); | ||
| 980 | if (!uid_valid(kuid)) | ||
| 981 | return old_fsuid; | ||
| 901 | 982 | ||
| 902 | new = prepare_creds(); | 983 | new = prepare_creds(); |
| 903 | if (!new) | 984 | if (!new) |
| 904 | return current_fsuid(); | 985 | return old_fsuid; |
| 905 | old = current_cred(); | ||
| 906 | old_fsuid = old->fsuid; | ||
| 907 | 986 | ||
| 908 | if (uid == old->uid || uid == old->euid || | 987 | if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || |
| 909 | uid == old->suid || uid == old->fsuid || | 988 | uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || |
| 910 | nsown_capable(CAP_SETUID)) { | 989 | nsown_capable(CAP_SETUID)) { |
| 911 | if (uid != old_fsuid) { | 990 | if (!uid_eq(kuid, old->fsuid)) { |
| 912 | new->fsuid = uid; | 991 | new->fsuid = kuid; |
| 913 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 992 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
| 914 | goto change_okay; | 993 | goto change_okay; |
| 915 | } | 994 | } |
| @@ -931,18 +1010,24 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
| 931 | const struct cred *old; | 1010 | const struct cred *old; |
| 932 | struct cred *new; | 1011 | struct cred *new; |
| 933 | gid_t old_fsgid; | 1012 | gid_t old_fsgid; |
| 1013 | kgid_t kgid; | ||
| 1014 | |||
| 1015 | old = current_cred(); | ||
| 1016 | old_fsgid = from_kgid_munged(old->user_ns, old->fsgid); | ||
| 1017 | |||
| 1018 | kgid = make_kgid(old->user_ns, gid); | ||
| 1019 | if (!gid_valid(kgid)) | ||
| 1020 | return old_fsgid; | ||
| 934 | 1021 | ||
| 935 | new = prepare_creds(); | 1022 | new = prepare_creds(); |
| 936 | if (!new) | 1023 | if (!new) |
| 937 | return current_fsgid(); | 1024 | return old_fsgid; |
| 938 | old = current_cred(); | ||
| 939 | old_fsgid = old->fsgid; | ||
| 940 | 1025 | ||
| 941 | if (gid == old->gid || gid == old->egid || | 1026 | if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || |
| 942 | gid == old->sgid || gid == old->fsgid || | 1027 | gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || |
| 943 | nsown_capable(CAP_SETGID)) { | 1028 | nsown_capable(CAP_SETGID)) { |
| 944 | if (gid != old_fsgid) { | 1029 | if (!gid_eq(kgid, old->fsgid)) { |
| 945 | new->fsgid = gid; | 1030 | new->fsgid = kgid; |
| 946 | goto change_okay; | 1031 | goto change_okay; |
| 947 | } | 1032 | } |
| 948 | } | 1033 | } |
| @@ -1295,8 +1380,8 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | |||
| 1295 | memcpy(u->nodename, tmp, len); | 1380 | memcpy(u->nodename, tmp, len); |
| 1296 | memset(u->nodename + len, 0, sizeof(u->nodename) - len); | 1381 | memset(u->nodename + len, 0, sizeof(u->nodename) - len); |
| 1297 | errno = 0; | 1382 | errno = 0; |
| 1383 | uts_proc_notify(UTS_PROC_HOSTNAME); | ||
| 1298 | } | 1384 | } |
| 1299 | uts_proc_notify(UTS_PROC_HOSTNAME); | ||
| 1300 | up_write(&uts_sem); | 1385 | up_write(&uts_sem); |
| 1301 | return errno; | 1386 | return errno; |
| 1302 | } | 1387 | } |
| @@ -1346,8 +1431,8 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
| 1346 | memcpy(u->domainname, tmp, len); | 1431 | memcpy(u->domainname, tmp, len); |
| 1347 | memset(u->domainname + len, 0, sizeof(u->domainname) - len); | 1432 | memset(u->domainname + len, 0, sizeof(u->domainname) - len); |
| 1348 | errno = 0; | 1433 | errno = 0; |
| 1434 | uts_proc_notify(UTS_PROC_DOMAINNAME); | ||
| 1349 | } | 1435 | } |
| 1350 | uts_proc_notify(UTS_PROC_DOMAINNAME); | ||
| 1351 | up_write(&uts_sem); | 1436 | up_write(&uts_sem); |
| 1352 | return errno; | 1437 | return errno; |
| 1353 | } | 1438 | } |
| @@ -1498,15 +1583,14 @@ static int check_prlimit_permission(struct task_struct *task) | |||
| 1498 | return 0; | 1583 | return 0; |
| 1499 | 1584 | ||
| 1500 | tcred = __task_cred(task); | 1585 | tcred = __task_cred(task); |
| 1501 | if (cred->user->user_ns == tcred->user->user_ns && | 1586 | if (uid_eq(cred->uid, tcred->euid) && |
| 1502 | (cred->uid == tcred->euid && | 1587 | uid_eq(cred->uid, tcred->suid) && |
| 1503 | cred->uid == tcred->suid && | 1588 | uid_eq(cred->uid, tcred->uid) && |
| 1504 | cred->uid == tcred->uid && | 1589 | gid_eq(cred->gid, tcred->egid) && |
| 1505 | cred->gid == tcred->egid && | 1590 | gid_eq(cred->gid, tcred->sgid) && |
| 1506 | cred->gid == tcred->sgid && | 1591 | gid_eq(cred->gid, tcred->gid)) |
| 1507 | cred->gid == tcred->gid)) | ||
| 1508 | return 0; | 1592 | return 0; |
| 1509 | if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE)) | 1593 | if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) |
| 1510 | return 0; | 1594 | return 0; |
| 1511 | 1595 | ||
| 1512 | return -EPERM; | 1596 | return -EPERM; |
| @@ -1702,77 +1786,102 @@ SYSCALL_DEFINE1(umask, int, mask) | |||
| 1702 | } | 1786 | } |
| 1703 | 1787 | ||
| 1704 | #ifdef CONFIG_CHECKPOINT_RESTORE | 1788 | #ifdef CONFIG_CHECKPOINT_RESTORE |
| 1789 | static bool vma_flags_mismatch(struct vm_area_struct *vma, | ||
| 1790 | unsigned long required, | ||
| 1791 | unsigned long banned) | ||
| 1792 | { | ||
| 1793 | return (vma->vm_flags & required) != required || | ||
| 1794 | (vma->vm_flags & banned); | ||
| 1795 | } | ||
| 1796 | |||
| 1797 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) | ||
| 1798 | { | ||
| 1799 | struct file *exe_file; | ||
| 1800 | struct dentry *dentry; | ||
| 1801 | int err; | ||
| 1802 | |||
| 1803 | /* | ||
| 1804 | * Setting new mm::exe_file is only allowed when no VM_EXECUTABLE vma's | ||
| 1805 | * remain. So perform a quick test first. | ||
| 1806 | */ | ||
| 1807 | if (mm->num_exe_file_vmas) | ||
| 1808 | return -EBUSY; | ||
| 1809 | |||
| 1810 | exe_file = fget(fd); | ||
| 1811 | if (!exe_file) | ||
| 1812 | return -EBADF; | ||
| 1813 | |||
| 1814 | dentry = exe_file->f_path.dentry; | ||
| 1815 | |||
| 1816 | /* | ||
| 1817 | * Because the original mm->exe_file points to executable file, make | ||
| 1818 | * sure that this one is executable as well, to avoid breaking an | ||
| 1819 | * overall picture. | ||
| 1820 | */ | ||
| 1821 | err = -EACCES; | ||
| 1822 | if (!S_ISREG(dentry->d_inode->i_mode) || | ||
| 1823 | exe_file->f_path.mnt->mnt_flags & MNT_NOEXEC) | ||
| 1824 | goto exit; | ||
| 1825 | |||
| 1826 | err = inode_permission(dentry->d_inode, MAY_EXEC); | ||
| 1827 | if (err) | ||
| 1828 | goto exit; | ||
| 1829 | |||
| 1830 | /* | ||
| 1831 | * The symlink can be changed only once, just to disallow arbitrary | ||
| 1832 | * transitions malicious software might bring in. This means one | ||
| 1833 | * could make a snapshot over all processes running and monitor | ||
| 1834 | * /proc/pid/exe changes to notice unusual activity if needed. | ||
| 1835 | */ | ||
| 1836 | down_write(&mm->mmap_sem); | ||
| 1837 | if (likely(!mm->exe_file)) | ||
| 1838 | set_mm_exe_file(mm, exe_file); | ||
| 1839 | else | ||
| 1840 | err = -EBUSY; | ||
| 1841 | up_write(&mm->mmap_sem); | ||
| 1842 | |||
| 1843 | exit: | ||
| 1844 | fput(exe_file); | ||
| 1845 | return err; | ||
| 1846 | } | ||
| 1847 | |||
| 1705 | static int prctl_set_mm(int opt, unsigned long addr, | 1848 | static int prctl_set_mm(int opt, unsigned long addr, |
| 1706 | unsigned long arg4, unsigned long arg5) | 1849 | unsigned long arg4, unsigned long arg5) |
| 1707 | { | 1850 | { |
| 1708 | unsigned long rlim = rlimit(RLIMIT_DATA); | 1851 | unsigned long rlim = rlimit(RLIMIT_DATA); |
| 1709 | unsigned long vm_req_flags; | ||
| 1710 | unsigned long vm_bad_flags; | ||
| 1711 | struct vm_area_struct *vma; | ||
| 1712 | int error = 0; | ||
| 1713 | struct mm_struct *mm = current->mm; | 1852 | struct mm_struct *mm = current->mm; |
| 1853 | struct vm_area_struct *vma; | ||
| 1854 | int error; | ||
| 1714 | 1855 | ||
| 1715 | if (arg4 | arg5) | 1856 | if (arg5 || (arg4 && opt != PR_SET_MM_AUXV)) |
| 1716 | return -EINVAL; | 1857 | return -EINVAL; |
| 1717 | 1858 | ||
| 1718 | if (!capable(CAP_SYS_RESOURCE)) | 1859 | if (!capable(CAP_SYS_RESOURCE)) |
| 1719 | return -EPERM; | 1860 | return -EPERM; |
| 1720 | 1861 | ||
| 1862 | if (opt == PR_SET_MM_EXE_FILE) | ||
| 1863 | return prctl_set_mm_exe_file(mm, (unsigned int)addr); | ||
| 1864 | |||
| 1721 | if (addr >= TASK_SIZE) | 1865 | if (addr >= TASK_SIZE) |
| 1722 | return -EINVAL; | 1866 | return -EINVAL; |
| 1723 | 1867 | ||
| 1868 | error = -EINVAL; | ||
| 1869 | |||
| 1724 | down_read(&mm->mmap_sem); | 1870 | down_read(&mm->mmap_sem); |
| 1725 | vma = find_vma(mm, addr); | 1871 | vma = find_vma(mm, addr); |
| 1726 | 1872 | ||
| 1727 | if (opt != PR_SET_MM_START_BRK && opt != PR_SET_MM_BRK) { | ||
| 1728 | /* It must be existing VMA */ | ||
| 1729 | if (!vma || vma->vm_start > addr) | ||
| 1730 | goto out; | ||
| 1731 | } | ||
| 1732 | |||
| 1733 | error = -EINVAL; | ||
| 1734 | switch (opt) { | 1873 | switch (opt) { |
| 1735 | case PR_SET_MM_START_CODE: | 1874 | case PR_SET_MM_START_CODE: |
| 1875 | mm->start_code = addr; | ||
| 1876 | break; | ||
| 1736 | case PR_SET_MM_END_CODE: | 1877 | case PR_SET_MM_END_CODE: |
| 1737 | vm_req_flags = VM_READ | VM_EXEC; | 1878 | mm->end_code = addr; |
| 1738 | vm_bad_flags = VM_WRITE | VM_MAYSHARE; | ||
| 1739 | |||
| 1740 | if ((vma->vm_flags & vm_req_flags) != vm_req_flags || | ||
| 1741 | (vma->vm_flags & vm_bad_flags)) | ||
| 1742 | goto out; | ||
| 1743 | |||
| 1744 | if (opt == PR_SET_MM_START_CODE) | ||
| 1745 | mm->start_code = addr; | ||
| 1746 | else | ||
| 1747 | mm->end_code = addr; | ||
| 1748 | break; | 1879 | break; |
| 1749 | |||
| 1750 | case PR_SET_MM_START_DATA: | 1880 | case PR_SET_MM_START_DATA: |
| 1751 | case PR_SET_MM_END_DATA: | 1881 | mm->start_data = addr; |
| 1752 | vm_req_flags = VM_READ | VM_WRITE; | ||
| 1753 | vm_bad_flags = VM_EXEC | VM_MAYSHARE; | ||
| 1754 | |||
| 1755 | if ((vma->vm_flags & vm_req_flags) != vm_req_flags || | ||
| 1756 | (vma->vm_flags & vm_bad_flags)) | ||
| 1757 | goto out; | ||
| 1758 | |||
| 1759 | if (opt == PR_SET_MM_START_DATA) | ||
| 1760 | mm->start_data = addr; | ||
| 1761 | else | ||
| 1762 | mm->end_data = addr; | ||
| 1763 | break; | 1882 | break; |
| 1764 | 1883 | case PR_SET_MM_END_DATA: | |
| 1765 | case PR_SET_MM_START_STACK: | 1884 | mm->end_data = addr; |
| 1766 | |||
| 1767 | #ifdef CONFIG_STACK_GROWSUP | ||
| 1768 | vm_req_flags = VM_READ | VM_WRITE | VM_GROWSUP; | ||
| 1769 | #else | ||
| 1770 | vm_req_flags = VM_READ | VM_WRITE | VM_GROWSDOWN; | ||
| 1771 | #endif | ||
| 1772 | if ((vma->vm_flags & vm_req_flags) != vm_req_flags) | ||
| 1773 | goto out; | ||
| 1774 | |||
| 1775 | mm->start_stack = addr; | ||
| 1776 | break; | 1885 | break; |
| 1777 | 1886 | ||
| 1778 | case PR_SET_MM_START_BRK: | 1887 | case PR_SET_MM_START_BRK: |
| @@ -1799,16 +1908,77 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
| 1799 | mm->brk = addr; | 1908 | mm->brk = addr; |
| 1800 | break; | 1909 | break; |
| 1801 | 1910 | ||
| 1911 | /* | ||
| 1912 | * If command line arguments and environment | ||
| 1913 | * are placed somewhere else on stack, we can | ||
| 1914 | * set them up here, ARG_START/END to setup | ||
| 1915 | * command line argumets and ENV_START/END | ||
| 1916 | * for environment. | ||
| 1917 | */ | ||
| 1918 | case PR_SET_MM_START_STACK: | ||
| 1919 | case PR_SET_MM_ARG_START: | ||
| 1920 | case PR_SET_MM_ARG_END: | ||
| 1921 | case PR_SET_MM_ENV_START: | ||
| 1922 | case PR_SET_MM_ENV_END: | ||
| 1923 | if (!vma) { | ||
| 1924 | error = -EFAULT; | ||
| 1925 | goto out; | ||
| 1926 | } | ||
| 1927 | #ifdef CONFIG_STACK_GROWSUP | ||
| 1928 | if (vma_flags_mismatch(vma, VM_READ | VM_WRITE | VM_GROWSUP, 0)) | ||
| 1929 | #else | ||
| 1930 | if (vma_flags_mismatch(vma, VM_READ | VM_WRITE | VM_GROWSDOWN, 0)) | ||
| 1931 | #endif | ||
| 1932 | goto out; | ||
| 1933 | if (opt == PR_SET_MM_START_STACK) | ||
| 1934 | mm->start_stack = addr; | ||
| 1935 | else if (opt == PR_SET_MM_ARG_START) | ||
| 1936 | mm->arg_start = addr; | ||
| 1937 | else if (opt == PR_SET_MM_ARG_END) | ||
| 1938 | mm->arg_end = addr; | ||
| 1939 | else if (opt == PR_SET_MM_ENV_START) | ||
| 1940 | mm->env_start = addr; | ||
| 1941 | else if (opt == PR_SET_MM_ENV_END) | ||
| 1942 | mm->env_end = addr; | ||
| 1943 | break; | ||
| 1944 | |||
| 1945 | /* | ||
| 1946 | * This doesn't move auxiliary vector itself | ||
| 1947 | * since it's pinned to mm_struct, but allow | ||
| 1948 | * to fill vector with new values. It's up | ||
| 1949 | * to a caller to provide sane values here | ||
| 1950 | * otherwise user space tools which use this | ||
| 1951 | * vector might be unhappy. | ||
| 1952 | */ | ||
| 1953 | case PR_SET_MM_AUXV: { | ||
| 1954 | unsigned long user_auxv[AT_VECTOR_SIZE]; | ||
| 1955 | |||
| 1956 | if (arg4 > sizeof(user_auxv)) | ||
| 1957 | goto out; | ||
| 1958 | up_read(&mm->mmap_sem); | ||
| 1959 | |||
| 1960 | if (copy_from_user(user_auxv, (const void __user *)addr, arg4)) | ||
| 1961 | return -EFAULT; | ||
| 1962 | |||
| 1963 | /* Make sure the last entry is always AT_NULL */ | ||
| 1964 | user_auxv[AT_VECTOR_SIZE - 2] = 0; | ||
| 1965 | user_auxv[AT_VECTOR_SIZE - 1] = 0; | ||
| 1966 | |||
| 1967 | BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv)); | ||
| 1968 | |||
| 1969 | task_lock(current); | ||
| 1970 | memcpy(mm->saved_auxv, user_auxv, arg4); | ||
| 1971 | task_unlock(current); | ||
| 1972 | |||
| 1973 | return 0; | ||
| 1974 | } | ||
| 1802 | default: | 1975 | default: |
| 1803 | error = -EINVAL; | ||
| 1804 | goto out; | 1976 | goto out; |
| 1805 | } | 1977 | } |
| 1806 | 1978 | ||
| 1807 | error = 0; | 1979 | error = 0; |
| 1808 | |||
| 1809 | out: | 1980 | out: |
| 1810 | up_read(&mm->mmap_sem); | 1981 | up_read(&mm->mmap_sem); |
| 1811 | |||
| 1812 | return error; | 1982 | return error; |
| 1813 | } | 1983 | } |
| 1814 | #else /* CONFIG_CHECKPOINT_RESTORE */ | 1984 | #else /* CONFIG_CHECKPOINT_RESTORE */ |
| @@ -1908,7 +2078,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
| 1908 | error = prctl_get_seccomp(); | 2078 | error = prctl_get_seccomp(); |
| 1909 | break; | 2079 | break; |
| 1910 | case PR_SET_SECCOMP: | 2080 | case PR_SET_SECCOMP: |
| 1911 | error = prctl_set_seccomp(arg2); | 2081 | error = prctl_set_seccomp(arg2, (char __user *)arg3); |
| 1912 | break; | 2082 | break; |
| 1913 | case PR_GET_TSC: | 2083 | case PR_GET_TSC: |
| 1914 | error = GET_TSC_CTL(arg2); | 2084 | error = GET_TSC_CTL(arg2); |
| @@ -1979,6 +2149,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
| 1979 | error = put_user(me->signal->is_child_subreaper, | 2149 | error = put_user(me->signal->is_child_subreaper, |
| 1980 | (int __user *) arg2); | 2150 | (int __user *) arg2); |
| 1981 | break; | 2151 | break; |
| 2152 | case PR_SET_NO_NEW_PRIVS: | ||
| 2153 | if (arg2 != 1 || arg3 || arg4 || arg5) | ||
| 2154 | return -EINVAL; | ||
| 2155 | |||
| 2156 | current->no_new_privs = 1; | ||
| 2157 | break; | ||
| 2158 | case PR_GET_NO_NEW_PRIVS: | ||
| 2159 | if (arg2 || arg3 || arg4 || arg5) | ||
| 2160 | return -EINVAL; | ||
| 2161 | return current->no_new_privs ? 1 : 0; | ||
| 1982 | default: | 2162 | default: |
| 1983 | error = -EINVAL; | 2163 | error = -EINVAL; |
| 1984 | break; | 2164 | break; |
| @@ -2022,7 +2202,6 @@ int orderly_poweroff(bool force) | |||
| 2022 | NULL | 2202 | NULL |
| 2023 | }; | 2203 | }; |
| 2024 | int ret = -ENOMEM; | 2204 | int ret = -ENOMEM; |
| 2025 | struct subprocess_info *info; | ||
| 2026 | 2205 | ||
| 2027 | if (argv == NULL) { | 2206 | if (argv == NULL) { |
| 2028 | printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", | 2207 | printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", |
| @@ -2030,18 +2209,16 @@ int orderly_poweroff(bool force) | |||
| 2030 | goto out; | 2209 | goto out; |
| 2031 | } | 2210 | } |
| 2032 | 2211 | ||
| 2033 | info = call_usermodehelper_setup(argv[0], argv, envp, GFP_ATOMIC); | 2212 | ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_NO_WAIT, |
| 2034 | if (info == NULL) { | 2213 | NULL, argv_cleanup, NULL); |
| 2035 | argv_free(argv); | 2214 | out: |
| 2036 | goto out; | 2215 | if (likely(!ret)) |
| 2037 | } | 2216 | return 0; |
| 2038 | |||
| 2039 | call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL); | ||
| 2040 | 2217 | ||
| 2041 | ret = call_usermodehelper_exec(info, UMH_NO_WAIT); | 2218 | if (ret == -ENOMEM) |
| 2219 | argv_free(argv); | ||
| 2042 | 2220 | ||
| 2043 | out: | 2221 | if (force) { |
| 2044 | if (ret && force) { | ||
| 2045 | printk(KERN_WARNING "Failed to start orderly shutdown: " | 2222 | printk(KERN_WARNING "Failed to start orderly shutdown: " |
| 2046 | "forcing the issue\n"); | 2223 | "forcing the issue\n"); |
| 2047 | 2224 | ||
