From 3c967f777a56165a7de1279c4720c9f34401181f Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Mon, 9 Nov 2026 13:34:30 -0800 Subject: [PATCH] ffi: check permission before reading VFS library new DynamicLibrary(path) read a library inside a mounted VFS before the native --allow-ffi check ran, so a missing VFS path threw ENOENT instead of ERR_ACCESS_DENIED. Check the permission first, as ffi.dlopen() does. Also correct a comment that claimed dlopen errors report the library's own path. Signed-off-by: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Assisted-by: claude:opus-5.5 --- lib/ffi.js | 1 + src/node_ffi.cc | 5 +++-- test/ffi/test-ffi-permissions.js | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/ffi.js b/lib/ffi.js index f3295ad0ee77..d58922d7c9b0 100644 --- a/lib/ffi.js +++ b/lib/ffi.js @@ -135,6 +135,7 @@ function DynamicLibrary(path) { // Let the native constructor produce its usual error. return FunctionPrototypeCall(NativeDynamicLibrary, this, path); } + checkFFIPermission(); const readVirtualLibrary = getVfsLibraryReader(); const binary = readVirtualLibrary === null || typeof path !== 'string' ? diff --git a/src/node_ffi.cc b/src/node_ffi.cc index b8127587d4e5..2d6529cf827f 100644 --- a/src/node_ffi.cc +++ b/src/node_ffi.cc @@ -614,8 +614,9 @@ void DynamicLibrary::New(const FunctionCallbackInfo& args) { // that lives somewhere the dynamic loader cannot open by path (a virtual // file system). Materialize them into a private, self-cleaning image - the // same mechanism process.dlopen() uses for such native addons - and load - // that, while still reporting the library's own path in `library.path` and - // any error. + // that. `library.path` and errors from materializing the image report the + // library's own path; a dlopen failure reports the image's path, as given + // by the dynamic loader. binding::AddonImage image; if (args.Length() > 1 && !args[1]->IsUndefined()) { if (!args[1]->IsArrayBufferView()) { diff --git a/test/ffi/test-ffi-permissions.js b/test/ffi/test-ffi-permissions.js index ff4a4ef3a67b..286cde458003 100644 --- a/test/ffi/test-ffi-permissions.js +++ b/test/ffi/test-ffi-permissions.js @@ -1,4 +1,4 @@ -// Flags: --permission --allow-fs-read=* +// Flags: --permission --allow-fs-read=* --allow-fs-vfs 'use strict'; const common = require('../common'); const assert = require('node:assert'); @@ -27,6 +27,10 @@ test('permission model blocks dynamic library access', () => { assert.throws(() => { new ffi.DynamicLibrary(dummyLibraryPath); }, denied); + const vfsLibraryPath = `${require('node:vfs').create().mount()}/missing.so`; + assert.throws(() => { + new ffi.DynamicLibrary(vfsLibraryPath); + }, denied); }); test('permission model blocks ffi memory and helper APIs', () => {