Watch out for any Linux malware sneakily evading syscall-watching antivirus
A proof-of-concept program has been released to demonstrate a so-called monitoring “blind spot” in how some Linux antivirus and other endpoint protection tools use the kernel’s io_uring interface.
That interface allows applications to make IO requests without using traditional system calls. That’s a problem for security tools that rely on syscall monitoring to detect threats.
Rather than making a system call for each request, these operations – such as reading and writing files – are queued in ring buffers that the kernel rattles through and returns the results in separate buffers. Antivirus that watches syscalls for malicious activity may miss changes that are instead going through the io_uring queues.
To demonstrate this, security shop ARMO built a proof-of-concept named Curing that lives entirely through io_uring. Because it avoids system calls, the program apparently went undetected by tools including Falco, Tetragon, and Microsoft Defender in their default configurations. ARMO claimed this is a “major blind spot” in the Linux security stack.
The io_uring interface was introduced in Linux kernel version 5.1, released in 2019. It was, technically speaking now, designed to enhance performance by enabling asynchronous I/O operations between user space and the Linux kernel through shared ring buffers. This architecture reduces the number of system calls required for I/O operations and minimizes the overhead associated with frequent transitions between user space and kernel space.
“Not many companies are using it but you don’t need to be using it for an attacker to use it as enabled by default in most Linux systems, potentially tens of thousands of servers,” ARMO’s CEO Shauli Rozen told The Register. “If you’re not using io_uring then disable it, but that’s not always easy with cloud vendors.”
While syscalls are required to set up io_uring buffers, these management calls look entirely innocent, and the actual malicious activity happens out of sight in the queues. You can see a demonstration of the code in the video below.
We guess antivirus could be updated to flag up any io_uring set-up as potentially harmful; or it could be updated to reach into the kernel, perhaps via eBPF, to monitor io_uring; or you could just switch off the feature if it’s not needed. On a recent-enough kernel, seemingly since version 6.6, use this command to disable the interface:
sysctl -w kernel.io_uring_disabled=2
“Many vendors take the most straightforward path: Hooking directly into system calls,” said Amit Schendel, head of security research at ARMO, in a write-up about the interface.
“While this approach offers quick visibility, it comes with limitations. Most notably, system calls aren’t always guaranteed to be invoked. io_uring, which can bypass them entirely, is a positive and great example.”
We reached out to the antivirus vendors named in ARMO’s report. Falco acknowledged the issue and said a fix is in the works. Tetragon claimed the attack is detectable, though not with the default settings most users rely on. As for Redmond:
Microsoft Defender has detections in place to detect and block this threat activity. As a security best practice, we encourage customers to enable always-on protection in Microsoft Defender, and to exercise caution when downloading files from unknown sources as indicated in security warnings, which have been designed to recognize and warn users about potentially harmful files.
Meanwhile, over at Google, patience with io_uring ran out a while ago. In mid-2023, the tech giant disabled it entirely in ChromeOS, restricted its use on Android via seccomp and SELinux policies, and removed it from production servers. The clampdown came after Google shelled out around $1 million in bug bounties linked to io_uring flaws.
Of course, ARMO has also proposed ways to detect malware abusing io_uring. The code for Curing is available on GitHub. ®
READ MORE HERE