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:
- The initial permission check fails with
EACCES(no read permission) - The file is a regular file (
S_ISREG) - The operation requests read access (
NFSD_MAY_READ) - The internal NFS operation flag
NFSD_MAY_READ_IF_EXECis set - The server retries the check using
MAY_EXECinstead ofMAY_READ - 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:
- READDIRPLUS harvesting: During the export scan, READDIRPLUS returns file attributes including mode bits for every entry.
- Mode bit analysis: Files where
(mode & 0o444) == 0(no read for anyone) and(mode & 0o111) != 0(execute for someone) are flagged as candidates. - 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¶
-
Accept the behavior as inherent to NFS -- the read-if-exec fallback is required for NFS-mounted executables to function. Removing it would break
./binaryon NFS mounts. -
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.
-
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. -
Restrict export scope -- do not export directories containing sensitive execute-only files.
-
Use
root_squash-- prevents the attacker from using uid=0 to read SUID execute-only binaries owned by root.
Related findings¶
| 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 |