Skip to content

Commit 6252e91

Browse files
committed
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
2 parents bcc8fd3 + ea64aa5 commit 6252e91

6 files changed

Lines changed: 151 additions & 25 deletions

File tree

security/selinux/hooks.c

Lines changed: 139 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
737737
goto out;
738738
}
739739

740+
sbsec->creator_sid = current_sid();
741+
740742
if (strcmp(sb->s_type->name, "proc") == 0)
741743
sbsec->flags |= SE_SBPROC | SE_SBGENFS;
742744

@@ -908,6 +910,8 @@ static int selinux_cmp_sb_context(const struct super_block *oldsb,
908910
if (oldroot->sid != newroot->sid)
909911
goto mismatch;
910912
}
913+
if (old->creator_sid != new->creator_sid)
914+
goto mismatch;
911915
return 0;
912916
mismatch:
913917
pr_warn("SELinux: mount invalid. Same superblock, "
@@ -967,6 +971,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
967971
newsbsec->sid = oldsbsec->sid;
968972
newsbsec->def_sid = oldsbsec->def_sid;
969973
newsbsec->behavior = oldsbsec->behavior;
974+
newsbsec->creator_sid = oldsbsec->creator_sid;
970975

971976
if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
972977
!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
@@ -1654,7 +1659,6 @@ static int cred_has_capability(const struct cred *cred,
16541659
break;
16551660
default:
16561661
pr_err("SELinux: out of range capability %d\n", cap);
1657-
BUG();
16581662
return -EINVAL;
16591663
}
16601664

@@ -2586,6 +2590,7 @@ static int selinux_sb_alloc_security(struct super_block *sb)
25862590
sbsec->sid = SECINITSID_UNLABELED;
25872591
sbsec->def_sid = SECINITSID_FILE;
25882592
sbsec->mntpoint_sid = SECINITSID_UNLABELED;
2593+
sbsec->creator_sid = SECINITSID_UNLABELED;
25892594

25902595
return 0;
25912596
}
@@ -7043,6 +7048,9 @@ static int selinux_bpf(int cmd, union bpf_attr *attr,
70437048
u32 sid = current_sid();
70447049
int ret;
70457050

7051+
if (selinux_policycap_bpf_token_perms())
7052+
return 0;
7053+
70467054
switch (cmd) {
70477055
case BPF_MAP_CREATE:
70487056
ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
@@ -7124,60 +7132,144 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
71247132
BPF__PROG_RUN, NULL);
71257133
}
71267134

7135+
static u32 selinux_bpffs_creator_sid(u32 fd)
7136+
{
7137+
struct path path;
7138+
struct super_block *sb;
7139+
struct superblock_security_struct *sbsec;
7140+
7141+
CLASS(fd, f)(fd);
7142+
7143+
if (fd_empty(f))
7144+
return SECSID_NULL;
7145+
7146+
path = fd_file(f)->f_path;
7147+
sb = path.dentry->d_sb;
7148+
sbsec = selinux_superblock(sb);
7149+
7150+
return sbsec->creator_sid;
7151+
}
7152+
71277153
static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
71287154
struct bpf_token *token, bool kernel)
71297155
{
71307156
struct bpf_security_struct *bpfsec;
7157+
u32 ssid;
71317158

71327159
bpfsec = selinux_bpf_map_security(map);
71337160
bpfsec->sid = current_sid();
71347161

7135-
return 0;
7162+
if (!token)
7163+
ssid = bpfsec->sid;
7164+
else
7165+
ssid = selinux_bpffs_creator_sid(attr->map_token_fd);
7166+
7167+
return avc_has_perm(ssid, bpfsec->sid, SECCLASS_BPF, BPF__MAP_CREATE,
7168+
NULL);
71367169
}
71377170

71387171
static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
71397172
struct bpf_token *token, bool kernel)
71407173
{
71417174
struct bpf_security_struct *bpfsec;
7175+
u32 ssid;
71427176

71437177
bpfsec = selinux_bpf_prog_security(prog);
71447178
bpfsec->sid = current_sid();
71457179

7146-
return 0;
7180+
if (!token)
7181+
ssid = bpfsec->sid;
7182+
else
7183+
ssid = selinux_bpffs_creator_sid(attr->prog_token_fd);
7184+
7185+
return avc_has_perm(ssid, bpfsec->sid, SECCLASS_BPF, BPF__PROG_LOAD,
7186+
NULL);
71477187
}
71487188

