From 81501012078250fe50655fc6652f8a469be4d790 Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Fri, 14 Aug 2026 07:56:24 -0700 Subject: [PATCH] ffi: validate DynamicLibrary getter receivers Bind the path, symbols, and functions getter templates to the DynamicLibrary constructor signature. This causes V8 to reject incompatible receivers before invoking the native callbacks, preventing them from crashing the process. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: codex:gpt-5.6-sol --- src/node_ffi.cc | 11 ++++++++--- test/ffi/test-ffi-dynamic-library.js | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/node_ffi.cc b/src/node_ffi.cc index 7e3da95b958..88327f1f1c4 100644 --- a/src/node_ffi.cc +++ b/src/node_ffi.cc @@ -35,6 +35,7 @@ using v8::MaybeLocal; using v8::Object; using v8::PropertyAttribute; using v8::ReadOnly; +using v8::Signature; using v8::String; using v8::TryCatch; using v8::Value; @@ -1238,16 +1239,19 @@ Local DynamicLibrary::GetConstructorTemplate( tmpl = NewFunctionTemplate(isolate, DynamicLibrary::New); tmpl->InstanceTemplate()->SetInternalFieldCount( DynamicLibrary::kInternalFieldCount); + Local signature = Signature::New(isolate, tmpl); tmpl->InstanceTemplate()->SetAccessorProperty( env->path_string(), - FunctionTemplate::New(env->isolate(), DynamicLibrary::GetPath), + FunctionTemplate::New( + isolate, DynamicLibrary::GetPath, Local(), signature), Local(), attributes); tmpl->InstanceTemplate()->SetAccessorProperty( FIXED_ONE_BYTE_STRING(isolate, "symbols"), - FunctionTemplate::New(env->isolate(), DynamicLibrary::GetSymbols), + FunctionTemplate::New( + isolate, DynamicLibrary::GetSymbols, Local(), signature), Local(), attributes); @@ -1257,7 +1261,8 @@ Local DynamicLibrary::GetConstructorTemplate( // reason. tmpl->PrototypeTemplate()->SetAccessorProperty( FIXED_ONE_BYTE_STRING(isolate, "functions"), - FunctionTemplate::New(env->isolate(), DynamicLibrary::GetFunctions), + FunctionTemplate::New( + isolate, DynamicLibrary::GetFunctions, Local(), signature), Local(), static_cast(ReadOnly)); diff --git a/test/ffi/test-ffi-dynamic-library.js b/test/ffi/test-ffi-dynamic-library.js index c7dab03f64e..1fb444eba5c 100644 --- a/test/ffi/test-ffi-dynamic-library.js +++ b/test/ffi/test-ffi-dynamic-library.js @@ -124,6 +124,24 @@ test('DynamicLibrary exposes functions and symbols', () => { } }); +test('DynamicLibrary getters reject incompatible receivers', () => { + const lib = new ffi.DynamicLibrary(libraryPath); + + try { + const invalidGets = [ + () => Reflect.get(lib, 'path', {}), + () => Reflect.get(lib, 'symbols', {}), + () => Reflect.get(ffi.DynamicLibrary.prototype, 'functions', {}), + ]; + + for (const invalidGet of invalidGets) { + assert.throws(invalidGet, TypeError); + } + } finally { + lib.close(); + } +}); + test('DynamicLibrary evaluates function signatures once', () => { function makeChangingSignature() { const reads = { arguments: 0, return: 0 };