diff --git a/deps/uv/include/uv/win.h b/deps/uv/include/uv/win.h
index 7b4ebd4b7b2e85..c4e9e1e631dd4a 100644
--- a/deps/uv/include/uv/win.h
+++ b/deps/uv/include/uv/win.h
@@ -684,6 +684,7 @@ typedef struct {
#define UV_FS_O_TEMPORARY _O_TEMPORARY
#define UV_FS_O_TRUNC _O_TRUNC
#define UV_FS_O_WRONLY _O_WRONLY
+#define UV_FS_O_READLOCK 0x40000000 /* READ ONLY SHARING MODE*/
/* fs open() flags supported on other platforms (or mapped on this platform): */
#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index 4092de0ab31e56..c6428098151783 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -508,6 +508,8 @@ void fs__open(uv_fs_t* req) {
*/
if (flags & UV_FS_O_EXLOCK) {
share = 0;
+ } else if (flags & UV_FS_O_READLOCK) {
+ share = FILE_SHARE_READ;;
} else {
share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
}
diff --git a/doc/api/code_integrity.md b/doc/api/code_integrity.md
new file mode 100644
index 00000000000000..5d47867c94a720
--- /dev/null
+++ b/doc/api/code_integrity.md
@@ -0,0 +1,138 @@
+# Code Integrity
+
+
+
+
+
+> Stability: 1.1 - Active development
+
+This feature is only available on Windows platforms.
+
+Code integrity refers to the assurance that software code has not been
+altered or tampered with in any unauthorized way. It ensures that
+the code running on a system is exactly what was intended by the developers.
+
+Code integrity in Node.js integrates with platform features for code integrity
+policy enforcement. See platform speficic sections below for more information.
+
+The Node.js threat model considers the code that the runtime executes to be
+trusted. As such, this feature is an additional safety belt, not a strict
+security boundary.
+
+If you find a potential security vulnerability, please refer to our
+[Security Policy][].
+
+## Code Integrity on Windows
+
+Code integrity is an opt-in feature that leverages Window Defender Application Control
+to verify the code executing conforms to system policy and has not been modified since
+signing time.
+
+There are three audiences that are involved when using Node.js in an
+environment enforcing code integrity: the application developers,
+those administrating the system enforcing code integrity, and
+the end user. The following sections describe how each audience
+can interact with code integrity enforcement.
+
+### Windows Code Integrity and Application Developers
+
+Windows Defender Application Control uses digital signatures to verify
+a file's integrity. Application developers are responsible for generating and
+distributing the signature information for their Node.js application.
+Application developers are also expected to design their application
+in robust ways to avoid unintended code execution. This includes
+avoiding the use of `eval` and avoiding loading modules outside
+of standard methods.
+
+Signature information for files which Node.js is intended to execute
+can be stored in a catalog file. Application developers can generate
+a Windows catalog file to store the hash of all files Node.js
+is expected to execute.
+
+A catalog can be generated using the `New-FileCatalog` Powershell
+cmdlet. For example
+
+```powershell
+New-FileCatalog -Version 2 -CatalogFilePath MyApplicationCatalog.cat -Path \my\application\path\
+```
+
+The `Path` argument should point to the root folder containing your application's code. If
+your application's code is fully contained in one file, `Path` can point to that single file.
+
+Be sure that the catalog is generated using the final version of the files that you intend to ship
+(i.e. after minifying).
+
+The application developer should then sign the generated catalog with their Code Signing certificate
+to ensure the catalog is not tampered with between distribution and execution.
+
+This can be done with the [Set-AuthenticodeSignature commandlet][].
+
+### Windows Code Integrity and System Administrators
+
+This section is intended for system administrators who want to enable Node.js
+code integrity features in their environments.
+
+This section assumes familiarity with managing WDAC polcies.
+[Official documentation for WDAC][].
+
+Code integrity enforcement on Windows has two toggleable settings:
+`EnforceCodeIntegrity` and `DisableInteractiveMode`. These settings are configured
+by WDAC policy.
+
+`EnforceCodeIntegrity` causes Node.js to call WldpCanExecuteFile whenever a module is loaded using `require`.
+WldpCanExecuteFile verifies that the file's integrity has not been tampered with from signing time.
+The system administrator should sign and install the application's file catalog where the application
+is running, per WDAC guidance.
+
+`DisableInteractiveMode` prevents Node.js from being run in interactive mode, and also disables the `-e` and `--eval`
+command line options.
+
+#### Enabling Code Integrity Enforcement
+
+On newer Windows versions (22H2+), the preferred method of configuring application settings is done using
+`AppSettings` in your WDAC Policy.
+
+```text
+
+
+
+ True
+
+
+ True
+
+
+
+```
+
+On older Windows versions, use the `Settings` section of your WDAC Policy.
+
+```text
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+```
+
+## Code Integrity on Linux
+
+Code integrity on Linux is not yet implemented. Plans for implementation will
+be made once the necessary APIs on Linux have been upstreamed. More information
+can be found here:
+
+## Code Integrity on MacOS
+
+Code integrity on MacOS is not yet implemented. Currently, there is no
+timeline for implementation.
+
+[Official documentation for WDAC]: https://learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/
+[Security Policy]: https://github.com/nodejs/node/blob/main/SECURITY.md
+[Set-AuthenticodeSignature commandlet]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-authenticodesignature
diff --git a/doc/api/errors.md b/doc/api/errors.md
index 98073d49d62098..0e95ff3ec58a6a 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -805,6 +805,22 @@ changes:
There was an attempt to use a `MessagePort` instance in a closed
state, usually after `.close()` has been called.
+
+
+### `ERR_CODE_INTEGRITY_BLOCKED`
+
+> Stability: 1.1 - Active development
+
+Feature has been disabled due to OS Code Integrity policy.
+
+
+
+### `ERR_CODE_INTEGRITY_VIOLATION`
+
+> Stability: 1.1 - Active development
+
+JavaScript code intended to be executed was rejected by system code integrity policy.
+
### `ERR_CONSOLE_WRITABLE_STREAM`
diff --git a/doc/api/index.md b/doc/api/index.md
index fab284fe652809..5001a822b7c1d8 100644
--- a/doc/api/index.md
+++ b/doc/api/index.md
@@ -16,6 +16,7 @@
* [C++ embedder API](embedding.md)
* [Child processes](child_process.md)
* [Cluster](cluster.md)
+* [Code integrity](code_integrity.md)
* [Command-line options](cli.md)
* [Console](console.md)
* [Crypto](crypto.md)
diff --git a/doc/api/wdac-manifest.xml b/doc/api/wdac-manifest.xml
new file mode 100644
index 00000000000000..264de029012bf7
--- /dev/null
+++ b/doc/api/wdac-manifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/lib/internal/code_integrity.js b/lib/internal/code_integrity.js
new file mode 100644
index 00000000000000..e1ce4620fc6a44
--- /dev/null
+++ b/lib/internal/code_integrity.js
@@ -0,0 +1,44 @@
+// Code integrity is a security feature which prevents unsigned
+// code from executing. More information can be found in the docs
+// doc/api/code_integrity.md
+
+'use strict';
+
+const { emitWarning } = require('internal/process/warning');
+const {
+ isFileTrustedBySystemCodeIntegrityPolicy,
+ isInteractiveModeDisabled,
+ isSystemEnforcingCodeIntegrity,
+} = internalBinding('code_integrity');
+
+let isCodeIntegrityEnforced;
+let alreadyQueriedSystemCodeEnforcmentMode = false;
+
+function isAllowedToExecuteFile(filepath) {
+ if (!alreadyQueriedSystemCodeEnforcmentMode) {
+ isCodeIntegrityEnforced = isSystemEnforcingCodeIntegrity();
+
+ if (isCodeIntegrityEnforced) {
+ emitWarning(
+ 'Code integrity is being enforced by system policy.' +
+ '\nCode integrity is an experimental feature.' +
+ ' See docs for more info.',
+ 'ExperimentalWarning');
+ }
+
+ alreadyQueriedSystemCodeEnforcmentMode = true;
+ }
+
+ if (!isCodeIntegrityEnforced) {
+ return true;
+ }
+
+ return isFileTrustedBySystemCodeIntegrityPolicy(filepath);
+}
+
+module.exports = {
+ isAllowedToExecuteFile,
+ isFileTrustedBySystemCodeIntegrityPolicy,
+ isInteractiveModeDisabled,
+ isSystemEnforcingCodeIntegrity,
+};
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 206e2a24716022..c003165005b71d 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1161,6 +1161,10 @@ E('ERR_CHILD_PROCESS_IPC_REQUIRED',
Error);
E('ERR_CHILD_PROCESS_STDIO_MAXBUFFER', '%s maxBuffer length exceeded',
RangeError);
+E('ERR_CODE_INTEGRITY_BLOCKED',
+ 'The feature "%s" is blocked by OS Code Integrity policy', Error);
+E('ERR_CODE_INTEGRITY_VIOLATION',
+ 'The file %s did not pass OS Code Integrity validation', Error);
E('ERR_CONSOLE_WRITABLE_STREAM',
'Console expects a writable stream instance for %s', TypeError);
E('ERR_CONSTRUCT_CALL_REQUIRED', 'Class constructor %s cannot be invoked without `new`', TypeError);
diff --git a/lib/internal/main/eval_string.js b/lib/internal/main/eval_string.js
index 998c3fb4ada52d..7586b516e2e225 100644
--- a/lib/internal/main/eval_string.js
+++ b/lib/internal/main/eval_string.js
@@ -23,10 +23,24 @@ const {
const { addBuiltinLibsToObject } = require('internal/modules/helpers');
const { getOptionValue } = require('internal/options');
+const {
+ codes: {
+ ERR_CODE_INTEGRITY_BLOCKED,
+ },
+} = require('internal/errors');
+
prepareMainThreadExecution();
addBuiltinLibsToObject(globalThis, '');
markBootstrapComplete();
+const { isWindows } = require('internal/util');
+if (isWindows) {
+ const ci = require('internal/code_integrity');
+ if (ci.isInteractiveModeDisabled()) {
+ throw new ERR_CODE_INTEGRITY_BLOCKED('"eval"');
+ }
+}
+
const code = getOptionValue('--eval');
const print = getOptionValue('--print');
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index 827655bedb65bf..e10e28adb9d4e2 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -190,6 +190,7 @@ const {
const {
codes: {
+ ERR_CODE_INTEGRITY_VIOLATION,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_INVALID_MODULE_SPECIFIER,
@@ -225,6 +226,11 @@ const onRequire = getLazy(() => tracingChannel('module.require'));
const relativeResolveCache = { __proto__: null };
+let ci;
+if (isWindows) {
+ ci = require('internal/code_integrity');
+}
+
let requireDepth = 0;
let isPreloading = false;
let statCache = null;
@@ -1164,7 +1170,19 @@ function defaultLoadImpl(filename, format) {
case 'module-typescript':
case 'commonjs-typescript':
case 'typescript': {
- return fs.readFileSync(filename, 'utf8');
+ let fd;
+ if (isWindows) {
+ fd = fs.openSync(filename, 0x40000000);
+ const isAllowedToExecute = ci.isAllowedToExecuteFile(fd);
+ if (!isAllowedToExecute) {
+ throw new ERR_CODE_INTEGRITY_VIOLATION(filename);
+ }
+ let source = fs.readFileSync(fd, 'utf8');
+ //fs.closeSync(fd);
+ return source;
+ } else {
+ return fs.readFileSync(filename, 'utf8');
+ }
}
case 'builtin':
return null;
@@ -1268,6 +1286,13 @@ Module._load = function(request, parent, isMain, internalResolveOptions = kEmpty
// TODO(joyeecheung): a more sensible handling is probably, if there are hooks, always go through the hooks
// first before checking the cache. Otherwise, check the cache first, then proceed to default loading.
if (request === url && StringPrototypeStartsWith(request, 'node:')) {
+ if (isWindows) {
+ const isAllowedToExecute = ci.isAllowedToExecuteFile(filename);
+ if (!isAllowedToExecute) {
+ throw new ERR_CODE_INTEGRITY_VIOLATION(filename);
+ }
+ }
+
const normalized = BuiltinModule.normalizeRequirableId(request);
if (normalized) { // It's a builtin module.
const { resultFromHook, builtinExports } = loadBuiltinWithHooks(normalized, url, format);
@@ -1309,6 +1334,13 @@ Module._load = function(request, parent, isMain, internalResolveOptions = kEmpty
}
if (resultFromLoadHook === undefined && BuiltinModule.canBeRequiredWithoutScheme(filename)) {
+ if (isWindows) {
+ const isAllowedToExecute = ci.isAllowedToExecuteFile(filename);
+ if (!isAllowedToExecute) {
+ throw new ERR_CODE_INTEGRITY_VIOLATION(filename);
+ }
+ }
+
const { resultFromHook, builtinExports } = loadBuiltinWithHooks(filename, url, format);
if (builtinExports) {
return builtinExports;
diff --git a/lib/internal/modules/esm/load.js b/lib/internal/modules/esm/load.js
index c284163fba86ec..88d5554b6d4c9a 100644
--- a/lib/internal/modules/esm/load.js
+++ b/lib/internal/modules/esm/load.js
@@ -4,17 +4,20 @@ const {
RegExpPrototypeExec,
} = primordials;
const {
+ isWindows,
kEmptyObject,
} = require('internal/util');
const { defaultGetFormat } = require('internal/modules/esm/get_format');
const { validateAttributes, emitImportAssertionWarning } = require('internal/modules/esm/assert');
-const { readFileSync } = require('fs');
+const { closeSync, openSync, readFileSync } = require('fs');
+const { O_EXCL } = require('fs').constants;
const { Buffer: { from: BufferFrom } } = require('buffer');
-const { URL } = require('internal/url');
+const { URL, fileURLToPath } = require('internal/url');
const {
+ ERR_CODE_INTEGRITY_VIOLATION,
ERR_INVALID_URL,
ERR_UNKNOWN_MODULE_FORMAT,
ERR_UNSUPPORTED_ESM_URL_SCHEME,
@@ -24,6 +27,11 @@ const {
dataURLProcessor,
} = require('internal/data_url');
+let ci;
+if (isWindows) {
+ ci = require('internal/code_integrity');
+}
+
/**
* @param {URL} url URL to the module
* @param {LoadContext} context used to decorate error messages
@@ -33,8 +41,23 @@ function getSourceSync(url, context) {
const { protocol, href } = url;
const responseURL = href;
let source;
+ let fd;
if (protocol === 'file:') {
- source = readFileSync(url);
+ if (isWindows) {
+ let filePath = fileURLToPath(url);
+ fd = openSync(filePath, 0x40000000);
+
+ const isAllowedToExecute = ci.isAllowedToExecuteFile(fd);
+ if (!isAllowedToExecute) {
+ throw new ERR_CODE_INTEGRITY_VIOLATION(url);
+ }
+ source = readFileSync(fd);
+ closeSync(fd);
+ }
+ else
+ {
+ source = readFileSync(filePath);
+ }
} else if (protocol === 'data:') {
const result = dataURLProcessor(url);
if (result === 'failure') {
diff --git a/node.gyp b/node.gyp
index ed699e0d4c03f1..e66ea033c99707 100644
--- a/node.gyp
+++ b/node.gyp
@@ -246,6 +246,7 @@
'src/node_blob.h',
'src/node_buffer.h',
'src/node_builtins.h',
+ 'src/node_code_integrity.h',
'src/node_config_file.h',
'src/node_constants.h',
'src/node_context_data.h',
@@ -491,6 +492,14 @@
}, {
'use_openssl_def%': 0,
}],
+ # Only compile node_code_integrity on Windows
+ [ 'OS=="win"', {
+ 'node_sources': [
+ '<(node_sources)',
+ 'src/node_code_integrity.cc',
+ 'src/node_code_integrity.h',
+ ],
+ }],
],
},
diff --git a/src/node_binding.cc b/src/node_binding.cc
index b76ecc8cab47df..8cc1e49413df77 100644
--- a/src/node_binding.cc
+++ b/src/node_binding.cc
@@ -100,6 +100,12 @@
V(worker) \
V(zlib)
+#define NODE_BUILTIN_OS_SPECIFIC_BINDINGS(V)
+
+#ifdef _WIN32
+#define NODE_BUILTIN_OS_SPECIFIC_BINDINGS(V) V(code_integrity)
+#endif
+
#define NODE_BUILTIN_BINDINGS(V) \
NODE_BUILTIN_STANDARD_BINDINGS(V) \
NODE_BUILTIN_OPENSSL_BINDINGS(V) \
@@ -107,7 +113,8 @@
NODE_BUILTIN_PROFILER_BINDINGS(V) \
NODE_BUILTIN_DEBUG_BINDINGS(V) \
NODE_BUILTIN_QUIC_BINDINGS(V) \
- NODE_BUILTIN_SQLITE_BINDINGS(V)
+ NODE_BUILTIN_SQLITE_BINDINGS(V) \
+ NODE_BUILTIN_OS_SPECIFIC_BINDINGS(V)
// This is used to load built-in bindings. Instead of using
// __attribute__((constructor)), we call the _register_
diff --git a/src/node_builtins.cc b/src/node_builtins.cc
index b02252540d1f3b..7a2cb002d689f8 100644
--- a/src/node_builtins.cc
+++ b/src/node_builtins.cc
@@ -151,6 +151,10 @@ BuiltinLoader::BuiltinCategories BuiltinLoader::GetBuiltinCategories() const {
"internal/inspector/webstorage",
#endif
"internal/test/binding", "internal/v8_prof_polyfill",
+ "internal/v8_prof_processor",
+#if !_WIN32
+ "internal/code_integrity", // Only implemented on Windows
+#endif
};
auto source = source_.read();
diff --git a/src/node_code_integrity.cc b/src/node_code_integrity.cc
new file mode 100644
index 00000000000000..e5d4ee0561f090
--- /dev/null
+++ b/src/node_code_integrity.cc
@@ -0,0 +1,295 @@
+#ifdef _WIN32
+
+#include "node_code_integrity.h"
+#include "env-inl.h"
+#include "node.h"
+#include "node_errors.h"
+#include "node_external_reference.h"
+#include "util.h"
+#include "uv.h"
+#include "v8.h"
+
+namespace node {
+
+using v8::Boolean;
+using v8::Context;
+using v8::FunctionCallbackInfo;
+using v8::Local;
+using v8::Object;
+using v8::Value;
+
+namespace per_process {
+bool isWldpInitialized = false;
+
+// WldpCanExecuteFile queries system code integrity policy
+// to determine if the contents of a file are allowed to be executed.
+pfnWldpCanExecuteFile WldpCanExecuteFile;
+
+// WldpGetApplicationSettingBoolean queries system code integrity policy
+// for an arbitrary flag. NodeJS uses the "Node.js EnforceCodeIntegrity"
+// flag to determine if NodeJS should be calling WldpCanExecuteFile
+// on files intended for execution
+// NodeJS also uses the "Node.js DisableInteractiveMode" flag to determine
+// if it should restrict interactive code execution. More details
+// on how to configure these flags can be found in doc/api/code_integrity.md
+pfnWldpGetApplicationSettingBoolean WldpGetApplicationSettingBoolean;
+
+// WldpQuerySecurityPolicy performs similar functionality to
+// WldpGetApplicationSettingBoolean, except for legacy Windows systems.
+// WldpGetApplicationSettingBoolean was introduced Win10 2023H2,
+// and is the modern API. However, to support more Node users,
+// we also fall back to WldpQuerySecurityPolicy,
+// which is available on Windows systems back to Win10 RS2
+pfnWldpQuerySecurityPolicy WldpQuerySecurityPolicy;
+} // namespace per_process
+
+namespace code_integrity {
+
+static PCWSTR NODEJS = L"Node.js";
+static PCWSTR ENFORCE_CODE_INTEGRITY_SETTING_NAME = L"EnforceCodeIntegrity";
+static PCWSTR DISABLE_INTERPRETIVE_MODE_SETTING_NAME =
+ L"DisableInteractiveMode";
+
+// InitWldp loads WLDP.dll (the Windows code integrity for interpreters DLL)
+// and the relevant function pointers
+void InitWldp(Environment* env) {
+ if (per_process::isWldpInitialized) {
+ return;
+ }
+
+ HMODULE wldp_module =
+ LoadLibraryExA("wldp.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+
+ if (wldp_module == nullptr) {
+ // Wldp is included on all Windows systems that are supported by Node.js
+ // If Wldp is unable to be loaded, something is very wrong with
+ // the system state
+ THROW_ERR_INVALID_STATE(env, "WLDP.DLL does not exist");
+ return;
+ }
+
+ per_process::WldpCanExecuteFile =
+ (pfnWldpCanExecuteFile)GetProcAddress(wldp_module, "WldpCanExecuteFile");
+
+ per_process::WldpGetApplicationSettingBoolean =
+ (pfnWldpGetApplicationSettingBoolean)GetProcAddress(
+ wldp_module, "WldpGetApplicationSettingBoolean");
+
+ per_process::WldpQuerySecurityPolicy =
+ (pfnWldpQuerySecurityPolicy)GetProcAddress(wldp_module,
+ "WldpQuerySecurityPolicy");
+
+ per_process::isWldpInitialized = true;
+}
+
+// IsFileTrustedBySystemCodeIntegrityPolicy
+// Queries operating system to determine if the contents of a file are
+// allowed to be executed according to system code integrity policy.
+static void IsFileTrustedBySystemCodeIntegrityPolicy(
+ const FunctionCallbackInfo& args) {
+ CHECK_EQ(args.Length(), 1);
+
+ CHECK(args[0]->IsInt32());
+ const int fd = args[0].As()->Value();
+
+ Environment* env = Environment::GetCurrent(args);
+ if (!per_process::isWldpInitialized) {
+ InitWldp(env);
+ }
+
+ // BufferValue path(env->isolate(), args[0]);
+ // CHECK_NOT_NULL(*path);
+
+ // HANDLE hFile = CreateFileA(*path,
+ // GENERIC_READ,
+ // FILE_SHARE_READ,
+ // nullptr,
+ // OPEN_EXISTING,
+ // FILE_ATTRIBUTE_NORMAL,
+ // nullptr);
+
+ // if (hFile == INVALID_HANDLE_VALUE || hFile == nullptr) {
+ // return args.GetReturnValue().SetFalse();
+ // }
+
+ HANDLE hFile = uv_get_osfhandle(fd);
+
+ if (hFile == INVALID_HANDLE_VALUE || hFile == nullptr) {
+ return args.GetReturnValue().SetFalse();
+ }
+
+ const GUID wldp_host_other = WLDP_HOST_OTHER;
+ WLDP_EXECUTION_POLICY result;
+ HRESULT hr =
+ per_process::WldpCanExecuteFile(wldp_host_other,
+ WLDP_EXECUTION_EVALUATION_OPTION_NONE,
+ hFile,
+ NODEJS,
+ &result);
+
+ if (FAILED(hr)) {
+ // The failure cases from WldpCanExecuteFile are generally
+ // not recoverable. Inspection of the Windows event logs is necessary.
+ // The secure failure mode is not executing the file
+ args.GetReturnValue().SetFalse();
+ return;
+ }
+
+ bool isFileTrusted = (result == WLDP_EXECUTION_POLICY_ALLOWED);
+ args.GetReturnValue().Set(isFileTrusted);
+}
+
+// IsInteractiveModeDisabled
+// Queries operating system code integrity policy to determine if
+// the policy is requesting NodeJS to disable interactive mode.
+static void IsInteractiveModeDisabled(const FunctionCallbackInfo& args) {
+ CHECK_EQ(args.Length(), 0);
+
+ Environment* env = Environment::GetCurrent(args);
+
+ if (!per_process::isWldpInitialized) {
+ InitWldp(env);
+ }
+
+ if (per_process::WldpGetApplicationSettingBoolean != nullptr) {
+ bool isInteractiveModeDisabled;
+ HRESULT hr = per_process::WldpGetApplicationSettingBoolean(
+ NODEJS,
+ DISABLE_INTERPRETIVE_MODE_SETTING_NAME,
+ &isInteractiveModeDisabled);
+
+ if (SUCCEEDED(hr)) {
+ args.GetReturnValue().Set(isInteractiveModeDisabled);
+ return;
+ } else if (hr != E_NOTFOUND) {
+ // If the setting is not found, continue through to attempt
+ // WldpQuerySecurityPolicy, as the setting may be defined
+ // in the old settings format
+ args.GetReturnValue().SetFalse();
+ return;
+ }
+ }
+
+ // WldpGetApplicationSettingBoolean is the preferred way for applications to
+ // query security policy values. However, this method only exists on Windows
+ // versions going back to circa Win10 2023H2. In order to support systems
+ // older than that (down to Win10RS2), we can use the deprecated
+ // WldpQuerySecurityPolicy
+ if (per_process::WldpQuerySecurityPolicy != nullptr) {
+ DECLARE_CONST_UNICODE_STRING(providerName, L"Node.js");
+ DECLARE_CONST_UNICODE_STRING(keyName, L"Settings");
+ DECLARE_CONST_UNICODE_STRING(valueName, L"DisableInteractiveMode");
+ WLDP_SECURE_SETTING_VALUE_TYPE valueType =
+ WLDP_SECURE_SETTING_VALUE_TYPE_BOOLEAN;
+ ULONG valueSize = sizeof(int);
+ int isInteractiveModeDisabled = 0;
+ HRESULT hr =
+ per_process::WldpQuerySecurityPolicy(&providerName,
+ &keyName,
+ &valueName,
+ &valueType,
+ &isInteractiveModeDisabled,
+ &valueSize);
+
+ if (FAILED(hr)) {
+ args.GetReturnValue().SetFalse();
+ return;
+ }
+
+ args.GetReturnValue().Set(Boolean::New(
+ env->isolate(), static_cast(isInteractiveModeDisabled)));
+ }
+}
+
+// IsSystemEnforcingCodeIntegrity
+// Queries the operating system to determine if NodeJS should be enforcing
+// integrity checks by calling WldpCanExecuteFile
+static void IsSystemEnforcingCodeIntegrity(
+ const FunctionCallbackInfo& args) {
+ CHECK_EQ(args.Length(), 0);
+
+ Environment* env = Environment::GetCurrent(args);
+
+ if (!per_process::isWldpInitialized) {
+ InitWldp(env);
+ }
+
+ if (per_process::WldpGetApplicationSettingBoolean != nullptr) {
+ bool isCodeIntegrityEnforced;
+ HRESULT hr = per_process::WldpGetApplicationSettingBoolean(
+ NODEJS, ENFORCE_CODE_INTEGRITY_SETTING_NAME, &isCodeIntegrityEnforced);
+
+ if (SUCCEEDED(hr)) {
+ args.GetReturnValue().Set(isCodeIntegrityEnforced);
+ return;
+ } else if (hr != E_NOTFOUND) {
+ // If the setting is not found, continue through to attempt
+ // WldpQuerySecurityPolicy, as the setting may be defined
+ // in the old settings format
+ args.GetReturnValue().SetFalse();
+ return;
+ }
+ }
+
+ // WldpGetApplicationSettingBoolean is the preferred way for applications to
+ // query security policy values. However, this method only exists on Windows
+ // versions going back to circa Win10 2023H2. In order to support systems
+ // older than that (down to Win10RS2), we can use the deprecated
+ // WldpQuerySecurityPolicy
+ if (per_process::WldpQuerySecurityPolicy != nullptr) {
+ DECLARE_CONST_UNICODE_STRING(providerName, L"Node.js");
+ DECLARE_CONST_UNICODE_STRING(keyName, L"Settings");
+ DECLARE_CONST_UNICODE_STRING(valueName, L"EnforceCodeIntegrity");
+ WLDP_SECURE_SETTING_VALUE_TYPE valueType =
+ WLDP_SECURE_SETTING_VALUE_TYPE_BOOLEAN;
+ ULONG valueSize = sizeof(int);
+ int isCodeIntegrityEnforced = 0;
+ HRESULT hr = per_process::WldpQuerySecurityPolicy(&providerName,
+ &keyName,
+ &valueName,
+ &valueType,
+ &isCodeIntegrityEnforced,
+ &valueSize);
+
+ if (FAILED(hr)) {
+ args.GetReturnValue().SetFalse();
+ return;
+ }
+
+ args.GetReturnValue().Set(Boolean::New(
+ env->isolate(), static_cast(isCodeIntegrityEnforced)));
+ }
+}
+
+void Initialize(Local