LSM & Cgroup Hooks¶
Blog series: Part 20 — BPF LSM security hooks
Javadoc: LSMHook · CGroupHook
Source: LSMHook.java · CGroupHook.java
See also: TC Hook · XDP Hook · BPF Maps
BPF LSM¶
BPF LSM (Linux Security Module) lets you attach BPF programs to the same hook points as traditional LSM modules like SELinux and AppArmor. This gives you fine-grained, programmable security policies without recompiling the kernel.
Prerequisites¶
CONFIG_BPF_LSM=yin kernel configlsm=bpfin kernel boot parameters (orlsm=...,bpfappended to existing list)
Verify:
Implementing LSMHook¶
import me.bechberger.ebpf.annotations.bpf.BPF;
import me.bechberger.ebpf.annotations.bpf.BPFFunction;
import me.bechberger.ebpf.bpf.BPFProgram;
import me.bechberger.ebpf.bpf.LSMHook;
import me.bechberger.ebpf.type.Ptr;
import static me.bechberger.ebpf.bpf.raw.Lib_1.*;
@BPF(license = "GPL")
public abstract class FileOpenRestrict extends BPFProgram implements LSMHook {
/** PIDs to block (set from Java). */
@BPFMapDefinition(maxEntries = 256)
final BPFHashMap<Integer, Integer> blockedPids = BPFHashMap.newInstance();
@Override
@BPFFunction
public int onFileOpen(Ptr<file> file) {
int pid = BPFJ.currentPid();
if (blockedPids.bpf_get(pid) != null) {
return -EACCES; // deny
}
return 0; // allow
}
}
Available LSM hooks¶
LSM hooks correspond to the security_* functions in the kernel. Common ones:
| Method | Fires when |
|---|---|
onFileOpen(Ptr<file>) |
A process opens a file |
onFilePermission(Ptr<file>, int mask) |
A file permission check (read/write/exec) |
onBpf(int cmd, Ptr<?> attr, int size) |
A process calls the bpf() syscall |
onBprmCheckSecurity(Ptr<linux_binprm>) |
A process calls execve |
onSocketCreate(int family, int type, int protocol, int kern) |
A process creates a socket |
onSocketConnect(Ptr<socket>, Ptr<sockaddr>, int) |
A socket connects |
Return 0 to allow, a negative errno to deny (e.g. -EACCES, -EPERM).
Standard errno constants are available via import static me.bechberger.ebpf.bpf.raw.Lib_1.*.
Attaching¶
public static void main(String[] args) throws Exception {
try (FileOpenRestrict prog = BPFProgram.load(FileOpenRestrict.class)) {
prog.autoAttachPrograms();
// Block PID 12345
prog.blockedPids.put(12345, 1);
System.out.println("LSM active. Ctrl-C to stop.");
Thread.currentThread().join();
}
}
CAP_MAC_ADMIN required
Loading BPF LSM programs requires CAP_MAC_ADMIN in addition to CAP_BPF. Run as root
or grant the capability explicitly.
Cgroup Hooks¶
Cgroup BPF programs attach to cgroup v2 hierarchies and filter traffic for all processes in a cgroup. They are useful for per-container network policies.
Implementing CGroupHook¶
@BPF(license = "GPL")
public abstract class CGroupFilter extends BPFProgram implements CGroupHook {
@BPFMapDefinition(maxEntries = 1024)
final BPFHashMap<Integer, Long> byteCount = BPFHashMap.newInstance();
@Override
@BPFFunction
public CGroupAction cgroupHandleIngress(Ptr<__sk_buff> skb) {
int mark = skb.val().mark;
Ptr<Long> c = byteCount.bpf_get(mark);
if (c != null) {
c.set(c.val() + skb.val().len);
} else {
long len = skb.val().len;
byteCount.bpf_put(mark, len);
}
return CGroupAction.PASS;
}
@Override
@BPFFunction
public CGroupAction cgroupHandleEgress(Ptr<__sk_buff> skb) {
return CGroupAction.PASS;
}
}
The context type is __sk_buff (same as TC). Return CGroupAction.PASS to allow or
CGroupAction.DROP to drop.
Attaching to a cgroup¶
public static void main(String[] args) throws Exception {
try (CGroupFilter prog = BPFProgram.load(CGroupFilter.class)) {
// Attach to root cgroup (affects all processes)
prog.cgroupAttachIngress("/sys/fs/cgroup");
prog.cgroupAttachEgress("/sys/fs/cgroup");
// Or a specific cgroup
prog.cgroupAttachIngress("/sys/fs/cgroup/mycontainer");
System.out.println("Cgroup hook active.");
Thread.currentThread().join();
}
}
Cgroup v2 required
Cgroup BPF hooks require cgroup v2 (unified hierarchy). Check with:
Available cgroup hook types¶
| Method | BPF attach type | Description |
|---|---|---|
cgroupHandleIngress |
BPF_CGROUP_INET_INGRESS |
Incoming packets for cgroup sockets |
cgroupHandleEgress |
BPF_CGROUP_INET_EGRESS |
Outgoing packets from cgroup sockets |
cgroupSockCreate |
BPF_CGROUP_INET_SOCK_CREATE |
Socket creation |
cgroupSockRelease |
BPF_CGROUP_INET_SOCK_RELEASE |
Socket close |
cgroupConnect4 |
BPF_CGROUP_INET4_CONNECT |
IPv4 connect() |
cgroupConnect6 |
BPF_CGROUP_INET6_CONNECT |
IPv6 connect() |
Examples¶
LSMDemo.java— BPF LSM hook demoCGroupBlockHTTPEgress.java— cgroup egress filter