Skip to content

F-5.9: Execute-Only File Content Disclosure (Read-If-Exec Fallback)

Classification

  • Severity: Low
  • CVSS Vector: Network / Low Complexity / Low Privileges Required
  • Affected Versions: NFSv2, NFSv3, NFSv4 on Linux knfsd
  • RFC Reference: None (implementation-specific; no RFC requires or describes this behavior)
  • Prerequisite: File has execute permission but no read permission (e.g., mode 0111, 0110, 0100)
  • Kernel Code: fs/nfsd/vfs.c:nfsd_permission():2894-2898

Summary

Linux knfsd implements a "read-if-exec" fallback in its permission check: when an NFS READ request is denied because the caller lacks read permission, the server checks whether the caller has execute permission on the file instead. If execute is granted, the READ succeeds and the full file contents are returned to the client. This is intentional -- the server assumes that a client needs to download an executable before it can run it locally. But the behavior violates the POSIX permission model, where mode 0111 means "execute but not read." An attacker with execute-only access to a file can retrieve its full contents over NFS, even though cat on the server itself would return EACCES.

Technical detail

The permission fallback path

In fs/nfsd/vfs.c, the function nfsd_permission() handles access checks for all NFS operations. The read-if-exec fallback is:

/* Line 2894-2898 */
if (err == -EACCES && S_ISREG(inode->i_mode) &&
    (acc & NFSD_MAY_READ) && (acc & NFSD_MAY_READ_IF_EXEC)) {
    err = inode_permission(idmap, inode, MAY_EXEC);
}

The logic:

  1. The initial permission check fails with EACCES (no read permission)
  2. The file is a regular file (S_ISREG)
  3. The operation requests read access (NFSD_MAY_READ)
  4. The internal NFS operation flag NFSD_MAY_READ_IF_EXEC is set
  5. The server retries the check using MAY_EXEC instead of MAY_READ
  6. If execute permission is granted, the read proceeds

The NFSD_MAY_READ_IF_EXEC flag is set by the NFSv3 READ procedure handler and the NFSv4 READ operation handler. It is not set for READDIR, READLINK, or other data-returning operations.

POSIX permission model violation

On a local filesystem, the distinction between read and execute is clear:

Permission Local Behavior NFS Behavior
r-- (0400) cat succeeds, ./file fails READ succeeds
--x (0100) cat fails, ./file succeeds READ succeeds (fallback)
--- (0000) Both fail READ fails
r-x (0500) Both succeed READ succeeds

The NFS server treats --x identically to r-x for READ operations. A file set to mode 0111 (execute-only for everyone) is fully readable over NFS by anyone.

Why this exists

The rationale is practical: NFS clients cannot execute a remote binary without first downloading it. When a user runs ./binary on an NFS-mounted filesystem, the kernel's ELF loader issues READ calls to fetch the binary's contents into memory. If the NFS server denied READ on an execute-only file, no NFS-mounted executable could run unless it also had read permission.

This is a deliberate trade-off: the server sacrifices the read/execute distinction to make NFS-mounted executables usable.

Files affected in practice

Execute-only files without read permission are uncommon but not nonexistent:

File Type Typical Mode Purpose of Execute-Only
SUID binaries 4111 Prevent reverse-engineering of privileged logic
License-checked executables 0111 Obscure proprietary binary internals
Wrapper scripts with embedded secrets 0111 Prevent reading credentials while allowing execution
Security tools 0110 Restrict to group members, hide implementation

Exploitation

1. READDIRPLUS on a directory -> enumerate entries with file attributes
2. Identify files with execute permission but no read permission (mode & 0444 == 0 && mode & 0111 != 0)
3. READ the file -> full contents returned despite no read permission
4. Examine binary for hardcoded credentials, cryptographic keys, or exploitable logic

No special credentials are needed beyond whatever identity grants execute permission. If the file is mode 0111 (execute for all), AUTH_SYS with any uid/gid suffices.

Impact

  • Binary content disclosure: Proprietary or security-sensitive executables can be downloaded and reverse-engineered
  • Secret extraction: Wrapper scripts or binaries with embedded credentials (API keys, database passwords, encryption keys) are exposed
  • SUID binary analysis: SUID binaries set to execute-only to prevent reverse-engineering are fully readable, enabling offline vulnerability research
  • Practical severity is low: Few files are deliberately set to execute-only, and the contents of most executables are not sensitive. The finding is primarily relevant in environments that rely on the read/execute distinction for security.

Detection (nfswolf)

The analyzer detects this condition by:

  1. READDIRPLUS harvesting: During the export scan, READDIRPLUS returns file attributes including mode bits for every entry.
  2. Mode bit analysis: Files where (mode & 0o444) == 0 (no read for anyone) and (mode & 0o111) != 0 (execute for someone) are flagged as candidates.
  3. READ confirmation: A READ call on the flagged file confirms that the server returns file contents despite the absence of read permission.

The check does not modify any files and only reads the first 4096 bytes to confirm the behavior.

Remediation

  1. Accept the behavior as inherent to NFS -- the read-if-exec fallback is required for NFS-mounted executables to function. Removing it would break ./binary on NFS mounts.

  2. Do not rely on the read/execute distinction for security on NFS exports -- if a binary must not be readable, do not export it via NFS. Keep it on a local filesystem.

  3. Use Kerberos (sec=krb5p) -- prevents credential spoofing, limiting the attacker to their legitimate identity. The read-if-exec fallback still applies, but the attacker can only read files they have legitimate execute permission on.

  4. Restrict export scope -- do not export directories containing sensitive execute-only files.

  5. Use root_squash -- prevents the attacker from using uid=0 to read SUID execute-only binaries owned by root.

Finding Relationship
F-5.6: Metadata on Access Denial Mode bits in post_op_attr reveal execute-only files as targets
F-5.2: READDIRPLUS Harvesting READDIRPLUS provides file attributes used to identify candidates
F-4.2: SUID/SGID Escalation SUID binaries set to execute-only are readable, enabling offline analysis
F-1.1: UID/GID Spoofing Spoofed credentials may grant execute permission needed to trigger the fallback