7149-
static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
7189+
#define bpf_token_cmd(T, C) \
7190+
((T)->allowed_cmds & (1ULL << (C)))
7191+
7192+
static int selinux_bpf_token_create(struct bpf_token *token,
7193+
union bpf_attr *attr,
71507194
const struct path *path)
71517195
{
71527196
struct bpf_security_struct *bpfsec;
7197+
u32 sid = selinux_bpffs_creator_sid(attr->token_create.bpffs_fd);
7198+
int err;
71537199

71547200
bpfsec = selinux_bpf_token_security(token);
71557201
bpfsec->sid = current_sid();
7202+
bpfsec->grantor_sid = sid;
7203+
7204+
bpfsec->perms = 0;
7205+
/**
7206+
* 'token->allowed_cmds' is a bit mask of allowed commands
7207+
* Convert the BPF command enum to a bitmask representing its position
7208+
* in the allowed_cmds bitmap.
7209+
*/
7210+
if (bpf_token_cmd(token, BPF_MAP_CREATE)) {
7211+
err = avc_has_perm(bpfsec->sid, sid, SECCLASS_BPF,
7212+
BPF__MAP_CREATE_AS, NULL);
7213+
if (err)
7214+
return err;
7215+
bpfsec->perms |= BPF__MAP_CREATE;
7216+
}
7217+
if (bpf_token_cmd(token, BPF_PROG_LOAD)) {
7218+
err = avc_has_perm(bpfsec->sid, sid, SECCLASS_BPF,
7219+
BPF__PROG_LOAD_AS, NULL);
7220+
if (err)
7221+
return err;
7222+
bpfsec->perms |= BPF__PROG_LOAD;
7223+
}
71567224

71577225
return 0;
71587226
}
7159-
#endif
71607227

7161-
struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
7162-
.lbs_cred = sizeof(struct cred_security_struct),
7163-
.lbs_task = sizeof(struct task_security_struct),
7164-
.lbs_file = sizeof(struct file_security_struct),
7165-
.lbs_inode = sizeof(struct inode_security_struct),
7166-
.lbs_ipc = sizeof(struct ipc_security_struct),
7167-
.lbs_key = sizeof(struct key_security_struct),
7168-
.lbs_msg_msg = sizeof(struct msg_security_struct),
7169-
#ifdef CONFIG_PERF_EVENTS
7170-
.lbs_perf_event = sizeof(struct perf_event_security_struct),
7228+
static int selinux_bpf_token_cmd(const struct bpf_token *token,
7229+
enum bpf_cmd cmd)
7230+
{
7231+
struct bpf_security_struct *bpfsec;
7232+
7233+
bpfsec = token->security;
7234+
switch (cmd) {
7235+
case BPF_MAP_CREATE:
7236+
if (!(bpfsec->perms & BPF__MAP_CREATE))
7237+
return -EACCES;
7238+
break;
7239+
case BPF_PROG_LOAD:
7240+
if (!(bpfsec->perms & BPF__PROG_LOAD))
7241+
return -EACCES;
7242+
break;
7243+
default:
7244+
break;
7245+
}
7246+
7247+
return 0;
7248+
}
7249+
7250+
static int selinux_bpf_token_capable(const struct bpf_token *token, int cap)
7251+
{
7252+
u16 sclass;
7253+
struct bpf_security_struct *bpfsec = token->security;
7254+
bool initns = (token->userns == &init_user_ns);
7255+
u32 av = CAP_TO_MASK(cap);
7256+
7257+
switch (CAP_TO_INDEX(cap)) {
7258+
case 0:
7259+
sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS;
7260+
break;
7261+
case 1:
7262+
sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS;
7263+
break;
7264+
default:
7265+
pr_err("SELinux: out of range capability %d\n", cap);
7266+
return -EINVAL;
7267+
}
7268+
7269+
return avc_has_perm(current_sid(), bpfsec->grantor_sid, sclass, av,
7270+
NULL);
7271+
}
71717272
#endif
7172-
.lbs_sock = sizeof(struct sk_security_struct),
7173-
.lbs_superblock = sizeof(struct superblock_security_struct),
7174-
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
7175-
.lbs_tun_dev = sizeof(struct tun_security_struct),
7176-
.lbs_ib = sizeof(struct ib_security_struct),
7177-
.lbs_bpf_map = sizeof(struct bpf_security_struct),
7178-
.lbs_bpf_prog = sizeof(struct bpf_security_struct),
7179-
.lbs_bpf_token = sizeof(struct bpf_security_struct),
7180-
};
71817273

