php2shell patches (CVE-2026-109618 and CVE-2026-109619) for EOL PHP are out now. With sales replies slower than usual due to high demand, the fastest route to patched packages is to buy ELS for Runtimes online (opens in new tab). Read the patch FAQ

Go straight to an AI summary of this blog post instead

  • Summarize this post with Perplexity
  • Summarize this post with Gemini

The Short Version

What: A new Linux local privilege escalation called PinTheft. It chains a refcount bug in the kernel’s RDS (Reliable Datagram Sockets) zerocopy send path with io_uring to overwrite a SUID root binary in memory. The result is a root shell from an unprivileged local account. No CVE has been assigned at the time of publication.

Impact: A public proof of concept from V12 Security gives any local unprivileged user a reliable path to root on affected hosts. The underlying bug has been latent in the Linux kernel since version 4.17, released in 2018.

Status: Aaron Esau of V12 Security, the firm credited with the discovery, disclosed PinTheft in May with a kernel patch already available. The candidate upstream fix was posted to the netdev kernel mailing list on May 5, 2026. CVE-2026-43494 was assigned, no CVSS score. See the KernelCare Rebootless Patch section below for current status.

Severity: Local vector; requires the ability to run code on the host as any local user; no user interaction. Practical exploitability requires all of the following on the target: RDS and RDS_TCP available and loadable, io_uring enabled, a readable SUID-root binary, and an x86_64 payload (the PoC is architecture-specific even though the technique is not). V12 stated that, among common distributions they tested, RDS was default-loadable only on Arch Linux. Other distributions ship the module blocked from autoloading or do not build it at all.

Why this matters: The exploit chain is reliable, the proof of concept is public, and there is no CVE or formal vendor advisory yet. Multi-tenant Linux systems (shared hosting, CI runners, container hosts) on the affected distributions should be treated as immediately at risk.

Do this now: If your host does not run an RDS workload – and most don’t – block the rds and rds_tcp modules with a modprobe rule. If io_uring is not required and your kernel is 6.6 or newer, you can additionally disable it with one sysctl. Mitigation commands and the older-kernel fallback are below.

Don’t want a fifth emergency reboot window this month?
KernelCare applies rebootless Linux kernel patches without
downtime or disruptions.

*Update (2026-05-21, 12 PM UTC): KernelCare patches for all distros (excluding Debian 12 and Proxmox8) were promoted to the main feed.

The Long Version

V12 Security published the PinTheft proof of concept and a technical writeup in May 2026. Aaron Esau is credited with the discovery. The flaw itself has been sitting in the Linux kernel since version 4.17 in 2018, but the exploit chain depends on io_uring features that did not exist when the bug was introduced.

The candidate kernel fix went out to the netdev mailing list on May 5, 2026. Downstream distribution kernels are still picking it up. KernelCare engineering is preparing rebootless patches for affected supported kernels.

Some early coverage tied PinTheft specifically to kernel 6.13 and later. That reflects the released PoC’s dependencies, not the lifetime of the underlying bug – the refcount issue in the RDS zerocopy path is much older, but a working exploit chain mirroring the PoC still requires recent io_uring features.

How the Exploit Works

When a program sends data over a network socket, the kernel normally copies that data from the program’s memory into kernel buffers. To save CPU cycles, modern kernels also offer “zerocopy” sending: the kernel locks the user’s memory pages and uses them directly. RDS, a less common protocol intended for high-performance datacenter networking, supports this zerocopy mode.

The bug is in how RDS cleans up after a zerocopy send fails partway through. The kernel ends up releasing the same pages twice instead of once. Each failed send steals one reference from the first user page.

On its own, that is just a small bookkeeping bug. PinTheft turns it into a root exploit through io_uring, the modern Linux async I/O interface. io_uring lets a program register a memory page as a fixed buffer, which adds 1,024 references to the page. The attacker then forces 1,024 failing RDS zerocopy sends to silently drain all those references. The kernel now thinks no one is using the page and frees it, but io_uring still holds a pointer to it.

Next, the attacker reads any SUID root binary. The kernel loads that binary into the same freed page in its page cache. A single io_uring write to the stale buffer overwrites the binary in memory with shellcode. Running the SUID binary now drops the user into a root shell.

The on-disk file is untouched. The page cache copy in memory is what gets overwritten. That matters for cleanup, covered in the mitigation section.

The latent refcount bug appears to date back to the introduction of RDS zerocopy support in Linux 4.x. Reliable exploitation as shown in the PoC additionally depends on more recent io_uring features (notably IORING_REGISTER_CLONE_BUFFERS, available from 6.12), so although the bug is old, the practical exploit window is narrower.

Who Is Affected

The single property that matters is whether the running kernel can load the RDS modules, not the distribution name. Check kernel config and module-loading policy directly using the commands in the next section.

Default-loadable RDS (confirmed by the researchers): Arch Linux.

RDS module shipped but blocked from autoloading by default: Ubuntu (all currently supported releases, via a blacklist file in the kmod package), Debian 11 and 12 (via a Debian-specific patch that disables RDS autoload as a local-exploit mitigation), Fedora (CONFIG_RDS=m, but the module ships in kernel-modules-extra and includes its own blacklist file). On these systems the PoC requires an administrator or workload to deliberately load rds_tcp first. Independent testing also reports that loading the module on a stock Debian-derived system is not always sufficient for the PoC to succeed, so behaviour varies.

Needs vendor- or config-specific verification: Amazon Linux 2023, openSUSE Tumbleweed, Proxmox VE 7/8/9, Oracle Linux UEK 6 and 7. Check CONFIG_RDS in /boot/config-$(uname -r) and look for vendor-supplied modprobe rules under /etc/modprobe.d/ and /lib/modprobe.d/.

