Skip to content

Commit bb85b45

Browse files
committed
sea: reject malformed --node-options values
Propagate tokenization errors from ParseNodeOptionsEnvVar through FixupArgsForSEA and abort startup with an invalid command-line status instead of applying partially parsed options. Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com>
1 parent 6a3d80f commit bb85b45

4 files changed

Lines changed: 40 additions & 11 deletions

File tree

src/node.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1633,7 +1633,14 @@ static ExitCode StartInternal(int argc, char** argv) {
16331633

16341634
int Start(int argc, char** argv) {
16351635
#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION
1636-
std::tie(argc, argv) = sea::FixupArgsForSEA(argc, argv);
1636+
std::vector<std::string> errors;
1637+
std::tie(argc, argv) = sea::FixupArgsForSEA(argc, argv, &errors);
1638+
if (!errors.empty()) {
1639+
for (const std::string& error : errors) {
1640+
FPrintF(stderr, "%s: %s\n", argv[0], error);
1641+
}
1642+
return static_cast<int>(ExitCode::kInvalidCommandLineArgument);
1643+
}
16371644
#endif
16381645
return static_cast<int>(StartInternal(argc, argv));
16391646
}

src/node_sea.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ void IsExperimentalSeaWarningNeeded(const FunctionCallbackInfo<Value>& args) {
283283
sea_resource.flags & SeaFlags::kDisableExperimentalSeaWarning));
284284
}
285285

286-
std::tuple<int, char**> FixupArgsForSEA(int argc, char** argv) {
286+
std::tuple<int, char**> FixupArgsForSEA(
287+
int argc, char** argv, std::vector<std::string>* errors) {
287288
// Repeats argv[0] at position 1 on argv as a replacement for the missing
288289
// entry point file path.
289290
if (IsSingleExecutable()) {
@@ -303,8 +304,10 @@ std::tuple<int, char**> FixupArgsForSEA(int argc, char** argv) {
303304
for (int i = 1; i < argc; ++i) {
304305
if (strncmp(argv[i], "--node-options=", 15) == 0) {
305306
std::string node_options = argv[i] + 15;
306-
std::vector<std::string> errors;
307-
cli_extension_args = ParseNodeOptionsEnvVar(node_options, &errors);
307+
cli_extension_args = ParseNodeOptionsEnvVar(node_options, errors);
308+
if (!errors->empty()) {
309+
return {argc, argv};
310+
}
308311
// Remove this argument by shifting the rest
309312
for (int j = i; j < argc - 1; ++j) {
310313
argv[j] = argv[j + 1];

src/node_sea.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ struct SeaResource {
7070
bool IsSingleExecutable();
7171
std::string_view FindSingleExecutableBlob();
7272
SeaResource FindSingleExecutableResource();
73-
std::tuple<int, char**> FixupArgsForSEA(int argc, char** argv);
73+
std::tuple<int, char**> FixupArgsForSEA(
74+
int argc, char** argv, std::vector<std::string>* errors);
7475
node::ExitCode WriteSingleExecutableBlob(
7576
const std::string& config_path,
7677
const std::vector<std::string>& args,

test/sea/test-single-executable-application-exec-argv-extension-cli.js

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,36 @@ tmpdir.refresh();
2020

2121
const outputFile = buildSEA(fixtures.path('sea', 'exec-argv-extension-cli'));
2222

23+
const env = {
24+
...process.env,
25+
NODE_OPTIONS: '--max-old-space-size=2048', // Should be ignored
26+
COMMON_DIRECTORY: join(__dirname, '..', 'common'),
27+
NODE_DEBUG_NATIVE: 'SEA',
28+
};
29+
2330
// Test that --node-options works with execArgvExtension: "cli"
2431
spawnSyncAndAssert(
2532
outputFile,
2633
['--node-options=--max-old-space-size=1024', 'user-arg1', 'user-arg2'],
2734
{
28-
env: {
29-
...process.env,
30-
NODE_OPTIONS: '--max-old-space-size=2048', // Should be ignored
31-
COMMON_DIRECTORY: join(__dirname, '..', 'common'),
32-
NODE_DEBUG_NATIVE: 'SEA',
33-
},
35+
env,
3436
},
3537
{
3638
stdout: /execArgvExtension cli test passed/,
3739
});
40+
41+
// Test that malformed --node-options values are rejected.
42+
[
43+
['--no-warnings "', /unterminated string/],
44+
['"--no-warnings\\', /invalid escape/],
45+
].forEach(([nodeOptions, stderr]) => {
46+
spawnSyncAndAssert(
47+
outputFile,
48+
[`--node-options=${nodeOptions}`],
49+
{ env },
50+
{
51+
status: 9,
52+
stdout: '',
53+
stderr,
54+
});
55+
});

0 commit comments

Comments
 (0)