diff --git a/lib/ffi.js b/lib/ffi.js index f3295ad0ee7..d58922d7c9b 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 b8127587d4e..2d6529cf827 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 ff4a4ef3a67..286cde45800 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', () => {