Linux - LSM

"Traditional" Linux Security Module

SELinux

SELinux: an implementation of Mandatory Access Control (MAC)

As contrasted to the standard Unix model of Discretionary Access Control (DAC).

SELinux comes installed by default on Red Hat distributions.

To check your SELinux mode, run sestatus and check the output. For example:

$ sestatus
SELinux status:                 disabled

$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing

Mode from config file:          error (Success)
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      28

concepts:

  • Multi-Level Security (MLS)
  • Multi-Category Security (MCS)

Permissive vs Enforcing Mode:

  • Permissive Mode: SELinux will log access control infringements but will not enforce them
  • Enforcing Mode: enforce!

AppArmor

Ubuntu Server's Mandatory Access Control (MAC) system. Equivelant to Redhat's SELinux.

AppArmor vs SELinux

  • SELinux identifies file system objects by inode number; difficult for administrators to set up and maintain.
  • AppArmor relies on path.

Under AppArmor an inaccessible file may become accessible if a hard link to it is created. SELinux's inode-based model has always inherently denied access through newly created hard links because the hard link would be pointing to an inaccessible inode.

eBPF-based Linux Security Module (LSM)

KRSI (Kernel Runtime Security Instrumentation) is Google’s new Linux Security Module – LSM. Unlike other LSMs, such as AppArmor and SELinux, you can customize KRSI with a scripting language called eBPF.

The core idea behind KRSI—using eBPF programs to attach to LSM hooks for dynamic security policies—has been successfully integrated into the Linux kernel under the name BPF-LSM.

BPF-LSM is a "stackable" LSM, which means it can be enabled and used alongside other, more traditional LSMs like SELinux and AppArmor. This is a powerful feature because it allows you to combine the strengths of different security models. For example, you can have a general, system-wide policy from SELinux and then use a more dynamic, specific BPF-LSM policy to add fine-grained security checks for a particular application.

FAQ

Is BPF LSM only used for enforcement, or is it also used for runtime security monitoring?

BPF LSM (BPF_PROG_TYPE_LSM) is widely used for both blocking enforcement and passive runtime security monitoring (simply by logging the event to an eBPF ring buffer and returning 0 to allow the operation). While you can monitor events with kprobes or syscall tracepoints, security agents (like Cilium Tetragon, Falco, and Tracee) prefer BPF LSM hooks for monitoring because of TOCTOU immunity and stable context:

  • Why syscall tracepoints fall short for security monitoring: Hooking raw syscall tracepoints (sys_enter_openat) suffers from the exact same Time-of-Check to Time-of-Use (TOCTOU) race as seccomp—an attacker can swap the user-space filename string after the tracepoint fires, tricking your monitor into logging a benign path while the kernel actually opens /etc/shadow.
  • Why BPF LSM is superior to kprobes for auditing: Unlike internal kernel functions (kprobes) whose signatures change across kernel versions, LSM hooks (security_file_open, security_bprm_check_security) are deliberately placed at stable, security-critical choke points after the kernel has already resolved user pointers into immutable kernel objects (struct file *, struct inode *, struct cred *). Furthermore, BPF LSM supports sleepable eBPF programs (BPF_F_SLEEPABLE), allowing your monitoring agent to safely fault in user memory, walk full VFS dentry paths, or compute file hashes synchronously—things non-sleepable kprobes cannot safely do.

Are kprobes and tracepoints also programmable with eBPF, or only BPF LSM?

All three—BPF LSM, kprobes (fentry/fexit), and tracepoints—are fully programmable with eBPF. The difference is not programmability, but hook placement, safety guarantees, and allowed kernel helpers:

  • Observation vs. Enforcement: kprobes and tracepoints are strictly for passive observation (their return values cannot block a kernel operation), whereas a BPF LSM program can either passively log an event (returning 0) or actively block it in-place (returning -EPERM).
  • Choke-Point Integrity (Zero TOCTOU): Syscall tracepoints (sys_enter_*) fire before user-space pointers are copied into the kernel, leaving monitors vulnerable to TOCTOU memory-swapping attacks. kprobes can hook deeper C functions, but internal functions frequently get inlined or bypassed by alternative syscalls across kernel versions. BPF LSM hooks sit at mandatory, kernel-guaranteed security choke points after VFS and network structs (struct file *, struct inode *, struct socket *) are safely resolved.
  • Sleepable eBPF & Exclusive Helpers: Unlike kprobes (which run in non-sleepable atomic contexts where unmapped user memory reads fail with -EFAULT), BPF LSM supports sleepable eBPF (BPF_F_SLEEPABLE) and unlocks restricted helpers like bpf_d_path() (for full VFS path resolution) and bpf_ima_file_hash() (for binary hashing).

Recommended Reading

📖 BPF Performance Tools by Brendan Gregg The definitive reference for modern kernel observability, security auditing, and dynamic tracing using eBPF. Covers probe safety, execution overhead, and kernel tracepoint mechanics with battle-tested recipes. View on Amazon ↗