Skip to content

Commit

Permalink
env: fix environment variable parsing
Browse files Browse the repository at this point in the history
Environment variables are fairly free-form; all characters are allowed
except for '\0', so FOO-BAR=baz should work.

This leaves callers in a bit of a conundrum if they don't know (and
don't particularly trust) program names in advance. To make things
safer, and more explicit, a second -- can now be added to the
environment variable list.
  • Loading branch information
Snaipe committed Jul 6, 2023
1 parent 560db31 commit b23d5e0
Show file tree
Hide file tree
Showing 5 changed files with 400 additions and 342 deletions.
47 changes: 39 additions & 8 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,27 +796,58 @@ int main(int argc, char *argv[], char *envp[])
}

/* Intepret any NAME=value at the start of the command line as environment
variable overrides. */
variable overrides.
The general form is [<VAR=val...> [--]] [args...]. This is how the
parsing works for the following commands:
* bst --no-env -- FOO-BAR=baz env
argv = [env]
envp = [FOO-BAR=baz]
* bst --no-env -- FOO-BAR=baz -- env
argv = [env]
envp = [FOO-BAR=baz]
* bst --no-env -- FOO-BAR=baz -- -- env
argv = [--, env]
envp = [FOO-BAR=baz]
* bst --no-env -- -- env
argv = [--, env]
envp = []
* bst --no-env -- env
argv = [env]
envp = []
*/
bool has_env = false;
for (; optind + 1 <= argc; ++optind) {
/* Specifying another -- means we end the environment list.
This is necessary to handle the case where the program name
is untrusted and may contain a '='. */
if (!strcmp(argv[optind], "--")) {
/* This is the case where no environment variables are specified,
but two -- were passed (e.g. bst -- -- arg).
In this situation, we do not interpret the second --; it needs
to be passed as-is as the first argument to init. */
if (has_env) {
++optind;
}
break;
}

char *c = argv[optind];
for (; *c != '\0'; ++c) {
if (*c == '=' && c != argv[optind]) {
newenv[i++] = argv[optind];
has_env = true;
break;
}
if (!isalnum(*c) && *c != '_') {
/* This is not a word, and thus not an environment variable
name, meaning this is the program name. */
goto end;
}
}
if (*c == '\0') {
/* This was a word, but we didn't encounter an '='; this is also the
/* This was a word, but we didn't encounter an '='; this is the
program name. */
break;
}
}
end:
newenv[i] = NULL;

/* Use our own default init if we unshare the pid namespace, and no
Expand Down
7 changes: 5 additions & 2 deletions man/bst.1.scd
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ bst - run executables in their own spacetime.

# SYNOPSIS

bst [options] [--] [VAR=value...] [executable [args...]]
bst [options] [--] [<VAR=value...> [--]] [executable [args...]]

# DESCRIPTION

Expand All @@ -24,7 +24,10 @@ time, namespaces, and filesystem structure.
Users of bst may choose to opt-out of some of the isolation.

Environment variables can be overriden for the spacetime process by specifying
_VAR=value_ before the executable to run.
_VAR=value_ before the executable to run. This can be useful in conjunction
with --no-env if environment variables used by bst (LC_\*, TERM, ...) and
the setup program should be different from the environment variables of the
spacetime process.

# OPTIONS

Expand Down
16 changes: 16 additions & 0 deletions test/bst.t
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,22 @@ Testing Environment
ROOT=/
EXECUTABLE=/bin/true

$ bst --no-env -- FOO-BAR=baz env
FOO-BAR=baz

$ bst --no-env -- FOO-BAR=baz -- env
FOO-BAR=baz

$ bst --no-env -- FOO-BAR=baz -- -- env
bst-init: execvpe --: No such file or directory
[1]

$ bst --no-env -- -- env
bst-init: execvpe --: No such file or directory
[1]

$ bst --no-env -- env

Testing close-fds

$ echo -n '--close-fd=3 should close fd 3: '
Expand Down
Loading

0 comments on commit b23d5e0

Please sign in to comment.