.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Common capabilities, needed by capability.o. |
---|
2 | | - * |
---|
3 | | - * This program is free software; you can redistribute it and/or modify |
---|
4 | | - * it under the terms of the GNU General Public License as published by |
---|
5 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
6 | | - * (at your option) any later version. |
---|
7 | | - * |
---|
8 | 3 | */ |
---|
9 | 4 | |
---|
10 | 5 | #include <linux/capability.h> |
---|
11 | 6 | #include <linux/audit.h> |
---|
12 | | -#include <linux/module.h> |
---|
13 | 7 | #include <linux/init.h> |
---|
14 | 8 | #include <linux/kernel.h> |
---|
15 | 9 | #include <linux/lsm_hooks.h> |
---|
.. | .. |
---|
58 | 52 | * @cred: The credentials to use |
---|
59 | 53 | * @ns: The user namespace in which we need the capability |
---|
60 | 54 | * @cap: The capability to check for |
---|
61 | | - * @audit: Whether to write an audit message or not |
---|
| 55 | + * @opts: Bitmask of options defined in include/linux/security.h |
---|
62 | 56 | * |
---|
63 | 57 | * Determine whether the nominated task has the specified capability amongst |
---|
64 | 58 | * its effective set, returning 0 if it does, -ve if it does not. |
---|
.. | .. |
---|
303 | 297 | struct inode *inode = d_backing_inode(dentry); |
---|
304 | 298 | int error; |
---|
305 | 299 | |
---|
306 | | - error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0); |
---|
| 300 | + error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0, |
---|
| 301 | + XATTR_NOSECURITY); |
---|
307 | 302 | return error > 0; |
---|
308 | 303 | } |
---|
309 | 304 | |
---|
.. | .. |
---|
397 | 392 | &tmpbuf, size, GFP_NOFS); |
---|
398 | 393 | dput(dentry); |
---|
399 | 394 | |
---|
400 | | - if (ret < 0 || !tmpbuf) |
---|
401 | | - return ret; |
---|
| 395 | + if (ret < 0 || !tmpbuf) { |
---|
| 396 | + size = ret; |
---|
| 397 | + goto out_free; |
---|
| 398 | + } |
---|
402 | 399 | |
---|
403 | 400 | fs_ns = inode->i_sb->s_user_ns; |
---|
404 | 401 | cap = (struct vfs_cap_data *) tmpbuf; |
---|
.. | .. |
---|
611 | 608 | |
---|
612 | 609 | fs_ns = inode->i_sb->s_user_ns; |
---|
613 | 610 | size = __vfs_getxattr((struct dentry *)dentry, inode, |
---|
614 | | - XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ); |
---|
| 611 | + XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ, |
---|
| 612 | + XATTR_NOSECURITY); |
---|
615 | 613 | if (size == -ENODATA || size == -EOPNOTSUPP) |
---|
616 | 614 | /* no data, that's ok */ |
---|
617 | 615 | return -ENODATA; |
---|
.. | .. |
---|
662 | 660 | cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; |
---|
663 | 661 | cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; |
---|
664 | 662 | |
---|
| 663 | + cpu_caps->rootid = rootkuid; |
---|
| 664 | + |
---|
665 | 665 | return 0; |
---|
666 | 666 | } |
---|
667 | 667 | |
---|
.. | .. |
---|
670 | 670 | * its xattrs and, if present, apply them to the proposed credentials being |
---|
671 | 671 | * constructed by execve(). |
---|
672 | 672 | */ |
---|
673 | | -static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_fcap) |
---|
| 673 | +static int get_file_caps(struct linux_binprm *bprm, struct file *file, |
---|
| 674 | + bool *effective, bool *has_fcap) |
---|
674 | 675 | { |
---|
675 | 676 | int rc = 0; |
---|
676 | 677 | struct cpu_vfs_cap_data vcaps; |
---|
.. | .. |
---|
680 | 681 | if (!file_caps_enabled) |
---|
681 | 682 | return 0; |
---|
682 | 683 | |
---|
683 | | - if (!mnt_may_suid(bprm->file->f_path.mnt)) |
---|
| 684 | + if (!mnt_may_suid(file->f_path.mnt)) |
---|
684 | 685 | return 0; |
---|
685 | 686 | |
---|
686 | 687 | /* |
---|
.. | .. |
---|
688 | 689 | * explicit that capability bits are limited to s_user_ns and its |
---|
689 | 690 | * descendants. |
---|
690 | 691 | */ |
---|
691 | | - if (!current_in_userns(bprm->file->f_path.mnt->mnt_sb->s_user_ns)) |
---|
| 692 | + if (!current_in_userns(file->f_path.mnt->mnt_sb->s_user_ns)) |
---|
692 | 693 | return 0; |
---|
693 | 694 | |
---|
694 | | - rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); |
---|
| 695 | + rc = get_vfs_caps_from_disk(file->f_path.dentry, &vcaps); |
---|
695 | 696 | if (rc < 0) { |
---|
696 | 697 | if (rc == -EINVAL) |
---|
697 | 698 | printk(KERN_NOTICE "Invalid argument reading file caps for %s\n", |
---|
.. | .. |
---|
702 | 703 | } |
---|
703 | 704 | |
---|
704 | 705 | rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_fcap); |
---|
705 | | - if (rc == -EINVAL) |
---|
706 | | - printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", |
---|
707 | | - __func__, rc, bprm->filename); |
---|
708 | 706 | |
---|
709 | 707 | out: |
---|
710 | 708 | if (rc) |
---|
.. | .. |
---|
823 | 821 | } |
---|
824 | 822 | |
---|
825 | 823 | /** |
---|
826 | | - * cap_bprm_set_creds - Set up the proposed credentials for execve(). |
---|
| 824 | + * cap_bprm_creds_from_file - Set up the proposed credentials for execve(). |
---|
827 | 825 | * @bprm: The execution parameters, including the proposed creds |
---|
| 826 | + * @file: The file to pull the credentials from |
---|
828 | 827 | * |
---|
829 | 828 | * Set up the proposed credentials for a new execution context being |
---|
830 | 829 | * constructed by execve(). The proposed creds in @bprm->cred is altered, |
---|
831 | 830 | * which won't take effect immediately. Returns 0 if successful, -ve on error. |
---|
832 | 831 | */ |
---|
833 | | -int cap_bprm_set_creds(struct linux_binprm *bprm) |
---|
| 832 | +int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) |
---|
834 | 833 | { |
---|
| 834 | + /* Process setpcap binaries and capabilities for uid 0 */ |
---|
835 | 835 | const struct cred *old = current_cred(); |
---|
836 | 836 | struct cred *new = bprm->cred; |
---|
837 | 837 | bool effective = false, has_fcap = false, is_setid; |
---|
838 | 838 | int ret; |
---|
839 | 839 | kuid_t root_uid; |
---|
840 | 840 | |
---|
841 | | - new->cap_ambient = old->cap_ambient; |
---|
842 | 841 | if (WARN_ON(!cap_ambient_invariant_ok(old))) |
---|
843 | 842 | return -EPERM; |
---|
844 | 843 | |
---|
845 | | - ret = get_file_caps(bprm, &effective, &has_fcap); |
---|
| 844 | + ret = get_file_caps(bprm, file, &effective, &has_fcap); |
---|
846 | 845 | if (ret < 0) |
---|
847 | 846 | return ret; |
---|
848 | 847 | |
---|
.. | .. |
---|
911 | 910 | return -EPERM; |
---|
912 | 911 | |
---|
913 | 912 | /* Check for privilege-elevated exec. */ |
---|
914 | | - bprm->cap_elevated = 0; |
---|
915 | 913 | if (is_setid || |
---|
916 | 914 | (!__is_real(root_uid, new) && |
---|
917 | 915 | (effective || |
---|
918 | 916 | __cap_grew(permitted, ambient, new)))) |
---|
919 | | - bprm->cap_elevated = 1; |
---|
| 917 | + bprm->secureexec = 1; |
---|
920 | 918 | |
---|
921 | 919 | return 0; |
---|
922 | 920 | } |
---|
.. | .. |
---|
942 | 940 | |
---|
943 | 941 | /* Ignore non-security xattrs */ |
---|
944 | 942 | if (strncmp(name, XATTR_SECURITY_PREFIX, |
---|
945 | | - sizeof(XATTR_SECURITY_PREFIX) - 1) != 0) |
---|
| 943 | + XATTR_SECURITY_PREFIX_LEN) != 0) |
---|
946 | 944 | return 0; |
---|
947 | 945 | |
---|
948 | 946 | /* |
---|
.. | .. |
---|
974 | 972 | |
---|
975 | 973 | /* Ignore non-security xattrs */ |
---|
976 | 974 | if (strncmp(name, XATTR_SECURITY_PREFIX, |
---|
977 | | - sizeof(XATTR_SECURITY_PREFIX) - 1) != 0) |
---|
| 975 | + XATTR_SECURITY_PREFIX_LEN) != 0) |
---|
978 | 976 | return 0; |
---|
979 | 977 | |
---|
980 | 978 | if (strcmp(name, XATTR_NAME_CAPS) == 0) { |
---|
.. | .. |
---|
1366 | 1364 | |
---|
1367 | 1365 | #ifdef CONFIG_SECURITY |
---|
1368 | 1366 | |
---|
1369 | | -struct security_hook_list capability_hooks[] __lsm_ro_after_init = { |
---|
| 1367 | +static struct security_hook_list capability_hooks[] __lsm_ro_after_init = { |
---|
1370 | 1368 | LSM_HOOK_INIT(capable, cap_capable), |
---|
1371 | 1369 | LSM_HOOK_INIT(settime, cap_settime), |
---|
1372 | 1370 | LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check), |
---|
1373 | 1371 | LSM_HOOK_INIT(ptrace_traceme, cap_ptrace_traceme), |
---|
1374 | 1372 | LSM_HOOK_INIT(capget, cap_capget), |
---|
1375 | 1373 | LSM_HOOK_INIT(capset, cap_capset), |
---|
1376 | | - LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds), |
---|
| 1374 | + LSM_HOOK_INIT(bprm_creds_from_file, cap_bprm_creds_from_file), |
---|
1377 | 1375 | LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), |
---|
1378 | 1376 | LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), |
---|
1379 | 1377 | LSM_HOOK_INIT(inode_getsecurity, cap_inode_getsecurity), |
---|
.. | .. |
---|
1387 | 1385 | LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory), |
---|
1388 | 1386 | }; |
---|
1389 | 1387 | |
---|
1390 | | -void __init capability_add_hooks(void) |
---|
| 1388 | +static int __init capability_init(void) |
---|
1391 | 1389 | { |
---|
1392 | 1390 | security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks), |
---|
1393 | 1391 | "capability"); |
---|
| 1392 | + return 0; |
---|
1394 | 1393 | } |
---|
1395 | 1394 | |
---|
| 1395 | +DEFINE_LSM(capability) = { |
---|
| 1396 | + .name = "capability", |
---|
| 1397 | + .order = LSM_ORDER_FIRST, |
---|
| 1398 | + .init = capability_init, |
---|
| 1399 | +}; |
---|
| 1400 | + |
---|
1396 | 1401 | #endif /* CONFIG_SECURITY */ |
---|