include/linux/lsm_hooks.h | 3 + security/security.c | 120 +++++++++++++++++++++++++++++- security/selinux/hooks.c | 56 +++----------- security/selinux/include/objsec.h | 17 +++++ 4 files changed, 147 insertions(+), 49 deletions(-)
This patch introduces LSM blob support for BPF maps, programs, and
tokens to enable LSM stacking and multiplexing of LSM modules that
govern BPF objects. Additionally, the existing BPF hooks used by
SELinux have been updated to utilize the new blob infrastructure,
removing the assumption of exclusive ownership of the security
pointer.
Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
---
include/linux/lsm_hooks.h | 3 +
security/security.c | 120 +++++++++++++++++++++++++++++-
security/selinux/hooks.c | 56 +++-----------
security/selinux/include/objsec.h | 17 +++++
4 files changed, 147 insertions(+), 49 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 090d1d3e19fed..79ec5a2bdcca7 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -116,6 +116,9 @@ struct lsm_blob_sizes {
int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
int lbs_tun_dev;
int lbs_bdev;
+ int lbs_bpf_map;
+ int lbs_bpf_prog;
+ int lbs_bpf_token;
};
/*
diff --git a/security/security.c b/security/security.c
index 596d418185773..8c413b84f33db 100644
--- a/security/security.c
+++ b/security/security.c
@@ -283,6 +283,9 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
lsm_set_blob_size(&needed->lbs_xattr_count,
&blob_sizes.lbs_xattr_count);
lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
+ lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
+ lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
+ lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
}
/* Prepare LSM for initialization. */
@@ -480,6 +483,9 @@ static void __init ordered_lsm_init(void)
init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
+ init_debug("bpf map blob size = %d\n", blob_sizes.lbs_bpf_map);
+ init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog);
+ init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token);
/*
* Create any kmem_caches needed for blobs
@@ -835,6 +841,72 @@ static int lsm_bdev_alloc(struct block_device *bdev)
return 0;
}
+/**
+ * lsm_bpf_map_alloc - allocate a composite bpf_map blob
+ * @map: the bpf_map that needs a blob
+ *
+ * Allocate the bpf_map blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_bpf_map_alloc(struct bpf_map *map)
+{
+ if (blob_sizes.lbs_bpf_map == 0) {
+ map->security = NULL;
+ return 0;
+ }
+
+ map->security = kzalloc(blob_sizes.lbs_bpf_map, GFP_KERNEL);
+ if (!map->security)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * lsm_bpf_prog_alloc - allocate a composite bpf_prog blob
+ * @prog: the bpf_prog that needs a blob
+ *
+ * Allocate the bpf_prog blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_bpf_prog_alloc(struct bpf_prog *prog)
+{
+ if (blob_sizes.lbs_bpf_prog == 0) {
+ prog->aux->security = NULL;
+ return 0;
+ }
+
+ prog->aux->security = kzalloc(blob_sizes.lbs_bpf_prog, GFP_KERNEL);
+ if (!prog->aux->security)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * lsm_bpf_token_alloc - allocate a composite bpf_token blob
+ * @token: the bpf_token that needs a blob
+ *
+ * Allocate the bpf_token blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_bpf_token_alloc(struct bpf_token *token)
+{
+ if (blob_sizes.lbs_bpf_token == 0) {
+ token->security = NULL;
+ return 0;
+ }
+
+ token->security = kzalloc(blob_sizes.lbs_bpf_token, GFP_KERNEL);
+ if (!token->security)
+ return -ENOMEM;
+
+ return 0;
+}
+
/**
* lsm_early_task - during initialization allocate a composite task blob
* @task: the task that needs a blob
@@ -5684,7 +5756,16 @@ int security_bpf_prog(struct bpf_prog *prog)
int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
struct bpf_token *token, bool kernel)
{
- return call_int_hook(bpf_map_create, map, attr, token, kernel);
+ int rc = 0;
+
+ rc = lsm_bpf_map_alloc(map);
+ if (unlikely(rc))
+ return rc;
+
+ rc = call_int_hook(bpf_map_create, map, attr, token, kernel);
+ if (unlikely(rc))
+ security_bpf_map_free(map);
+ return rc;
}
/**
@@ -5703,7 +5784,16 @@ int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
struct bpf_token *token, bool kernel)
{
- return call_int_hook(bpf_prog_load, prog, attr, token, kernel);
+ int rc = 0;
+
+ rc = lsm_bpf_prog_alloc(prog);
+ if (unlikely(rc))
+ return rc;
+
+ rc = call_int_hook(bpf_prog_load, prog, attr, token, kernel);
+ if (unlikely(rc))
+ security_bpf_prog_free(prog);
+ return rc;
}
/**
@@ -5720,7 +5810,16 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
const struct path *path)
{
- return call_int_hook(bpf_token_create, token, attr, path);
+ int rc = 0;
+
+ rc = lsm_bpf_token_alloc(token);
+ if (unlikely(rc))
+ return rc;
+
+ rc = call_int_hook(bpf_token_create, token, attr, path);
+ if (unlikely(rc))
+ security_bpf_token_free(token);
+ return rc;
}
/**
@@ -5763,7 +5862,12 @@ int security_bpf_token_capable(const struct bpf_token *token, int cap)
*/
void security_bpf_map_free(struct bpf_map *map)
{
+ if (!map->security)
+ return;
+
call_void_hook(bpf_map_free, map);
+ kfree(map->security);
+ map->security = NULL;
}
/**
@@ -5774,7 +5878,12 @@ void security_bpf_map_free(struct bpf_map *map)
*/
void security_bpf_prog_free(struct bpf_prog *prog)
{
+ if (!prog->aux->security)
+ return;
+
call_void_hook(bpf_prog_free, prog);
+ kfree(prog->aux->security);
+ prog->aux->security = NULL;
}
/**
@@ -5785,7 +5894,12 @@ void security_bpf_prog_free(struct bpf_prog *prog)
*/
void security_bpf_token_free(struct bpf_token *token)
{
+ if (!token->security)
+ return;
+
call_void_hook(bpf_token_free, token);
+ kfree(token->security);
+ token->security = NULL;
}
#endif /* CONFIG_BPF_SYSCALL */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 595ceb314aeb3..8052fb5fafc4d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7038,14 +7038,14 @@ static int bpf_fd_pass(const struct file *file, u32 sid)
if (file->f_op == &bpf_map_fops) {
map = file->private_data;
- bpfsec = map->security;
+ bpfsec = selinux_bpf_map_security(map);
ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(file->f_mode), NULL);
if (ret)
return ret;
} else if (file->f_op == &bpf_prog_fops) {
prog = file->private_data;
- bpfsec = prog->aux->security;
+ bpfsec = selinux_bpf_prog_security(prog);
ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
if (ret)
@@ -7059,7 +7059,7 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
u32 sid = current_sid();
struct bpf_security_struct *bpfsec;
- bpfsec = map->security;
+ bpfsec = selinux_bpf_map_security(map);
return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(fmode), NULL);
}
@@ -7069,7 +7069,7 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
u32 sid = current_sid();
struct bpf_security_struct *bpfsec;
- bpfsec = prog->aux->security;
+ bpfsec = selinux_bpf_prog_security(prog);
return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
}
@@ -7079,69 +7079,33 @@ static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
{
struct bpf_security_struct *bpfsec;
- bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
- if (!bpfsec)
- return -ENOMEM;
-
+ bpfsec = selinux_bpf_map_security(map);
bpfsec->sid = current_sid();
- map->security = bpfsec;
return 0;
}
-static void selinux_bpf_map_free(struct bpf_map *map)
-{
- struct bpf_security_struct *bpfsec = map->security;
-
- map->security = NULL;
- kfree(bpfsec);
-}
-
static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
struct bpf_token *token, bool kernel)
{
struct bpf_security_struct *bpfsec;
- bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
- if (!bpfsec)
- return -ENOMEM;
-
+ bpfsec = selinux_bpf_prog_security(prog);
bpfsec->sid = current_sid();
- prog->aux->security = bpfsec;
return 0;
}
-static void selinux_bpf_prog_free(struct bpf_prog *prog)
-{
- struct bpf_security_struct *bpfsec = prog->aux->security;
-
- prog->aux->security = NULL;
- kfree(bpfsec);
-}
-
static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
const struct path *path)
{
struct bpf_security_struct *bpfsec;
- bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
- if (!bpfsec)
- return -ENOMEM;
-
+ bpfsec = selinux_bpf_token_security(token);
bpfsec->sid = current_sid();
- token->security = bpfsec;
return 0;
}
-
-static void selinux_bpf_token_free(struct bpf_token *token)
-{
- struct bpf_security_struct *bpfsec = token->security;
-
- token->security = NULL;
- kfree(bpfsec);
-}
#endif
struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
@@ -7159,6 +7123,9 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
.lbs_tun_dev = sizeof(struct tun_security_struct),
.lbs_ib = sizeof(struct ib_security_struct),
+ .lbs_bpf_map = sizeof(struct bpf_security_struct),
+ .lbs_bpf_prog = sizeof(struct bpf_security_struct),
+ .lbs_bpf_token = sizeof(struct bpf_security_struct),
};
#ifdef CONFIG_PERF_EVENTS
@@ -7510,9 +7477,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(bpf, selinux_bpf),
LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
- LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free),
- LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free),
- LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free),
#endif
#ifdef CONFIG_PERF_EVENTS
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 6ee7dc4dfd6e0..9f935ed9a761f 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -26,6 +26,7 @@
#include <linux/lsm_hooks.h>
#include <linux/msg.h>
#include <net/net_namespace.h>
+#include <linux/bpf.h>
#include "flask.h"
#include "avc.h"
@@ -237,4 +238,20 @@ selinux_perf_event(void *perf_event)
return perf_event + selinux_blob_sizes.lbs_perf_event;
}
+#ifdef CONFIG_BPF_SYSCALL
+static inline struct bpf_security_struct *selinux_bpf_map_security(struct bpf_map *map)
+{
+ return map->security + selinux_blob_sizes.lbs_bpf_map;
+}
+
+static inline struct bpf_security_struct *selinux_bpf_prog_security(struct bpf_prog *prog)
+{
+ return prog->aux->security + selinux_blob_sizes.lbs_bpf_prog;
+}
+
+static inline struct bpf_security_struct *selinux_bpf_token_security(struct bpf_token *token)
+{
+ return token->security + selinux_blob_sizes.lbs_bpf_token;
+}
+#endif /* CONFIG_BPF_SYSCALL */
#endif /* _SELINUX_OBJSEC_H_ */
--
2.48.1
On Jul 15, 2025 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote: > > This patch introduces LSM blob support for BPF maps, programs, and > tokens to enable LSM stacking and multiplexing of LSM modules that > govern BPF objects. Additionally, the existing BPF hooks used by > SELinux have been updated to utilize the new blob infrastructure, > removing the assumption of exclusive ownership of the security > pointer. > > Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com> > --- > include/linux/lsm_hooks.h | 3 + > security/security.c | 120 +++++++++++++++++++++++++++++- > security/selinux/hooks.c | 56 +++----------- > security/selinux/include/objsec.h | 17 +++++ > 4 files changed, 147 insertions(+), 49 deletions(-) ... > @@ -835,6 +841,72 @@ static int lsm_bdev_alloc(struct block_device *bdev) > return 0; > } > > +/** > + * lsm_bpf_map_alloc - allocate a composite bpf_map blob > + * @map: the bpf_map that needs a blob > + * > + * Allocate the bpf_map blob for all the modules > + * > + * Returns 0, or -ENOMEM if memory can't be allocated. > + */ > +static int lsm_bpf_map_alloc(struct bpf_map *map) > +{ > + if (blob_sizes.lbs_bpf_map == 0) { > + map->security = NULL; > + return 0; > + } > + > + map->security = kzalloc(blob_sizes.lbs_bpf_map, GFP_KERNEL); > + if (!map->security) > + return -ENOMEM; > + > + return 0; > +} Casey suggested considering kmem_cache for the different BPF objects, but my gut feeling is that none ofthe BPF objects are going to be allocated with either enough frequency, or enough quantity, where a simple kzalloc() wouldn't be sufficient, at least for now. Thoughts on this Blaise? Assuming we stick with kazlloc() based allocation, please look at using the lsm_blob_alloc() helper function as Song mentioned As I'm writing this I'm realizing there are a few allocatiors that aren't using the helper, I need to fix those up ... It's worth mentioning that the allocation scheme is an internal LSM implementation detail, something we can change at any time with a small patch, so I wouldn't stress too much about "Getting it Right" at this point in time. > @@ -5763,7 +5862,12 @@ int security_bpf_token_capable(const struct bpf_token *token, int cap) > */ > void security_bpf_map_free(struct bpf_map *map) > { > + if (!map->security) > + return; > + We don't currently check if map->security is NULL in the current hook, or the SELinux callback (it's not a common pattern for the LSM blobs), did you run into a problem where the blob pointer was NULL? The same comment applies to all three blob types. > call_void_hook(bpf_map_free, map); > + kfree(map->security); > + map->security = NULL; > } > > /** -- paul-moore.com
Paul Moore <paul@paul-moore.com> writes: > On Jul 15, 2025 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote: >> >> This patch introduces LSM blob support for BPF maps, programs, and >> tokens to enable LSM stacking and multiplexing of LSM modules that >> govern BPF objects. Additionally, the existing BPF hooks used by >> SELinux have been updated to utilize the new blob infrastructure, >> removing the assumption of exclusive ownership of the security >> pointer. >> >> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com> >> --- >> include/linux/lsm_hooks.h | 3 + >> security/security.c | 120 +++++++++++++++++++++++++++++- >> security/selinux/hooks.c | 56 +++----------- >> security/selinux/include/objsec.h | 17 +++++ >> 4 files changed, 147 insertions(+), 49 deletions(-) > > ... > >> @@ -835,6 +841,72 @@ static int lsm_bdev_alloc(struct block_device *bdev) >> return 0; >> } >> >> +/** >> + * lsm_bpf_map_alloc - allocate a composite bpf_map blob >> + * @map: the bpf_map that needs a blob >> + * >> + * Allocate the bpf_map blob for all the modules >> + * >> + * Returns 0, or -ENOMEM if memory can't be allocated. >> + */ >> +static int lsm_bpf_map_alloc(struct bpf_map *map) >> +{ >> + if (blob_sizes.lbs_bpf_map == 0) { >> + map->security = NULL; >> + return 0; >> + } >> + >> + map->security = kzalloc(blob_sizes.lbs_bpf_map, GFP_KERNEL); >> + if (!map->security) >> + return -ENOMEM; >> + >> + return 0; >> +} > > Casey suggested considering kmem_cache for the different BPF objects, > but my gut feeling is that none ofthe BPF objects are going to be > allocated with either enough frequency, or enough quantity, where a > simple kzalloc() wouldn't be sufficient, at least for now. Thoughts > on this Blaise? Yeah, I agree, the number of allocations should be very low in comparision to something like inodes. We are probably okay using kzalloc forf the time being. > > Assuming we stick with kazlloc() based allocation, please look at using > the lsm_blob_alloc() helper function as Song mentioned As I'm writing > this I'm realizing there are a few allocatiors that aren't using the > helper, I need to fix those up ... Will do. > > It's worth mentioning that the allocation scheme is an internal LSM > implementation detail, something we can change at any time with a small > patch, so I wouldn't stress too much about "Getting it Right" at this > point in time. > >> @@ -5763,7 +5862,12 @@ int security_bpf_token_capable(const struct bpf_token *token, int cap) >> */ >> void security_bpf_map_free(struct bpf_map *map) >> { >> + if (!map->security) >> + return; >> + > > We don't currently check if map->security is NULL in the current hook, > or the SELinux callback (it's not a common pattern for the LSM blobs), > did you run into a problem where the blob pointer was NULL? > > The same comment applies to all three blob types. No real issues that I ran into. I was cribbing off the pattern used in block devices. After taking a second look, it looks safe to remove that check. I'll get that fixed in v2. -blaise > >> call_void_hook(bpf_map_free, map); >> + kfree(map->security); >> + map->security = NULL; >> } >> >> /** > > -- > paul-moore.com
On Tue, Jul 15, 2025 at 3:27 PM Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote: [...] > +/** > + * lsm_bpf_map_alloc - allocate a composite bpf_map blob > + * @map: the bpf_map that needs a blob > + * > + * Allocate the bpf_map blob for all the modules > + * > + * Returns 0, or -ENOMEM if memory can't be allocated. > + */ > +static int lsm_bpf_map_alloc(struct bpf_map *map) > +{ > + if (blob_sizes.lbs_bpf_map == 0) { > + map->security = NULL; > + return 0; > + } > + > + map->security = kzalloc(blob_sizes.lbs_bpf_map, GFP_KERNEL); > + if (!map->security) > + return -ENOMEM; > + > + return 0; > +} > + > +/** > + * lsm_bpf_prog_alloc - allocate a composite bpf_prog blob > + * @prog: the bpf_prog that needs a blob > + * > + * Allocate the bpf_prog blob for all the modules > + * > + * Returns 0, or -ENOMEM if memory can't be allocated. > + */ > +static int lsm_bpf_prog_alloc(struct bpf_prog *prog) > +{ > + if (blob_sizes.lbs_bpf_prog == 0) { > + prog->aux->security = NULL; > + return 0; > + } > + > + prog->aux->security = kzalloc(blob_sizes.lbs_bpf_prog, GFP_KERNEL); > + if (!prog->aux->security) > + return -ENOMEM; > + > + return 0; > +} > + > +/** > + * lsm_bpf_token_alloc - allocate a composite bpf_token blob > + * @token: the bpf_token that needs a blob > + * > + * Allocate the bpf_token blob for all the modules > + * > + * Returns 0, or -ENOMEM if memory can't be allocated. > + */ > +static int lsm_bpf_token_alloc(struct bpf_token *token) > +{ > + if (blob_sizes.lbs_bpf_token == 0) { > + token->security = NULL; > + return 0; > + } > + > + token->security = kzalloc(blob_sizes.lbs_bpf_token, GFP_KERNEL); > + if (!token->security) > + return -ENOMEM; > + > + return 0; > +} We need the above 3 functions inside #ifdef CONFIG_BPF_SYSCALL. Also, can we use lsm_blob_alloc() in these functions? Thanks, Song [...]
Song Liu <song@kernel.org> writes: > On Tue, Jul 15, 2025 at 3:27 PM Blaise Boscaccy > <bboscaccy@linux.microsoft.com> wrote: > [...] >> +/** >> + * lsm_bpf_map_alloc - allocate a composite bpf_map blob >> + * @map: the bpf_map that needs a blob >> + * >> + * Allocate the bpf_map blob for all the modules >> + * >> + * Returns 0, or -ENOMEM if memory can't be allocated. >> + */ >> +static int lsm_bpf_map_alloc(struct bpf_map *map) >> +{ >> + if (blob_sizes.lbs_bpf_map == 0) { >> + map->security = NULL; >> + return 0; >> + } >> + >> + map->security = kzalloc(blob_sizes.lbs_bpf_map, GFP_KERNEL); >> + if (!map->security) >> + return -ENOMEM; >> + >> + return 0; >> +} >> + >> +/** >> + * lsm_bpf_prog_alloc - allocate a composite bpf_prog blob >> + * @prog: the bpf_prog that needs a blob >> + * >> + * Allocate the bpf_prog blob for all the modules >> + * >> + * Returns 0, or -ENOMEM if memory can't be allocated. >> + */ >> +static int lsm_bpf_prog_alloc(struct bpf_prog *prog) >> +{ >> + if (blob_sizes.lbs_bpf_prog == 0) { >> + prog->aux->security = NULL; >> + return 0; >> + } >> + >> + prog->aux->security = kzalloc(blob_sizes.lbs_bpf_prog, GFP_KERNEL); >> + if (!prog->aux->security) >> + return -ENOMEM; >> + >> + return 0; >> +} >> + >> +/** >> + * lsm_bpf_token_alloc - allocate a composite bpf_token blob >> + * @token: the bpf_token that needs a blob >> + * >> + * Allocate the bpf_token blob for all the modules >> + * >> + * Returns 0, or -ENOMEM if memory can't be allocated. >> + */ >> +static int lsm_bpf_token_alloc(struct bpf_token *token) >> +{ >> + if (blob_sizes.lbs_bpf_token == 0) { >> + token->security = NULL; >> + return 0; >> + } >> + >> + token->security = kzalloc(blob_sizes.lbs_bpf_token, GFP_KERNEL); >> + if (!token->security) >> + return -ENOMEM; >> + >> + return 0; >> +} > > We need the above 3 functions inside #ifdef CONFIG_BPF_SYSCALL. > > Also, can we use lsm_blob_alloc() in these functions? > > Thanks, > Song Sure, I'll get that fixed in V2. Thanks -blaise > > [...]
On 7/15/2025 3:25 PM, Blaise Boscaccy wrote: > This patch introduces LSM blob support for BPF maps, programs, and > tokens to enable LSM stacking and multiplexing of LSM modules that > govern BPF objects. Additionally, the existing BPF hooks used by > SELinux have been updated to utilize the new blob infrastructure, > removing the assumption of exclusive ownership of the security > pointer. > > Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com> > --- > include/linux/lsm_hooks.h | 3 + > security/security.c | 120 +++++++++++++++++++++++++++++- > security/selinux/hooks.c | 56 +++----------- > security/selinux/include/objsec.h | 17 +++++ > 4 files changed, 147 insertions(+), 49 deletions(-) > > diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h > index 090d1d3e19fed..79ec5a2bdcca7 100644 > --- a/include/linux/lsm_hooks.h > +++ b/include/linux/lsm_hooks.h > @@ -116,6 +116,9 @@ struct lsm_blob_sizes { > int lbs_xattr_count; /* number of xattr slots in new_xattrs array */ > int lbs_tun_dev; > int lbs_bdev; > + int lbs_bpf_map; > + int lbs_bpf_prog; > + int lbs_bpf_token; > }; > > /* > diff --git a/security/security.c b/security/security.c > index 596d418185773..8c413b84f33db 100644 > --- a/security/security.c > +++ b/security/security.c > @@ -283,6 +283,9 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) > lsm_set_blob_size(&needed->lbs_xattr_count, > &blob_sizes.lbs_xattr_count); > lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev); > + lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map); > + lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog); > + lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token); > } > > /* Prepare LSM for initialization. */ > @@ -480,6 +483,9 @@ static void __init ordered_lsm_init(void) > init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev); > init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count); > init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev); > + init_debug("bpf map blob size = %d\n", blob_sizes.lbs_bpf_map); > + init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog); > + init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token); > > /* > * Create any kmem_caches needed for blobs > @@ -835,6 +841,72 @@ static int lsm_bdev_alloc(struct block_device *bdev) > return 0; > } > > +/** > + * lsm_bpf_map_alloc - allocate a composite bpf_map blob > + * @map: the bpf_map that needs a blob > + * > + * Allocate the bpf_map blob for all the modules > + * > + * Returns 0, or -ENOMEM if memory can't be allocated. > + */ > +static int lsm_bpf_map_alloc(struct bpf_map *map) > +{ > + if (blob_sizes.lbs_bpf_map == 0) { > + map->security = NULL; > + return 0; > + } > + > + map->security = kzalloc(blob_sizes.lbs_bpf_map, GFP_KERNEL); Some of the blobs use kmem_cache_alloc(). You should consider if that might be right for you. > + if (!map->security) > + return -ENOMEM; > + > + return 0; > +} > + > +/** > + * lsm_bpf_prog_alloc - allocate a composite bpf_prog blob > + * @prog: the bpf_prog that needs a blob > + * > + * Allocate the bpf_prog blob for all the modules > + * > + * Returns 0, or -ENOMEM if memory can't be allocated. > + */ > +static int lsm_bpf_prog_alloc(struct bpf_prog *prog) > +{ > + if (blob_sizes.lbs_bpf_prog == 0) { > + prog->aux->security = NULL; > + return 0; > + } > + > + prog->aux->security = kzalloc(blob_sizes.lbs_bpf_prog, GFP_KERNEL); > + if (!prog->aux->security) > + return -ENOMEM; > + > + return 0; > +} > + > +/** > + * lsm_bpf_token_alloc - allocate a composite bpf_token blob > + * @token: the bpf_token that needs a blob > + * > + * Allocate the bpf_token blob for all the modules > + * > + * Returns 0, or -ENOMEM if memory can't be allocated. > + */ > +static int lsm_bpf_token_alloc(struct bpf_token *token) > +{ > + if (blob_sizes.lbs_bpf_token == 0) { > + token->security = NULL; > + return 0; > + } > + > + token->security = kzalloc(blob_sizes.lbs_bpf_token, GFP_KERNEL); > + if (!token->security) > + return -ENOMEM; > + > + return 0; > +} > + > /** > * lsm_early_task - during initialization allocate a composite task blob > * @task: the task that needs a blob > @@ -5684,7 +5756,16 @@ int security_bpf_prog(struct bpf_prog *prog) > int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, > struct bpf_token *token, bool kernel) > { > - return call_int_hook(bpf_map_create, map, attr, token, kernel); > + int rc = 0; > + > + rc = lsm_bpf_map_alloc(map); > + if (unlikely(rc)) > + return rc; > + > + rc = call_int_hook(bpf_map_create, map, attr, token, kernel); > + if (unlikely(rc)) > + security_bpf_map_free(map); > + return rc; > } > > /** > @@ -5703,7 +5784,16 @@ int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, > int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, > struct bpf_token *token, bool kernel) > { > - return call_int_hook(bpf_prog_load, prog, attr, token, kernel); > + int rc = 0; > + > + rc = lsm_bpf_prog_alloc(prog); > + if (unlikely(rc)) > + return rc; > + > + rc = call_int_hook(bpf_prog_load, prog, attr, token, kernel); > + if (unlikely(rc)) > + security_bpf_prog_free(prog); > + return rc; > } > > /** > @@ -5720,7 +5810,16 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, > int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, > const struct path *path) > { > - return call_int_hook(bpf_token_create, token, attr, path); > + int rc = 0; > + > + rc = lsm_bpf_token_alloc(token); > + if (unlikely(rc)) > + return rc; > + > + rc = call_int_hook(bpf_token_create, token, attr, path); > + if (unlikely(rc)) > + security_bpf_token_free(token); > + return rc; > } > > /** > @@ -5763,7 +5862,12 @@ int security_bpf_token_capable(const struct bpf_token *token, int cap) > */ > void security_bpf_map_free(struct bpf_map *map) > { > + if (!map->security) > + return; > + > call_void_hook(bpf_map_free, map); > + kfree(map->security); > + map->security = NULL; > } > > /** > @@ -5774,7 +5878,12 @@ void security_bpf_map_free(struct bpf_map *map) > */ > void security_bpf_prog_free(struct bpf_prog *prog) > { > + if (!prog->aux->security) > + return; > + > call_void_hook(bpf_prog_free, prog); > + kfree(prog->aux->security); > + prog->aux->security = NULL; > } > > /** > @@ -5785,7 +5894,12 @@ void security_bpf_prog_free(struct bpf_prog *prog) > */ > void security_bpf_token_free(struct bpf_token *token) > { > + if (!token->security) > + return; > + > call_void_hook(bpf_token_free, token); > + kfree(token->security); > + token->security = NULL; > } > #endif /* CONFIG_BPF_SYSCALL */ > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c > index 595ceb314aeb3..8052fb5fafc4d 100644 > --- a/security/selinux/hooks.c > +++ b/security/selinux/hooks.c > @@ -7038,14 +7038,14 @@ static int bpf_fd_pass(const struct file *file, u32 sid) > > if (file->f_op == &bpf_map_fops) { > map = file->private_data; > - bpfsec = map->security; > + bpfsec = selinux_bpf_map_security(map); > ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, > bpf_map_fmode_to_av(file->f_mode), NULL); > if (ret) > return ret; > } else if (file->f_op == &bpf_prog_fops) { > prog = file->private_data; > - bpfsec = prog->aux->security; > + bpfsec = selinux_bpf_prog_security(prog); > ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, > BPF__PROG_RUN, NULL); > if (ret) > @@ -7059,7 +7059,7 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) > u32 sid = current_sid(); > struct bpf_security_struct *bpfsec; > > - bpfsec = map->security; > + bpfsec = selinux_bpf_map_security(map); > return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, > bpf_map_fmode_to_av(fmode), NULL); > } > @@ -7069,7 +7069,7 @@ static int selinux_bpf_prog(struct bpf_prog *prog) > u32 sid = current_sid(); > struct bpf_security_struct *bpfsec; > > - bpfsec = prog->aux->security; > + bpfsec = selinux_bpf_prog_security(prog); > return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, > BPF__PROG_RUN, NULL); > } > @@ -7079,69 +7079,33 @@ static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, > { > struct bpf_security_struct *bpfsec; > > - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); > - if (!bpfsec) > - return -ENOMEM; > - > + bpfsec = selinux_bpf_map_security(map); > bpfsec->sid = current_sid(); > - map->security = bpfsec; > > return 0; > } > > -static void selinux_bpf_map_free(struct bpf_map *map) > -{ > - struct bpf_security_struct *bpfsec = map->security; > - > - map->security = NULL; > - kfree(bpfsec); > -} > - > static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, > struct bpf_token *token, bool kernel) > { > struct bpf_security_struct *bpfsec; > > - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); > - if (!bpfsec) > - return -ENOMEM; > - > + bpfsec = selinux_bpf_prog_security(prog); > bpfsec->sid = current_sid(); > - prog->aux->security = bpfsec; > > return 0; > } > > -static void selinux_bpf_prog_free(struct bpf_prog *prog) > -{ > - struct bpf_security_struct *bpfsec = prog->aux->security; > - > - prog->aux->security = NULL; > - kfree(bpfsec); > -} > - > static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, > const struct path *path) > { > struct bpf_security_struct *bpfsec; > > - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); > - if (!bpfsec) > - return -ENOMEM; > - > + bpfsec = selinux_bpf_token_security(token); > bpfsec->sid = current_sid(); > - token->security = bpfsec; > > return 0; > } > - > -static void selinux_bpf_token_free(struct bpf_token *token) > -{ > - struct bpf_security_struct *bpfsec = token->security; > - > - token->security = NULL; > - kfree(bpfsec); > -} > #endif > > struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { > @@ -7159,6 +7123,9 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { > .lbs_xattr_count = SELINUX_INODE_INIT_XATTRS, > .lbs_tun_dev = sizeof(struct tun_security_struct), > .lbs_ib = sizeof(struct ib_security_struct), > + .lbs_bpf_map = sizeof(struct bpf_security_struct), > + .lbs_bpf_prog = sizeof(struct bpf_security_struct), > + .lbs_bpf_token = sizeof(struct bpf_security_struct), > }; > > #ifdef CONFIG_PERF_EVENTS > @@ -7510,9 +7477,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { > LSM_HOOK_INIT(bpf, selinux_bpf), > LSM_HOOK_INIT(bpf_map, selinux_bpf_map), > LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), > - LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free), > - LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), > - LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free), > #endif > > #ifdef CONFIG_PERF_EVENTS > diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h > index 6ee7dc4dfd6e0..9f935ed9a761f 100644 > --- a/security/selinux/include/objsec.h > +++ b/security/selinux/include/objsec.h > @@ -26,6 +26,7 @@ > #include <linux/lsm_hooks.h> > #include <linux/msg.h> > #include <net/net_namespace.h> > +#include <linux/bpf.h> > #include "flask.h" > #include "avc.h" > > @@ -237,4 +238,20 @@ selinux_perf_event(void *perf_event) > return perf_event + selinux_blob_sizes.lbs_perf_event; > } > > +#ifdef CONFIG_BPF_SYSCALL > +static inline struct bpf_security_struct *selinux_bpf_map_security(struct bpf_map *map) > +{ > + return map->security + selinux_blob_sizes.lbs_bpf_map; > +} > + > +static inline struct bpf_security_struct *selinux_bpf_prog_security(struct bpf_prog *prog) > +{ > + return prog->aux->security + selinux_blob_sizes.lbs_bpf_prog; > +} > + > +static inline struct bpf_security_struct *selinux_bpf_token_security(struct bpf_token *token) > +{ > + return token->security + selinux_blob_sizes.lbs_bpf_token; > +} > +#endif /* CONFIG_BPF_SYSCALL */ > #endif /* _SELINUX_OBJSEC_H_ */
Casey Schaufler <casey@schaufler-ca.com> writes: > On 7/15/2025 3:25 PM, Blaise Boscaccy wrote: >> This patch introduces LSM blob support for BPF maps, programs, and >> tokens to enable LSM stacking and multiplexing of LSM modules that >> govern BPF objects. Additionally, the existing BPF hooks used by >> SELinux have been updated to utilize the new blob infrastructure, >> removing the assumption of exclusive ownership of the security >> pointer. >> >> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com> >> --- >> include/linux/lsm_hooks.h | 3 + >> security/security.c | 120 +++++++++++++++++++++++++++++- >> security/selinux/hooks.c | 56 +++----------- >> security/selinux/include/objsec.h | 17 +++++ >> 4 files changed, 147 insertions(+), 49 deletions(-) >> >> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h >> index 090d1d3e19fed..79ec5a2bdcca7 100644 >> --- a/include/linux/lsm_hooks.h >> +++ b/include/linux/lsm_hooks.h >> @@ -116,6 +116,9 @@ struct lsm_blob_sizes { >> int lbs_xattr_count; /* number of xattr slots in new_xattrs array */ >> int lbs_tun_dev; >> int lbs_bdev; >> + int lbs_bpf_map; >> + int lbs_bpf_prog; >> + int lbs_bpf_token; >> }; >> >> /* >> diff --git a/security/security.c b/security/security.c >> index 596d418185773..8c413b84f33db 100644 >> --- a/security/security.c >> +++ b/security/security.c >> @@ -283,6 +283,9 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) >> lsm_set_blob_size(&needed->lbs_xattr_count, >> &blob_sizes.lbs_xattr_count); >> lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev); >> + lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map); >> + lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog); >> + lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token); >> } >> >> /* Prepare LSM for initialization. */ >> @@ -480,6 +483,9 @@ static void __init ordered_lsm_init(void) >> init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev); >> init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count); >> init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev); >> + init_debug("bpf map blob size = %d\n", blob_sizes.lbs_bpf_map); >> + init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog); >> + init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token); >> >> /* >> * Create any kmem_caches needed for blobs >> @@ -835,6 +841,72 @@ static int lsm_bdev_alloc(struct block_device *bdev) >> return 0; >> } >> >> +/** >> + * lsm_bpf_map_alloc - allocate a composite bpf_map blob >> + * @map: the bpf_map that needs a blob >> + * >> + * Allocate the bpf_map blob for all the modules >> + * >> + * Returns 0, or -ENOMEM if memory can't be allocated. >> + */ >> +static int lsm_bpf_map_alloc(struct bpf_map *map) >> +{ >> + if (blob_sizes.lbs_bpf_map == 0) { >> + map->security = NULL; >> + return 0; >> + } >> + >> + map->security = kzalloc(blob_sizes.lbs_bpf_map, GFP_KERNEL); > > Some of the blobs use kmem_cache_alloc(). You should consider if that > might be right for you. > I looked into that, allocation numbers for this are going to very low in volume compared to something like inodes. I think we are okay for the time being using kzalloc. If this turns out to be a bottleneck, we can totally switch to that. -blaise >> + if (!map->security) >> + return -ENOMEM; >> + >> + return 0; >> +} >> + >> +/** >> + * lsm_bpf_prog_alloc - allocate a composite bpf_prog blob >> + * @prog: the bpf_prog that needs a blob >> + * >> + * Allocate the bpf_prog blob for all the modules >> + * >> + * Returns 0, or -ENOMEM if memory can't be allocated. >> + */ >> +static int lsm_bpf_prog_alloc(struct bpf_prog *prog) >> +{ >> + if (blob_sizes.lbs_bpf_prog == 0) { >> + prog->aux->security = NULL; >> + return 0; >> + } >> + >> + prog->aux->security = kzalloc(blob_sizes.lbs_bpf_prog, GFP_KERNEL); >> + if (!prog->aux->security) >> + return -ENOMEM; >> + >> + return 0; >> +} >> + >> +/** >> + * lsm_bpf_token_alloc - allocate a composite bpf_token blob >> + * @token: the bpf_token that needs a blob >> + * >> + * Allocate the bpf_token blob for all the modules >> + * >> + * Returns 0, or -ENOMEM if memory can't be allocated. >> + */ >> +static int lsm_bpf_token_alloc(struct bpf_token *token) >> +{ >> + if (blob_sizes.lbs_bpf_token == 0) { >> + token->security = NULL; >> + return 0; >> + } >> + >> + token->security = kzalloc(blob_sizes.lbs_bpf_token, GFP_KERNEL); >> + if (!token->security) >> + return -ENOMEM; >> + >> + return 0; >> +} >> + >> /** >> * lsm_early_task - during initialization allocate a composite task blob >> * @task: the task that needs a blob >> @@ -5684,7 +5756,16 @@ int security_bpf_prog(struct bpf_prog *prog) >> int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, >> struct bpf_token *token, bool kernel) >> { >> - return call_int_hook(bpf_map_create, map, attr, token, kernel); >> + int rc = 0; >> + >> + rc = lsm_bpf_map_alloc(map); >> + if (unlikely(rc)) >> + return rc; >> + >> + rc = call_int_hook(bpf_map_create, map, attr, token, kernel); >> + if (unlikely(rc)) >> + security_bpf_map_free(map); >> + return rc; >> } >> >> /** >> @@ -5703,7 +5784,16 @@ int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, >> int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, >> struct bpf_token *token, bool kernel) >> { >> - return call_int_hook(bpf_prog_load, prog, attr, token, kernel); >> + int rc = 0; >> + >> + rc = lsm_bpf_prog_alloc(prog); >> + if (unlikely(rc)) >> + return rc; >> + >> + rc = call_int_hook(bpf_prog_load, prog, attr, token, kernel); >> + if (unlikely(rc)) >> + security_bpf_prog_free(prog); >> + return rc; >> } >> >> /** >> @@ -5720,7 +5810,16 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, >> int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, >> const struct path *path) >> { >> - return call_int_hook(bpf_token_create, token, attr, path); >> + int rc = 0; >> + >> + rc = lsm_bpf_token_alloc(token); >> + if (unlikely(rc)) >> + return rc; >> + >> + rc = call_int_hook(bpf_token_create, token, attr, path); >> + if (unlikely(rc)) >> + security_bpf_token_free(token); >> + return rc; >> } >> >> /** >> @@ -5763,7 +5862,12 @@ int security_bpf_token_capable(const struct bpf_token *token, int cap) >> */ >> void security_bpf_map_free(struct bpf_map *map) >> { >> + if (!map->security) >> + return; >> + >> call_void_hook(bpf_map_free, map); >> + kfree(map->security); >> + map->security = NULL; >> } >> >> /** >> @@ -5774,7 +5878,12 @@ void security_bpf_map_free(struct bpf_map *map) >> */ >> void security_bpf_prog_free(struct bpf_prog *prog) >> { >> + if (!prog->aux->security) >> + return; >> + >> call_void_hook(bpf_prog_free, prog); >> + kfree(prog->aux->security); >> + prog->aux->security = NULL; >> } >> >> /** >> @@ -5785,7 +5894,12 @@ void security_bpf_prog_free(struct bpf_prog *prog) >> */ >> void security_bpf_token_free(struct bpf_token *token) >> { >> + if (!token->security) >> + return; >> + >> call_void_hook(bpf_token_free, token); >> + kfree(token->security); >> + token->security = NULL; >> } >> #endif /* CONFIG_BPF_SYSCALL */ >> >> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c >> index 595ceb314aeb3..8052fb5fafc4d 100644 >> --- a/security/selinux/hooks.c >> +++ b/security/selinux/hooks.c >> @@ -7038,14 +7038,14 @@ static int bpf_fd_pass(const struct file *file, u32 sid) >> >> if (file->f_op == &bpf_map_fops) { >> map = file->private_data; >> - bpfsec = map->security; >> + bpfsec = selinux_bpf_map_security(map); >> ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, >> bpf_map_fmode_to_av(file->f_mode), NULL); >> if (ret) >> return ret; >> } else if (file->f_op == &bpf_prog_fops) { >> prog = file->private_data; >> - bpfsec = prog->aux->security; >> + bpfsec = selinux_bpf_prog_security(prog); >> ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, >> BPF__PROG_RUN, NULL); >> if (ret) >> @@ -7059,7 +7059,7 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) >> u32 sid = current_sid(); >> struct bpf_security_struct *bpfsec; >> >> - bpfsec = map->security; >> + bpfsec = selinux_bpf_map_security(map); >> return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, >> bpf_map_fmode_to_av(fmode), NULL); >> } >> @@ -7069,7 +7069,7 @@ static int selinux_bpf_prog(struct bpf_prog *prog) >> u32 sid = current_sid(); >> struct bpf_security_struct *bpfsec; >> >> - bpfsec = prog->aux->security; >> + bpfsec = selinux_bpf_prog_security(prog); >> return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, >> BPF__PROG_RUN, NULL); >> } >> @@ -7079,69 +7079,33 @@ static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, >> { >> struct bpf_security_struct *bpfsec; >> >> - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); >> - if (!bpfsec) >> - return -ENOMEM; >> - >> + bpfsec = selinux_bpf_map_security(map); >> bpfsec->sid = current_sid(); >> - map->security = bpfsec; >> >> return 0; >> } >> >> -static void selinux_bpf_map_free(struct bpf_map *map) >> -{ >> - struct bpf_security_struct *bpfsec = map->security; >> - >> - map->security = NULL; >> - kfree(bpfsec); >> -} >> - >> static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, >> struct bpf_token *token, bool kernel) >> { >> struct bpf_security_struct *bpfsec; >> >> - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); >> - if (!bpfsec) >> - return -ENOMEM; >> - >> + bpfsec = selinux_bpf_prog_security(prog); >> bpfsec->sid = current_sid(); >> - prog->aux->security = bpfsec; >> >> return 0; >> } >> >> -static void selinux_bpf_prog_free(struct bpf_prog *prog) >> -{ >> - struct bpf_security_struct *bpfsec = prog->aux->security; >> - >> - prog->aux->security = NULL; >> - kfree(bpfsec); >> -} >> - >> static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, >> const struct path *path) >> { >> struct bpf_security_struct *bpfsec; >> >> - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); >> - if (!bpfsec) >> - return -ENOMEM; >> - >> + bpfsec = selinux_bpf_token_security(token); >> bpfsec->sid = current_sid(); >> - token->security = bpfsec; >> >> return 0; >> } >> - >> -static void selinux_bpf_token_free(struct bpf_token *token) >> -{ >> - struct bpf_security_struct *bpfsec = token->security; >> - >> - token->security = NULL; >> - kfree(bpfsec); >> -} >> #endif >> >> struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { >> @@ -7159,6 +7123,9 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { >> .lbs_xattr_count = SELINUX_INODE_INIT_XATTRS, >> .lbs_tun_dev = sizeof(struct tun_security_struct), >> .lbs_ib = sizeof(struct ib_security_struct), >> + .lbs_bpf_map = sizeof(struct bpf_security_struct), >> + .lbs_bpf_prog = sizeof(struct bpf_security_struct), >> + .lbs_bpf_token = sizeof(struct bpf_security_struct), >> }; >> >> #ifdef CONFIG_PERF_EVENTS >> @@ -7510,9 +7477,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { >> LSM_HOOK_INIT(bpf, selinux_bpf), >> LSM_HOOK_INIT(bpf_map, selinux_bpf_map), >> LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), >> - LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free), >> - LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), >> - LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free), >> #endif >> >> #ifdef CONFIG_PERF_EVENTS >> diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h >> index 6ee7dc4dfd6e0..9f935ed9a761f 100644 >> --- a/security/selinux/include/objsec.h >> +++ b/security/selinux/include/objsec.h >> @@ -26,6 +26,7 @@ >> #include <linux/lsm_hooks.h> >> #include <linux/msg.h> >> #include <net/net_namespace.h> >> +#include <linux/bpf.h> >> #include "flask.h" >> #include "avc.h" >> >> @@ -237,4 +238,20 @@ selinux_perf_event(void *perf_event) >> return perf_event + selinux_blob_sizes.lbs_perf_event; >> } >> >> +#ifdef CONFIG_BPF_SYSCALL >> +static inline struct bpf_security_struct *selinux_bpf_map_security(struct bpf_map *map) >> +{ >> + return map->security + selinux_blob_sizes.lbs_bpf_map; >> +} >> + >> +static inline struct bpf_security_struct *selinux_bpf_prog_security(struct bpf_prog *prog) >> +{ >> + return prog->aux->security + selinux_blob_sizes.lbs_bpf_prog; >> +} >> + >> +static inline struct bpf_security_struct *selinux_bpf_token_security(struct bpf_token *token) >> +{ >> + return token->security + selinux_blob_sizes.lbs_bpf_token; >> +} >> +#endif /* CONFIG_BPF_SYSCALL */ >> #endif /* _SELINUX_OBJSEC_H_ */
Hi Blaise, kernel test robot noticed the following build warnings: [auto build test WARNING on pcmoore-selinux/next] [also build test WARNING on linus/master v6.16-rc6 next-20250715] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Blaise-Boscaccy/lsm-selinux-Add-LSM-blob-support-for-BPF-objects/20250716-062844 base: https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git next patch link: https://lore.kernel.org/r/20250715222655.705241-1-bboscaccy%40linux.microsoft.com patch subject: [PATCH] lsm,selinux: Add LSM blob support for BPF objects config: x86_64-defconfig (https://download.01.org/0day-ci/archive/20250716/202507161903.ToApi2Jk-lkp@intel.com/config) compiler: gcc-11 (Debian 11.3.0-12) 11.3.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250716/202507161903.ToApi2Jk-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202507161903.ToApi2Jk-lkp@intel.com/ All warnings (new ones prefixed by >>): >> security/security.c:896:12: warning: 'lsm_bpf_token_alloc' defined but not used [-Wunused-function] 896 | static int lsm_bpf_token_alloc(struct bpf_token *token) | ^~~~~~~~~~~~~~~~~~~ >> security/security.c:874:12: warning: 'lsm_bpf_prog_alloc' defined but not used [-Wunused-function] 874 | static int lsm_bpf_prog_alloc(struct bpf_prog *prog) | ^~~~~~~~~~~~~~~~~~ >> security/security.c:852:12: warning: 'lsm_bpf_map_alloc' defined but not used [-Wunused-function] 852 | static int lsm_bpf_map_alloc(struct bpf_map *map) | ^~~~~~~~~~~~~~~~~ vim +/lsm_bpf_token_alloc +896 security/security.c 843 844 /** 845 * lsm_bpf_map_alloc - allocate a composite bpf_map blob 846 * @map: the bpf_map that needs a blob 847 * 848 * Allocate the bpf_map blob for all the modules 849 * 850 * Returns 0, or -ENOMEM if memory can't be allocated. 851 */ > 852 static int lsm_bpf_map_alloc(struct bpf_map *map) 853 { 854 if (blob_sizes.lbs_bpf_map == 0) { 855 map->security = NULL; 856 return 0; 857 } 858 859 map->security = kzalloc(blob_sizes.lbs_bpf_map, GFP_KERNEL); 860 if (!map->security) 861 return -ENOMEM; 862 863 return 0; 864 } 865 866 /** 867 * lsm_bpf_prog_alloc - allocate a composite bpf_prog blob 868 * @prog: the bpf_prog that needs a blob 869 * 870 * Allocate the bpf_prog blob for all the modules 871 * 872 * Returns 0, or -ENOMEM if memory can't be allocated. 873 */ > 874 static int lsm_bpf_prog_alloc(struct bpf_prog *prog) 875 { 876 if (blob_sizes.lbs_bpf_prog == 0) { 877 prog->aux->security = NULL; 878 return 0; 879 } 880 881 prog->aux->security = kzalloc(blob_sizes.lbs_bpf_prog, GFP_KERNEL); 882 if (!prog->aux->security) 883 return -ENOMEM; 884 885 return 0; 886 } 887 888 /** 889 * lsm_bpf_token_alloc - allocate a composite bpf_token blob 890 * @token: the bpf_token that needs a blob 891 * 892 * Allocate the bpf_token blob for all the modules 893 * 894 * Returns 0, or -ENOMEM if memory can't be allocated. 895 */ > 896 static int lsm_bpf_token_alloc(struct bpf_token *token) 897 { 898 if (blob_sizes.lbs_bpf_token == 0) { 899 token->security = NULL; 900 return 0; 901 } 902 903 token->security = kzalloc(blob_sizes.lbs_bpf_token, GFP_KERNEL); 904 if (!token->security) 905 return -ENOMEM; 906 907 return 0; 908 } 909 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.