From: Luca Boccassi Date: Mon, 29 Jun 2026 14:05:51 +0000 (+0100) Subject: env-util: ensure NUL termination of the replace_env_argv() output array X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1958539136e502bdefac1852e23a667b23bfc120;p=thirdparty%2Fsystemd.git env-util: ensure NUL termination of the replace_env_argv() output array The output array is allocated with new() and left uninitialized, but a bare unset "$VAR" token expands to nothing and writes no terminator. When such a token leads or is the only word, the returned strv is left without a trailing NULL. Follow-up for f331434d13488425ccd8485327085d15f8f92aea --- diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 4f6240e5465..934428e7f52 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -948,6 +948,8 @@ int replace_env_argv( } k += q; + /* reallocarray() does not zero-initialize the grown tail, add NUL termination */ + n[k] = NULL; continue; } diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c index 281ea7951cb..7c55bcc3d86 100644 --- a/src/test/test-env-util.c +++ b/src/test/test-env-util.c @@ -590,4 +590,28 @@ TEST(strv_env_get_merged) { ASSERT_TRUE(strv_equal(m, expected)); } +TEST(replace_env_argv_unterminated) { + /* A bare unset "$VAR" token expands to nothing and advances neither the write index nor writes a + * terminator, so the output strv must still be NUL-terminated when such a token leads or is the + * only word. */ + + _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; + + /* Single bare unset variable: result must be a properly terminated empty strv. */ + ASSERT_OK(replace_env_argv(STRV_MAKE("$THIS_IS_UNSET"), STRV_MAKE("FOO=BAR"), &a, NULL, NULL)); + ASSERT_TRUE(strv_isempty(a)); + + /* Only unset variables. */ + ASSERT_OK(replace_env_argv(STRV_MAKE("$THIS_IS_UNSET", "$ALSO_UNSET"), STRV_MAKE("FOO=BAR"), &b, NULL, NULL)); + ASSERT_TRUE(strv_isempty(b)); + + /* Trailing bare unset variable after an expanded one. */ + ASSERT_OK(replace_env_argv(STRV_MAKE("$FOO", "$THIS_IS_UNSET"), STRV_MAKE("FOO=BAR"), &c, NULL, NULL)); + ASSERT_TRUE(strv_equal(c, STRV_MAKE("BAR"))); + + /* Trailing bare unset variable after a literal word. */ + ASSERT_OK(replace_env_argv(STRV_MAKE("hello", "$THIS_IS_UNSET"), STRV_MAKE("FOO=BAR"), &d, NULL, NULL)); + ASSERT_TRUE(strv_equal(d, STRV_MAKE("hello"))); +} + DEFINE_TEST_MAIN(LOG_DEBUG);