| .. | .. |
|---|
| 49 | 49 | #include <linux/syscalls.h> |
|---|
| 50 | 50 | #include <linux/kprobes.h> |
|---|
| 51 | 51 | #include <linux/user_namespace.h> |
|---|
| 52 | +#include <linux/time_namespace.h> |
|---|
| 52 | 53 | #include <linux/binfmts.h> |
|---|
| 53 | 54 | |
|---|
| 54 | 55 | #include <linux/sched.h> |
|---|
| .. | .. |
|---|
| 74 | 75 | #include <asm/unistd.h> |
|---|
| 75 | 76 | |
|---|
| 76 | 77 | #include "uid16.h" |
|---|
| 78 | + |
|---|
| 79 | +#include <trace/hooks/sys.h> |
|---|
| 77 | 80 | |
|---|
| 78 | 81 | #ifndef SET_UNALIGN_CTL |
|---|
| 79 | 82 | # define SET_UNALIGN_CTL(a, b) (-EINVAL) |
|---|
| .. | .. |
|---|
| 105 | 108 | #ifndef SET_TSC_CTL |
|---|
| 106 | 109 | # define SET_TSC_CTL(a) (-EINVAL) |
|---|
| 107 | 110 | #endif |
|---|
| 108 | | -#ifndef MPX_ENABLE_MANAGEMENT |
|---|
| 109 | | -# define MPX_ENABLE_MANAGEMENT() (-EINVAL) |
|---|
| 110 | | -#endif |
|---|
| 111 | | -#ifndef MPX_DISABLE_MANAGEMENT |
|---|
| 112 | | -# define MPX_DISABLE_MANAGEMENT() (-EINVAL) |
|---|
| 113 | | -#endif |
|---|
| 114 | 111 | #ifndef GET_FP_MODE |
|---|
| 115 | 112 | # define GET_FP_MODE(a) (-EINVAL) |
|---|
| 116 | 113 | #endif |
|---|
| .. | .. |
|---|
| 122 | 119 | #endif |
|---|
| 123 | 120 | #ifndef SVE_GET_VL |
|---|
| 124 | 121 | # define SVE_GET_VL() (-EINVAL) |
|---|
| 122 | +#endif |
|---|
| 123 | +#ifndef PAC_RESET_KEYS |
|---|
| 124 | +# define PAC_RESET_KEYS(a, b) (-EINVAL) |
|---|
| 125 | +#endif |
|---|
| 126 | +#ifndef PAC_SET_ENABLED_KEYS |
|---|
| 127 | +# define PAC_SET_ENABLED_KEYS(a, b, c) (-EINVAL) |
|---|
| 128 | +#endif |
|---|
| 129 | +#ifndef PAC_GET_ENABLED_KEYS |
|---|
| 130 | +# define PAC_GET_ENABLED_KEYS(a) (-EINVAL) |
|---|
| 125 | 131 | #endif |
|---|
| 126 | 132 | #ifndef SET_TAGGED_ADDR_CTRL |
|---|
| 127 | 133 | # define SET_TAGGED_ADDR_CTRL(a) (-EINVAL) |
|---|
| .. | .. |
|---|
| 377 | 383 | if (rgid != (gid_t) -1) { |
|---|
| 378 | 384 | if (gid_eq(old->gid, krgid) || |
|---|
| 379 | 385 | gid_eq(old->egid, krgid) || |
|---|
| 380 | | - ns_capable(old->user_ns, CAP_SETGID)) |
|---|
| 386 | + ns_capable_setid(old->user_ns, CAP_SETGID)) |
|---|
| 381 | 387 | new->gid = krgid; |
|---|
| 382 | 388 | else |
|---|
| 383 | 389 | goto error; |
|---|
| .. | .. |
|---|
| 386 | 392 | if (gid_eq(old->gid, kegid) || |
|---|
| 387 | 393 | gid_eq(old->egid, kegid) || |
|---|
| 388 | 394 | gid_eq(old->sgid, kegid) || |
|---|
| 389 | | - ns_capable(old->user_ns, CAP_SETGID)) |
|---|
| 395 | + ns_capable_setid(old->user_ns, CAP_SETGID)) |
|---|
| 390 | 396 | new->egid = kegid; |
|---|
| 391 | 397 | else |
|---|
| 392 | 398 | goto error; |
|---|
| .. | .. |
|---|
| 396 | 402 | (egid != (gid_t) -1 && !gid_eq(kegid, old->gid))) |
|---|
| 397 | 403 | new->sgid = new->egid; |
|---|
| 398 | 404 | new->fsgid = new->egid; |
|---|
| 405 | + |
|---|
| 406 | + retval = security_task_fix_setgid(new, old, LSM_SETID_RE); |
|---|
| 407 | + if (retval < 0) |
|---|
| 408 | + goto error; |
|---|
| 399 | 409 | |
|---|
| 400 | 410 | return commit_creds(new); |
|---|
| 401 | 411 | |
|---|
| .. | .. |
|---|
| 432 | 442 | old = current_cred(); |
|---|
| 433 | 443 | |
|---|
| 434 | 444 | retval = -EPERM; |
|---|
| 435 | | - if (ns_capable(old->user_ns, CAP_SETGID)) |
|---|
| 445 | + if (ns_capable_setid(old->user_ns, CAP_SETGID)) |
|---|
| 436 | 446 | new->gid = new->egid = new->sgid = new->fsgid = kgid; |
|---|
| 437 | 447 | else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) |
|---|
| 438 | 448 | new->egid = new->fsgid = kgid; |
|---|
| 439 | 449 | else |
|---|
| 450 | + goto error; |
|---|
| 451 | + |
|---|
| 452 | + retval = security_task_fix_setgid(new, old, LSM_SETID_ID); |
|---|
| 453 | + if (retval < 0) |
|---|
| 440 | 454 | goto error; |
|---|
| 441 | 455 | |
|---|
| 442 | 456 | return commit_creds(new); |
|---|
| .. | .. |
|---|
| 521 | 535 | new->uid = kruid; |
|---|
| 522 | 536 | if (!uid_eq(old->uid, kruid) && |
|---|
| 523 | 537 | !uid_eq(old->euid, kruid) && |
|---|
| 524 | | - !ns_capable(old->user_ns, CAP_SETUID)) |
|---|
| 538 | + !ns_capable_setid(old->user_ns, CAP_SETUID)) |
|---|
| 525 | 539 | goto error; |
|---|
| 526 | 540 | } |
|---|
| 527 | 541 | |
|---|
| .. | .. |
|---|
| 530 | 544 | if (!uid_eq(old->uid, keuid) && |
|---|
| 531 | 545 | !uid_eq(old->euid, keuid) && |
|---|
| 532 | 546 | !uid_eq(old->suid, keuid) && |
|---|
| 533 | | - !ns_capable(old->user_ns, CAP_SETUID)) |
|---|
| 547 | + !ns_capable_setid(old->user_ns, CAP_SETUID)) |
|---|
| 534 | 548 | goto error; |
|---|
| 535 | 549 | } |
|---|
| 536 | 550 | |
|---|
| .. | .. |
|---|
| 589 | 603 | old = current_cred(); |
|---|
| 590 | 604 | |
|---|
| 591 | 605 | retval = -EPERM; |
|---|
| 592 | | - if (ns_capable(old->user_ns, CAP_SETUID)) { |
|---|
| 606 | + if (ns_capable_setid(old->user_ns, CAP_SETUID)) { |
|---|
| 593 | 607 | new->suid = new->uid = kuid; |
|---|
| 594 | 608 | if (!uid_eq(kuid, old->uid)) { |
|---|
| 595 | 609 | retval = set_user(new); |
|---|
| .. | .. |
|---|
| 630 | 644 | struct cred *new; |
|---|
| 631 | 645 | int retval; |
|---|
| 632 | 646 | kuid_t kruid, keuid, ksuid; |
|---|
| 647 | + bool ruid_new, euid_new, suid_new; |
|---|
| 633 | 648 | |
|---|
| 634 | 649 | kruid = make_kuid(ns, ruid); |
|---|
| 635 | 650 | keuid = make_kuid(ns, euid); |
|---|
| .. | .. |
|---|
| 644 | 659 | if ((suid != (uid_t) -1) && !uid_valid(ksuid)) |
|---|
| 645 | 660 | return -EINVAL; |
|---|
| 646 | 661 | |
|---|
| 662 | + old = current_cred(); |
|---|
| 663 | + |
|---|
| 664 | + /* check for no-op */ |
|---|
| 665 | + if ((ruid == (uid_t) -1 || uid_eq(kruid, old->uid)) && |
|---|
| 666 | + (euid == (uid_t) -1 || (uid_eq(keuid, old->euid) && |
|---|
| 667 | + uid_eq(keuid, old->fsuid))) && |
|---|
| 668 | + (suid == (uid_t) -1 || uid_eq(ksuid, old->suid))) |
|---|
| 669 | + return 0; |
|---|
| 670 | + |
|---|
| 671 | + ruid_new = ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && |
|---|
| 672 | + !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid); |
|---|
| 673 | + euid_new = euid != (uid_t) -1 && !uid_eq(keuid, old->uid) && |
|---|
| 674 | + !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid); |
|---|
| 675 | + suid_new = suid != (uid_t) -1 && !uid_eq(ksuid, old->uid) && |
|---|
| 676 | + !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid); |
|---|
| 677 | + if ((ruid_new || euid_new || suid_new) && |
|---|
| 678 | + !ns_capable_setid(old->user_ns, CAP_SETUID)) |
|---|
| 679 | + return -EPERM; |
|---|
| 680 | + |
|---|
| 647 | 681 | new = prepare_creds(); |
|---|
| 648 | 682 | if (!new) |
|---|
| 649 | 683 | return -ENOMEM; |
|---|
| 650 | | - |
|---|
| 651 | | - old = current_cred(); |
|---|
| 652 | | - |
|---|
| 653 | | - retval = -EPERM; |
|---|
| 654 | | - if (!ns_capable(old->user_ns, CAP_SETUID)) { |
|---|
| 655 | | - if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && |
|---|
| 656 | | - !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) |
|---|
| 657 | | - goto error; |
|---|
| 658 | | - if (euid != (uid_t) -1 && !uid_eq(keuid, old->uid) && |
|---|
| 659 | | - !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid)) |
|---|
| 660 | | - goto error; |
|---|
| 661 | | - if (suid != (uid_t) -1 && !uid_eq(ksuid, old->uid) && |
|---|
| 662 | | - !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid)) |
|---|
| 663 | | - goto error; |
|---|
| 664 | | - } |
|---|
| 665 | 684 | |
|---|
| 666 | 685 | if (ruid != (uid_t) -1) { |
|---|
| 667 | 686 | new->uid = kruid; |
|---|
| .. | .. |
|---|
| 722 | 741 | struct cred *new; |
|---|
| 723 | 742 | int retval; |
|---|
| 724 | 743 | kgid_t krgid, kegid, ksgid; |
|---|
| 744 | + bool rgid_new, egid_new, sgid_new; |
|---|
| 725 | 745 | |
|---|
| 726 | 746 | krgid = make_kgid(ns, rgid); |
|---|
| 727 | 747 | kegid = make_kgid(ns, egid); |
|---|
| .. | .. |
|---|
| 734 | 754 | if ((sgid != (gid_t) -1) && !gid_valid(ksgid)) |
|---|
| 735 | 755 | return -EINVAL; |
|---|
| 736 | 756 | |
|---|
| 757 | + old = current_cred(); |
|---|
| 758 | + |
|---|
| 759 | + /* check for no-op */ |
|---|
| 760 | + if ((rgid == (gid_t) -1 || gid_eq(krgid, old->gid)) && |
|---|
| 761 | + (egid == (gid_t) -1 || (gid_eq(kegid, old->egid) && |
|---|
| 762 | + gid_eq(kegid, old->fsgid))) && |
|---|
| 763 | + (sgid == (gid_t) -1 || gid_eq(ksgid, old->sgid))) |
|---|
| 764 | + return 0; |
|---|
| 765 | + |
|---|
| 766 | + rgid_new = rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && |
|---|
| 767 | + !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid); |
|---|
| 768 | + egid_new = egid != (gid_t) -1 && !gid_eq(kegid, old->gid) && |
|---|
| 769 | + !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid); |
|---|
| 770 | + sgid_new = sgid != (gid_t) -1 && !gid_eq(ksgid, old->gid) && |
|---|
| 771 | + !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid); |
|---|
| 772 | + if ((rgid_new || egid_new || sgid_new) && |
|---|
| 773 | + !ns_capable_setid(old->user_ns, CAP_SETGID)) |
|---|
| 774 | + return -EPERM; |
|---|
| 775 | + |
|---|
| 737 | 776 | new = prepare_creds(); |
|---|
| 738 | 777 | if (!new) |
|---|
| 739 | 778 | return -ENOMEM; |
|---|
| 740 | | - old = current_cred(); |
|---|
| 741 | | - |
|---|
| 742 | | - retval = -EPERM; |
|---|
| 743 | | - if (!ns_capable(old->user_ns, CAP_SETGID)) { |
|---|
| 744 | | - if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && |
|---|
| 745 | | - !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid)) |
|---|
| 746 | | - goto error; |
|---|
| 747 | | - if (egid != (gid_t) -1 && !gid_eq(kegid, old->gid) && |
|---|
| 748 | | - !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid)) |
|---|
| 749 | | - goto error; |
|---|
| 750 | | - if (sgid != (gid_t) -1 && !gid_eq(ksgid, old->gid) && |
|---|
| 751 | | - !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid)) |
|---|
| 752 | | - goto error; |
|---|
| 753 | | - } |
|---|
| 754 | 779 | |
|---|
| 755 | 780 | if (rgid != (gid_t) -1) |
|---|
| 756 | 781 | new->gid = krgid; |
|---|
| .. | .. |
|---|
| 759 | 784 | if (sgid != (gid_t) -1) |
|---|
| 760 | 785 | new->sgid = ksgid; |
|---|
| 761 | 786 | new->fsgid = new->egid; |
|---|
| 787 | + |
|---|
| 788 | + retval = security_task_fix_setgid(new, old, LSM_SETID_RES); |
|---|
| 789 | + if (retval < 0) |
|---|
| 790 | + goto error; |
|---|
| 762 | 791 | |
|---|
| 763 | 792 | return commit_creds(new); |
|---|
| 764 | 793 | |
|---|
| .. | .. |
|---|
| 819 | 848 | |
|---|
| 820 | 849 | if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || |
|---|
| 821 | 850 | uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || |
|---|
| 822 | | - ns_capable(old->user_ns, CAP_SETUID)) { |
|---|
| 851 | + ns_capable_setid(old->user_ns, CAP_SETUID)) { |
|---|
| 823 | 852 | if (!uid_eq(kuid, old->fsuid)) { |
|---|
| 824 | 853 | new->fsuid = kuid; |
|---|
| 825 | 854 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
|---|
| .. | .. |
|---|
| 863 | 892 | |
|---|
| 864 | 893 | if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || |
|---|
| 865 | 894 | gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || |
|---|
| 866 | | - ns_capable(old->user_ns, CAP_SETGID)) { |
|---|
| 895 | + ns_capable_setid(old->user_ns, CAP_SETGID)) { |
|---|
| 867 | 896 | if (!gid_eq(kgid, old->fsgid)) { |
|---|
| 868 | 897 | new->fsgid = kgid; |
|---|
| 869 | | - goto change_okay; |
|---|
| 898 | + if (security_task_fix_setgid(new,old,LSM_SETID_FS) == 0) |
|---|
| 899 | + goto change_okay; |
|---|
| 870 | 900 | } |
|---|
| 871 | 901 | } |
|---|
| 872 | 902 | |
|---|
| .. | .. |
|---|
| 1212 | 1242 | /* |
|---|
| 1213 | 1243 | * Work around broken programs that cannot handle "Linux 3.0". |
|---|
| 1214 | 1244 | * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40 |
|---|
| 1215 | | - * And we map 4.x to 2.6.60+x, so 4.0 would be 2.6.60. |
|---|
| 1245 | + * And we map 4.x and later versions to 2.6.60+x, so 4.0/5.0/6.0/... would be |
|---|
| 1246 | + * 2.6.60. |
|---|
| 1216 | 1247 | */ |
|---|
| 1217 | 1248 | static int override_release(char __user *release, size_t len) |
|---|
| 1218 | 1249 | { |
|---|
| .. | .. |
|---|
| 1538 | 1569 | |
|---|
| 1539 | 1570 | if (resource >= RLIM_NLIMITS) |
|---|
| 1540 | 1571 | return -EINVAL; |
|---|
| 1572 | + resource = array_index_nospec(resource, RLIM_NLIMITS); |
|---|
| 1573 | + |
|---|
| 1541 | 1574 | if (new_rlim) { |
|---|
| 1542 | 1575 | if (new_rlim->rlim_cur > new_rlim->rlim_max) |
|---|
| 1543 | 1576 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1563 | 1596 | retval = -EPERM; |
|---|
| 1564 | 1597 | if (!retval) |
|---|
| 1565 | 1598 | retval = security_task_setrlimit(tsk, resource, new_rlim); |
|---|
| 1566 | | - if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) { |
|---|
| 1567 | | - /* |
|---|
| 1568 | | - * The caller is asking for an immediate RLIMIT_CPU |
|---|
| 1569 | | - * expiry. But we use the zero value to mean "it was |
|---|
| 1570 | | - * never set". So let's cheat and make it one second |
|---|
| 1571 | | - * instead |
|---|
| 1572 | | - */ |
|---|
| 1573 | | - new_rlim->rlim_cur = 1; |
|---|
| 1574 | | - } |
|---|
| 1575 | 1599 | } |
|---|
| 1576 | 1600 | if (!retval) { |
|---|
| 1577 | 1601 | if (old_rlim) |
|---|
| .. | .. |
|---|
| 1582 | 1606 | task_unlock(tsk->group_leader); |
|---|
| 1583 | 1607 | |
|---|
| 1584 | 1608 | /* |
|---|
| 1585 | | - * RLIMIT_CPU handling. Note that the kernel fails to return an error |
|---|
| 1586 | | - * code if it rejected the user's attempt to set RLIMIT_CPU. This is a |
|---|
| 1587 | | - * very long-standing error, and fixing it now risks breakage of |
|---|
| 1588 | | - * applications, so we live with it |
|---|
| 1609 | + * RLIMIT_CPU handling. Arm the posix CPU timer if the limit is not |
|---|
| 1610 | + * infite. In case of RLIM_INFINITY the posix CPU timer code |
|---|
| 1611 | + * ignores the rlimit. |
|---|
| 1589 | 1612 | */ |
|---|
| 1590 | 1613 | if (!retval && new_rlim && resource == RLIMIT_CPU && |
|---|
| 1591 | 1614 | new_rlim->rlim_cur != RLIM_INFINITY && |
|---|
| .. | .. |
|---|
| 1753 | 1776 | |
|---|
| 1754 | 1777 | if (who == RUSAGE_CHILDREN) |
|---|
| 1755 | 1778 | break; |
|---|
| 1779 | + fallthrough; |
|---|
| 1756 | 1780 | |
|---|
| 1757 | 1781 | case RUSAGE_SELF: |
|---|
| 1758 | 1782 | thread_group_cputime_adjusted(p, &tgutime, &tgstime); |
|---|
| .. | .. |
|---|
| 1778 | 1802 | unlock_task_sighand(p, &flags); |
|---|
| 1779 | 1803 | |
|---|
| 1780 | 1804 | out: |
|---|
| 1781 | | - r->ru_utime = ns_to_timeval(utime); |
|---|
| 1782 | | - r->ru_stime = ns_to_timeval(stime); |
|---|
| 1805 | + r->ru_utime = ns_to_kernel_old_timeval(utime); |
|---|
| 1806 | + r->ru_stime = ns_to_kernel_old_timeval(stime); |
|---|
| 1783 | 1807 | |
|---|
| 1784 | 1808 | if (who != RUSAGE_CHILDREN) { |
|---|
| 1785 | 1809 | struct mm_struct *mm = get_task_mm(p); |
|---|
| .. | .. |
|---|
| 1858 | 1882 | if (exe_file) { |
|---|
| 1859 | 1883 | struct vm_area_struct *vma; |
|---|
| 1860 | 1884 | |
|---|
| 1861 | | - down_read(&mm->mmap_sem); |
|---|
| 1885 | + mmap_read_lock(mm); |
|---|
| 1862 | 1886 | for (vma = mm->mmap; vma; vma = vma->vm_next) { |
|---|
| 1863 | 1887 | if (!vma->vm_file) |
|---|
| 1864 | 1888 | continue; |
|---|
| .. | .. |
|---|
| 1867 | 1891 | goto exit_err; |
|---|
| 1868 | 1892 | } |
|---|
| 1869 | 1893 | |
|---|
| 1870 | | - up_read(&mm->mmap_sem); |
|---|
| 1894 | + mmap_read_unlock(mm); |
|---|
| 1871 | 1895 | fput(exe_file); |
|---|
| 1872 | 1896 | } |
|---|
| 1873 | 1897 | |
|---|
| .. | .. |
|---|
| 1881 | 1905 | fdput(exe); |
|---|
| 1882 | 1906 | return err; |
|---|
| 1883 | 1907 | exit_err: |
|---|
| 1884 | | - up_read(&mm->mmap_sem); |
|---|
| 1908 | + mmap_read_unlock(mm); |
|---|
| 1885 | 1909 | fput(exe_file); |
|---|
| 1886 | 1910 | goto exit; |
|---|
| 1887 | 1911 | } |
|---|
| 1888 | 1912 | |
|---|
| 1889 | 1913 | /* |
|---|
| 1914 | + * Check arithmetic relations of passed addresses. |
|---|
| 1915 | + * |
|---|
| 1890 | 1916 | * WARNING: we don't require any capability here so be very careful |
|---|
| 1891 | 1917 | * in what is allowed for modification from userspace. |
|---|
| 1892 | 1918 | */ |
|---|
| 1893 | | -static int validate_prctl_map(struct prctl_mm_map *prctl_map) |
|---|
| 1919 | +static int validate_prctl_map_addr(struct prctl_mm_map *prctl_map) |
|---|
| 1894 | 1920 | { |
|---|
| 1895 | 1921 | unsigned long mmap_max_addr = TASK_SIZE; |
|---|
| 1896 | | - struct mm_struct *mm = current->mm; |
|---|
| 1897 | 1922 | int error = -EINVAL, i; |
|---|
| 1898 | 1923 | |
|---|
| 1899 | 1924 | static const unsigned char offsets[] = { |
|---|
| .. | .. |
|---|
| 1947 | 1972 | prctl_map->start_data)) |
|---|
| 1948 | 1973 | goto out; |
|---|
| 1949 | 1974 | |
|---|
| 1950 | | - /* |
|---|
| 1951 | | - * Someone is trying to cheat the auxv vector. |
|---|
| 1952 | | - */ |
|---|
| 1953 | | - if (prctl_map->auxv_size) { |
|---|
| 1954 | | - if (!prctl_map->auxv || prctl_map->auxv_size > sizeof(mm->saved_auxv)) |
|---|
| 1955 | | - goto out; |
|---|
| 1956 | | - } |
|---|
| 1957 | | - |
|---|
| 1958 | | - /* |
|---|
| 1959 | | - * Finally, make sure the caller has the rights to |
|---|
| 1960 | | - * change /proc/pid/exe link: only local sys admin should |
|---|
| 1961 | | - * be allowed to. |
|---|
| 1962 | | - */ |
|---|
| 1963 | | - if (prctl_map->exe_fd != (u32)-1) { |
|---|
| 1964 | | - if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN)) |
|---|
| 1965 | | - goto out; |
|---|
| 1966 | | - } |
|---|
| 1967 | | - |
|---|
| 1968 | 1975 | error = 0; |
|---|
| 1969 | 1976 | out: |
|---|
| 1970 | 1977 | return error; |
|---|
| .. | .. |
|---|
| 1991 | 1998 | if (copy_from_user(&prctl_map, addr, sizeof(prctl_map))) |
|---|
| 1992 | 1999 | return -EFAULT; |
|---|
| 1993 | 2000 | |
|---|
| 1994 | | - error = validate_prctl_map(&prctl_map); |
|---|
| 2001 | + error = validate_prctl_map_addr(&prctl_map); |
|---|
| 1995 | 2002 | if (error) |
|---|
| 1996 | 2003 | return error; |
|---|
| 1997 | 2004 | |
|---|
| 1998 | 2005 | if (prctl_map.auxv_size) { |
|---|
| 2006 | + /* |
|---|
| 2007 | + * Someone is trying to cheat the auxv vector. |
|---|
| 2008 | + */ |
|---|
| 2009 | + if (!prctl_map.auxv || |
|---|
| 2010 | + prctl_map.auxv_size > sizeof(mm->saved_auxv)) |
|---|
| 2011 | + return -EINVAL; |
|---|
| 2012 | + |
|---|
| 1999 | 2013 | memset(user_auxv, 0, sizeof(user_auxv)); |
|---|
| 2000 | 2014 | if (copy_from_user(user_auxv, |
|---|
| 2001 | 2015 | (const void __user *)prctl_map.auxv, |
|---|
| .. | .. |
|---|
| 2008 | 2022 | } |
|---|
| 2009 | 2023 | |
|---|
| 2010 | 2024 | if (prctl_map.exe_fd != (u32)-1) { |
|---|
| 2025 | + /* |
|---|
| 2026 | + * Check if the current user is checkpoint/restore capable. |
|---|
| 2027 | + * At the time of this writing, it checks for CAP_SYS_ADMIN |
|---|
| 2028 | + * or CAP_CHECKPOINT_RESTORE. |
|---|
| 2029 | + * Note that a user with access to ptrace can masquerade an |
|---|
| 2030 | + * arbitrary program as any executable, even setuid ones. |
|---|
| 2031 | + * This may have implications in the tomoyo subsystem. |
|---|
| 2032 | + */ |
|---|
| 2033 | + if (!checkpoint_restore_ns_capable(current_user_ns())) |
|---|
| 2034 | + return -EPERM; |
|---|
| 2035 | + |
|---|
| 2011 | 2036 | error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd); |
|---|
| 2012 | 2037 | if (error) |
|---|
| 2013 | 2038 | return error; |
|---|
| 2014 | 2039 | } |
|---|
| 2015 | 2040 | |
|---|
| 2016 | 2041 | /* |
|---|
| 2017 | | - * arg_lock protects concurent updates but we still need mmap_sem for |
|---|
| 2042 | + * arg_lock protects concurent updates but we still need mmap_lock for |
|---|
| 2018 | 2043 | * read to exclude races with sys_brk. |
|---|
| 2019 | 2044 | */ |
|---|
| 2020 | | - down_read(&mm->mmap_sem); |
|---|
| 2045 | + mmap_read_lock(mm); |
|---|
| 2021 | 2046 | |
|---|
| 2022 | 2047 | /* |
|---|
| 2023 | 2048 | * We don't validate if these members are pointing to |
|---|
| .. | .. |
|---|
| 2025 | 2050 | * VMAs already unmapped and kernel uses these members for statistics |
|---|
| 2026 | 2051 | * output in procfs mostly, except |
|---|
| 2027 | 2052 | * |
|---|
| 2028 | | - * - @start_brk/@brk which are used in do_brk but kernel lookups |
|---|
| 2053 | + * - @start_brk/@brk which are used in do_brk_flags but kernel lookups |
|---|
| 2029 | 2054 | * for VMAs when updating these memvers so anything wrong written |
|---|
| 2030 | 2055 | * here cause kernel to swear at userspace program but won't lead |
|---|
| 2031 | 2056 | * to any problem in kernel itself |
|---|
| .. | .. |
|---|
| 2056 | 2081 | if (prctl_map.auxv_size) |
|---|
| 2057 | 2082 | memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv)); |
|---|
| 2058 | 2083 | |
|---|
| 2059 | | - up_read(&mm->mmap_sem); |
|---|
| 2084 | + mmap_read_unlock(mm); |
|---|
| 2060 | 2085 | return 0; |
|---|
| 2061 | 2086 | } |
|---|
| 2062 | 2087 | #endif /* CONFIG_CHECKPOINT_RESTORE */ |
|---|
| .. | .. |
|---|
| 2095 | 2120 | unsigned long arg4, unsigned long arg5) |
|---|
| 2096 | 2121 | { |
|---|
| 2097 | 2122 | struct mm_struct *mm = current->mm; |
|---|
| 2098 | | - struct prctl_mm_map prctl_map; |
|---|
| 2123 | + struct prctl_mm_map prctl_map = { |
|---|
| 2124 | + .auxv = NULL, |
|---|
| 2125 | + .auxv_size = 0, |
|---|
| 2126 | + .exe_fd = -1, |
|---|
| 2127 | + }; |
|---|
| 2099 | 2128 | struct vm_area_struct *vma; |
|---|
| 2100 | 2129 | int error; |
|---|
| 2101 | 2130 | |
|---|
| .. | .. |
|---|
| 2123 | 2152 | |
|---|
| 2124 | 2153 | error = -EINVAL; |
|---|
| 2125 | 2154 | |
|---|
| 2126 | | - down_write(&mm->mmap_sem); |
|---|
| 2155 | + /* |
|---|
| 2156 | + * arg_lock protects concurent updates of arg boundaries, we need |
|---|
| 2157 | + * mmap_lock for a) concurrent sys_brk, b) finding VMA for addr |
|---|
| 2158 | + * validation. |
|---|
| 2159 | + */ |
|---|
| 2160 | + mmap_read_lock(mm); |
|---|
| 2127 | 2161 | vma = find_vma(mm, addr); |
|---|
| 2128 | 2162 | |
|---|
| 2163 | + spin_lock(&mm->arg_lock); |
|---|
| 2129 | 2164 | prctl_map.start_code = mm->start_code; |
|---|
| 2130 | 2165 | prctl_map.end_code = mm->end_code; |
|---|
| 2131 | 2166 | prctl_map.start_data = mm->start_data; |
|---|
| .. | .. |
|---|
| 2137 | 2172 | prctl_map.arg_end = mm->arg_end; |
|---|
| 2138 | 2173 | prctl_map.env_start = mm->env_start; |
|---|
| 2139 | 2174 | prctl_map.env_end = mm->env_end; |
|---|
| 2140 | | - prctl_map.auxv = NULL; |
|---|
| 2141 | | - prctl_map.auxv_size = 0; |
|---|
| 2142 | | - prctl_map.exe_fd = -1; |
|---|
| 2143 | 2175 | |
|---|
| 2144 | 2176 | switch (opt) { |
|---|
| 2145 | 2177 | case PR_SET_MM_START_CODE: |
|---|
| .. | .. |
|---|
| 2179 | 2211 | goto out; |
|---|
| 2180 | 2212 | } |
|---|
| 2181 | 2213 | |
|---|
| 2182 | | - error = validate_prctl_map(&prctl_map); |
|---|
| 2214 | + error = validate_prctl_map_addr(&prctl_map); |
|---|
| 2183 | 2215 | if (error) |
|---|
| 2184 | 2216 | goto out; |
|---|
| 2185 | 2217 | |
|---|
| .. | .. |
|---|
| 2216 | 2248 | |
|---|
| 2217 | 2249 | error = 0; |
|---|
| 2218 | 2250 | out: |
|---|
| 2219 | | - up_write(&mm->mmap_sem); |
|---|
| 2251 | + spin_unlock(&mm->arg_lock); |
|---|
| 2252 | + mmap_read_unlock(mm); |
|---|
| 2220 | 2253 | return error; |
|---|
| 2221 | 2254 | } |
|---|
| 2222 | 2255 | |
|---|
| 2223 | 2256 | #ifdef CONFIG_CHECKPOINT_RESTORE |
|---|
| 2224 | | -static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) |
|---|
| 2257 | +static int prctl_get_tid_address(struct task_struct *me, int __user * __user *tid_addr) |
|---|
| 2225 | 2258 | { |
|---|
| 2226 | 2259 | return put_user(me->clear_child_tid, tid_addr); |
|---|
| 2227 | 2260 | } |
|---|
| 2228 | 2261 | #else |
|---|
| 2229 | | -static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) |
|---|
| 2262 | +static int prctl_get_tid_address(struct task_struct *me, int __user * __user *tid_addr) |
|---|
| 2230 | 2263 | { |
|---|
| 2231 | 2264 | return -EINVAL; |
|---|
| 2232 | 2265 | } |
|---|
| .. | .. |
|---|
| 2358 | 2391 | return error; |
|---|
| 2359 | 2392 | if (prev) |
|---|
| 2360 | 2393 | vma = prev->vm_next; |
|---|
| 2361 | | - else /* madvise_remove dropped mmap_sem */ |
|---|
| 2394 | + else /* madvise_remove dropped mmap_lock */ |
|---|
| 2362 | 2395 | vma = find_vma(current->mm, start); |
|---|
| 2363 | 2396 | } |
|---|
| 2364 | 2397 | } |
|---|
| .. | .. |
|---|
| 2386 | 2419 | if (end == start) |
|---|
| 2387 | 2420 | return 0; |
|---|
| 2388 | 2421 | |
|---|
| 2389 | | - down_write(&mm->mmap_sem); |
|---|
| 2422 | + mmap_write_lock(mm); |
|---|
| 2390 | 2423 | |
|---|
| 2391 | 2424 | switch (opt) { |
|---|
| 2392 | 2425 | case PR_SET_VMA_ANON_NAME: |
|---|
| .. | .. |
|---|
| 2396 | 2429 | error = -EINVAL; |
|---|
| 2397 | 2430 | } |
|---|
| 2398 | 2431 | |
|---|
| 2399 | | - up_write(&mm->mmap_sem); |
|---|
| 2432 | + mmap_write_unlock(mm); |
|---|
| 2400 | 2433 | |
|---|
| 2401 | 2434 | return error; |
|---|
| 2402 | 2435 | } |
|---|
| .. | .. |
|---|
| 2407 | 2440 | return -EINVAL; |
|---|
| 2408 | 2441 | } |
|---|
| 2409 | 2442 | #endif |
|---|
| 2443 | + |
|---|
| 2444 | +#define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE) |
|---|
| 2410 | 2445 | |
|---|
| 2411 | 2446 | SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, |
|---|
| 2412 | 2447 | unsigned long, arg4, unsigned long, arg5) |
|---|
| .. | .. |
|---|
| 2555 | 2590 | error = prctl_set_mm(arg2, arg3, arg4, arg5); |
|---|
| 2556 | 2591 | break; |
|---|
| 2557 | 2592 | case PR_GET_TID_ADDRESS: |
|---|
| 2558 | | - error = prctl_get_tid_address(me, (int __user **)arg2); |
|---|
| 2593 | + error = prctl_get_tid_address(me, (int __user * __user *)arg2); |
|---|
| 2559 | 2594 | break; |
|---|
| 2560 | 2595 | case PR_SET_CHILD_SUBREAPER: |
|---|
| 2561 | 2596 | me->signal->is_child_subreaper = !!arg2; |
|---|
| .. | .. |
|---|
| 2586 | 2621 | case PR_SET_THP_DISABLE: |
|---|
| 2587 | 2622 | if (arg3 || arg4 || arg5) |
|---|
| 2588 | 2623 | return -EINVAL; |
|---|
| 2589 | | - if (down_write_killable(&me->mm->mmap_sem)) |
|---|
| 2624 | + if (mmap_write_lock_killable(me->mm)) |
|---|
| 2590 | 2625 | return -EINTR; |
|---|
| 2591 | 2626 | if (arg2) |
|---|
| 2592 | 2627 | set_bit(MMF_DISABLE_THP, &me->mm->flags); |
|---|
| 2593 | 2628 | else |
|---|
| 2594 | 2629 | clear_bit(MMF_DISABLE_THP, &me->mm->flags); |
|---|
| 2595 | | - up_write(&me->mm->mmap_sem); |
|---|
| 2630 | + mmap_write_unlock(me->mm); |
|---|
| 2596 | 2631 | break; |
|---|
| 2597 | 2632 | case PR_MPX_ENABLE_MANAGEMENT: |
|---|
| 2598 | | - if (arg2 || arg3 || arg4 || arg5) |
|---|
| 2599 | | - return -EINVAL; |
|---|
| 2600 | | - error = MPX_ENABLE_MANAGEMENT(); |
|---|
| 2601 | | - break; |
|---|
| 2602 | 2633 | case PR_MPX_DISABLE_MANAGEMENT: |
|---|
| 2603 | | - if (arg2 || arg3 || arg4 || arg5) |
|---|
| 2604 | | - return -EINVAL; |
|---|
| 2605 | | - error = MPX_DISABLE_MANAGEMENT(); |
|---|
| 2606 | | - break; |
|---|
| 2634 | + /* No longer implemented: */ |
|---|
| 2635 | + return -EINVAL; |
|---|
| 2607 | 2636 | case PR_SET_FP_MODE: |
|---|
| 2608 | 2637 | error = SET_FP_MODE(me, arg2); |
|---|
| 2609 | 2638 | break; |
|---|
| .. | .. |
|---|
| 2629 | 2658 | case PR_SET_VMA: |
|---|
| 2630 | 2659 | error = prctl_set_vma(arg2, arg3, arg4, arg5); |
|---|
| 2631 | 2660 | break; |
|---|
| 2661 | + case PR_PAC_RESET_KEYS: |
|---|
| 2662 | + if (arg3 || arg4 || arg5) |
|---|
| 2663 | + return -EINVAL; |
|---|
| 2664 | + error = PAC_RESET_KEYS(me, arg2); |
|---|
| 2665 | + break; |
|---|
| 2666 | + case PR_PAC_SET_ENABLED_KEYS: |
|---|
| 2667 | + if (arg4 || arg5) |
|---|
| 2668 | + return -EINVAL; |
|---|
| 2669 | + error = PAC_SET_ENABLED_KEYS(me, arg2, arg3); |
|---|
| 2670 | + break; |
|---|
| 2671 | + case PR_PAC_GET_ENABLED_KEYS: |
|---|
| 2672 | + if (arg2 || arg3 || arg4 || arg5) |
|---|
| 2673 | + return -EINVAL; |
|---|
| 2674 | + error = PAC_GET_ENABLED_KEYS(me); |
|---|
| 2675 | + break; |
|---|
| 2632 | 2676 | case PR_SET_TAGGED_ADDR_CTRL: |
|---|
| 2633 | 2677 | if (arg3 || arg4 || arg5) |
|---|
| 2634 | 2678 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 2639 | 2683 | return -EINVAL; |
|---|
| 2640 | 2684 | error = GET_TAGGED_ADDR_CTRL(); |
|---|
| 2641 | 2685 | break; |
|---|
| 2686 | + case PR_SET_IO_FLUSHER: |
|---|
| 2687 | + if (!capable(CAP_SYS_RESOURCE)) |
|---|
| 2688 | + return -EPERM; |
|---|
| 2689 | + |
|---|
| 2690 | + if (arg3 || arg4 || arg5) |
|---|
| 2691 | + return -EINVAL; |
|---|
| 2692 | + |
|---|
| 2693 | + if (arg2 == 1) |
|---|
| 2694 | + current->flags |= PR_IO_FLUSHER; |
|---|
| 2695 | + else if (!arg2) |
|---|
| 2696 | + current->flags &= ~PR_IO_FLUSHER; |
|---|
| 2697 | + else |
|---|
| 2698 | + return -EINVAL; |
|---|
| 2699 | + break; |
|---|
| 2700 | + case PR_GET_IO_FLUSHER: |
|---|
| 2701 | + if (!capable(CAP_SYS_RESOURCE)) |
|---|
| 2702 | + return -EPERM; |
|---|
| 2703 | + |
|---|
| 2704 | + if (arg2 || arg3 || arg4 || arg5) |
|---|
| 2705 | + return -EINVAL; |
|---|
| 2706 | + |
|---|
| 2707 | + error = (current->flags & PR_IO_FLUSHER) == PR_IO_FLUSHER; |
|---|
| 2708 | + break; |
|---|
| 2642 | 2709 | default: |
|---|
| 2643 | 2710 | error = -EINVAL; |
|---|
| 2644 | 2711 | break; |
|---|
| 2645 | 2712 | } |
|---|
| 2713 | + trace_android_vh_syscall_prctl_finished(option, me); |
|---|
| 2646 | 2714 | return error; |
|---|
| 2647 | 2715 | } |
|---|
| 2648 | 2716 | |
|---|
| .. | .. |
|---|
| 2672 | 2740 | memset(info, 0, sizeof(struct sysinfo)); |
|---|
| 2673 | 2741 | |
|---|
| 2674 | 2742 | ktime_get_boottime_ts64(&tp); |
|---|
| 2743 | + timens_add_boottime(&tp); |
|---|
| 2675 | 2744 | info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); |
|---|
| 2676 | 2745 | |
|---|
| 2677 | 2746 | get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT); |
|---|
| .. | .. |
|---|
| 2758 | 2827 | COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info) |
|---|
| 2759 | 2828 | { |
|---|
| 2760 | 2829 | struct sysinfo s; |
|---|
| 2830 | + struct compat_sysinfo s_32; |
|---|
| 2761 | 2831 | |
|---|
| 2762 | 2832 | do_sysinfo(&s); |
|---|
| 2763 | 2833 | |
|---|
| .. | .. |
|---|
| 2782 | 2852 | s.freehigh >>= bitcount; |
|---|
| 2783 | 2853 | } |
|---|
| 2784 | 2854 | |
|---|
| 2785 | | - if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) || |
|---|
| 2786 | | - __put_user(s.uptime, &info->uptime) || |
|---|
| 2787 | | - __put_user(s.loads[0], &info->loads[0]) || |
|---|
| 2788 | | - __put_user(s.loads[1], &info->loads[1]) || |
|---|
| 2789 | | - __put_user(s.loads[2], &info->loads[2]) || |
|---|
| 2790 | | - __put_user(s.totalram, &info->totalram) || |
|---|
| 2791 | | - __put_user(s.freeram, &info->freeram) || |
|---|
| 2792 | | - __put_user(s.sharedram, &info->sharedram) || |
|---|
| 2793 | | - __put_user(s.bufferram, &info->bufferram) || |
|---|
| 2794 | | - __put_user(s.totalswap, &info->totalswap) || |
|---|
| 2795 | | - __put_user(s.freeswap, &info->freeswap) || |
|---|
| 2796 | | - __put_user(s.procs, &info->procs) || |
|---|
| 2797 | | - __put_user(s.totalhigh, &info->totalhigh) || |
|---|
| 2798 | | - __put_user(s.freehigh, &info->freehigh) || |
|---|
| 2799 | | - __put_user(s.mem_unit, &info->mem_unit)) |
|---|
| 2855 | + memset(&s_32, 0, sizeof(s_32)); |
|---|
| 2856 | + s_32.uptime = s.uptime; |
|---|
| 2857 | + s_32.loads[0] = s.loads[0]; |
|---|
| 2858 | + s_32.loads[1] = s.loads[1]; |
|---|
| 2859 | + s_32.loads[2] = s.loads[2]; |
|---|
| 2860 | + s_32.totalram = s.totalram; |
|---|
| 2861 | + s_32.freeram = s.freeram; |
|---|
| 2862 | + s_32.sharedram = s.sharedram; |
|---|
| 2863 | + s_32.bufferram = s.bufferram; |
|---|
| 2864 | + s_32.totalswap = s.totalswap; |
|---|
| 2865 | + s_32.freeswap = s.freeswap; |
|---|
| 2866 | + s_32.procs = s.procs; |
|---|
| 2867 | + s_32.totalhigh = s.totalhigh; |
|---|
| 2868 | + s_32.freehigh = s.freehigh; |
|---|
| 2869 | + s_32.mem_unit = s.mem_unit; |
|---|
| 2870 | + if (copy_to_user(info, &s_32, sizeof(s_32))) |
|---|
| 2800 | 2871 | return -EFAULT; |
|---|
| 2801 | | - |
|---|
| 2802 | 2872 | return 0; |
|---|
| 2803 | 2873 | } |
|---|
| 2804 | 2874 | #endif /* CONFIG_COMPAT */ |
|---|