Skip to content

Commit 0d2db57

Browse files
committed
Prevent script paths from being parsed as options
1 parent d68c6c9 commit 0d2db57

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,24 @@ See [https://docs.python.org/3/using/cmdline.html#cmdoption-I](https://docs.pyth
8282
8383
See [https://www.man7.org/linux/man-pages/man1/bash.1.html#INVOCATION](https://www.man7.org/linux/man-pages/man1/bash.1.html#INVOCATION)
8484

85+
### PHP
86+
87+
PHP expects the script path to immediately follow its `-f` option, so the implicit interpreter separator must be disabled:
88+
89+
```
90+
#!/usr/bin/exec-suid --no-interpreter-separator -- /usr/bin/php -f
91+
```
92+
93+
See [https://www.php.net/manual/en/features.commandline.options.php](https://www.php.net/manual/en/features.commandline.options.php).
94+
8595
## Options
8696

97+
### Interpreter Separator (`--no-interpreter-separator`)
98+
99+
By default, `exec-suid` inserts `--` between the configured interpreter arguments and the script path. This prevents an option-like script path from being interpreted as an interpreter argument.
100+
101+
Some interpreters instead require the script path to immediately follow an option. Use `--no-interpreter-separator` for these command forms so that `exec-suid` does not insert `--` before the script path. See the [PHP interpreter](#php) example.
102+
87103
### Effective vs Real (`--real`)
88104

89105
By default, `exec-suid` will elevate only the effective user id (and saved user id), but not the real id.

‎src/main.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ fn main() {
3737
// Deprecated: kept temporarily for compatibility. New scripts should rely on the safe default and --env overrides.
3838
opts.optopt("", "environ", "Environment policy: safe (default), none, or all", "MODE");
3939
opts.optmulti("", "env", "Set an environment variable in the invoked script", "KEY=VALUE");
40+
opts.optflag("", "no-interpreter-separator", "Do not insert -- before the script path");
4041
let matches = opts.parse(&exec_argv[1..]).unwrap();
4142

43+
if !matches.opt_present("no-interpreter-separator") {
44+
script_argv.push("--".to_string());
45+
}
4246
script_argv.push(path.to_str().unwrap().to_string());
4347
script_argv.extend_from_slice(&args[if args.len() == 2 { 2.. } else { 3.. }]);
4448

‎tests/test_interpreters.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,26 @@ def test_sh(run_program):
2828
id -u
2929
""",
3030
)) == 0
31+
32+
33+
def test_option_like_script_path(run_program):
34+
assert run_program(
35+
"""
36+
#!/usr/bin/exec-suid -- /usr/bin/python3 -I
37+
38+
print("script")
39+
""",
40+
script_path="-cprint('injected')",
41+
executable="/usr/bin/exec-suid",
42+
args=["/usr/bin/exec-suid", "-cprint('injected')"],
43+
cwd="/tests",
44+
) == "script"
45+
46+
47+
def test_no_interpreter_separator(run_program):
48+
assert run_program(
49+
"""
50+
#!/usr/bin/exec-suid --no-interpreter-separator -- /usr/bin/python3 -I -c print(__import__('sys').argv[1])
51+
""",
52+
executable="/tests/test_no_interpreter_separator",
53+
) == "/tests/test_no_interpreter_separator"

0 commit comments

Comments
 (0)