Not affected: RHEL, AlmaLinux, Rocky Linux, and CentOS Stream 8/9/10 running the stock Red Hat Compatible Kernel — these builds do not include RDS. RHEL 9 and 10 also disable io_uring by default, removing the other half of the chain.

One caveat that overrides everything above: any host running a custom or alternative kernel may behave differently from its parent distribution. Oracle Linux UEK in particular often runs alongside the RHCK and is in a different posture.

Mitigate Now

There are two practical mitigations. Choose based on whether your host actually uses RDS or io_uring.

Recommended for most hosts: block the RDS modules

The vast majority of Linux servers do not use RDS. It is mostly found in Oracle clusterware and some HPC InfiniBand setups. On any host that does not run an RDS workload, the simplest fix is to stop the rds and rds_tcp modules from loading.

sudo sh -c "printf 'install rds /bin/false\ninstall rds_tcp /bin/false\n' > /etc/modprobe.d/pintheft.conf"
sudo rmmod rds_tcp rds 2>/dev/null || true

The exploit overwrites the SUID binary in memory only. The file on disk is unchanged. On any host that may have been targeted before mitigation, drop the page cache to flush out any in-memory modifications:

sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'

Revert after the kernel patch or KernelCare livepatch is applied:

sudo rm /etc/modprobe.d/pintheft.conf

If you run RDS workloads (Oracle clusterware, certain HPC stacks), do not apply this mitigation. Use the io_uring alternative below or wait for the patched kernel.

Alternative: disable io_uring system-wide

The kernel.io_uring_disabled sysctl is available on Linux 6.6 and newer. Distribution kernels older than that — including Ubuntu 22.04 (5.15), Debian 11 (5.10) and 12 (6.1), Amazon Linux 2023 (6.1), RHEL 9 (5.14), and Ubuntu 24.04 (6.8 — check your point release) — do not expose this sysctl.

On those kernels, blocking the RDS modules is the practical option. Disabling io_uring entirely on older kernels requires a boot parameter or a kernel rebuild and is generally not worth the effort compared to blocking RDS.

If io_uring is not required by your workloads, shut down the other half of the exploit chain instead.

sudo sysctl -w kernel.io_uring_disabled=2

This is the default setting on RHEL 10 and is the reason that distribution family stays out of scope regardless of RDS state. Note that disabling io_uring can affect some modern database engines and async I/O workloads. Validate in your environment before applying.

Persist across reboots:

echo 'kernel.io_uring_disabled = 2' | sudo tee /etc/sysctl.d/99-pintheft.conf
sudo sysctl --system

Defence in depth on hardened hosts

If your workload does not load kernel modules at runtime, setting kernel.modules_disabled=1 after boot prevents any further modprobe call from succeeding, which closes the autoload path for RDS and every other module at once.

This is more aggressive than blacklisting RDS specifically and should only be used where no runtime module loading is expected (no hot-plug hardware, no on-demand filesystem or networking modules, no container runtimes that load modules on first use).

sudo sysctl -w kernel.modules_disabled=1

Note that this setting is a one-way switch within a boot – it cannot be cleared back to 0 without rebooting. Validate in a non-production environment before rolling out.

Check whether your host is exposed

Run the three checks below and compare the results to the criteria at the end of this section.

  1. Is RDS available in the kernel build?
    grep -E 'CONFIG_(RDS|RDS_TCP|IO_URING)' /boot/config-$(uname -r)
    modprobe -n -v rds_tcp
    ls /lib/modules/$(uname -r)/kernel/net/rds/ 2>/dev/null
  2. Is io_uring enabled?
    cat /proc/sys/kernel/io_uring_disabled
  3. Are the modules already blacklisted?
    grep -rEn '^\s*(blacklist|install)\s+rds' /etc/modprobe.d/ /etc/modules-load.d/ 2>/dev/null

A host is a viable target only if all of the following are true: CONFIG_RDS and CONFIG_RDS_TCP are available, io_uring_disabled is 0, and the rds and rds_tcp modules are not blacklisted.

KernelCare Rebootless Patch

This section is updated as patches land. Check the timestamp on the update line at the top of the post.

Status as of 2026-05-21, 12 PM UTC: KernelCare patches for all distros (excluding Debian 12 and Proxmox8) were promoted to the main feed.

Once available in the testing feed:

kcarectl --update --prefix test

After validation, the patch arrives on the next scheduled run, or pull it on demand:

kcarectl --update

Verify the patch is applied. Once a CVE is assigned, check with:

kcarectl --patch-info | grep CVE-XXXX-XXXXX   # replace with the CVE

What to Watch as This Develops

  • CVE assignment (none at the time of writing)
  • A formal advisory from V12 Security or the kernel security team
  • Distribution kernel updates from Ubuntu, Debian, Amazon Linux, openSUSE, Oracle, and Proxmox
  • KernelCare patch release across supported kernel lines

This post will be updated when the CVE is assigned and as KernelCare patches move from testing to stable. KernelCare customers will receive the patch automatically once it is promoted to the main feed.

Patch every kernel, no reboot required

If you are not yet a KernelCare user, now is a good time to see how rebootless patching can protect critical Linux systems without emergency maintenance windows or downtime.

Learn more about KernelCare here →

Join 4,500+ Linux & Open Source Professionals!

2x a month. No spam.

Table of Contents
Get the open-source security answers you need

Join 4,500+ Linux & Open Source Professionals!

2x a month. No spam.