BPF List
 help / color / mirror / Atom feed
From: Justin Suess <utilityemal77@gmail.com>
To: Paul Moore <paul@paul-moore.com>
Cc: "Mickaël Salaün" <mic@digikod.net>,
	ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
	kpsingh@kernel.org, viro@zeniv.linux.org.uk, brauner@kernel.org,
	kees@kernel.org, gnoack@google.com, jack@suse.cz,
	jmorris@namei.org, serge@hallyn.com, song@kernel.org,
	yonghong.song@linux.dev, martin.lau@linux.dev, m@maowtm.org,
	eddyz87@gmail.com, john.fastabend@gmail.com, sdf@fomichev.me,
	skhan@linuxfoundation.org, bpf@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	"Frederick Lawler" <fred@cloudflare.com>
Subject: Re: [RFC PATCH 06/20] bpf: lsm: Add Landlock kfuncs
Date: Tue, 21 Jul 2026 17:55:18 -0400	[thread overview]
Message-ID: <al_TBtXYUNGLZHC2@zenbox> (raw)
In-Reply-To: <CAHC9VhRp6pvQXskNU0FXBkDw=MAF8Ht1Mk7BbUeU8JnEkSk52g@mail.gmail.com>

On Wed, Jul 01, 2026 at 02:33:26PM -0400, Paul Moore wrote:
> On Wed, Jul 1, 2026 at 2:29 PM Justin Suess <utilityemal77@gmail.com> wrote:
> > On Wed, Jul 01, 2026 at 09:28:22AM -0400, Paul Moore wrote:
> > > On Wed, Jul 1, 2026 at 8:52 AM Justin Suess <utilityemal77@gmail.com> wrote:
> > > > On Wed, Jul 01, 2026 at 08:12:34AM -0400, Paul Moore wrote:
> > > > > On Wed, Jul 1, 2026 at 6:59 AM Mickaël Salaün <mic@digikod.net> wrote:
> > > > > > On Tue, Apr 07, 2026 at 04:01:28PM -0400, Justin Suess wrote:
> [..]
>
> Please keep in mind that the LSM framework API needs to be reasonably
> generic.  We've got some general guidance on adding new LSM hooks at
> the link below:
> 
> https://github.com/LinuxSecurityModule/kernel/blob/main/README.md#new-lsm-hooks
>

Howdy,

I'd like to reopen this conversation with a fresh proposal.

Apologies it's been a while.. hope this isn't too long.

I've re-read the LSM design documents linked above, plus some of the
older discussions where similar things were proposed, and this is a
redesign I'd like feedback on before wasting time prototyping.

Background
==========

Refresher (since it's been a minute):

The original RFC exposed kfuncs (non-ABI functions callable
from sleepable BPF LSM programs) straight out of security/landlock, to
apply a userspace-created Landlock ruleset to a binprm during exec.
That skipped the LSM framework entirely and was basically a direct
line into one LSM.

Paul and Casey, as I understand it your objection breaks down into
two parts:

1. LSM configuration/policy interfaces shouldn't exist outside the
   LSM framework. If every LSM grows its own kernel-internal API
   surface it gets messy and hard to refactor.

2. Anything at the framework level has to be reasonably generic. From
   the design docs:

   "Hooks should be designed to be LSM agnostic. While it is possible
   that only one LSM might implement the hook at the time of
   submission, the hook's behavior should be generic enough that
   other LSMs could provide a meaningful implementation."

The proposal here should meet this better.

Proposal
========

Broadly, I am seeking to propose an LSM framework API for kfuncs.

This would be ALL through the existing LSM hook interface.

Instead of individual LSMs exporting kfuncs, the LSM framework exports
all LSM kfuncs and dispatches them to LSMs through generic LSM hooks.

Here's an ASCII diagram (hopefully it doesn't get mangled)
of the framework:

     bpf_landlock_restrict_binprm(bprm, ruleset, flags)
                        |
                        |  strongly BTF-typed
                        |  (struct bpf_landlock_ruleset *)
                        v
   +-------------------------------------------------------------+
   |                       LSM framework                         |
   |                                                             |
   |  security/lsm_kfuncs.c            (owns all kfuncs)         |
   |     - kfunc filter: prog type / sleepable / LSM enabled?    |
   |     - type erasure: ruleset -> void *policy                 |
   |                        |                                    |
   |                        v                                    |
   |  security_kfunc_enforce_bprm_policy(LSM_ID_LANDLOCK,        |
   |                                     bprm, policy, flags)    |
   |                        |                                    |
   |     lsm_for_each_hook: | dispatch by lsm_id                 |
   |        +---------------+---------------+                    |
   |        |               |               |                    |
   +--------|---------------|---------------|--------------------+
            v               v               v
      id != lsm_id     id != lsm_id    id == LSM_ID_LANDLOCK
      (skipped)        (skipped)            |
                                            v
   +-------------------------------------------------------------+
   |  security/landlock                                          |
   |                                                             |
   |  LSM_HOOK_INIT(kfunc_enforce_bprm_policy,                   |
   |                hook_enforce_bprm_policy)                    |
   |     - applies ruleset, staged to bprm_committing_creds      |
   +-------------------------------------------------------------+

      no LSM matches / hook not implemented  ->  -EOPNOTSUPP

