mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Justin Suess <utilityemal77@gmail.com>
To: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
	kpsingh@kernel.org, matt@bobrowski.net, paul@paul-moore.com,
	mic@digikod.net, viro@zeniv.linux.org.uk, brauner@kernel.org,
	kees@kernel.org
Cc: casey@schaufler-ca.com, gnoack@google.com, jack@suse.cz,
	song@kernel.org, yonghong.song@linux.dev, martin.lau@linux.dev,
	eddyz87@gmail.com, memxor@gmail.com, jolsa@kernel.org,
	m@maowtm.org, bpf@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Justin Suess <utilityemal77@gmail.com>
Subject: [PATCH bpf-next v3 07/15] lsm: Add the bpf_lsm_policy_apply_bprm kfunc
Date: Wed,  9 Sep 2026 15:37:10 -0400	[thread overview]
Message-ID: <20260909193719.518517-8-utilityemal77@gmail.com> (raw)
In-Reply-To: <20260909193719.518517-1-utilityemal77@gmail.com>

Add the kfunc applying a policy object to an execution:

  bpf_lsm_policy_apply_bprm(object, bprm, flags)        KF_SLEEPABLE

It asks the LSM owning @object, through the bprm_apply_policy_object
hook, to restrict the credentials prepared in @bprm, so that the
executed task starts confined by the policy.  The meaning of @flags
and the composition with restrictions the credentials already carry
are the owning LSM's; an LSM without execution policy support makes
the call fail with -EOPNOTSUPP.

The kfunc runs the hook in a root memcg charging scope: the policy
restricts the execution on behalf of the BPF program, not of the
mediated task, so what the owning LSM allocates to compute it, e.g.
Landlock's merged domain, is not charged to the task the program
supervises.

The filter makes the kfunc exclusive to the sleepable LSM programs
attached to the bprm_creds_for_exec() or bprm_creds_from_file()
hooks, the only contexts where the bprm's credentials are prepared
but not yet committed.  The verifier's argument typing does not draw
this boundary on its own: a trusted struct linux_binprm pointer is
also available at the other bprm hooks -- bprm_check_security(),
which runs per binfmt while an interpreter may still rewrite the
execution, and bprm_committing_creds()/bprm_committed_creds(), which
run at or past the point of no return, where the prepared
credentials are frozen or installed -- and to tp_btf programs via
the sched_prepare_exec and sched_process_exec tracepoints, which
resolve kfuncs from the same registration bucket as LSM programs.
The attach-point filter, not the argument type, is the authorization
boundary.

