1+ #include " node_code_integrity.h"
2+ #include " v8.h"
3+ #include " node.h"
4+ #include " env-inl.h"
5+ #include " node_external_reference.h"
6+
7+ namespace node {
8+
9+ using v8::Boolean;
10+ using v8::Context;
11+ using v8::FunctionCallbackInfo;
12+ using v8::Local;
13+ using v8::Object;
14+ using v8::Value;
15+
16+ namespace codeintegrity {
17+
18+ #ifdef _WIN32
19+ static bool isWldpInitialized = false ;
20+ static pfnWldpCanExecuteFile WldpCanExecuteFile;
21+ static pfnWldpGetApplicationSettingBoolean WldpGetApplicationSettingBoolean;
22+ static pfnWldpQuerySecurityPolicy WldpQuerySecurityPolicy;
23+ static PCWSTR NODEJS = L" Node.js" ;
24+ static PCWSTR ENFORCE_CODE_INTEGRITY_SETTING_NAME = L" EnforceCodeIntegrity" ;
25+
26+ void InitWldp (Environment* env) {
27+
28+ if (isWldpInitialized)
29+ {
30+ return ;
31+ }
32+
33+ HMODULE wldp_module = LoadLibraryExA (
34+ " wldp.dll" ,
35+ nullptr ,
36+ LOAD_LIBRARY_SEARCH_SYSTEM32);
37+
38+ if (wldp_module == nullptr ) {
39+ return env->ThrowError (" Unable to load wldp.dll" );
40+ }
41+
42+ WldpCanExecuteFile =
43+ (pfnWldpCanExecuteFile)GetProcAddress (
44+ wldp_module,
45+ " WldpCanExecuteFile" );
46+
47+ WldpGetApplicationSettingBoolean =
48+ (pfnWldpGetApplicationSettingBoolean)GetProcAddress (
49+ wldp_module,
50+ " WldpGetApplicationSettingBoolean" );
51+
52+ WldpQuerySecurityPolicy =
53+ (pfnWldpQuerySecurityPolicy)GetProcAddress (
54+ wldp_module,
55+ " WldpQuerySecurityPolicy" );
56+
57+ isWldpInitialized = true ;
58+ }
59+
60+ static void IsFileTrustedBySystemCodeIntegrityPolicy (
61+ const FunctionCallbackInfo<Value>& args) {
62+ CHECK_EQ (args.Length (), 1 );
63+ CHECK (args[0 ]->IsString ());
64+
65+ Environment* env = Environment::GetCurrent (args);
66+ if (!isWldpInitialized) {
67+ InitWldp (env);
68+ }
69+
70+ BufferValue path (env->isolate (), args[0 ]);
71+ if (*path == nullptr ) {
72+ return env->ThrowError (" path cannot be empty" );
73+ }
74+
75+ HANDLE hFile = CreateFileA (
76+ *path,
77+ GENERIC_READ,
78+ FILE_SHARE_READ,
79+ nullptr ,
80+ OPEN_EXISTING,
81+ FILE_ATTRIBUTE_NORMAL,
82+ nullptr );
83+
84+ if (hFile == INVALID_HANDLE_VALUE || hFile == nullptr ) {
85+ return env->ThrowError (" Unable to open file" );
86+ }
87+
88+ const GUID wldp_host_other = WLDP_HOST_OTHER;
89+ WLDP_EXECUTION_POLICY result;
90+ HRESULT hr = WldpCanExecuteFile (
91+ wldp_host_other,
92+ WLDP_EXECUTION_EVALUATION_OPTION_NONE,
93+ hFile,
94+ NODEJS,
95+ &result);
96+ CloseHandle (hFile);
97+
98+ if (FAILED (hr)) {
99+ return env->ThrowError (" WldpCanExecuteFile failed" );
100+ }
101+
102+ bool isFileTrusted = (result == WLDP_EXECUTION_POLICY_ALLOWED);
103+ args.GetReturnValue ().Set (isFileTrusted);
104+ }
105+
106+ static void IsSystemEnforcingCodeIntegrity (
107+ const FunctionCallbackInfo<Value>& args) {
108+ CHECK_EQ (args.Length (), 0 );
109+
110+ Environment* env = Environment::GetCurrent (args);
111+
112+ if (!isWldpInitialized) {
113+ InitWldp (env);
114+ }
115+
116+ if (WldpGetApplicationSettingBoolean != nullptr )
117+ {
118+ BOOL ret;
119+ HRESULT hr = WldpGetApplicationSettingBoolean (
120+ NODEJS,
121+ ENFORCE_CODE_INTEGRITY_SETTING_NAME,
122+ &ret);
123+
124+ if (SUCCEEDED (hr)) {
125+ args.GetReturnValue ().Set (
126+ Boolean::New (env->isolate (), ret));
127+ return ;
128+ } else if (hr != E_NOTFOUND) {
129+ // If the setting is not found, continue through to attempt WldpQuerySecurityPolicy,
130+ // as the setting may be defined in the old settings format
131+ args.GetReturnValue ().Set (Boolean::New (env->isolate (), false ));
132+ return ;
133+ }
134+ }
135+
136+ // WldpGetApplicationSettingBoolean is the preferred way for applications to
137+ // query security policy values. However, this method only exists on Windows
138+ // versions going back to circa Win10 2023H2. In order to support systems
139+ // older than that (down to Win10RS2), we can use the deprecated
140+ // WldpQuerySecurityPolicy
141+ if (WldpQuerySecurityPolicy != nullptr ) {
142+ DECLARE_CONST_UNICODE_STRING (providerName, L" Node.js" );
143+ DECLARE_CONST_UNICODE_STRING (keyName, L" Settings" );
144+ DECLARE_CONST_UNICODE_STRING (valueName, L" EnforceCodeIntegrity" );
145+ WLDP_SECURE_SETTING_VALUE_TYPE valueType =
146+ WLDP_SECURE_SETTING_VALUE_TYPE_BOOLEAN;
147+ ULONG valueSize = sizeof (int );
148+ int ret = 0 ;
149+ HRESULT hr = WldpQuerySecurityPolicy (
150+ &providerName,
151+ &keyName,
152+ &valueName,
153+ &valueType,
154+ &ret,
155+ &valueSize);
156+ if (FAILED (hr)) {
157+ args.GetReturnValue ().Set (Boolean::New (env->isolate (), false ));
158+ return ;
159+ }
160+
161+ args.GetReturnValue ().Set (
162+ Boolean::New (env->isolate (), static_cast <bool >(ret)));
163+ }
164+ }
165+ #endif // _WIN32
166+
167+ #ifndef _WIN32
168+ static void IsFileTrustedBySystemCodeIntegrityPolicy (
169+ const FunctionCallbackInfo<Value>& args) {
170+ args.GetReturnValue ().Set (true );
171+ }
172+
173+ static void IsSystemEnforcingCodeIntegrity (
174+ const FunctionCallbackInfo<Value>& args) {
175+ args.GetReturnValue ().Set (false );
176+ }
177+ #endif // ifndef _WIN32
178+
179+ void Initialize (Local<Object> target,
180+ Local<Value> unused,
181+ Local<Context> context,
182+ void * priv) {
183+ SetMethod (
184+ context,
185+ target,
186+ " isFileTrustedBySystemCodeIntegrityPolicy" ,
187+ IsFileTrustedBySystemCodeIntegrityPolicy);
188+
189+ SetMethod (
190+ context,
191+ target,
192+ " isSystemEnforcingCodeIntegrity" ,
193+ IsSystemEnforcingCodeIntegrity);
194+ }
195+
196+ void RegisterExternalReferences (ExternalReferenceRegistry* registry) {
197+ // BindingData::RegisterExternalReferences(registry);
198+
199+ registry->Register (IsFileTrustedBySystemCodeIntegrityPolicy);
200+ registry->Register (IsSystemEnforcingCodeIntegrity);
201+ }
202+
203+ } // namespace codeintegrity
204+ } // namespace node
205+ NODE_BINDING_CONTEXT_AWARE_INTERNAL (code_integrity,
206+ node::codeintegrity::Initialize)
207+ NODE_BINDING_EXTERNAL_REFERENCE(code_integrity,
208+ node::codeintegrity::RegisterExternalReferences)
0 commit comments