1. The LSM framework owns the kfuncs.

   Individual LSMs never register or export a kfunc. All kfuncs live
   under security/ (say security/lsm_kfuncs.c) and go through the LSM
   tree. LSMs only ever implement ordinary LSM hooks, via
   LSM_HOOK_INIT() like anything else. No LSM touches BPF.

   The kfuncs break down into two categories:

   a. kfuncs that talk to the LSM framework itself and no specific
      LSM. There's already userspace precedent for this category in
      the LSM syscalls (lsm_list_modules() etc). To be honest
      category (a) may not need any kfuncs at all to start with; I'm
      including it for completeness of the model :)

   b. kfuncs that carry a policy operation to one specific LSM.
      Applying a Landlock ruleset to a binprm (this series), or
      hypothetically loading an AppArmor profile. The kfunc from
      this series is one of these:

      bpf_landlock_restrict_binprm(struct linux_binprm *bprm,
                                   const struct bpf_landlock_ruleset *ruleset,
                                   u32 flags);

2. Either way, every kfunc call passes through a generic LSM hook. No
   kfunc calls directly into an individual LSM. The shim in
   security/security.c (or other lsm framework owned file) is the
   only caller of the hook.

3. Category (a) kfuncs map 1:1 onto an LSM hook. The framework
   dispatches to every LSM implementing the hook and returns the
   collective verdict, same as any hook today.

4. Category (b) kfuncs follow the existing
   security_getprocattr()/security_setprocattr() precedent: a generic
   hook dispatched by LSM id. For the Landlock case the shim would
   look something like:

      int security_kfunc_enforce_bprm_policy(int lsm_id,
                                             struct linux_binprm *bprm,
                                             void *policy,
                                             u32 flags);

   dispatched by lsm_id:

      lsm_for_each_hook(scall, kfunc_enforce_bprm_policy) {
              if (scall->hl->lsmid->id != lsm_id)
                      continue;
              return scall->hl->hook.kfunc_enforce_bprm_policy(bprm,
                                                        policy, flags);
      }
      return -EOPNOTSUPP;

   The hook is generic in that any LSM with a notion of a per-task or
   per-exec policy object can implement it. Landlock implements it
   like any other hook:

      LSM_HOOK_INIT(kfunc_enforce_bprm_policy,
                    hook_enforce_bprm_policy),

   Critically, Landlock only receives hook calls with a matching
   LSM_ID, so another LSM implementing the same hook never sees calls
   meant for a different kfunc.

5. Type safety at the kfunc boundary is preserved.

   Note the asymmetry between the kfunc signature and the hook
   signature above: the kfunc the BPF verifier sees stays strongly
   BTF-typed (struct bpf_landlock_ruleset *), so BPF programs get
   full verifier type checking and can't pass an arbitrary pointer.

   This also avoids a user facing multiplexer.

   The erasure to void * happens inside the shim, after the verifier
   has already guaranteed the pointer's type, and the receiving LSM
   (picked by lsm_id) is the only LSM that will ever see it. Think
   the relationship setprocattr has with its string payloads, just
   with stronger (BPF verifier-enforced) typing on the kfunc side.

6. The shim checks that the target LSM is actually enabled at
   runtime, and that the calling context is OK (i.e. implementing a
   kfunc filter). This is centralized to make it easier for review
   from both LSM and BPF subsystems.

BPF Side
=========

Alexei / Song / Kumar / BPF maintainers,

Even if this proposal doesn't touch kernel/bpf/, I still would
need to hear your feedback / review on this every bit as much
as I need to hear the LSM side.

I think the kfunc / kptr model with strong typing fits this well.
We can have reference counted and strongly typed policy objects
for the LSMs, and kfuncs give more flexibility for API deprecation
as they are not considered to be ABI like helpers...

Obviously any new kfunc / kptr would need to be reviewed by BPF tree
especially with regards to kptr lifetimes and the calling context.

But hopefully this centralizes the interface that would otherwise be an
ad-hoc mess of individual LSMs trying to define kfuncs willy-nilly and
causing regressions.

One particular point that I would need to know is what should happen if
an LSM is not loaded / compiled in, but the kfunc is called. Is a
verifier rejection acceptible? Or is a runtime error more appropriate
for this?

