Skip to content

Prevent symlink-following chown in vcap-writable directories - #234

Draft
colins wants to merge 1 commit into
masterfrom
fix/TNZGOV-18900-symlink-chown-container-escape
Draft

colins wants to merge 1 commit into
masterfrom
fix/TNZGOV-18900-symlink-chown-container-escape

Conversation

@colins

@colins colins commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Overview

Problem

CreateJobPrerequisites() runs as root on the host before launching a bpm container. Previously:

  1. Additional volume paths were checked via os.Stat and chowned via os.Chown, both of which follow symlinks.
  2. Directory creation via createDirFor performed os.MkdirAll followed by os.Chown, which also followed symlinks.

Because these paths reside in or can be placed in directories writable by the vcap user (such as ephemeral data directories or log directories), a compromised container could plant a symlink to an arbitrary host file or directory (e.g. /etc or /etc/shadow). On the next bpm start or restart, root-bpm would dereference the symlink and chown the host target to vcap, enabling container escape and root escalation.

Fix

  • Added safeio.MkdirAllChown and safeio.Lchown which use os.Lstat and os.Lchown (lchown(2)) to verify targets are not symlinks and prevent following symbolic links during ownership changes.
  • Updated CreateJobPrerequisites to inspect additional volume paths with os.Lstat, rejecting symlink paths.
  • Replaced createDirFor and chownPaths with safeio.MkdirAllChown and safeio.Lchown.
  • Added comprehensive unit tests in src/bpm/safeio/safeio_test.go and src/bpm/runc/adapter/adapter_test.go.

CreateJobPrerequisites runs as root on the host before launching a
bpm container. Previously:
1. Additional volume paths were checked via os.Stat and paths were
   chowned via os.Chown, both of which follow symlinks.
2. Directory creation via createDirFor performed os.MkdirAll followed by
   os.Chown, which also followed symlinks.

Because these paths reside in or can be placed in directories writable
by the vcap user (such as ephemeral data directories or log directories),
a compromised container could plant a symlink to an arbitrary host file
or directory (e.g. /etc or /etc/shadow). On the next bpm restart, root-bpm
would dereference the symlink and chown the host target to vcap.

Fix:
- Added safeio.MkdirAllChown and safeio.Lchown which use os.Lstat and
  os.Lchown to ensure symlinks are rejected and ownership changes do not
  follow symbolic links.
- Updated CreateJobPrerequisites to verify additional volume paths with
  os.Lstat, rejecting symlink paths.
- Replaced createDirFor and chownPaths with safeio.MkdirAllChown and
  safeio.Lchown.
- Added comprehensive unit tests in safeio_test.go and adapter_test.go.

[TNZGOV-18900] ai-assisted=yes
@coderabbitai

coderabbitai Bot commented Oct 9, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant