linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] lsm,selinux: Add LSM blob support for BPF objects
@ 2025-07-15 22:25 Blaise Boscaccy
  2025-07-16 12:14 ` kernel test robot
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Blaise Boscaccy @ 2025-07-15 22:25 UTC (permalink / raw)
  To: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
	Ondrej Mosnacek, Casey Schaufler, John Johansen, Blaise Boscaccy,
	Christian Göttsche, linux-security-module, linux-kernel,
	selinux, bpf

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


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] lsm,selinux: Add LSM blob support for BPF objects
  2025-07-15 22:25 [PATCH] lsm,selinux: Add LSM blob support for BPF objects Blaise Boscaccy
@ 2025-07-16 12:14 ` kernel test robot
  2025-07-16 17:44 ` Casey Schaufler
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: kernel test robot @ 2025-07-16 12:14 UTC (permalink / raw)
  To: Blaise Boscaccy, Paul Moore, James Morris, Serge E. Hallyn,
	Stephen Smalley, Ondrej Mosnacek, Casey Schaufler, John Johansen,
	Christian Göttsche, linux-security-module, linux-kernel,
	selinux, bpf
  Cc: oe-kbuild-all

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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] lsm,selinux: Add LSM blob support for BPF objects
  2025-07-15 22:25 [PATCH] lsm,selinux: Add LSM blob support for BPF objects Blaise Boscaccy
  2025-07-16 12:14 ` kernel test robot
@ 2025-07-16 17:44 ` Casey Schaufler
  2025-07-18 15:32   ` Blaise Boscaccy
  2025-07-16 20:48 ` Song Liu
  2025-07-17  2:11 ` Paul Moore
  3 siblings, 1 reply; 8+ messages in thread
From: Casey Schaufler @ 2025-07-16 17:44 UTC (permalink / raw)
  To: Blaise Boscaccy, Paul Moore, James Morris, Serge E. Hallyn,
	Stephen Smalley, Ondrej Mosnacek, John Johansen,
	Christian Göttsche, linux-security-module, linux-kernel,
	selinux, bpf, Casey Schaufler

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_ */

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] lsm,selinux: Add LSM blob support for BPF objects
  2025-07-15 22:25 [PATCH] lsm,selinux: Add LSM blob support for BPF objects Blaise Boscaccy
  2025-07-16 12:14 ` kernel test robot
  2025-07-16 17:44 ` Casey Schaufler
@ 2025-07-16 20:48 ` Song Liu
  2025-07-18 15:32   ` Blaise Boscaccy
  2025-07-17  2:11 ` Paul Moore
  3 siblings, 1 reply; 8+ messages in thread
From: Song Liu @ 2025-07-16 20:48 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
	Ondrej Mosnacek, Casey Schaufler, John Johansen,
	Christian Göttsche, linux-security-module, linux-kernel,
	selinux, bpf

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

[...]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] lsm,selinux: Add LSM blob support for BPF objects
  2025-07-15 22:25 [PATCH] lsm,selinux: Add LSM blob support for BPF objects Blaise Boscaccy
                   ` (2 preceding siblings ...)
  2025-07-16 20:48 ` Song Liu
@ 2025-07-17  2:11 ` Paul Moore
  2025-07-18 15:35   ` Blaise Boscaccy
  3 siblings, 1 reply; 8+ messages in thread
From: Paul Moore @ 2025-07-17  2:11 UTC (permalink / raw)
  To: Blaise Boscaccy, James Morris, Serge E. Hallyn, Stephen Smalley,
	Ondrej Mosnacek, Casey Schaufler, John Johansen, Blaise Boscaccy,
	Christian Göttsche, linux-security-module, linux-kernel,
	selinux, bpf

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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] lsm,selinux: Add LSM blob support for BPF objects
  2025-07-16 17:44 ` Casey Schaufler
@ 2025-07-18 15:32   ` Blaise Boscaccy
  0 siblings, 0 replies; 8+ messages in thread
From: Blaise Boscaccy @ 2025-07-18 15:32 UTC (permalink / raw)
  To: Casey Schaufler, Paul Moore, James Morris, Serge E. Hallyn,
	Stephen Smalley, Ondrej Mosnacek, John Johansen,
	Christian Göttsche, linux-security-module, linux-kernel,
	selinux, bpf, Casey Schaufler

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_ */

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] lsm,selinux: Add LSM blob support for BPF objects
  2025-07-16 20:48 ` Song Liu
@ 2025-07-18 15:32   ` Blaise Boscaccy
  0 siblings, 0 replies; 8+ messages in thread
From: Blaise Boscaccy @ 2025-07-18 15:32 UTC (permalink / raw)
  To: Song Liu
  Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
	Ondrej Mosnacek, Casey Schaufler, John Johansen,
	Christian Göttsche, linux-security-module, linux-kernel,
	selinux, bpf

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

>
> [...]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] lsm,selinux: Add LSM blob support for BPF objects
  2025-07-17  2:11 ` Paul Moore
@ 2025-07-18 15:35   ` Blaise Boscaccy
  0 siblings, 0 replies; 8+ messages in thread
From: Blaise Boscaccy @ 2025-07-18 15:35 UTC (permalink / raw)
  To: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
	Ondrej Mosnacek, Casey Schaufler, John Johansen,
	Christian Göttsche, linux-security-module, linux-kernel,
	selinux, bpf

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

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-07-18 15:35 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-15 22:25 [PATCH] lsm,selinux: Add LSM blob support for BPF objects Blaise Boscaccy
2025-07-16 12:14 ` kernel test robot
2025-07-16 17:44 ` Casey Schaufler
2025-07-18 15:32   ` Blaise Boscaccy
2025-07-16 20:48 ` Song Liu
2025-07-18 15:32   ` Blaise Boscaccy
2025-07-17  2:11 ` Paul Moore
2025-07-18 15:35   ` Blaise Boscaccy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).