Skip to content

fix(scripting/node): resolve symlinked resource sandbox paths#3959

Open
gtolontop wants to merge 3 commits into
citizenfx:masterfrom
gtolontop:fix/symlink-resource-sandbox
Open

fix(scripting/node): resolve symlinked resource sandbox paths#3959
gtolontop wants to merge 3 commits into
citizenfx:masterfrom
gtolontop:fix/symlink-resource-sandbox

Conversation

@gtolontop
Copy link
Copy Markdown
Contributor

Goal of this PR

Fix Node.js resources mounted through a symbolic link being unable to access their own files through require() and fs.* APIs.

The sandbox permission callback can receive a resolved native path for a symlinked resource, while the resource is mounted in VFS through its lexical symlink path. This made the permission lookup fail before the normal resource-local filesystem checks could run.

How is this PR achieving the goal

The fix teaches VFS device lookup how to map canonical native paths back to mounted resource devices, and lets the Node.js sandbox prefer the currently running resource mount when several mounts resolve to the same native path.

Key changes:

  1. Canonical VFS lookup (ManagerServer): mounted devices now cache both their lexical absolute path and their canonical absolute path at mount time. FindDevice() keeps the existing lexical fast path, and only falls back to canonical matching when a symlink/canonical mount exists.

  2. Preferred resource mount (NodeScriptRuntime): Node filesystem permission checks pass @<resourceName>/ as the preferred mount prefix, so paths resolved through a resource symlink are transformed back to the current resource VFS path.

  3. Longest-prefix semantics preserved (ManagerServer): when both lexical and canonical matches are possible, the existing VFS longest-prefix behavior is preserved. A more specific canonical mount still wins over a preferred parent mount.

  4. Regression coverage (TestLua.cpp): adds server-side VFS coverage for symlinked resources, duplicate symlinks, direct mounts, nested symlink mounts, not-yet-created file/directory paths used by write/mkdir flows, and sibling path rejection.

This keeps the sandbox resource-based instead of allowing broad native filesystem paths, while fixing the symlinked resource workflow reported in the issue.

This PR applies to the following area(s)

FXServer, ScRT: JS, VFS

Successfully tested on

  • git diff --check
  • Added C++ server regression coverage for symlinked resource VFS lookup in TestLua.cpp
  • Locally reviewed the Node sandbox path flow from NodePermissionCallback() to vfs::FindDevice()

A full local CitiTest run was not performed because this checkout does not include a generated build directory or an existing test executable.

Checklist

  • Code compiles and has been tested successfully.
  • Code explains itself well and/or is documented.
  • My commit messages explain what the changes do and what they are for.
  • No extra compilation warnings are expected from these changes.

Fixes issues

Fixes #3878

@github-actions github-actions Bot added the invalid Requires changes before it's considered valid and can be (re)triaged label May 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

invalid Requires changes before it's considered valid and can be (re)triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SANDBOXING] Node require fails when the resource is a symbolic link

1 participant