Alpha Cyber

Below the Syscall Line: How eBPF and io_uring Rootkits Slip Past Linux EDR

Most Linux runtime security watches system calls. A growing class of stealth techniques, eBPF abuse and the io_uring asynchronous-I/O interface, does its work without the syscalls those tools hook.

Alpha Cyber Research4 min readupdated 7 Jul 2026
  • Linux Rootkits
Curing Rootkit

Bottom line. If your Linux detection relies on system-call monitoring, assume it can be blind to io_uring-based activity. This is a demonstrated technique (ARMO’s Curing proof-of-concept), not yet a confirmed in-the-wild campaign, but the gap is real today. Prioritise LSM/KRSI-based visibility, baseline and alert on anomalous io_uring use, and stop treating syscall-only telemetry as complete.

Background

io_uring is a Linux asynchronous-I/O interface introduced in 2019 with kernel 5.1. Instead of issuing a system call per operation, a process submits requests into ring buffers shared between user space and the kernel, which are serviced asynchronously. Because the work no longer flows through per-operation syscalls, security tools that monitor syscalls (via eBPF, ptrace, seccomp or kernel modules) can be completely blind to it. io_uring supports 61 operation types, file reads and writes, creating and accepting network connections, changing file permissions and reading directories, which is more than enough surface to build a full rootkit.

The risk is well established: Google disabled io_uring by default on Android and ChromeOS, and researchers (notably Daniel Teixeira at Form3 in 2022) showed it bypassing syscall monitoring years ago. In April 2025, ARMO turned the idea into a working proof-of-concept rootkit, ‘Curing’, and demonstrated the blind spot against widely used tools. Separately, eBPF. The technology most modern Linux EDRs are built on, can itself be undermined (ARMO has shown eBPF map tampering and time-of-check/time-of-use attacks), a reminder that observability instrumentation is not the same as tamper-resistant security enforcement.

What we observed

What the public research actually demonstrates:

  • Syscall-free I/O: io_uring submits operations through shared ring buffers rather than individual system calls. Its 61 op types cover file read/write, network connect/accept, file-permission changes and directory reads, enough to operate without the syscalls (openat, read, write, connect) that EDRs hook.
  • The Curing PoC: ARMO’s rootkit (written in Go and C, conceived at the 38C3 conference) pulls commands from a remote C2 and reads files, writes files and creates symbolic links entirely over io_uring. Running it under strace shows no attack-relevant syscalls; process execution is currently the one io_uring operation still blocked upstream.
  • A real tool-coverage gap: under default configuration ARMO found Falco entirely blind (even with custom rules) and Microsoft Defender for Endpoint on Linux missing sensitive-file reads, an EICAR drop, XMRig execution and a low-reputation network callout, only its fanotify-based File Integrity Monitoring caught file changes. Tetragon can detect io_uring activity but only when operators add Kprobe/LSM hooks; SentinelOne confirmed its agent was unaffected.
  • eBPF cuts both ways: most modern Linux EDRs are eBPF-based, but if they attach at the syscall layer they inherit the same blind spot. The durable fix, KRSI (Kernel Runtime Security Instrumentation), is itself eBPF attached to LSM hooks, which sit in the kernel’s enforcement path and are far harder to sidestep than syscall hooks.

How io_uring evades syscall monitoring

Deploy rootkituserland, kernel 5.1+Use io_uringring buffers, nosyscallEvade EDRsyscall hooks blindPull C2 & actread / write / symlink

The durable fix is LSM/KRSI visibility, hooks in the kernel’s enforcement path that see the operation regardless of whether a syscall was used.

Attribution

This is security research and a public proof-of-concept, not an attributed intrusion. There is no confirmed in-the-wild io_uring rootkit at time of writing, and no threat actor is named, Curing is a defensive PoC released by ARMO so teams can test their own tooling. The honest read is that this is an emerging capability with a low barrier to weaponisation (the code is public and the interface ships in every modern Linux kernel), so defenders should close the visibility gap proactively rather than wait for a confirmed campaign.

Confidence: 90%.

You cannot alert on a system call that never happens, and io_uring is built so it never happens.

Tactics, techniques & procedures (MITRE ATT&CK)

Techniques below are drawn directly from the analysed samples/reporting – no technique is asserted without evidence:

TacticTechniqueIDEvidence
Defense EvasionRootkitT1014ARMO’s Curing operates as a rootkit that performs its actions over io_uring to stay invisible to host security tooling; the same class covers eBPF-based rootkits.
Defense EvasionImpair Defenses: Indicator BlockingT1562.006io_uring performs file and network I/O via shared ring buffers, so syscall-monitoring EDRs (e.g. Falco, Defender for Endpoint) never observe the operations, telemetry is effectively suppressed at the source.
Command and ControlApplication Layer ProtocolT1071The Curing client pulls commands from a remote C2 using io_uring network operations instead of socket syscalls.
CollectionData from Local SystemT1005Curing reads local files (including sensitive paths) via io_uring read operations, bypassing read()/openat() syscall visibility.

Detection

Copy-ready hunting query:

# io_uring is *set up* via a syscall even though its operations are not -- audit the setup call.
# x86_64 syscall numbers: io_uring_setup=425, io_uring_enter=426, io_uring_register=427
auditctl -a always,exit -F arch=b64 -S io_uring_setup -S io_uring_enter -k io_uring_activity
ausearch -k io_uring_activity | aureport -syscall -summary

# Baseline + alert on unexpected io_uring users (most workloads never call it):
#   Flag any process invoking io_uring_setup that is NOT on a known-good allowlist
#   (databases, proxies and some language runtimes legitimately use io_uring).

# Prefer LSM / KRSI visibility over syscall hooks so io_uring ops are still seen:
#   Falco LSM plugin, or Tetragon with LSM + Kprobe hooks on file_open,
#   bprm_check_security and socket_connect (the kernel enforcement path).

# Reduce attack surface where io_uring is unused:
#   sysctl -w kernel.io_uring_disabled=2      # kernel 6.6+, fully disables io_uring
#   or seccomp-filter io_uring_setup/enter/register for workloads that don't need it.

Recommendations

  • Stop relying on syscall-only monitoring: add LSM-based visibility (KRSI / eBPF-on-LSM) via Falco’s LSM plugin or Tetragon’s LSM + Kprobe hooks so io_uring operations are observed in the kernel’s enforcement path.
  • Baseline io_uring usage and alert on anomalies, most workloads never touch it, so a process that suddenly starts using io_uring is a strong signal (tune out databases, proxies and runtimes that legitimately use it).
  • Disable io_uring where it is not needed: set sysctl kernel.io_uring_disabled=2 (kernel 6.6+) or seccomp-filter the io_uring_setup/enter/register syscalls; Google already disables it by default on Android and ChromeOS.
  • Validate your EDR honestly: run ARMO’s open-source Curing PoC against your stack to see what your tooling actually catches, and keep fanotify-based File Integrity Monitoring as a backstop for file changes.
  • Keep kernels patched (io_uring has a long vulnerability history) and track KRSI/LSM-hook support in your distribution as the strategic detection foundation.

Keep reading

Related research

Daxin Rootkit
Threat ReportsTLP:AMBER

Daxin Returns: A 13-Year-Old China-Linked Rootkit That Never Called Home

Symantec found the Daxin kernel rootkit still operational on a Taiwan manufacturing subsidiary in 2026, alongside a previously undocumented backdoor, Stupig, that runs SYSTEM commands from the Windows logon screen before anyone signs in.

6 min readAPT

Contact

Talk to someone who has seen this before.

You speak directly to the people doing the work, wherever in the world you operate.

Or email [email protected]