Skip to content

Commit d244930

Browse files
committed
nix-store --print-env: fix shell quoting on _args output
The previous implementation double-quoted the _args variable by escaping each argument individually and then wrapping them all in single quotes, producing output like: _args=''-e' 'arg1' 'arg2'' This fix concatenates all arguments into a single string first, then escapes that string once, producing correct output like: _args='-e arg1 arg2' This prevents potential command injection issues when the output is sourced in shell scripts. Fixes #14327
1 parent 091c0a9 commit d244930

File tree

3 files changed

+41
-11
lines changed

3 files changed

+41
-11
lines changed

src/nix/nix-store/nix-store.cc

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "nix/store/globals.hh"
1616
#include "nix/store/path-with-outputs.hh"
1717
#include "nix/store/export-import.hh"
18+
#include "nix/util/strings.hh"
1819

1920
#include "man-pages.hh"
2021

@@ -534,17 +535,9 @@ static void opPrintEnv(Strings opFlags, Strings opArgs)
534535
for (auto & i : drv.env)
535536
logger->cout("export %1%; %1%=%2%\n", i.first, escapeShellArgAlways(i.second));
536537

537-
/* Also output the arguments. This doesn't preserve whitespace in
538-
arguments. */
539-
cout << "export _args; _args='";
540-
bool first = true;
541-
for (auto & i : drv.args) {
542-
if (!first)
543-
cout << ' ';
544-
first = false;
545-
cout << escapeShellArgAlways(i);
546-
}
547-
cout << "'\n";
538+
/* Also output the arguments. */
539+
std::string argsStr = concatStringsSep(" ", drv.args);
540+
cout << "export _args; _args=" << escapeShellArgAlways(argsStr) << "\n";
548541
}
549542

550543
static void opReadLog(Strings opFlags, Strings opArgs)

tests/functional/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ suites = [
160160
'nix-profile.sh',
161161
'suggestions.sh',
162162
'store-info.sh',
163+
'store-print-env.sh',
163164
'fetchClosure.sh',
164165
'completions.sh',
165166
'impure-derivations.sh',
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env bash
2+
3+
source common.sh
4+
5+
clearStore
6+
7+
# Regression test for nix-store --print-env argument escaping
8+
# This tests that arguments in _args are properly escaped as a single string
9+
# rather than double-escaped which could lead to command injection
10+
11+
cat > "$TEST_ROOT/test-args.nix" <<'EOF'
12+
derivation {
13+
name = "test-print-env-args";
14+
system = builtins.currentSystem;
15+
builder = "/bin/sh";
16+
args = [ "-c" "echo hello world" ];
17+
}
18+
EOF
19+
20+
drvPath=$(nix-instantiate "$TEST_ROOT/test-args.nix")
21+
output=$(nix-store --print-env "$drvPath" | grep "^export _args")
22+
23+
# The output should be: export _args; _args='-c echo hello world'
24+
# NOT: export _args; _args=''-c' 'echo hello world''
25+
26+
# Test that it can be safely evaluated
27+
eval "$output"
28+
expected="-c echo hello world"
29+
# shellcheck disable=SC2154 # _args is set by the eval above
30+
if [ "$_args" != "$expected" ]; then
31+
echo "ERROR: _args not properly escaped!"
32+
echo "Expected: $expected"
33+
echo "Got: $_args"
34+
echo "Raw output: $output"
35+
exit 1
36+
fi

0 commit comments

Comments
 (0)