Thanks,
Justin

  reply	other threads:[~2026-07-21 21:55 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-07 20:01 [RFC PATCH 00/20] BPF interface for applying Landlock rulesets Justin Suess
2026-04-07 20:01 ` [RFC PATCH 01/20] landlock: Move operations from syscall into ruleset code Justin Suess
2026-04-07 20:01 ` [RFC PATCH 02/20] execve: Add set_nnp_on_point_of_no_return Justin Suess
2026-04-07 20:01 ` [RFC PATCH 03/20] landlock: Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-04-07 20:01 ` [RFC PATCH 04/20] selftests/landlock: Cover LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-04-07 20:01 ` [RFC PATCH 05/20] landlock: Make ruleset deferred free RCU safe Justin Suess
2026-04-07 20:01 ` [RFC PATCH 06/20] bpf: lsm: Add Landlock kfuncs Justin Suess
2026-07-01 10:59   ` Mickaël Salaün
2026-07-01 12:12     ` Paul Moore
2026-07-01 12:52       ` Justin Suess
2026-07-01 13:28         ` Paul Moore
2026-07-01 18:29           ` Justin Suess
2026-07-01 18:33             ` Paul Moore
2026-07-21 21:55               ` Justin Suess [this message]
2026-07-01 18:34           ` Mickaël Salaün
2026-07-01 18:38             ` Paul Moore
2026-07-01 19:49               ` Mickaël Salaün
2026-07-01 19:55                 ` Justin Suess
2026-07-01 20:02                   ` Paul Moore
2026-07-01 21:28                     ` Mickaël Salaün
2026-07-01 23:32                       ` Paul Moore
2026-07-02  9:53                         ` Mickaël Salaün
2026-07-09  2:52                           ` Paul Moore
2026-07-01 21:41                     ` Casey Schaufler
2026-07-02  9:51                       ` Mickaël Salaün
2026-07-01 19:56                 ` Paul Moore
2026-04-07 20:01 ` [RFC PATCH 07/20] bpf: arraymap: Implement Landlock ruleset map Justin Suess
2026-04-07 20:01 ` [RFC PATCH 08/20] bpf: Add Landlock ruleset map type Justin Suess
2026-04-16 21:12   ` Song Liu
2026-04-16 21:53     ` Justin Suess
2026-04-16 23:47       ` Song Liu
2026-04-17 14:09         ` Justin Suess
2026-04-17 15:18           ` Mickaël Salaün
2026-04-17 16:10             ` Song Liu
2026-04-17 18:01               ` Mickaël Salaün
2026-04-17 16:51             ` Justin Suess
2026-04-17 18:03               ` Mickaël Salaün
2026-04-17 20:33                 ` Justin Suess
2026-04-17 20:42                   ` Song Liu
2026-04-18 21:50                     ` Justin Suess
2026-04-17 16:01           ` Song Liu
2026-04-07 20:01 ` [RFC PATCH 09/20] bpf: syscall: Handle Landlock ruleset maps Justin Suess
2026-04-07 20:01 ` [RFC PATCH 10/20] bpf: verifier: Add Landlock ruleset map support Justin Suess
2026-04-07 20:01 ` [RFC PATCH 11/20] selftests/bpf: Add Landlock kfunc declarations Justin Suess
2026-04-07 20:01 ` [RFC PATCH 12/20] selftests/landlock: Rename gettid wrapper for BPF reuse Justin Suess
2026-04-07 20:01 ` [RFC PATCH 13/20] selftests/bpf: Enable Landlock in selftests kernel Justin Suess
2026-04-07 20:01 ` [RFC PATCH 14/20] selftests/bpf: Add Landlock kfunc test program Justin Suess
2026-04-07 20:01 ` [RFC PATCH 15/20] selftests/bpf: Add Landlock kfunc test runner Justin Suess
2026-04-07 20:01 ` [RFC PATCH 16/20] landlock: Bump ABI version Justin Suess
2026-04-07 20:01 ` [RFC PATCH 17/20] tools: bpftool: Add documentation for landlock_ruleset Justin Suess
2026-04-07 20:01 ` [RFC PATCH 18/20] landlock: Document LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-04-07 20:01 ` [RFC PATCH 19/20] bpf: Document BPF_MAP_TYPE_LANDLOCK_RULESET Justin Suess
2026-04-07 20:01 ` [RFC PATCH 20/20] MAINTAINERS: update entry for the Landlock subsystem Justin Suess
2026-04-08  4:40 ` [RFC PATCH 00/20] BPF interface for applying Landlock rulesets Ihor Solodrai
2026-04-08 11:41   ` Justin Suess
2026-04-08 14:00 ` Mickaël Salaün
2026-04-08 17:10   ` Justin Suess
2026-04-08 19:21     ` Mickaël Salaün
2026-04-10 12:43       ` Justin Suess
2026-04-13 15:06       ` 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=al_TBtXYUNGLZHC2@zenbox \
    --to=utilityemal77@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=brauner@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=fred@cloudflare.com \
    --cc=gnoack@google.com \
    --cc=jack@suse.cz \
    --cc=jmorris@namei.org \
    --cc=john.fastabend@gmail.com \
    --cc=kees@kernel.org \
    --cc=kpsingh@kernel.org \
    --cc=linux-fsdevel@vger.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=mic@digikod.net \
    --cc=paul@paul-moore.com \
    --cc=sdf@fomichev.me \
    --cc=serge@hallyn.com \
    --cc=skhan@linuxfoundation.org \
    --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