Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'selinux-pr-20260203' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull selinux updates from Paul Moore:

- Add support for SELinux based access control of BPF tokens

We worked with the BPF devs to add the necessary LSM hooks when the
BPF token code was first introduced, but it took us a bit longer to
add the SELinux wiring and support.

In order to preserve existing token-unaware SELinux policies, the new
code is gated by the new "bpf_token_perms" policy capability.

Additional details regarding the new permissions, and behaviors can
be found in the associated commit.

- Remove a BUG() from the SELinux capability code

We now perform a similar check during compile time so we can safely
remove the BUG() call.

* tag 'selinux-pr-20260203' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
selinux: drop the BUG() in cred_has_capability()
selinux: fix a capabilities parsing typo in selinux_bpf_token_capable()
selinux: add support for BPF token access control
selinux: move the selinux_blob_sizes struct

+151 -25
+139 -24
security/selinux/hooks.c
··· 737 737 goto out; 738 738 } 739 739 740 + sbsec->creator_sid = current_sid(); 741 + 740 742 if (strcmp(sb->s_type->name, "proc") == 0) 741 743 sbsec->flags |= SE_SBPROC | SE_SBGENFS; 742 744 ··· 910 908 if (oldroot->sid != newroot->sid) 911 909 goto mismatch; 912 910 } 911 + if (old->creator_sid != new->creator_sid) 912 + goto mismatch; 913 913 return 0; 914 914 mismatch: 915 915 pr_warn("SELinux: mount invalid. Same superblock, " ··· 971 967 newsbsec->sid = oldsbsec->sid; 972 968 newsbsec->def_sid = oldsbsec->def_sid; 973 969 newsbsec->behavior = oldsbsec->behavior; 970 + newsbsec->creator_sid = oldsbsec->creator_sid; 974 971 975 972 if (newsbsec->behavior == SECURITY_FS_USE_NATIVE && 976 973 !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) { ··· 1659 1654 break; 1660 1655 default: 1661 1656 pr_err("SELinux: out of range capability %d\n", cap); 1662 - BUG(); 1663 1657 return -EINVAL; 1664 1658 } 1665 1659 ··· 2590 2586 sbsec->sid = SECINITSID_UNLABELED; 2591 2587 sbsec->def_sid = SECINITSID_FILE; 2592 2588 sbsec->mntpoint_sid = SECINITSID_UNLABELED; 2589 + sbsec->creator_sid = SECINITSID_UNLABELED; 2593 2590 2594 2591 return 0; 2595 2592 } ··· 7048 7043 u32 sid = current_sid(); 7049 7044 int ret; 7050 7045 7046 + if (selinux_policycap_bpf_token_perms()) 7047 + return 0; 7048 + 7051 7049 switch (cmd) { 7052 7050 case BPF_MAP_CREATE: 7053 7051 ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, ··· 7132 7124 BPF__PROG_RUN, NULL); 7133 7125 } 7134 7126 7127 + static u32 selinux_bpffs_creator_sid(u32 fd) 7128 + { 7129 + struct path path; 7130 + struct super_block *sb; 7131 + struct superblock_security_struct *sbsec; 7132 + 7133 + CLASS(fd, f)(fd); 7134 + 7135 + if (fd_empty(f)) 7136 + return SECSID_NULL; 7137 + 7138 + path = fd_file(f)->f_path; 7139 + sb = path.dentry->d_sb; 7140 + sbsec = selinux_superblock(sb); 7141 + 7142 + return sbsec->creator_sid; 7143 + } 7144 + 7135 7145 static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, 7136 7146 struct bpf_token *token, bool kernel) 7137 7147 { 7138 7148 struct bpf_security_struct *bpfsec; 7149 + u32 ssid; 7139 7150 7140 7151 bpfsec = selinux_bpf_map_security(map); 7141 7152 bpfsec->sid = current_sid(); 7142 7153 7143 - return 0; 7154 + if (!token) 7155 + ssid = bpfsec->sid; 7156 + else 7157 + ssid = selinux_bpffs_creator_sid(attr->map_token_fd); 7158 + 7159 + return avc_has_perm(ssid, bpfsec->sid, SECCLASS_BPF, BPF__MAP_CREATE, 7160 + NULL); 7144 7161 } 7145 7162 7146 7163 static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, 7147 7164 struct bpf_token *token, bool kernel) 7148 7165 { 7149 7166 struct bpf_security_struct *bpfsec; 7167 + u32 ssid; 7150 7168 7151 7169 bpfsec = selinux_bpf_prog_security(prog); 7152 7170 bpfsec->sid = current_sid(); 7153 7171 7154 - return 0; 7172 + if (!token) 7173 + ssid = bpfsec->sid; 7174 + else 7175 + ssid = selinux_bpffs_creator_sid(attr->prog_token_fd); 7176 + 7177 + return avc_has_perm(ssid, bpfsec->sid, SECCLASS_BPF, BPF__PROG_LOAD, 7178 + NULL); 7155 7179 } 7156 7180 7157 - static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, 7181 + #define bpf_token_cmd(T, C) \ 7182 + ((T)->allowed_cmds & (1ULL << (C))) 7183 + 7184 + static int selinux_bpf_token_create(struct bpf_token *token, 7185 + union bpf_attr *attr, 7158 7186 const struct path *path) 7159 7187 { 7160 7188 struct bpf_security_struct *bpfsec; 7189 + u32 sid = selinux_bpffs_creator_sid(attr->token_create.bpffs_fd); 7190 + int err; 7161 7191 7162 7192 bpfsec = selinux_bpf_token_security(token); 7163 7193 bpfsec->sid = current_sid(); 7194 + bpfsec->grantor_sid = sid; 7195 + 7196 + bpfsec->perms = 0; 7197 + /** 7198 + * 'token->allowed_cmds' is a bit mask of allowed commands 7199 + * Convert the BPF command enum to a bitmask representing its position 7200 + * in the allowed_cmds bitmap. 7201 + */ 7202 + if (bpf_token_cmd(token, BPF_MAP_CREATE)) { 7203 + err = avc_has_perm(bpfsec->sid, sid, SECCLASS_BPF, 7204 + BPF__MAP_CREATE_AS, NULL); 7205 + if (err) 7206 + return err; 7207 + bpfsec->perms |= BPF__MAP_CREATE; 7208 + } 7209 + if (bpf_token_cmd(token, BPF_PROG_LOAD)) { 7210 + err = avc_has_perm(bpfsec->sid, sid, SECCLASS_BPF, 7211 + BPF__PROG_LOAD_AS, NULL); 7212 + if (err) 7213 + return err; 7214 + bpfsec->perms |= BPF__PROG_LOAD; 7215 + } 7164 7216 7165 7217 return 0; 7166 7218 } 7167 - #endif 7168 7219 7169 - struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { 7170 - .lbs_cred = sizeof(struct cred_security_struct), 7171 - .lbs_task = sizeof(struct task_security_struct), 7172 - .lbs_file = sizeof(struct file_security_struct), 7173 - .lbs_inode = sizeof(struct inode_security_struct), 7174 - .lbs_ipc = sizeof(struct ipc_security_struct), 7175 - .lbs_key = sizeof(struct key_security_struct), 7176 - .lbs_msg_msg = sizeof(struct msg_security_struct), 7177 - #ifdef CONFIG_PERF_EVENTS 7178 - .lbs_perf_event = sizeof(struct perf_event_security_struct), 7220 + static int selinux_bpf_token_cmd(const struct bpf_token *token, 7221 + enum bpf_cmd cmd) 7222 + { 7223 + struct bpf_security_struct *bpfsec; 7224 + 7225 + bpfsec = token->security; 7226 + switch (cmd) { 7227 + case BPF_MAP_CREATE: 7228 + if (!(bpfsec->perms & BPF__MAP_CREATE)) 7229 + return -EACCES; 7230 + break; 7231 + case BPF_PROG_LOAD: 7232 + if (!(bpfsec->perms & BPF__PROG_LOAD)) 7233 + return -EACCES; 7234 + break; 7235 + default: 7236 + break; 7237 + } 7238 + 7239 + return 0; 7240 + } 7241 + 7242 + static int selinux_bpf_token_capable(const struct bpf_token *token, int cap) 7243 + { 7244 + u16 sclass; 7245 + struct bpf_security_struct *bpfsec = token->security; 7246 + bool initns = (token->userns == &init_user_ns); 7247 + u32 av = CAP_TO_MASK(cap); 7248 + 7249 + switch (CAP_TO_INDEX(cap)) { 7250 + case 0: 7251 + sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS; 7252 + break; 7253 + case 1: 7254 + sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS; 7255 + break; 7256 + default: 7257 + pr_err("SELinux: out of range capability %d\n", cap); 7258 + return -EINVAL; 7259 + } 7260 + 7261 + return avc_has_perm(current_sid(), bpfsec->grantor_sid, sclass, av, 7262 + NULL); 7263 + } 7179 7264 #endif 7180 - .lbs_sock = sizeof(struct sk_security_struct), 7181 - .lbs_superblock = sizeof(struct superblock_security_struct), 7182 - .lbs_xattr_count = SELINUX_INODE_INIT_XATTRS, 7183 - .lbs_tun_dev = sizeof(struct tun_security_struct), 7184 - .lbs_ib = sizeof(struct ib_security_struct), 7185 - .lbs_bpf_map = sizeof(struct bpf_security_struct), 7186 - .lbs_bpf_prog = sizeof(struct bpf_security_struct), 7187 - .lbs_bpf_token = sizeof(struct bpf_security_struct), 7188 - }; 7189 7265 7190 7266 #ifdef CONFIG_PERF_EVENTS 7191 7267 static int selinux_perf_event_open(int type) ··· 7387 7295 static const struct lsm_id selinux_lsmid = { 7388 7296 .name = "selinux", 7389 7297 .id = LSM_ID_SELINUX, 7298 + }; 7299 + 7300 + struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { 7301 + .lbs_cred = sizeof(struct cred_security_struct), 7302 + .lbs_task = sizeof(struct task_security_struct), 7303 + .lbs_file = sizeof(struct file_security_struct), 7304 + .lbs_inode = sizeof(struct inode_security_struct), 7305 + .lbs_ipc = sizeof(struct ipc_security_struct), 7306 + .lbs_key = sizeof(struct key_security_struct), 7307 + .lbs_msg_msg = sizeof(struct msg_security_struct), 7308 + #ifdef CONFIG_PERF_EVENTS 7309 + .lbs_perf_event = sizeof(struct perf_event_security_struct), 7310 + #endif 7311 + .lbs_sock = sizeof(struct sk_security_struct), 7312 + .lbs_superblock = sizeof(struct superblock_security_struct), 7313 + .lbs_xattr_count = SELINUX_INODE_INIT_XATTRS, 7314 + .lbs_tun_dev = sizeof(struct tun_security_struct), 7315 + .lbs_ib = sizeof(struct ib_security_struct), 7316 + .lbs_bpf_map = sizeof(struct bpf_security_struct), 7317 + .lbs_bpf_prog = sizeof(struct bpf_security_struct), 7318 + .lbs_bpf_token = sizeof(struct bpf_security_struct), 7390 7319 }; 7391 7320 7392 7321 /* ··· 7703 7590 LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create), 7704 7591 LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load), 7705 7592 LSM_HOOK_INIT(bpf_token_create, selinux_bpf_token_create), 7593 + LSM_HOOK_INIT(bpf_token_cmd, selinux_bpf_token_cmd), 7594 + LSM_HOOK_INIT(bpf_token_capable, selinux_bpf_token_capable), 7706 7595 #endif 7707 7596 #ifdef CONFIG_PERF_EVENTS 7708 7597 LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc),
+1 -1
security/selinux/include/classmap.h
··· 171 171 { "infiniband_endport", { "manage_subnet", NULL } }, 172 172 { "bpf", 173 173 { "map_create", "map_read", "map_write", "prog_load", "prog_run", 174 - NULL } }, 174 + "map_create_as", "prog_load_as", NULL } }, 175 175 { "xdp_socket", { COMMON_SOCK_PERMS, NULL } }, 176 176 { "mctp_socket", { COMMON_SOCK_PERMS, NULL } }, 177 177 { "perf_event",
+3
security/selinux/include/objsec.h
··· 92 92 u32 sid; /* SID of file system superblock */ 93 93 u32 def_sid; /* default SID for labeling */ 94 94 u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ 95 + u32 creator_sid; /* SID of privileged process */ 95 96 unsigned short behavior; /* labeling behavior */ 96 97 unsigned short flags; /* which mount options were specified */ 97 98 struct mutex lock; ··· 170 169 171 170 struct bpf_security_struct { 172 171 u32 sid; /* SID of bpf obj creator */ 172 + u32 perms; /* permissions for allowed bpf token commands */ 173 + u32 grantor_sid; /* SID of token grantor */ 173 174 }; 174 175 175 176 struct perf_event_security_struct {
+1
security/selinux/include/policycap.h
··· 19 19 POLICYDB_CAP_GENFS_SECLABEL_WILDCARD, 20 20 POLICYDB_CAP_FUNCTIONFS_SECLABEL, 21 21 POLICYDB_CAP_MEMFD_CLASS, 22 + POLICYDB_CAP_BPF_TOKEN_PERMS, 22 23 __POLICYDB_CAP_MAX 23 24 }; 24 25 #define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)
+1
security/selinux/include/policycap_names.h
··· 22 22 "genfs_seclabel_wildcard", 23 23 "functionfs_seclabel", 24 24 "memfd_class", 25 + "bpf_token_perms", 25 26 }; 26 27 /* clang-format on */ 27 28
+6
security/selinux/include/security.h
··· 214 214 return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_MEMFD_CLASS]); 215 215 } 216 216 217 + static inline bool selinux_policycap_bpf_token_perms(void) 218 + { 219 + return READ_ONCE( 220 + selinux_state.policycap[POLICYDB_CAP_BPF_TOKEN_PERMS]); 221 + } 222 + 217 223 struct selinux_policy_convert_data; 218 224 219 225 struct selinux_load_state {