No filter case is needed for BPF_LSM_CGROUP programs: since
commit 5b038319be44 ("bpf: Reject sleepable BPF_LSM_CGROUP programs
at load time") they cannot be sleepable, so KF_SLEEPABLE already
excludes them.

Cc: Paul Moore <paul@paul-moore.com>
Cc: KP Singh <kpsingh@kernel.org>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---

Notes:
    v2->v3:
        - Drop the BPF_LSM_CGROUP case from the kfunc filter: since
          commit 5b038319be44 ("bpf: Reject sleepable BPF_LSM_CGROUP
          programs at load time") such programs cannot be sleepable, so
          KF_SLEEPABLE already excludes them from the apply kfunc.
        - Document, in the commit message and the filter comment, why the
          attach-point filter rather than the verifier's argument typing
          is the authorization boundary.

 security/bpf_lsm_kfuncs.c | 68 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/security/bpf_lsm_kfuncs.c b/security/bpf_lsm_kfuncs.c
index 43a4bf57fd31..857e9a316d1c 100644
--- a/security/bpf_lsm_kfuncs.c
+++ b/security/bpf_lsm_kfuncs.c
@@ -2,16 +2,25 @@
 
 /* BPF kfuncs exposing LSM policy objects. */
 
+#include <linux/binfmts.h>
 #include <linux/bpf.h>
 #include <linux/btf.h>
 #include <linux/btf_ids.h>
 #include <linux/cfi.h>
 #include <linux/init.h>
 #include <linux/lsm_hooks.h>
+#include <linux/memcontrol.h>
+#include <linux/sched/mm.h>
 #include <linux/security.h>
 
 #include "lsm.h"
 
+/* The sleepable LSM hooks bpf_lsm_policy_apply_bprm() may be called from. */
+BTF_SET_START(bpf_lsm_policy_bprm_hooks)
+BTF_ID(func, bpf_lsm_bprm_creds_for_exec)
+BTF_ID(func, bpf_lsm_bprm_creds_from_file)
+BTF_SET_END(bpf_lsm_policy_bprm_hooks)
+
 __bpf_kfunc_start_defs();
 
 /**
@@ -44,6 +53,49 @@ bpf_lsm_policy_acquire(struct lsm_policy_object *object)
 	return NULL;
 }
 
+/**
+ * bpf_lsm_policy_apply_bprm - Apply a policy object to exec credentials
+ * @object: policy object to apply
+ * @bprm: execution context providing the prepared credentials to
+ *        restrict
+ * @flags: flags defined by the LSM owning @object
+ *
+ * Ask the LSM owning @object to restrict the credentials prepared in
+ * @bprm with it, so that the executed task starts confined by the
+ * policy.  How the policy composes with restrictions the credentials
+ * already carry, and the meaning of @flags, are defined by the owning
+ * LSM.  @object is only borrowed: the caller keeps its reference.
+ * The hook runs in a root memcg charging scope: policy the LSM
+ * computes on behalf of the program is not charged to the mediated
+ * task.
+ *
+ * Return: 0 on success, -EOPNOTSUPP if the LSM owning @object does
+ * not support applying policy to an execution, -EINVAL on unsupported
+ * @flags, other negative values on LSM-specific failures.
+ */
+__bpf_kfunc int bpf_lsm_policy_apply_bprm(struct lsm_policy_object *object,
+					  struct linux_binprm *bprm, u32 flags)
+{
+	struct lsm_static_call *scall;
+	struct mem_cgroup *old_memcg;
+	int err;
+
+	lsm_for_each_hook(scall, bprm_apply_policy_object) {
+		if (scall->hl->lsmid->id != object->lsmid)
+			continue;
+		/*
+		 * The hook runs on behalf of the BPF program, not of the
+		 * mediated task: charge its allocations to the root memcg.
+		 */
+		old_memcg = set_active_memcg(root_mem_cgroup);
+		err = scall->hl->hook.bprm_apply_policy_object(bprm, object,
+							       flags);
+		set_active_memcg(old_memcg);
+		return err;
+	}
+	return -EOPNOTSUPP;
+}
+
 /**
  * bpf_lsm_policy_from_fd - Get an LSM policy object from a fd
  * @fd: file descriptor referring to a policy object, resolved in the
@@ -115,6 +167,7 @@ __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(bpf_lsm_policy_kfunc_ids)
 BTF_ID_FLAGS(func, bpf_lsm_policy_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
+BTF_ID_FLAGS(func, bpf_lsm_policy_apply_bprm, KF_SLEEPABLE)
 BTF_ID_FLAGS(func, bpf_lsm_policy_from_fd,
 	     KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
 BTF_ID_FLAGS(func, bpf_lsm_policy_release, KF_RELEASE)
@@ -124,6 +177,8 @@ BTF_ID_LIST(bpf_lsm_policy_dtor_ids)
 BTF_ID(struct, lsm_policy_object)
 BTF_ID(func, bpf_lsm_policy_release_dtor)
 
+BTF_ID_LIST_SINGLE(bpf_lsm_policy_apply_bprm_ids, func,
+		   bpf_lsm_policy_apply_bprm)
 BTF_ID_LIST_SINGLE(bpf_lsm_policy_from_fd_ids, func, bpf_lsm_policy_from_fd)
 
 /*
@@ -132,6 +187,12 @@ BTF_ID_LIST_SINGLE(bpf_lsm_policy_from_fd_ids, func, bpf_lsm_policy_from_fd)
  * kfuncs requires a filter.  A policy object fd is only meaningful in
  * the fd table of the task that set the object up: the fd kfunc is
  * exclusive to syscall programs, which run in that task's context.
+ * Applying policy to an execution is exclusive to the sleepable bprm
+ * LSM hooks the operation is specified for.  The bprm argument's type
+ * alone does not draw that boundary: other bprm hooks and the tp_btf
+ * exec tracepoints, which share the LSM programs' kfunc bucket, also
+ * provide a trusted bprm pointer outside the window where the
+ * prepared credentials may still be updated.
  */
 static int bpf_lsm_policy_kfunc_filter(const struct bpf_prog *prog,
 				       u32 kfunc_id)
@@ -141,11 +202,18 @@ static int bpf_lsm_policy_kfunc_filter(const struct bpf_prog *prog,
 
 	switch (prog->type) {
 	case BPF_PROG_TYPE_SYSCALL:
+		if (kfunc_id == bpf_lsm_policy_apply_bprm_ids[0])
+			return -EACCES;
 		return 0;
 	case BPF_PROG_TYPE_LSM:
 		if (kfunc_id == bpf_lsm_policy_from_fd_ids[0])
 			return -EACCES;
 
+		if (kfunc_id == bpf_lsm_policy_apply_bprm_ids[0] &&
+		    !btf_id_set_contains(&bpf_lsm_policy_bprm_hooks,
+					 prog->aux->attach_btf_id))
+			return -EACCES;
+
 		return 0;
 	default:
 		return -EACCES;
-- 
2.55.0


  parent reply	other threads:[~2026-09-09 19:38 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-09 19:37 [PATCH bpf-next v3 00/15] BPF interface for applying Landlock rulesets Justin Suess
2026-09-09 19:37 ` [PATCH bpf-next v3 01/15] lsm: Add the LSM policy object lifetime hooks Justin Suess
2026-09-09 19:37 ` [PATCH bpf-next v3 02/15] lsm: Add the bprm_apply_policy_object LSM hook Justin Suess
2026-09-09 19:37 ` [PATCH bpf-next v3 03/15] lsm: Move the lsm_for_each_hook() macro to security/lsm.h Justin Suess
2026-09-09 19:37 ` [PATCH bpf-next v3 04/15] lsm: Add the bpf_lsm_policy_release kfunc and policy object destructor Justin Suess
2026-09-09 20:29   ` bot+bpf-ci
2026-09-09 21:34   ` Paul Moore
2026-09-09 22:20     ` Justin Suess
2026-09-09 23:08       ` Paul Moore
2026-09-12  3:37         ` Alexei Starovoitov
2026-09-12  5:26           ` Justin Suess
2026-09-12 19:33             ` Alexei Starovoitov
2026-09-09 19:37 ` [PATCH bpf-next v3 05/15] lsm: Add the bpf_lsm_policy_from_fd kfunc Justin Suess
2026-09-09 20:46   ` bot+bpf-ci
2026-09-09 19:37 ` [PATCH bpf-next v3 06/15] lsm: Add the bpf_lsm_policy_acquire kfunc Justin Suess
2026-09-09 20:30   ` bot+bpf-ci
2026-09-09 19:37 ` Justin Suess [this message]
2026-09-12  3:38   ` [PATCH bpf-next v3 07/15] lsm: Add the bpf_lsm_policy_apply_bprm kfunc Alexei Starovoitov
2026-09-12  5:39     ` Justin Suess
2026-09-09 19:37 ` [PATCH bpf-next v3 08/15] lsm: Document the LSM policy object interface Justin Suess
2026-09-09 19:37 ` [PATCH bpf-next v3 09/15] selftests/bpf: Add tests for the LSM policy object kfuncs Justin Suess
2026-09-09 20:30   ` bot+bpf-ci
2026-09-09 19:37 ` [PATCH bpf-next v3 10/15] landlock: Expose the ruleset fd lookup to the rest of Landlock Justin Suess
2026-09-09 19:37 ` [PATCH bpf-next v3 11/15] landlock: Factor the credential restriction out of landlock_restrict_self() Justin Suess
2026-09-09 20:29   ` bot+bpf-ci
2026-09-09 19:37 ` [PATCH bpf-next v3 12/15] landlock: Free rulesets after an RCU grace period Justin Suess
2026-09-09 20:46   ` bot+bpf-ci
2026-09-09 19:37 ` [PATCH bpf-next v3 13/15] landlock: Implement the LSM policy object hooks Justin Suess
2026-09-09 20:46   ` bot+bpf-ci
2026-09-09 19:37 ` [PATCH bpf-next v3 14/15] selftests/bpf: Test the LSM policy object kfuncs with Landlock Justin Suess
2026-09-09 20:46   ` bot+bpf-ci
2026-09-09 19:37 ` [PATCH bpf-next v3 15/15] landlock: Document the BPF policy interface Justin Suess

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260909193719.518517-8-utilityemal77@gmail.com \
    --to=utilityemal77@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=brauner@kernel.org \
    --cc=casey@schaufler-ca.com \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=gnoack@google.com \
    --cc=jack@suse.cz \
    --cc=jolsa@kernel.org \
    --cc=kees@kernel.org \
    --cc=kpsingh@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=m@maowtm.org \
    --cc=martin.lau@linux.dev \
    --cc=matt@bobrowski.net \
    --cc=memxor@gmail.com \
    --cc=mic@digikod.net \
    --cc=paul@paul-moore.com \
    --cc=song@kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®