1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-21 02:50:18 +03:00

Merge pull request #18129 from keszybz/envvars

Allow control characters in environment variable values
This commit is contained in:
Lennart Poettering 2021-01-19 16:02:27 +01:00 committed by GitHub
commit a2804e3cd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 19 deletions

View File

@ -1080,8 +1080,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<para><command>systemd</command> supports an environment block that is passed to processes the manager
spawns. The names of the variables can contain ASCII letters, digits, and the underscore
character. Variable names cannot be empty or start with a digit. In variable values, most characters
are allowed, but non-printable characters are currently rejected. The total length of the environment
block is limited to <constant>_SC_ARG_MAX</constant> value defined by
are allowed, but the whole sequence must be valid UTF-8. (Note that control characters like newline
(<constant>NL</constant>), tab (<constant>TAB</constant>), or the escape character
(<constant>ESC</constant>), <emphasis>are</emphasis> valid ASCII and thus valid UTF-8). The total
length of the environment block is limited to <constant>_SC_ARG_MAX</constant> value defined by
<citerefentry project='man-pages'><refentrytitle>sysconf</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>

View File

@ -57,16 +57,13 @@ bool env_value_is_valid(const char *e) {
if (!utf8_is_valid(e))
return false;
/* bash allows tabs and newlines in environment variables, and so
* should we */
if (string_has_cc(e, "\t\n"))
return false;
/* Note that variable *values* may contain control characters, in particular NL, TAB, BS, DEL, ESC…
* When printing those variables with show-environment, we'll escape them. Make sure to print
* environment variables carefully! */
/* POSIX says the overall size of the environment block cannot
* be > ARG_MAX, an individual assignment hence cannot be
* either. Discounting the shortest possible variable name of
* length 1, the equal sign and trailing NUL this hence leaves
* ARG_MAX-3 as longest possible variable value. */
/* POSIX says the overall size of the environment block cannot be > ARG_MAX, an individual assignment
* hence cannot be either. Discounting the shortest possible variable name of length 1, the equal
* sign and trailing NUL this hence leaves ARG_MAX-3 as longest possible variable value. */
if (strlen(e) > sc_arg_max() - 3)
return false;
@ -86,10 +83,8 @@ bool env_assignment_is_valid(const char *e) {
if (!env_value_is_valid(eq + 1))
return false;
/* POSIX says the overall size of the environment block cannot
* be > ARG_MAX, hence the individual variable assignments
* cannot be either, but let's leave room for one trailing NUL
* byte. */
/* POSIX says the overall size of the environment block cannot be > ARG_MAX, hence the individual
* variable assignments cannot be either, but let's leave room for one trailing NUL byte. */
if (strlen(e) > sc_arg_max() - 1)
return false;

View File

@ -127,6 +127,12 @@ int import_environment(int argc, char *argv[], void *userdata) {
strv_env_clean_with_callback(copy, invalid_callback, NULL);
char **e;
STRV_FOREACH(e, copy)
if (string_has_cc(*e, NULL))
log_notice("Environment variable $%.*s contains control characters, importing anyway.",
(int) strcspn(*e, "="), *e);
r = sd_bus_message_append_strv(m, copy);
} else {
@ -139,21 +145,30 @@ int import_environment(int argc, char *argv[], void *userdata) {
STRV_FOREACH(a, strv_skip(argv, 1)) {
if (!env_name_is_valid(*a))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid environment variable name: %s", *a);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Not a valid environment variable name: %s", *a);
bool found = false;
STRV_FOREACH(b, environ) {
const char *eq;
eq = startswith(*b, *a);
if (eq && *eq == '=') {
if (string_has_cc(eq + 1, NULL))
log_notice("Environment variable $%.*s contains control characters, importing anyway.",
(int) (eq - *b), *b);
r = sd_bus_message_append(m, "s", *b);
if (r < 0)
return bus_log_create_error(r);
found = true;
break;
}
}
if (!found)
log_notice("Environment variable $%s not set, ignoring.", *a);
}
r = sd_bus_message_close_container(m);

View File

@ -265,6 +265,7 @@ static void test_env_clean(void) {
"another=one",
"another=final one",
"CRLF=\r\n",
"LESS_TERMCAP_mb=\x1b[01;31m",
"BASH_FUNC_foo%%=() { echo foo\n}");
assert_se(e);
assert_se(!strv_env_is_valid(e));
@ -277,7 +278,9 @@ static void test_env_clean(void) {
assert_se(streq(e[3], "abcd=äöüß"));
assert_se(streq(e[4], "xyz=xyz\n"));
assert_se(streq(e[5], "another=final one"));
assert_se(e[6] == NULL);
assert_se(streq(e[6], "CRLF=\r\n"));
assert_se(streq(e[7], "LESS_TERMCAP_mb=\x1b[01;31m"));
assert_se(e[8] == NULL);
}
static void test_env_name_is_valid(void) {
@ -302,8 +305,11 @@ static void test_env_value_is_valid(void) {
assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
assert_se(env_value_is_valid("tab\tcharacter"));
assert_se(env_value_is_valid("new\nline"));
assert_se(!env_value_is_valid("Show this?\rNope. Show that!"));
assert_se(!env_value_is_valid("new DOS\r\nline"));
assert_se(env_value_is_valid("Show this?\rNope. Show that!"));
assert_se(env_value_is_valid("new DOS\r\nline"));
assert_se(!env_value_is_valid("\xc5")); /* A truncated utf-8-encoded "ł".
* We currently disallow that. */
}
static void test_env_assignment_is_valid(void) {