Hello,

On Tue, Oct 13, 2026 at 12:47 PM Aoife Moloney via devel-announce <
[email protected]> wrote:

> Wiki - https://fedoraproject.org/wiki/Changes/UnprivilegedEBPFRBACDaemon
> Discourse poll -
>
> https://discussion.fedoraproject.org/t/f46-change-proposal-unprivileged-ebpf-rbac-daemon-with-lsm-enforcement-and-rootless-access-system-wide/204731/2
>
> This is a proposed Change for Fedora Linux.
> This document represents a proposed Change. As part of the Changes
> process, proposals are publicly announced in order to receive
> community feedback. This proposal will only be implemented if approved
> by the Fedora Engineering Steering Committee.
>
>
> == Summary ==
>
> Ship <code>bpf-rbacd</code>, a system daemon that enables
> unprivileged, policy-controlled eBPF access in Fedora. It delegates
> BPF privileges to containers via BPF tokens with in-kernel LSM
> enforcement, and provides rootless BPF access to desktop users via
> proxy execution — both governed by a single YAML policy and gated by
> an <code>ebpf</code> system group.


I don't see anything about integration with the linux audit system.
Anything deciding access control or information flow decisions normally
needs to be auditable.

-Steve


> == Owner ==
>
> * Name: [[Fedora eBPF SIG|https://fedoraproject.org/wiki/SIGs/eBPF]]
> * FAS group: [https://accounts.fedoraproject.org/group/ebpf-sig/
> @ebpf-sig]
> * Email: [email protected]
> * Members:
> ** Daniel Mellado — [email protected]
> ** Toke Høiland-Jørgensen — [email protected]
> ** Viktor Malik — [email protected]
>
>
>
> == Detailed Description ==
>
> === Background ===
>
> eBPF is a powerful kernel technology for networking, observability,
> and security, but its use requires system-wide capabilities
> (<code>CAP_BPF</code> combined with <code>CAP_PERFMON</code>,
> <code>CAP_NET_ADMIN</code>, or <code>CAP_SYS_ADMIN</code>). This is an
> all-or-nothing proposition: applications need privileges close to
> root, which blocks adoption in containers and restricts desktop
> developers.
>
> The kernel's BPF token mechanism (Linux 6.9+) allows a privileged
> issuer to delegate a constrained set of BPF operations to unprivileged
> consumers inside user namespaces. However, tokens alone have two
> significant limitations:
>
> # '''No per-entity enforcement.''' Token constraints are set at the
> bpffs mount level and apply uniformly to all consumers. There is no
> mechanism to give different containers different allowed program
> types, or to revoke access dynamically.
> # '''No desktop path.''' BPF tokens are not supported in the initial
> user namespace (<code>BPF_TOKEN_CREATE</code> returns
> <code>EOPNOTSUPP</code>). Desktop developers running tracers or
> profilers must still use <code>sudo</code>.
>
> This change addresses both gaps through a single daemon that operates
> in two complementary modes simultaneously.
>
> === Dual-mode architecture ===
>
> <code>bpf-rbacd</code> serves two distinct classes of eBPF consumers
> from a single process, using the same policy engine and the same YAML
> configuration:
>
> {| class="wikitable"
> ! Mode !! Target environment !! Mechanism !! LSM enforcement
> |-
> | '''Capability granting''' || Containers and services in user
> namespaces || BPF token delegation via bpffs mount + "nsenter dance"
> || Yes — three LSM hooks enforce per-namespace policy bitmaps
> in-kernel
> |-
> | '''Proxy execution''' || Desktop users and applications in the
> initial user namespace (<code>init_user_ns</code>) || Daemon executes
> <code>bpf()</code> on behalf of clients, passes FDs via
> <code>SCM_RIGHTS</code> over a Unix socket || N/A — policy enforced
> daemon-side before executing the syscall
> |}
>
> '''Why two modes?''' BPF tokens only work inside user namespaces — the
> kernel explicitly rejects <code>BPF_TOKEN_CREATE</code> in
> <code>init_user_ns</code> with <code>EOPNOTSUPP</code>. Containers
> naturally have user namespaces, so tokens are the right mechanism
> there. Desktop users do not, so they need a different path. The proxy
> mode fills that gap without requiring application changes: standard
> tools like bpftrace or bcc can be adapted to request FDs from the
> daemon instead of calling <code>bpf()</code> directly.
>
> Both modes share the same policy model (allow-list only, fails closed,
> system-policy intersection) and the same group-based role resolution
> (<code>ebpf</code>, <code>ebpf-net</code>, <code>ebpf-admin</code>).
> An administrator writes one policy file and both modes obey it.
>
> <pre>
>                     bpf-rbacd (privileged daemon)
>                    ┌──────────────────────────────┐
>                    │         Policy Engine         │
>                    │    (YAML → role → bitmaps)    │
>                    └──────┬───────────┬────────────┘
>                           │           │
>               ┌───────────▼──┐   ┌────▼──────────────┐
>               │  Capability  │   │  Proxy execution   │
>               │  granting    │   │  (SCM_RIGHTS)      │
>               │  mode        │   │  mode              │
>               └──────┬───────┘   └────┬───────────────┘
>                      │                │
>          ┌───────────▼──┐   ┌────────▼────────────┐
>          │ Container /  │   │ Desktop user         │
>          │ service in   │   │ (init_user_ns)       │
>          │ user ns      │   │                      │
>          │              │   │ $ bpf-rbac create-map│
>          │ Uses BPF     │   │   → daemon executes  │
>          │ token from   │   │   → FD passed back   │
>          │ bpffs        │   │   via SCM_RIGHTS     │
>          │   ↓          │   └──────────────────────┘
>          │ LSM enforces │
>          │ per-ns policy│
>          └──────────────┘
> </pre>
>
> === What this change delivers ===
>
> ==== BPF token delegation and the ebpf system group ====
>
> <code>bpf-rbacd</code> uses systemd-driven bpffs delegation to provide
> BPF tokens to containers and services in user namespaces:
>
> * A fixed <code>ebpf</code> system group gates who may consume the
> delegated bpffs/token path. The group is for OS-level discovery and
> packaging defaults; the kernel still enforces token constraints
> independently.
> * The daemon performs the '''"nsenter dance"''' — entering the target
> user namespace via <code>setns()</code> before mounting bpffs, so the
> <code>s_user_ns</code> is set correctly and
> <code>BPF_TOKEN_CREATE</code> works inside the namespace.
> * Integration with systemd <code>PrivateBPF=</code> (upstream
> [https://github.com/systemd/systemd/pull/36134 PR #36134]) enables
> automatic namespace delegation for systemd-managed services.
> * Libraries such as libbpf, bpftool, and bcc automatically discover
> and use delegated tokens without requiring <code>sudo</code>.
>
> ==== In-kernel eBPF LSM policy enforcement ====
>
> The daemon loads eBPF LSM programs at startup that attach to the
> kernel's security hooks for BPF operations. Each hook looks up the
> calling process's user namespace inode ID in an eBPF hash map,
> retrieves the policy bitmaps for that namespace's role, and returns
> allow or deny. This gives administrators '''per-namespace, per-role
> granularity''' enforced in-kernel, on top of the bpffs mount-level
> token constraints.
>
> '''Core hooks''' (implemented in both the Aya and C codebases):
>
> {| class="wikitable"
> ! LSM Hook !! What it controls !! Policy dimension
> |-
> | <code>security_bpf</code> || Every <code>bpf()</code> syscall
> invocation || <code>allowed_cmds</code> bitmap (PROG_LOAD, MAP_CREATE,
> etc.)
> |-
> | <code>security_bpf_prog_load</code> || Program loading — inspects
> program type || <code>allowed_prog_types</code> bitmap (kprobe, xdp,
> etc.)
> |-
> | <code>security_bpf_map_create</code> || Map creation — inspects map
> type || <code>allowed_map_types</code> bitmap (hash, array, etc.)
> |}
>
> '''Extended hooks''' (implemented in the C codebase —
> [https://github.com/tohojo/bpf-rbac-lsm tohojo/bpf-rbac-lsm]):
>
> {| class="wikitable"
> ! LSM Hook !! What it controls !! Why it matters
> |-
> | <code>security_bpf_prog</code> || FD-level access to existing
> programs || Controls who can inspect or reuse loaded programs
> |-
> | <code>security_mmap</code> || Memory-mapping of BPF maps || Controls
> map data access mode (read/write/exec)
> |}
>
> '''Bytecode walking for helper/kfunc policy:''' The C implementation
> also uses open-coded iterators to walk BPF program bytecode at
> <code>security_bpf_prog_load</code> time, extracting the helper
> function IDs and kfunc BTF IDs that the program calls. This enables a
> future policy dimension: restricting ''which kernel functions'' a
> program may invoke, not just which program type it is. Events are
> reported to userspace via a BPF ring buffer for audit logging and
> policy decisions.
>
> '''How LSM and tokens complement each other:'''
>
> <pre>
> Token says "you may load            LSM checks: "your namespace
> kprobe programs"                    role only permits tracepoint"
>         ↓                                   → DENIED
> </pre>
>
> Even if a token is overly permissive (broad bpffs mount options), the
> per-namespace LSM policy restricts actual operations to the role's
> intersection with the system policy.
>
> '''eBPF program loading at daemon startup:''' The daemon loads and
> attaches the LSM programs before accepting any delegation requests.
> This requires <code>CAP_BPF</code> + <code>CAP_SYS_ADMIN</code> on the
> daemon itself (granted via the systemd unit's
> <code>AmbientCapabilities</code>). Once loaded, the LSM hooks are
> active system-wide; the eBPF policy map serves as the control plane
> between the daemon and the LSM.
>
> ==== Rootless BPF for desktop users (proxy mode) ====
>
> For users in the initial user namespace (desktops, developer
> workstations), <code>bpf-rbacd</code> provides a proxy execution mode:
>
> # User runs <code>bpf-rbac <command></code> (e.g., <code>bpf-rbac
> create-map --type hash ...</code>)
> # The CLI connects to the daemon's Unix socket at
> <code>/run/bpf-rbac.sock</code>
> # The daemon reads <code>SO_PEERCRED</code> — kernel-verified,
> tamper-proof credentials
> # Group membership is resolved to a policy role
> # The daemon executes the allowed <code>bpf()</code> syscall with its
> own privileges
> # Resulting file descriptors are passed back via <code>SCM_RIGHTS</code>
> # Denied operations return actionable error messages
>
> === Policy model ===
>
> Policies are defined in <code>/etc/bpf-rbac/policy.yaml</code> using
> an allow-list model that always fails closed:
>
> <pre>
> system_policy:                          # System-wide ceiling
>   commands: [PROG_LOAD, MAP_CREATE, MAP_LOOKUP_ELEM, MAP_UPDATE_ELEM,
>              LINK_CREATE, OBJ_PIN, OBJ_GET, BTF_LOAD]
>   prog_types:
>     kprobe: [load, attach, detach]
>     tracepoint: [load, attach, detach]
>     xdp: [load, attach, detach]
>   map_types:
>     hash: [create, read, write]
>     array: [create, read, write]
>     ringbuf: [create, read]
>
> roles:
>   ebpf:                                 # Tracing role
>     groups: [ebpf]
>     commands: [PROG_LOAD, MAP_CREATE, MAP_LOOKUP_ELEM, MAP_UPDATE_ELEM,
>                LINK_CREATE, BTF_LOAD]
>     prog_types:
>       kprobe: [load, attach]
>       tracepoint: [load, attach]
>     map_types:
>       hash: [create, read, write]
>       array: [create, read, write]
>       ringbuf: [create, read]
>
>   ebpf-net:                             # Networking role
>     groups: [ebpf-net]
>     prog_types:
>       xdp: [load, attach, detach]
>       sched_cls: [load, attach, detach]
>     map_types:
>       hash: [create, read, write]
>       devmap: [create, read, write]
>
>   ebpf-admin:                           # Unrestricted
>     groups: [ebpf-admin, wheel]
>     commands: [any]
>     prog_types: {any: [any]}
>     map_types: {any: [any]}
> </pre>
>
> The effective policy for any role is the '''set intersection''' of the
> role policy and the system policy. A role can never exceed
> administrator-defined system limits.
>
> === Two LSM implementations and the Rust BPF toolchain gap ===
>
> The eBPF LSM programs exist in two parallel implementations. This is
> not redundancy — it is a deliberate response to a Rust compiler
> limitation that currently prevents the Aya-based implementation from
> using advanced BPF features.
>
> ==== The Rust/DWARF/BTF problem ====
>
> eBPF programs that call kernel functions (kfuncs) or reference kernel
> symbols (ksyms) require BTF (BPF Type Format) metadata in the compiled
> ELF. The toolchain flow is:
>
> <pre>
> Rust source → rustc (BPF target) → LLVM → ELF with DWARF
>     → bpf-linker → ELF with BTF (including .ksyms DATASEC)
>         → kernel verifier resolves kfuncs/ksyms at load time
> </pre>
>
> The problem: '''<code>rustc</code> does not emit DWARF debug info for
> <code>extern</code> declarations on BPF targets.''' When a Rust eBPF
> program declares:
>
> <pre>
> #[link_section = ".ksyms"]
> extern "C" {
>     static LINUX_KERNEL_VERSION: u32;      // ksym
>     fn bpf_iter_num_new(it: *mut bpf_iter_num, start: i32, end: i32); //
> kfunc
> }
> </pre>
>
> …the compiler produces the LLVM global/function declaration but
> attaches no <code>DIGlobalVariable</code> or <code>DISubprogram</code>
> metadata. Without DWARF, <code>bpf-linker</code> cannot generate the
> <code>.ksyms</code> BTF DATASEC entry, and the kernel verifier cannot
> resolve these symbols at load time. The program fails to load.
>
> This blocks:
> * '''Open-coded iterators'''
> (<code>bpf_iter_num_new/next/destroy</code>) — needed for bytecode
> walking in the <code>security_bpf_prog_load</code> hook
> * '''kfunc calls''' (<code>bpf_task_acquire</code>, etc.) — needed for
> CO-RE task/namespace introspection
> * '''The userns ID resolver''' —
> <code>current->nsproxy->user_ns->ns.inum</code> access via BTF,
> currently stubbed to return 0
>
> The three core bitmap-based hooks (<code>security_bpf</code>,
> <code>security_bpf_prog_load</code>,
> <code>security_bpf_map_create</code>) work today with Aya because they
> only use map lookups and context argument reads — no kfuncs or ksyms.
> But the extended hooks (bytecode walking, FD access control, mmap
> control) require kfuncs and are blocked.
>
> ==== The upstream Rust compiler fix ====
>
> We are driving the fix in
> [https://github.com/rust-lang/rust/pull/161390 rust-lang/rust#161390]
> ("Generate debug info for BPF extern declarations"). This patch:
>
> * Allows <code>#[link_section]</code> on <code>ForeignStatic</code>
> and <code>ForeignFn</code> (gated to BPF targets)
> * Adds an <code>LLVMRustDIBuilderCreateGlobalVariableExpression</code>
> wrapper exposing the <code>isDefinition</code> parameter (the LLVM-C
> API hard-codes it to <code>true</code>)
> * Emits <code>DIGlobalVariable</code> with <code>isDefinition:
> false</code> for extern statics
> * Emits <code>DISubprogram</code> without
> <code>SPFlagDefinition</code> for extern functions
>
> This is a reworked version of
> [https://github.com/rust-lang/rust/pull/152899 #152899], rebased on
> current <code>main</code> with review feedback addressed. It is
> currently in review with the Rust compiler team (assigned to
> @jdonszelmann, reviews from @bjorn3 and @tamird). The Aya maintainer
> (@vadorovsky) is also involved.
>
> Once this lands in nightly <code>rustc</code>, the full chain works:
> Rust eBPF → DWARF with extern metadata → <code>bpf-linker</code> → BTF
> with <code>.ksyms</code> → kernel loads kfuncs. This unblocks the
> complete Aya-based LSM.
>
> ==== The C implementation: tohojo/bpf-rbac-lsm ====
>
> [https://github.com/tohojo/bpf-rbac-lsm tohojo/bpf-rbac-lsm] is an
> actively developed C-based LSM implementation (Toke Høiland-Jørgensen,
> latest commits Sep 2026) that sidesteps the Rust toolchain limitation
> entirely. It uses:
>
> * '''C for the eBPF programs''' — compiled with clang/llvm, full
> BTF/CO-RE support, no DWARF issues
> * '''Rust + libbpf-rs for userspace''' — loads the C eBPF programs via
> libbpf skeleton generation, processes ring buffer events, manages
> policies
>
> This implementation is more capable than the Aya version today:
>
> {| class="wikitable"
> ! Feature !! Aya (Rust eBPF) !! C eBPF + libbpf-rs
> |-
> | <code>security_bpf</code> (command filtering) || ✅ || ✅
> |-
> | <code>security_bpf_prog_load</code> (type filtering) || ✅ || ✅
> |-
> | <code>security_bpf_map_create</code> (type filtering) || ✅ || ✅
> |-
> | <code>security_bpf_prog</code> (FD access) || ❌ || ✅
> |-
> | <code>security_mmap</code> (map mmap control) || ❌ || ✅
> |-
> | Userns ID resolution (CO-RE/BTF) || ❌ (stubbed) || ✅
> |-
> | Bytecode walking (open-coded iterators) || ❌ (blocked on rustc) || ✅
> |-
> | Helper/kfunc ID extraction || ❌ (blocked on rustc) || ✅
> |-
> | Policy enforcement per namespace || ❌ (stub returns 0) || ✅
> |-
> | Ring buffer event reporting || ❌ || ✅
> |}
>
> ==== Integration strategy and the path to a pure Rust/Aya stack ====
>
> The two implementations share the same userspace daemon
> (<code>bpf-rbacd</code>) and the same policy engine. They are designed
> to converge:
>
> '''Phase 1 — Fedora 46 delivery (C eBPF + Rust userspace):'''
>
> Use the C eBPF programs from <code>bpf-rbac-lsm</code> loaded via
> <code>libbpf-rs</code> in the <code>bpf-rbacd</code> Rust userspace
> daemon. This gives us the full feature set (all hooks, bytecode
> walking, namespace resolution, policy enforcement) without waiting for
> the Rust compiler fix. The daemon, policy engine, CLI, and all
> userspace logic remain in Rust; only the eBPF kernel programs are in
> C. This is a pragmatic split — the same pattern used by many
> production eBPF projects (e.g., Cilium, bpfman).
>
> '''Phase 2 — After <code>rustc</code> fix lands (Aya catches up):'''
>
> Once [https://github.com/rust-lang/rust/pull/161390
> rust-lang/rust#161390] is merged and reaches stable
> <code>rustc</code>, we migrate the eBPF programs to Rust/Aya. The
> groundwork is already done:
>
> * The Aya-based LSM in [https://github.com/danielmellado/bpf-rbacd
> danielmellado/bpf-rbacd
> <https://github.com/danielmellado/bpf-rbacddanielmellado/bpf-rbacd>]
> already compiles and produces correct ELF
> relocations for the three core hooks.
> * The [https://github.com/tohojo/bpf-rbacd/tree/load-lsm load-lsm
> branch] already has kfunc declarations and open-coded iterator code
> that compiles — it only needs the BTF DATASEC generation that the
> <code>rustc</code> fix enables.
> * Aya's kfunc relocation support
> ([https://github.com/aya-rs/aya/pull/1372 aya-rs/aya#1372]) is
> progressing upstream.
>
> The migration is a drop-in replacement: the userspace daemon, policy
> engine, and CLI are unchanged. Only the eBPF binary source changes
> from C to Rust.
>
> '''Phase 3 — Target state (pure Rust):'''
>
> A fully Rust stack — daemon, CLI, policy engine, ''and'' eBPF kernel
> programs — all built with <code>cargo</code>. This is the desired end
> state for <code>bpf-rbacd</code> because:
>
> * '''Single toolchain:''' One <code>cargo build</code> compiles
> everything. No separate clang/llvm dependency for the eBPF programs.
> * '''Shared types:''' The <code>bpf-rbacd-common</code> crate already
> defines <code>#[repr(C)]</code> policy types (<code>PolicyKey</code>,
> <code>PolicyValue</code>) that compile for both <code>no_std</code>
> (eBPF target) and <code>std</code> (userspace). With Aya, these types
> are shared at compile time with full type safety — no manual struct
> layout synchronization between C and Rust.
> * '''Memory safety:''' Rust's borrow checker and type system apply to
> the eBPF programs too. While eBPF's verifier provides runtime safety,
> compile-time guarantees from Rust catch bugs earlier.
> * '''Ecosystem alignment:''' Aya is the standard Rust eBPF framework.
> Contributing improvements back (kfunc support, LSM patterns) benefits
> the entire Rust eBPF community.
>
> The <code>rustc</code> fix is not just a <code>bpf-rbacd</code>
> concern — it unblocks kfunc/ksym usage for ''every'' Rust eBPF
> program. We are driving this upstream because it is the right thing
> for the ecosystem, and <code>bpf-rbacd</code> is a concrete,
> high-profile consumer that validates the fix.
>
> This phased approach means the Fedora 46 deliverable is '''not blocked
> by the Rust compiler fix''', while the Rust/Aya migration remains a
> first-class goal tracked by the eBPF SIG.
>
> === Kernel requirements ===
>
> {| class="wikitable"
> ! Config !! Required for !! In Fedora?
> |-
> | <code>CONFIG_BPF_SYSCALL=y</code> || All BPF operations || Yes
> |-
> | <code>CONFIG_BPF_LSM=y</code> || LSM hook attachment || Yes
> |-
> | <code>bpf</code> in active LSM list || LSM program loading || Needs
> verification
> |-
> | <code>CONFIG_DEBUG_INFO_BTF=y</code> || CO-RE/BTF for portable eBPF ||
> Yes
> |-
> | <code>CONFIG_BPF_TOKEN</code> || BPF token delegation || Yes
> |}
>
> '''Action item:''' Verify that <code>bpf</code> is in the kernel's
> compiled-in LSM list or <code>lsm=</code> boot parameter. If not, a
> kernel config change is needed to add <code>bpf</code> to the LSM
> order alongside <code>lockdown,yama,integrity,selinux</code>.
>
> == Feedback ==
>
> The design of <code>bpf-rbacd</code> is being presented at
> [https://lpc.events/event/20/contributions/2441/ Linux Plumbers
> Conference 2026] (Oct 6, eBPF Track) to solicit community feedback.
> The talk covers the architecture, policy model, and LSM enforcement,
> with the goal of making the design useful to other distributions and
> operators.
>
> Community consultation with kernel, systemd, and security stakeholders
> is ongoing.
>
> == Benefit to Fedora ==
>
> * '''Security posture:''' Moves eBPF access from all-or-nothing
> capabilities toward granular, role-based delegation. LSM enforcement
> adds a mandatory kernel-level policy layer that token delegation alone
> cannot provide.
> * '''Per-entity granularity:''' Different containers, services, or
> users get different eBPF permissions based on their role — not a
> single system-wide delegation.
> * '''Developer experience:''' Desktop developers and operators can run
> eBPF tools without <code>sudo</code>, with clear errors when an
> operation is outside their role's policy.
> * '''Unified policy:''' One YAML file governs both container (LSM +
> tokens) and desktop (proxy) access. Administrators learn one model.
> * '''Dynamic policy and revocation:''' Policies can be updated at
> runtime; removing a namespace's map entry causes the LSM to deny
> subsequent operations without killing processes.
> * '''Downstream alignment:''' Establishes the reference RBAC
> implementation for RHEL, OpenShift (user namespaces GA in 4.21+), and
> CoreOS. Kubernetes user namespaces are GA as of v1.36.
> * '''Rust BPF ecosystem:''' The upstream <code>rustc</code> fix
> ([https://github.com/rust-lang/rust/pull/161390 #161390]) benefits the
> entire Rust eBPF community. <code>bpf-rbacd</code> is designed to
> become a fully pure-Rust eBPF project (daemon + kernel programs via
> Aya) once the toolchain gap is closed, demonstrating that production
> eBPF LSM programs can be written entirely in Rust.
> * '''Community leadership:''' Fedora becomes the first distribution
> with a complete, integrated eBPF RBAC stack spanning containers and
> desktops.
>
> == Scope ==
>
> * Proposal owners:
> ** Package <code>bpf-rbacd</code> (daemon), <code>bpf-rbac</code> (CLI
> client), and <code>bpf-rbacd-common</code> (shared types) as RPMs.
> Source is hosted on [https://forge.fedoraproject.org/ebpf/bpf-rbacd
> Fedora Forge].
> ** Ship the eBPF LSM programs from
> [https://github.com/tohojo/bpf-rbac-lsm tohojo/bpf-rbac-lsm] (C eBPF +
> libbpf-rs for loading). Migrate to Rust/Aya once
> [https://github.com/rust-lang/rust/pull/161390 rust-lang/rust#161390]
> lands.
> ** Deliver systemd unit (<code>bpf-rbacd.service</code>) with security
> hardening (<code>ProtectSystem=strict</code>,
> <code>ProtectHome=true</code>, capability bounding).
> ** Deliver default policy (<code>/etc/bpf-rbac/policy.yaml</code>)
> reviewed with the Security Team.
> ** Create <code>ebpf</code>, <code>ebpf-net</code>, and
> <code>ebpf-admin</code> system groups via
> <code>systemd-sysusers</code>.
> ** Implement systemd-driven bpffs delegation (mount units,
> <code>PrivateBPF=</code> coordination).
> ** Coordinate with kernel team to ensure <code>bpf</code> is in the
> active LSM list.
> ** Drive the Rust compiler fix
> ([https://github.com/rust-lang/rust/pull/161390
> rust-lang/rust#161390]) or use C fallback.
> ** Complete the CO-RE/BTF userns ID resolver in the eBPF LSM.
> ** Wire container/namespace discovery into the daemon (cgroup events
> or CRI hooks).
> ** Coordinate library/tool updates for automatic token usage (libbpf,
> bpftool, bcc).
> ** File Fedora package review, FESCo process, and tracker bugs.
> ** Write Fedora Quick Docs article on usage and security model.
>
> * Other developers:
> ** Kernel maintainers: Confirm <code>CONFIG_BPF_LSM=y</code> and
> <code>bpf</code> in LSM list; advise on LSM hook semantics and
> regression triage.
> ** systemd maintainers: Coordinate on <code>PrivateBPF=</code>
> integration so systemd-launched services automatically get delegated
> namespaces.
> ** Rust compiler team: Review and land
> [https://github.com/rust-lang/rust/pull/161390 rust-lang/rust#161390].
> ** Aya maintainers: kfunc relocation support
> ([https://github.com/aya-rs/aya/pull/1372 aya-rs/aya#1372]).
> ** Security Team: Review default policy, group membership model, and
> LSM enforcement guarantees.
> ** eBPF tooling maintainers (bcc, bpftool, libbpf consumers): Ensure
> tools work with proxy-mode FD passing and token-based flows.
> ** Container runtime maintainers (podman, CRI-O): Test user namespace
> + BPF token + LSM enforcement end-to-end.
> ** Edition WGs (Workstation, Server, CoreOS): Consider default group
> membership and documentation per edition.
>
> * Release engineering: No release engineering changes required.
> <code>bpf-rbacd</code> is a new opt-in package with standard RPM
> packaging — no mass rebuild, no installer image changes, and no
> compose modifications.
>
> * Policies and guidelines: The initial delivery uses C eBPF programs
> compiled with clang/llvm and loaded via libbpf-rs — this follows
> standard Fedora packaging (clang and libbpf are already packaged). The
> future Aya-based path targets <code>bpfel-unknown-none</code> and
> requires nightly Rust + <code>rust-src</code>, which may need a
> packaging exemption or pre-built binary vendoring when that migration
> occurs. Default policy requires Security Team review.
>
> * Trademark approval: N/A (not needed for this Change)
>
> * Alignment with the Fedora Strategy: Aligns with secure-by-default,
> developer-friendly platform, and upstream-first goals. The change
> drives fixes in <code>rustc</code>, Aya, and systemd rather than
> carrying downstream patches.
>
> == Upgrade/compatibility impact ==
>
> This change introduces a new opt-in package. It does not modify
> existing system behavior.
>
> * '''Existing systems:''' No change unless <code>bpf-rbacd</code> is
> installed. Workflows that use root or explicit capabilities continue
> to work.
> * '''New path:''' Users or administrators who want unprivileged eBPF
> install <code>bpf-rbacd</code>, add users to the <code>ebpf</code>,
> <code>ebpf-net</code>, or <code>ebpf-admin</code> groups, and enable
> the service.
> * '''Kernel config:''' If <code>bpf</code> needs to be added to the
> LSM list, this could interact with other LSM consumers (notably
> SELinux). Must be coordinated with the kernel team.
> * '''ABI:''' No Fedora-specific ABI commitment beyond documented
> <code>bpf()</code> semantics and the policy YAML format. Tools that
> gain automatic token discovery may succeed in situations where they
> previously failed without sudo.
>
> == Early Testing (Optional) ==
>
> Do you require 'QA Blueprint' support? N
>
> == How To Test ==
>
> # '''Hardware/data:''' Standard x86_64 or aarch64 Fedora install. VM
> acceptable if BPF features are not stripped.
> # '''Prepare:''' Install <code>bpf-rbacd</code>, start the service,
> add test user to <code>ebpf</code> group.
> # '''Proxy mode (desktop):'''
> #: <pre>
> # As a user in the ebpf group:
> $ bpf-rbac status
> Connected to: /run/bpf-rbac.sock
> Your roles: ebpf
> Allowed operations:
>   Maps: hash, array, percpu_hash, percpu_array, ringbuf
>   Programs: kprobe, uprobe, tracepoint, perf_event
>
> # Create a map (should succeed)
> $ bpf-rbac create-map --type hash --name test \
>     --key-size 4 --value-size 8 --max-entries 64
>
> # Attempt a denied operation (should fail with clear error)
> $ bpf-rbac create-map --type devmap --name test \
>     --key-size 4 --value-size 8 --max-entries 64
> Error: map type 'devmap' is not allowed by your role 'ebpf'
> </pre>
> # '''LSM enforcement (requires root for setup):''' Launch a podman
> container in a user namespace (<code>podman run --userns=auto
> ...</code>). Verify that the daemon delegates bpffs and populates the
> policy map. Inside the container, attempt to load an allowed program
> type (should succeed) and a denied type (should fail with
> <code>EPERM</code>).
> # '''Non-member:''' As a user NOT in any ebpf group, verify that all
> operations are denied.
> # '''Unit tests (no root required):'''
> #: <pre>
> cargo test --lib               # Policy parsing, bitmaps, intersection
> cargo test --test integration  # Non-privileged integration tests
> </pre>
> # '''Expected results:''' Delegated operations succeed within the
> role's allowlist; out-of-scope operations fail with clear errors; no
> system instability or privilege escalation beyond the documented
> policy.
>
> == User Experience ==
>
> * Most users see no change unless they use eBPF tooling.
> * Desktop developers who run tracers or networking experiments may
> stop needing <code>sudo</code> for supported scenarios, with clear
> errors when an operation is denied.
> * Container workloads are transparent — applications use standard
> <code>bpf()</code> with automatic token acquisition; the LSM silently
> enforces the namespace's policy.
> * Administrators get a single documented policy file
> (<code>/etc/bpf-rbac/policy.yaml</code>) and <code>journalctl -u
> bpf-rbacd</code> for audit logging.
>
> == Dependencies ==
>
> * Linux kernel: 6.9+ with <code>CONFIG_BPF_TOKEN</code>,
> <code>CONFIG_BPF_LSM=y</code>, <code>bpf</code> in active LSM list,
> <code>CONFIG_DEBUG_INFO_BTF=y</code>
> * Rust: Stable 1.85+ (daemon and CLI)
> * [https://github.com/libbpf/libbpf libbpf] and
> [https://github.com/libbpf/libbpf-rs libbpf-rs]: For loading C-based
> eBPF LSM programs from the Rust daemon (initial delivery path)
> * clang/llvm: For compiling the C eBPF programs with full BTF/CO-RE support
> * [https://github.com/aya-rs/aya Aya]: eBPF library for Rust
> (long-term target once [https://github.com/rust-lang/rust/pull/161390
> rust-lang/rust#161390
> <https://github.com/rust-lang/rust/pull/161390rust-lang/rust#161390>]
> lands; requires nightly Rust +
> <code>bpfel-unknown-none</code> target)
> * systemd: <code>PrivateBPF=</code> support
> ([https://github.com/systemd/systemd/pull/36134 PR #36134])
> * Optional: podman with <code>--userns=auto</code>, CRI-O with user
> namespace support
>
> == Contingency Plan ==
>
> * Contingency mechanism:
> ** The primary delivery path already uses the C eBPF programs (via
> libbpf-rs), so the Rust compiler fix
> ([https://github.com/rust-lang/rust/pull/161390
> rust-lang/rust#161390]) is not on the critical path for F46.
> ** If BPF LSM cannot be enabled in the Fedora kernel (e.g., SELinux
> interaction with <code>bpf</code> in the LSM list): disable LSM
> loading in <code>bpf-rbacd</code>; ship proxy mode only and rely on
> token-level constraints for container workloads.
> ** If proxy mode has unresolved security concerns: ship LSM/container
> path only; desktop users fall back to
> <code>sudo</code>/<code>CAP_BPF</code>.
> ** If neither component is ready: do not ship <code>bpf-rbacd</code>.
> eBPF access continues to work as it does today (privileged only). No
> regression.
> * Contingency deadline: Beta freeze
> * Blocks release? No. <code>bpf-rbacd</code> is an opt-in package.
>
> == Documentation ==
>
> * Upstream code: [https://forge.fedoraproject.org/ebpf/bpf-rbacd
> Fedora Forge ebpf/bpf-rbacd] (primary),
> [https://github.com/danielmellado/bpf-rbacd GitHub mirror]
> * C reference implementation: [https://github.com/tohojo/bpf-rbac-lsm
> tohojo/bpf-rbac-lsm
> <https://github.com/tohojo/bpf-rbac-lsmtohojo/bpf-rbac-lsm>]
> * Rust compiler fix: [https://github.com/rust-lang/rust/pull/161390
> rust-lang/rust#161390
> <https://github.com/rust-lang/rust/pull/161390rust-lang/rust#161390>]
> * Kernel docs: [https://docs.kernel.org/bpf/bpf_token.html BPF Token
> documentation]
> * systemd: [https://github.com/systemd/systemd/pull/36134 PrivateBPF= PR]
> * LPC 2026 talk: [https://lpc.events/event/20/contributions/2441/
> BPF-RBACd <https://lpc.events/event/20/contributions/2441/BPF-RBACd>:
> Delegating BPF permissions with high granularity]
> * Fedora: Quick Docs article covering installation, group membership,
> policy customization, security model, and container vs. desktop usage
> paths.
> * eBPF SIG: [https://fedoraproject.org/wiki/SIGs/eBPF SIGs/eBPF],
> Matrix: [https://matrix.to/#/#ebpf:fedoraproject.org
> #ebpf:fedoraproject.org]
>
> == Release Notes ==
>
> Fedora 46 introduces <code>bpf-rbacd</code>, a system daemon that
> enables unprivileged, policy-controlled eBPF access through two
> complementary modes:
>
> * '''Capability granting''' for containers and services in user
> namespaces — transparent eBPF access via BPF token delegation with
> mandatory in-kernel LSM enforcement (three hooks:
> <code>security_bpf</code>, <code>security_bpf_prog_load</code>,
> <code>security_bpf_map_create</code>).
> * '''Proxy execution''' for desktop users in the initial user
> namespace — rootless BPF access via the <code>bpf-rbac</code> CLI,
> with the daemon executing allowed operations on the user's behalf and
> passing file descriptors back via <code>SCM_RIGHTS</code>.
>
> Both modes are governed by a single YAML policy file
> (<code>/etc/bpf-rbac/policy.yaml</code>) and gated by role-based
> groups (<code>ebpf</code>, <code>ebpf-net</code>,
> <code>ebpf-admin</code>). Install with <code>sudo dnf install
> bpf-rbacd</code>.
>
>
> --
> Aoife Moloney
>
> Fedora Operations Architect
>
> Fedora Project
>
> Matrix: @amoloney:fedora.im
>
> IRC: amoloney
>
> --
> _______________________________________________
> devel-announce mailing list -- [email protected]
> To unsubscribe send an email to
> [email protected]
> Fedora Code of Conduct:
> https://docs.fedoraproject.org/en-US/project/code-of-conduct/
> List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
> List Archives:
> https://lists.fedoraproject.org/archives/list/[email protected]
> Do not reply to spam, report it:
> https://forge.fedoraproject.org/infra/tickets/issues/new
> --
> _______________________________________________
> devel mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
> Fedora Code of Conduct:
> https://docs.fedoraproject.org/en-US/project/code-of-conduct/
> List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
> List Archives:
> https://lists.fedoraproject.org/archives/list/[email protected]
> Do not reply to spam, report it:
> https://forge.fedoraproject.org/infra/tickets/issues/new
>
-- 
_______________________________________________
devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedoraproject.org/archives/list/[email protected]
Do not reply to spam, report it: 
https://forge.fedoraproject.org/infra/tickets/issues/new

Reply via email to