Skip to content

Enforcement

Tyr enforces at the kernel via eBPF LSM (Linux Security Modules) hooks and tracepoints. This page documents what’s hooked, the verdict model, and bypass considerations.

Kernel version requirements

  • Minimum: kernel 5.15 with CONFIG_BPF_LSM=y built in.
  • Recommended: kernel 6.1+ for the full feature set.
  • BTF / CO-RE required (/sys/kernel/btf/vmlinux must exist).

Most modern distros ship with LSM BPF enabled:

  • Ubuntu 22.04+, Debian 12+, Fedora 36+, Amazon Linux 2023 — yes out of the box.
  • RHEL 9 — yes (kernel 5.14 backports LSM BPF).
  • Older kernels fall back to tracepoint-only mode where available (observe but limited enforce).

Verify on your host:

Terminal window
cat /sys/kernel/security/lsm # should include "bpf"
ls /sys/kernel/btf/vmlinux # should exist

Hook points

Kernel hookTypeWhat it covers
lsm/file_openLSMopen(), openat(), indirectly read()
lsm/bprm_check_securityLSMexecve() before the binary is loaded
lsm/socket_connectLSMoutbound connect() for TCP/UDP
tp/syscalls/sys_enter_openattracepointsupplemental path tracking
tp/sched/sched_process_exectracepointsuccessful exec for logging
uprobe on SSL_write / rustls senduprobeTLS SNI extraction (when --tls-capture)

The two-layer verdict pipeline

flowchart TD
Start(["syscall entry"]) --> L1
subgraph L1["Layer 1: BPF map lookup (kernel, nanoseconds)"]
Trie["file_deny_prefixes (trie)"]
Hash["exec_deny_exact (hash)"]
Lpm["net_deny_cidrs (lpm_trie)"]
end
L1 --> Decision{match?}
Decision -- "yes" --> Deny["return EPERM<br/>emit event (DENY)"]
Decision -- "no" --> Allow["emit event (ALLOW or ALERT)"]
Allow --> L2
subgraph L2["Layer 2: userspace (when needed)"]
RB["tyrd reads ring buffer"]
Cedar["evaluate Cedar rules<br/>(principal / context)"]
Audit["if deny \u2192 event.verdict = DENY<br/>(audit after-the-fact)"]
RB --> Cedar --> Audit
end

Good policies keep the deny rules in Layer 1 (kernel) so they actually prevent the syscall. Use Cedar for conditional allow / alert rules.

Processes exempt from enforcement

Some processes must never be blocked — tyrd itself, systemd-journald, the kernel worker queue. These are identified by:

  • Cgroup membership of tyr.service.
  • PID 1.
  • Kernel threads (PPID == 2).

Fine-grained exemptions via policy (exempt_pids: or exempt_binaries:) can be added but should be minimal.

Enforce vs audit-only

The tyrd --enforce flag is the master switch:

FlagFile deny/writeExec denyNet deny
--enforce (on)syscall → EPERMsyscall → EACCESconnect()ECONNREFUSED
(off, default)emits event onlyemits event onlyemits event only

Start in audit-only mode for your first week of deployment. Confirm your policies don’t false-positive on legitimate work, then flip --enforce on.

Bypass considerations

What Tyr catches that LD_PRELOAD / ptrace miss:

  • Statically-linked binaries.
  • setuid executions.
  • Processes that unset LD_PRELOAD in their environment.
  • Kernel-path code paths that don’t go through libc.

What Tyr doesn’t catch today:

  • Privileged processes that can unload LSM BPF programs (root, CAP_BPF) — if your attacker is already root-on-host with CAP_BPF, you’ve lost. Mitigation: run tyrd with its programs pinned and run kmem-lockdown.
  • Direct kernel module insertion — no userspace security tool can.
  • Workloads that never enter a governed syscall (e.g. a pure compute loop).

Next

See the TLS capture guide for how outbound HTTPS traffic is tagged with SNI, and the ADR on kernel enforcement for deeper design rationale.