Skip to main content

Free 30-min security demo Book Now

Offensive360 Offensive360
ZeroDays CVE-2026-18107
High CVE-2026-18107 CVSS 7.8 CRIU (Checkpoint/Restore In Userspace) C

CRIU rseq Credential Spoof

CVE-2026-18107: A CRIU rseq race lets a container process hijack parasite injection to spoof credentials, gaining elevated capabilities on restore.

Offensive360 Research Team
Affects: < 4.1 (fix introduced in PR #3097)
Source Code

Overview

CVE-2026-18107 is a credential-spoofing vulnerability in CRIU (Checkpoint/Restore In Userspace), the Linux tool used by container runtimes—including Podman and Kubernetes/OpenShift via the kubelet checkpoint API—to snapshot and restore running processes. The flaw lives at the intersection of two complex kernel features: CRIU’s parasite code injection mechanism and the kernel’s restartable sequences (rseq) subsystem introduced in Linux 4.18. A malicious process inside a container can deliberately craft an rseq critical section that survives into CRIU’s injection window, causing CRIU’s parasite to execute attacker-controlled code that overwrites the credential structures saved in the checkpoint image. When that image is later restored, the revived container process holds zeroed UIDs/GIDs and an inflated capability set.

The vulnerability was identified during an audit of CRIU’s rseq state-serialization path. It affects any deployment where CRIU is used to checkpoint containerized workloads—most practically Podman with --checkpoint on RHEL/CentOS/Fedora hosts and OpenShift clusters running 4.17+ with the kubelet checkpoint API enabled. Red Hat’s own advisory notes that real-world exploitation is substantially constrained by the requirement for root or cluster-admin privileges to initiate a checkpoint, by SELinux type enforcement, and by user namespace scoping on OpenShift; nevertheless the underlying primitive is architecturally significant and the CVSS 7.8 HIGH rating reflects worst-case impact in environments where those controls are absent or misconfigured.

Because CRIU is also consumed transitively by tools like runc --checkpoint, LXC/LXD, and various HPC migration frameworks, the affected surface extends beyond pure container deployments to any environment using live process migration on a Linux host.

Technical Analysis

CRIU checkpoints a process by injecting a small “parasite” shared library directly into the target process’s address space. The injection sequence is roughly:

  1. ptrace(PTRACE_SEIZE) the target.
  2. Locate a suitable code cave or mmap a new region in the target.
  3. Write parasite blob, redirect RIP/PC to parasite entry, and PTRACE_CONT.
  4. Parasite runs inside the target context, serializing memory maps, file descriptors, credentials, and signal state to image files.
  5. CRIU recaptures the target and restores original register state.

Restartable sequences (rseq) complicate step 3. An rseq critical section is a short code region the kernel guarantees will either complete atomically on the current CPU or be rewound to a defined abort handler. The kernel tracks the currently active rseq critical section via a per-thread struct rseq registered with sys_rseq. CRIU must serialize this structure and quiesce any active critical section before the parasite can safely run.

The vulnerable code path failed to verify that the abort IP recorded in the rseq structure actually fell within the target process’s legitimate text mappings before redirecting execution:

/* VULNERABLE: criu/parasite.c (simplified, pre-patch) */
static int parasite_fixup_rseq(struct parasite_ctl *ctl,
                                struct thread_ctx *ctx)
{
    struct rseq_cs *rseq_cs = ctx->rseq_cs;

    if (!rseq_cs)
        return 0;

    /*
     * If an rseq critical section is active, redirect to the
     * registered abort_ip so the critical section is cleanly exited
     * before we hand control to the parasite.
     */
    ctx->regs.ip = rseq_cs->abort_ip;   /* <-- abort_ip not validated */
    return 0;
}

A malicious process can register an rseq structure whose abort_ip points into a payload it has mapped in its own address space. When CRIU’s injection logic fires, it sets the instruction pointer to that attacker-controlled address before the parasite takes over. The attacker’s stub then runs with parasite-level access to the process’s credential structures and image FDs:

/* Attacker stub mapped at abort_ip */
void __attribute__((noreturn)) evil_abort_handler(void)
{
    /* At this point we execute inside the CRIU parasite context.
     * The parasite's image FD for creds is accessible via the
     * shared parasite args page. Overwrite uid/gid/caps. */
    struct parasite_dump_creds_args *creds = parasite_args_ptr();
    creds->uids[0] = creds->uids[1] = creds->uids[2] = creds->uids[3] = 0;
    creds->gids[0] = creds->gids[1] = creds->gids[2] = creds->gids[3] = 0;
    creds->cap_eff = CAP_FULL_SET;
    creds->cap_prm = CAP_FULL_SET;
    creds->cap_inh = CAP_FULL_SET;
    /* Return into the real parasite entry to avoid detection */
    parasite_entry();
}

Because the parasite writes those credential values verbatim into the checkpoint image, a subsequent criu restore replays a process that the kernel believes has UID 0 and a full effective capability set.

Impact

An attacker who can influence checkpoint behavior—for example, a malicious workload in a shared Podman host where an administrator routinely checkpoints jobs—can escalate from a restricted container process to root-equivalent capabilities within the restored container. In environments without user namespaces, those capabilities are host-scoped, enabling full container escape via CAP_SYS_ADMIN, CAP_NET_ADMIN, or CAP_DAC_OVERRIDE.

In hardened deployments (OpenShift with default user namespaces, SELinux enforcing, seccomp), the blast radius is reduced: capabilities remain namespace-scoped, SELinux container_t blocks privilege transitions, and seccomp filters are not corruptible through this path. However, lateral movement within the cluster namespace or disruption of co-located workloads remains feasible.

The CVSS 7.8 score (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) correctly reflects the local-access precondition but high confidentiality, integrity, and availability impact once the checkpoint is triggered by a privileged operator.

How to Fix It

The patch (CRIU PR #3097) introduces bounds validation of abort_ip against the target process’s known executable mappings before using it to redirect execution:

/* FIXED: criu/parasite.c (post-patch, simplified) */
static int parasite_fixup_rseq(struct parasite_ctl *ctl,
                                struct thread_ctx *ctx)
{
    struct rseq_cs *rseq_cs = ctx->rseq_cs;

    if (!rseq_cs)
        return 0;

    /* Validate abort_ip falls within a known executable VMA */
    if (!vma_area_is_valid(ctl->vmas, rseq_cs->abort_ip, PROT_EXEC)) {
        pr_err("rseq abort_ip %#llx outside executable mappings — "
               "aborting checkpoint\n",
               (unsigned long long)rseq_cs->abort_ip);
        return -EINVAL;
    }

    ctx->regs.ip = rseq_cs->abort_ip;
    return 0;
}

Additionally, CRIU now re-reads and cross-checks the credential structures written by the parasite against a kernel-authoritative snapshot obtained via /proc/<pid>/status before sealing the image, making post-parasite tampering detectable.

Upgrade commands:

# Fedora / RHEL with EPEL
sudo dnf upgrade criu

# Debian / Ubuntu
sudo apt-get update && sudo apt-get install --only-upgrade criu

# Build from source (minimum fix branch)
git clone https://github.com/checkpoint-restore/criu.git
cd criu && git fetch origin pull/3097/head:fix-rseq && git checkout fix-rseq
make -j$(nproc) && sudo make install

Until patched, consider disabling rseq support in workloads that will be checkpointed (LD_PRELOAD a stub that skips sys_rseq registration) or restricting checkpoint privileges to dedicated, audited service accounts.

Our Take

This vulnerability is a case study in feature interaction debt. Neither CRIU’s parasite injection nor the kernel’s rseq subsystem is individually flawed; the bug emerges when a new kernel primitive is added to an existing, complex injection workflow without adversarial review of the handoff boundary. We see this pattern repeatedly in system-level tooling: the original security model is sound, but each incremental kernel feature enlarges the attack surface in ways the original authors did not anticipate.

For enterprises relying on CRIU-based live migration—whether for stateful container mobility, HPC job scheduling, or forensic checkpointing—the lesson is that checkpoint/restore deserves the same threat-modeling rigor as container runtime itself. The privilege requirement (root/cluster-admin) provides meaningful defense-in-depth today, but it should not be treated as a permanent substitute for fixing the primitive.

Detection with SAST

This class of vulnerability—unvalidated attacker-controlled pointer used as a code-transfer target inside a privileged injection path—maps to CWE-822 (Untrusted Pointer Dereference) and CWE-123 (Write-what-where Condition). SAST detection focuses on two patterns:

  1. Unvalidated field dereference from external structures: dataflow from ptrace-read memory or user-space-supplied structs directly to instruction-pointer assignment (ctx->regs.ip = <tainted>) without an intervening range check against a trusted VMA list.
  2. Missing integrity verification after parasite execution: absence of a cross-check between parasite-written image data and an authoritative kernel source (/proc/pid/*) before the image is finalized.

Offensive360’s SAST engine tracks taint from ptrace(PTRACE_PEEKDATA/PTRACE_GETREGSET) calls and flags any path where tainted data reaches a register-assignment sink (ctx->regs.ip, ctx->regs.rip, or equivalent arch-specific fields) without a validated bounds assertion. The rule category is PTR_TAINT / CODE_TRANSFER and fires at HIGH confidence when the tainted value originates from a remotely influenced structure (rseq, signal frames, auxiliary vectors) in a process that performs subsequent code injection.

References

#container-security #privilege-escalation #checkpoint-restore #linux-capabilities

Detect this vulnerability class in your codebase

Offensive360 SAST scans your source code for CVE-2026-18107-class vulnerabilities and thousands of other patterns — across 60+ languages.