Cloudanix VulnDB

CVE-2026-98978

High · 8.4

CVSS

8.4

EPSS

0.2%

Published

Oct 23, 2026

CISA due date

—

Cloudanix analysis

Next patch cycle SSVC: Track

A recent Linux kernel bug lets someone with local access peek at files that were supposed to stay hidden behind special locked mounts used for isolation.

Exploitation
Local Privilege
Attacker needs
Low Privilege
Complexity
Low
Impact
Data Exposure
Component
OS kernel
Class
Authorization Bypass
Remediation
Upgrade
Effort
Medium
Patch risk
Low

What it actually does

The flaw allows shrink_submounts() to expire locked mounts that protect hidden files and directories, even though do_umount() correctly refuses such operations, enabling revelation of covered paths after MOVE_MOUNT_BENEATH operations in user namespaces.

Why it matters to the business

Attackers with local access can bypass mount-based isolation to read protected files, increasing risk of data exposure in container, namespace, or multi-tenant Linux environments; low immediate urgency given recent publication and minimal observed exploitation.

How an attack unfolds

An attacker in a user namespace creates a hidden mount, uses MOVE_MOUNT_BENEATH to place a locked mount underneath, then triggers umount on an ancestor; the kernel incorrectly expires the locked child first, exposing the covered directory contents before the lock can prevent it.

How to fix it

Apply the upstream Linux kernel commit that prevents mark_mounts_for_expiry and lock_mnt_tree from placing locked mounts on expiry lists; rebuild and deploy updated kernels across all affected systems; until patched, restrict unprivileged user namespace creation where feasible.

How to confirm the fix worked

Verify the fix by confirming locked mounts remain unexpired after MOVE_MOUNT_BENEATH and ancestor umount attempts return EBUSY; test with reproducer sequences exercising user-namespace mount locking and check kernel source for the added assert in mark_mounts_for_expiry.

Typical attack path

  1. Obtain local access inside a user namespace
  2. Create a mount tree with a hidden directory containing sensitive content
  3. Perform MOVE_MOUNT_BENEATH to position a locked mount beneath an ancestor
  4. Issue umount on the unlocked ancestor to trigger expiry
  5. Read the now-revealed hidden files or directories

How to detect it

Review kernel audit logs and system call traces for sequences involving MOVE_MOUNT_BENEATH followed by umount2 on ancestor mounts that result in unexpected EBUSY or successful unmount of locked children; correlate with user-namespace creation events.

What your security team should do

  • Prioritize kernel updates on systems using user namespaces or containers within the next patch cycle
  • Audit workloads that create mounts inside user namespaces for exposure risk
  • Monitor mount-related system calls in high-value environments until patches are applied

The record

In the Linux kernel, the following vulnerability has been resolved: namespace: never expire a locked mount Locked mounts are special. They protect the underlying files and directories from being revealed. do_umount() refuses to unmount locked mounts but shrink_submounts() doesn't. A shrinkable mount can become locked once the owner of a user namespace puts it beneath a locked mount with MOVE_MOUNT_BENEATH. The locked property now moves to the mount at the bottom making it possible to unmount the top mount. So umount() of an unlocked ancestor now expires the bottom mount first and the covered directory is revealed: move_mount(c -> x/hidden, MOVE_MOUNT_BENEATH) = 0 the cover after the lock moved: umount2(x/hidden) = 0 the holder of the lock: umount2(x/hidden) = EINVAL the root of the copy, busy: umount2(x) = EBUSY reads x/hidden/secret: "covered-by-root" So leave a locked mount alone as it dies together with its parent. A plain umount() of an unlocked mount with a locked one below it is EBUSY from now on. It's the same for any other locked child. A lazy umount still takes the whole tree. mark_mounts_for_expiry() never sees a locked mount. lock_mnt_tree() leaves a mount on an expiry list alone and nothing else puts a locked one on such a list. Add an assert for this.

Affected packages

Ecosystem Package Introduced Fixed