LoFP LoFP / the splice volume threshold (50 calls per 60 seconds from a single process in a user-writable path) is calibrated against the v4bel public poc, which produces 100-460 splice calls in 90 seconds depending on system state. legitimate user-mode workloads that may produce splice() calls (web servers, mail transfer agents, language runtimes) typically execute from system paths (/usr/sbin, /usr/bin, /usr/lib) and are excluded by the user-writable path filter. custom-compiled applications, developer test binaries, or container runtimes executing from /home or /tmp could theoretically reach the volume threshold during legitimate i/o-heavy workloads (large file copies, log rotation, archive operations). operators should baseline splice volume in their environment before enabling as a notable event. if false positives occur, add an allowlist of trusted binary paths via the linux_dirty_frag_kernel_privilege_escalation_filter macro, or raise the splice_count threshold based on observed legitimate-workload baseline.

Techniques

Sample rules

Linux Dirty Frag Kernel Privilege Escalation

Description

The following analytic detects exploitation of Dirty Frag (CVE-2026-43284 and CVE-2026-43500), a Linux kernel local privilege escalation vulnerability. The exploit corrupts the kernel page cache via the IPsec ESP or RxRPC subsystems using a high-frequency splice() syscall loop, followed by a privilege transition to root in the same audit session. This analytic anchors on the exploit-specific behavioral signature, a sustained splice() spray (50 or more calls within a 60-second window) from an unprivileged process executing from a user-writable path (/home, /tmp, /dev/shm, /var/tmp, /run/user, /root), followed within 5 minutes by execution of a set-uid binary in the same auditd session.

Detection logic

`linux_auditd`
type=SYSCALL
key=splice_user
exe IN (
    "/home/*",
    "/tmp/*",
    "/var/tmp/*",
    "/dev/shm/*",
    "/run/user/*",
    "/root/*"
)


| bin _time span=60s

| eval user = coalesce(user, auid, AUID)


| stats count AS splice_count
        values(exe) AS spray_binary
        values(pid) AS spray_pid
        values(user) AS user
        earliest(_time) AS spray_start
        latest(_time) AS spray_end
  BY auid host ses _time


| where splice_count >= 50


| join type=inner auid host ses [
    search `linux_auditd`
    type=SYSCALL
    key=process_creation
    exe IN (
        "/usr/bin/chfn",
        "/usr/bin/chsh",
        "/usr/bin/fusermount3",
        "/usr/bin/gpasswd",
        "/usr/bin/mount",
        "/usr/bin/newgrp",
        "/usr/bin/passwd",
        "/usr/bin/su",
        "/usr/bin/sudo",
        "/usr/bin/umount",
        "/usr/lib/dbus-1.0/dbus-daemon-launch-helper",
        "/usr/lib/landscape/apt-update",
        "/usr/lib/openssh/ssh-keysign",
        "/usr/lib/polkit-1/polkit-agent-helper-1"
    )

    
| stats earliest(_time) AS privesc_time
            values(exe) AS privesc_binary
            values(comm) AS privesc_comm
            values(ppid) AS privesc_ppid
      BY auid host ses
]


| eval window_secs = privesc_time - spray_end

| where window_secs >= 0 AND window_secs <= 300


| `security_content_ctime(spray_start)`

| `security_content_ctime(spray_end)`

| `security_content_ctime(privesc_time)`


| rename host AS dest


| table dest user auid ses spray_binary spray_pid
        splice_count spray_start spray_end privesc_binary
        privesc_comm privesc_ppid privesc_time window_secs


| `linux_dirty_frag_kernel_privilege_escalation_filter`