71827274
#ifdef CONFIG_PERF_EVENTS
71837275
static int selinux_perf_event_open(int type)
@@ -7297,6 +7389,27 @@ static const struct lsm_id selinux_lsmid = {
72977389
.id = LSM_ID_SELINUX,
72987390
};
72997391

7392+
struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
7393+
.lbs_cred = sizeof(struct cred_security_struct),
7394+
.lbs_task = sizeof(struct task_security_struct),
7395+
.lbs_file = sizeof(struct file_security_struct),
7396+
.lbs_inode = sizeof(struct inode_security_struct),
7397+
.lbs_ipc = sizeof(struct ipc_security_struct),
7398+
.lbs_key = sizeof(struct key_security_struct),
7399+
.lbs_msg_msg = sizeof(struct msg_security_struct),
7400+
#ifdef CONFIG_PERF_EVENTS
7401+
.lbs_perf_event = sizeof(struct perf_event_security_struct),
7402+
#endif
7403+
.lbs_sock = sizeof(struct sk_security_struct),
7404+
.lbs_superblock = sizeof(struct superblock_security_struct),
7405+
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
7406+
.lbs_tun_dev = sizeof(struct tun_security_struct),
7407+
.lbs_ib = sizeof(struct ib_security_struct),
7408+
.lbs_bpf_map = sizeof(struct bpf_security_struct),
7409+
.lbs_bpf_prog = sizeof(struct bpf_security_struct),
7410+
.lbs_bpf_token = sizeof(struct bpf_security_struct),
7411+
};
7412+
73007413
/*
73017414
* IMPORTANT NOTE: When adding new hooks, please be careful to keep this order:
73027415
* 1. any hooks that don't belong to (2.) or (3.) below,
@@ -7590,6 +7703,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
75907703
LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create),
75917704
LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load),
75927705
LSM_HOOK_INIT(bpf_token_create, selinux_bpf_token_create),
7706+
LSM_HOOK_INIT(bpf_token_cmd, selinux_bpf_token_cmd),
7707+
LSM_HOOK_INIT(bpf_token_capable, selinux_bpf_token_capable),
75937708
#endif
75947709
#ifdef CONFIG_PERF_EVENTS
75957710
LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc),

security/selinux/include/classmap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ const struct security_class_mapping secclass_map[] = {
171171
{ "infiniband_endport", { "manage_subnet", NULL } },
172172
{ "bpf",
173173
{ "map_create", "map_read", "map_write", "prog_load", "prog_run",
174-
NULL } },
174+
"map_create_as", "prog_load_as", NULL } },
175175
{ "xdp_socket", { COMMON_SOCK_PERMS, NULL } },
176176
{ "mctp_socket", { COMMON_SOCK_PERMS, NULL } },
177177
{ "perf_event",

security/selinux/include/objsec.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ struct superblock_security_struct {
9292
u32 sid; /* SID of file system superblock */
9393
u32 def_sid; /* default SID for labeling */
9494
u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
95+
u32 creator_sid; /* SID of privileged process */
9596
unsigned short behavior; /* labeling behavior */
9697
unsigned short flags; /* which mount options were specified */
9798
struct mutex lock;
@@ -169,6 +170,8 @@ struct pkey_security_struct {
169170

170171
struct bpf_security_struct {
171172
u32 sid; /* SID of bpf obj creator */
173+
u32 perms; /* permissions for allowed bpf token commands */
174+
u32 grantor_sid; /* SID of token grantor */
172175
};
173176

174177
struct perf_event_security_struct {

security/selinux/include/policycap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ enum {
1919
POLICYDB_CAP_GENFS_SECLABEL_WILDCARD,
2020
POLICYDB_CAP_FUNCTIONFS_SECLABEL,
2121
POLICYDB_CAP_MEMFD_CLASS,
22+
POLICYDB_CAP_BPF_TOKEN_PERMS,
2223
__POLICYDB_CAP_MAX
2324
};
2425
#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)

security/selinux/include/policycap_names.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = {
2222
"genfs_seclabel_wildcard",
2323
"functionfs_seclabel",
2424
"memfd_class",
25+
"bpf_token_perms",
2526
};
2627
/* clang-format on */
2728

security/selinux/include/security.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@ static inline bool selinux_policycap_memfd_class(void)
214214
return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_MEMFD_CLASS]);
215215
}
216216

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+
217223
struct selinux_policy_convert_data;
218224

219225
struct selinux_load_state {

0 commit comments

Comments
 (0)