Skip to content

logs: refuse symlinks when opening the log file (O_NOFOLLOW) - #323

Merged
robertswiecki merged 1 commit into
google:masterfrom
h1-mrz:harden-logfile-onofollow
Sep 30, 2026
Merged

robertswiecki merged 1 commit into
google:masterfrom
h1-mrz:harden-logfile-onofollow

Conversation

@h1-mrz

@h1-mrz h1-mrz commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Add O_NOFOLLOW to the open() call in logFile() so that nsjail does not silently follow a symlink at the user-supplied --log / log_file path.

Defect

logs.cc:logFile() opens the log file with O_CREAT | O_RDWR | O_APPEND | O_CLOEXEC but no O_NOFOLLOW. If an attacker can pre-plant a symlink at the log path (race condition in /tmp, shared tmp dir, predictable path), nsjail follows the symlink and appends log lines to the symlink target via O_APPEND. The existing PLOG_W warning is logged but the write still happens against the target file.

Repro (before fix)

$ touch /tmp/target
$ ln -s /tmp/target /tmp/log
$ nsjail -l /tmp/log -- /usr/bin/true
$ cat /tmp/target    # log lines appended to /tmp/target

Repro (after fix)

$ nsjail -l /tmp/log -- /usr/bin/true
[W] logFile(): Couldn't open('/tmp/log'): Too many levels of symbolic links
$ cat /tmp/target    # unchanged

Runtime-verified on nsjail HEAD (f100fd9) on 6-core Linux.

Fix

-		    open(log_file.c_str(), O_CREAT | O_RDWR | O_APPEND | O_CLOEXEC, 0640));
+		    open(log_file.c_str(), O_CREAT | O_RDWR | O_APPEND | O_CLOEXEC | O_NOFOLLOW,
+			0640));

2 insertions, 1 deletion. logs.cc only. Matches the O_NOFOLLOW convention used elsewhere in nsjail (createDirRecursively in util.cc) and in runc / Docker / systemd-nspawn for log and cgroup file writes.

Impact

Defense-in-depth hardening. Not a vulnerability in the strict sense, but a missing standard hardening that matches the convention used by every major container runtime for log / state file writes. The same util::writeBufToFile function is used at the cgroup write sites; this PR addresses the log file path only (the cgroup paths are a follow-up).

Notes

Add O_NOFOLLOW to the open() call in logFile() so that if an attacker
plants a symlink at the path passed via --log (or via the log_file
config), nsjail does not silently follow it and append log lines to
the symlink target.

Repro (before fix):
  $ touch /tmp/target
  $ ln -s /tmp/target /tmp/log
  $ nsjail -l /tmp/log -- /usr/bin/true
  $ cat /tmp/target    # log lines appended

Repro (after fix):
  $ nsjail -l /tmp/log -- /usr/bin/true
  [W] logFile(): Couldn't open('/tmp/log'): Too many levels of symbolic links
  $ cat /tmp/target    # unchanged

Matches the O_NOFOLLOW convention used elsewhere in nsjail (e.g.
createDirRecursively in util.cc) and in runc / Docker / systemd-nspawn
for log and cgroup file writes.
@h1-mrz

h1-mrz commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

Following up on this PR — it's been open for two weeks without review. The change is narrow (one file, one line) and introduces no behavior change for valid operator configurations; . happy to coordinate or close in favor of whichever approach you'd prefer. Please let me know if any changes are needed.

@h1-mrz

h1-mrz commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Hi, just checking in on this. It's been open since Sep 3.

@robertswiecki

Copy link
Copy Markdown
Collaborator

Thank you. Yes, not a security problem imo (no crossing of privilege boundaries, unless the admin/user uses problematic paths), but sure, as a defense-in-depth we can have it.

@robertswiecki
robertswiecki merged commit 61a5a75 into google:master Sep 30, 2026
7 checks passed
zerox80 pushed a commit to zerox80/nsjail that referenced this pull request Oct 16, 2026
logs: refuse symlinks when opening the log file (O_NOFOLLOW)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants