diff --git a/SOURCES/0762-unit-name-tighten-checks-for-building-valid-unit-nam.patch b/SOURCES/0762-unit-name-tighten-checks-for-building-valid-unit-nam.patch new file mode 100644 index 0000000..41dfb89 --- /dev/null +++ b/SOURCES/0762-unit-name-tighten-checks-for-building-valid-unit-nam.patch @@ -0,0 +1,181 @@ +From d4caf8718db1d2dddf7f87cbc192cff401ebcf59 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 25 May 2020 00:34:58 +0200 +Subject: [PATCH] unit-name: tighten checks for building valid unit names + +Let's be more thorough that whenever we build a unit name based on +parameters, that the result is actually a valid user name. If it isn't +fail early. + +This should allows us to catch various issues earlier, in particular +when we synthesize mount units from /proc/self/mountinfo: instead of +actually attempting to allocate a mount unit we will fail much earlier +when we build the name to synthesize the unit under. Failing early is a +good thing generally. + +(cherry picked from commit ab19db01ae1826efb3cbdf6dcb6a14412f8844d4) + +Related: #2094712 +--- + src/basic/unit-name.c | 61 ++++++++++++++++++++++++++++++------------- + 1 file changed, 43 insertions(+), 18 deletions(-) + +diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c +index 614eb8649b..f9b3fafd4d 100644 +--- a/src/basic/unit-name.c ++++ b/src/basic/unit-name.c +@@ -207,8 +207,9 @@ UnitType unit_name_to_type(const char *n) { + } + + int unit_name_change_suffix(const char *n, const char *suffix, char **ret) { +- char *e, *s; ++ _cleanup_free_ char *s = NULL; + size_t a, b; ++ char *e; + + assert(n); + assert(suffix); +@@ -230,8 +231,12 @@ int unit_name_change_suffix(const char *n, const char *suffix, char **ret) { + return -ENOMEM; + + strcpy(mempcpy(s, n, a), suffix); +- *ret = s; + ++ /* Make sure the name is still valid (i.e. didn't grow too large due to longer suffix) */ ++ if (!unit_name_is_valid(s, UNIT_NAME_ANY)) ++ return -EINVAL; ++ ++ *ret = TAKE_PTR(s); + return 0; + } + +@@ -253,8 +258,8 @@ int unit_name_build(const char *prefix, const char *instance, const char *suffix + } + + int unit_name_build_from_type(const char *prefix, const char *instance, UnitType type, char **ret) { ++ _cleanup_free_ char *s = NULL; + const char *ut; +- char *s; + + assert(prefix); + assert(type >= 0); +@@ -264,19 +269,23 @@ int unit_name_build_from_type(const char *prefix, const char *instance, UnitType + if (!unit_prefix_is_valid(prefix)) + return -EINVAL; + +- if (instance && !unit_instance_is_valid(instance)) +- return -EINVAL; +- + ut = unit_type_to_string(type); + +- if (!instance) +- s = strjoin(prefix, ".", ut); +- else ++ if (instance) { ++ if (!unit_instance_is_valid(instance)) ++ return -EINVAL; ++ + s = strjoin(prefix, "@", instance, ".", ut); ++ } else ++ s = strjoin(prefix, ".", ut); + if (!s) + return -ENOMEM; + +- *ret = s; ++ /* Verify that this didn't grow too large (or otherwise is invalid) */ ++ if (!unit_name_is_valid(s, instance ? UNIT_NAME_INSTANCE : UNIT_NAME_PLAIN)) ++ return -EINVAL; ++ ++ *ret = TAKE_PTR(s); + return 0; + } + +@@ -445,8 +454,8 @@ int unit_name_path_unescape(const char *f, char **ret) { + } + + int unit_name_replace_instance(const char *f, const char *i, char **ret) { ++ _cleanup_free_ char *s = NULL; + const char *p, *e; +- char *s; + size_t a, b; + + assert(f); +@@ -470,7 +479,11 @@ int unit_name_replace_instance(const char *f, const char *i, char **ret) { + + strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e); + +- *ret = s; ++ /* Make sure the resulting name still is valid, i.e. didn't grow too large */ ++ if (!unit_name_is_valid(s, UNIT_NAME_INSTANCE)) ++ return -EINVAL; ++ ++ *ret = TAKE_PTR(s); + return 0; + } + +@@ -501,8 +514,7 @@ int unit_name_template(const char *f, char **ret) { + } + + int unit_name_from_path(const char *path, const char *suffix, char **ret) { +- _cleanup_free_ char *p = NULL; +- char *s = NULL; ++ _cleanup_free_ char *p = NULL, *s = NULL; + int r; + + assert(path); +@@ -520,7 +532,11 @@ int unit_name_from_path(const char *path, const char *suffix, char **ret) { + if (!s) + return -ENOMEM; + +- *ret = s; ++ /* Refuse this if this got too long or for some other reason didn't result in a valid name */ ++ if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) ++ return -EINVAL; ++ ++ *ret = TAKE_PTR(s); + return 0; + } + +@@ -548,6 +564,10 @@ int unit_name_from_path_instance(const char *prefix, const char *path, const cha + if (!s) + return -ENOMEM; + ++ /* Refuse this if this got too long or for some other reason didn't result in a valid name */ ++ if (!unit_name_is_valid(s, UNIT_NAME_INSTANCE)) ++ return -EINVAL; ++ + *ret = s; + return 0; + } +@@ -601,7 +621,7 @@ static bool do_escape_mangle(const char *f, bool allow_globs, char *t) { + * If @allow_globs, globs characters are preserved. Otherwise, they are escaped. + */ + int unit_name_mangle_with_suffix(const char *name, UnitNameMangle flags, const char *suffix, char **ret) { +- char *s; ++ _cleanup_free_ char *s = NULL; + int r; + bool mangled; + +@@ -656,7 +676,12 @@ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle flags, const c + if ((!(flags & UNIT_NAME_MANGLE_GLOB) || !string_is_glob(s)) && unit_name_to_type(s) < 0) + strcat(s, suffix); + +- *ret = s; ++ /* Make sure mangling didn't grow this too large (but don't do this check if globbing is allowed, ++ * since globs generally do not qualify as valid unit names) */ ++ if (!FLAGS_SET(flags, UNIT_NAME_MANGLE_GLOB) && !unit_name_is_valid(s, UNIT_NAME_ANY)) ++ return -EINVAL; ++ ++ *ret = TAKE_PTR(s); + return 1; + + good: +@@ -664,7 +689,7 @@ good: + if (!s) + return -ENOMEM; + +- *ret = s; ++ *ret = TAKE_PTR(s); + return 0; + } + diff --git a/SOURCES/0763-core-shorten-long-unit-names-that-are-based-on-paths.patch b/SOURCES/0763-core-shorten-long-unit-names-that-are-based-on-paths.patch new file mode 100644 index 0000000..f1ad62f --- /dev/null +++ b/SOURCES/0763-core-shorten-long-unit-names-that-are-based-on-paths.patch @@ -0,0 +1,275 @@ +From b2cfcb1f3801ae007698fce9139b39cefdfd66e1 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 15 Mar 2022 19:02:05 +0100 +Subject: [PATCH] core: shorten long unit names that are based on paths and + append path hash at the end + +Fixes #18077 + +(cherry picked from commit 1d0727e76fd5e9a07cc9991ec9a10ea1d78a99c7) + +Resolves: #2094712 +--- + src/basic/string-util.h | 23 +++++----- + src/basic/unit-name.c | 88 ++++++++++++++++++++++++++++++++++++++- + src/basic/unit-name.h | 3 ++ + src/core/mount.c | 3 ++ + src/test/test-unit-name.c | 25 ++++++++++- + 5 files changed, 129 insertions(+), 13 deletions(-) + +diff --git a/src/basic/string-util.h b/src/basic/string-util.h +index 742b566932..0d406ff64a 100644 +--- a/src/basic/string-util.h ++++ b/src/basic/string-util.h +@@ -9,17 +9,18 @@ + #include "macro.h" + + /* What is interpreted as whitespace? */ +-#define WHITESPACE " \t\n\r" +-#define NEWLINE "\n\r" +-#define QUOTES "\"\'" +-#define COMMENTS "#;" +-#define GLOB_CHARS "*?[" +-#define DIGITS "0123456789" +-#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +-#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +-#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS +-#define ALPHANUMERICAL LETTERS DIGITS +-#define HEXDIGITS DIGITS "abcdefABCDEF" ++#define WHITESPACE " \t\n\r" ++#define NEWLINE "\n\r" ++#define QUOTES "\"\'" ++#define COMMENTS "#;" ++#define GLOB_CHARS "*?[" ++#define DIGITS "0123456789" ++#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" ++#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS ++#define ALPHANUMERICAL LETTERS DIGITS ++#define HEXDIGITS DIGITS "abcdefABCDEF" ++#define LOWERCASE_HEXDIGITS DIGITS "abcdef" + + #define streq(a,b) (strcmp((a),(b)) == 0) + #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c +index f9b3fafd4d..65ed979e39 100644 +--- a/src/basic/unit-name.c ++++ b/src/basic/unit-name.c +@@ -6,11 +6,17 @@ + #include + #include + ++#include "sd-id128.h" ++ + #include "alloc-util.h" + #include "glob-util.h" + #include "hexdecoct.h" + #include "path-util.h" ++#include "random-util.h" ++#include "siphash24.h" ++#include "sparse-endian.h" + #include "special.h" ++#include "stdio-util.h" + #include "string-util.h" + #include "strv.h" + #include "unit-name.h" +@@ -31,6 +37,9 @@ + VALID_CHARS_WITH_AT \ + "[]!-*?" + ++#define LONG_UNIT_NAME_HASH_KEY SD_ID128_MAKE(ec,f2,37,fb,58,32,4a,32,84,9f,06,9b,0d,21,eb,9a) ++#define UNIT_NAME_HASH_LENGTH_CHARS 16 ++ + bool unit_name_is_valid(const char *n, UnitNameFlags flags) { + const char *e, *i, *at; + +@@ -513,6 +522,68 @@ int unit_name_template(const char *f, char **ret) { + return 0; + } + ++bool unit_name_is_hashed(const char *name) { ++ char *s; ++ ++ if (!unit_name_is_valid(name, UNIT_NAME_PLAIN)) ++ return false; ++ ++ assert_se(s = strrchr(name, '.')); ++ ++ if (s - name < UNIT_NAME_HASH_LENGTH_CHARS + 1) ++ return false; ++ ++ s -= UNIT_NAME_HASH_LENGTH_CHARS; ++ if (s[-1] != '_') ++ return false; ++ ++ for (size_t i = 0; i < UNIT_NAME_HASH_LENGTH_CHARS; i++) ++ if (!strchr(LOWERCASE_HEXDIGITS, s[i])) ++ return false; ++ ++ return true; ++} ++ ++int unit_name_hash_long(const char *name, char **ret) { ++ _cleanup_free_ char *n = NULL, *hash = NULL; ++ char *suffix; ++ le64_t h; ++ size_t len; ++ ++ if (strlen(name) < UNIT_NAME_MAX) ++ return -EMSGSIZE; ++ ++ suffix = strrchr(name, '.'); ++ if (!suffix) ++ return -EINVAL; ++ ++ if (unit_type_from_string(suffix+1) < 0) ++ return -EINVAL; ++ ++ h = htole64(siphash24(name, strlen(name) + 1, LONG_UNIT_NAME_HASH_KEY.bytes)); ++ ++ hash = hexmem(&h, sizeof(h)); ++ if (!hash) ++ return -ENOMEM; ++ ++ assert_se(strlen(hash) == UNIT_NAME_HASH_LENGTH_CHARS); ++ ++ len = UNIT_NAME_MAX - 1 - strlen(suffix+1) - UNIT_NAME_HASH_LENGTH_CHARS - 2; ++ assert(len > 0 && len < UNIT_NAME_MAX); ++ ++ n = strndup(name, len); ++ if (!n) ++ return -ENOMEM; ++ ++ if (!strextend(&n, "_", hash, suffix, NULL)) ++ return -ENOMEM; ++ assert_se(unit_name_is_valid(n, UNIT_NAME_PLAIN)); ++ ++ *ret = TAKE_PTR(n); ++ ++ return 0; ++} ++ + int unit_name_from_path(const char *path, const char *suffix, char **ret) { + _cleanup_free_ char *p = NULL, *s = NULL; + int r; +@@ -532,7 +603,19 @@ int unit_name_from_path(const char *path, const char *suffix, char **ret) { + if (!s) + return -ENOMEM; + +- /* Refuse this if this got too long or for some other reason didn't result in a valid name */ ++ if (strlen(s) >= UNIT_NAME_MAX) { ++ _cleanup_free_ char *n = NULL; ++ ++ log_debug("Unit name \"%s\" too long, falling back to hashed unit name.", s); ++ ++ r = unit_name_hash_long(s, &n); ++ if (r < 0) ++ return r; ++ ++ free_and_replace(s, n); ++ } ++ ++ /* Refuse if this for some other reason didn't result in a valid name */ + if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) + return -EINVAL; + +@@ -582,6 +665,9 @@ int unit_name_to_path(const char *name, char **ret) { + if (r < 0) + return r; + ++ if (unit_name_is_hashed(name)) ++ return -ENAMETOOLONG; ++ + return unit_name_path_unescape(prefix, ret); + } + +diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h +index 61abcd585b..602295af8f 100644 +--- a/src/basic/unit-name.h ++++ b/src/basic/unit-name.h +@@ -45,6 +45,9 @@ int unit_name_replace_instance(const char *f, const char *i, char **ret); + + int unit_name_template(const char *f, char **ret); + ++int unit_name_hash_long(const char *name, char **ret); ++bool unit_name_is_hashed(const char *name); ++ + int unit_name_from_path(const char *path, const char *suffix, char **ret); + int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret); + int unit_name_to_path(const char *name, char **ret); +diff --git a/src/core/mount.c b/src/core/mount.c +index d37b5731f8..e69ecb7ce3 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -572,6 +572,9 @@ static int mount_add_extras(Mount *m) { + + if (!m->where) { + r = unit_name_to_path(u->id, &m->where); ++ if (r == -ENAMETOOLONG) ++ log_unit_error_errno(u, r, "Failed to derive mount point path from unit name, because unit name is hashed. " ++ "Set \"Where=\" in the unit file explicitly."); + if (r < 0) + return r; + } +diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c +index 2b00ef8cb7..35cfaafd30 100644 +--- a/src/test/test-unit-name.c ++++ b/src/test/test-unit-name.c +@@ -82,6 +82,7 @@ static void test_unit_name_replace_instance(void) { + + static void test_unit_name_from_path_one(const char *path, const char *suffix, const char *expected, int ret) { + _cleanup_free_ char *t = NULL; ++ int r; + + assert_se(unit_name_from_path(path, suffix, &t) == ret); + puts(strna(t)); +@@ -89,12 +90,31 @@ static void test_unit_name_from_path_one(const char *path, const char *suffix, c + + if (t) { + _cleanup_free_ char *k = NULL; +- assert_se(unit_name_to_path(t, &k) == 0); ++ ++ /* We don't support converting hashed unit names back to paths */ ++ r = unit_name_to_path(t, &k); ++ if (r == -ENAMETOOLONG) ++ return; ++ assert(r == 0); ++ + puts(strna(k)); + assert_se(path_equal(k, empty_to_root(path))); + } + } + ++static void test_unit_name_is_hashed(void) { ++ assert_se(!unit_name_is_hashed("")); ++ assert_se(!unit_name_is_hashed("foo@bar.service")); ++ assert_se(!unit_name_is_hashed("foo@.service")); ++ assert_se(unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9ed33c2ec55.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736D9ED33C2EC55.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!7736d9ed33c2ec55.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9gd33c2ec55.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_2103e1466b87f7f7@waldo.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_2103e1466b87f7f7@.mount")); ++} ++ + static void test_unit_name_from_path(void) { + puts("-------------------------------------------------"); + test_unit_name_from_path_one("/waldo", ".mount", "waldo.mount", 0); +@@ -105,6 +125,8 @@ static void test_unit_name_from_path(void) { + test_unit_name_from_path_one("///", ".mount", "-.mount", 0); + test_unit_name_from_path_one("/foo/../bar", ".mount", NULL, -EINVAL); + test_unit_name_from_path_one("/foo/./bar", ".mount", NULL, -EINVAL); ++ test_unit_name_from_path_one("/waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ".mount", ++ "waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9ed33c2ec55.mount", 0); + } + + static void test_unit_name_from_path_instance_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) { +@@ -824,6 +846,7 @@ int main(int argc, char* argv[]) { + + test_unit_name_is_valid(); + test_unit_name_replace_instance(); ++ test_unit_name_is_hashed(); + test_unit_name_from_path(); + test_unit_name_from_path_instance(); + test_unit_name_mangle(); diff --git a/SOURCES/0764-test-add-extended-test-for-triggering-mount-rate-lim.patch b/SOURCES/0764-test-add-extended-test-for-triggering-mount-rate-lim.patch new file mode 100644 index 0000000..684e346 --- /dev/null +++ b/SOURCES/0764-test-add-extended-test-for-triggering-mount-rate-lim.patch @@ -0,0 +1,162 @@ +From 294efa52d47be083704da51b148c685d347be4ac Mon Sep 17 00:00:00 2001 +From: Anita Zhang +Date: Tue, 8 Jun 2021 00:04:35 -0700 +Subject: [PATCH] test: add extended test for triggering mount rate limit + +It's hard to trigger the failure to exit the rate limit state in +isolation as it needs multiple event sources in order to show that it +gets stuck in the queue. Hence why this is an extended test. + +(cherry picked from commit 0c81900965a72b29eb76e0737ed899b925ee75b6) + +Related: #2094712 +--- + test/TEST-60-MOUNT-RATELIMIT/Makefile | 1 + + test/TEST-60-MOUNT-RATELIMIT/test.sh | 48 +++++++++++++++ + test/TEST-60-MOUNT-RATELIMIT/testsuite.sh | 73 +++++++++++++++++++++++ + 3 files changed, 122 insertions(+) + create mode 120000 test/TEST-60-MOUNT-RATELIMIT/Makefile + create mode 100755 test/TEST-60-MOUNT-RATELIMIT/test.sh + create mode 100755 test/TEST-60-MOUNT-RATELIMIT/testsuite.sh + +diff --git a/test/TEST-60-MOUNT-RATELIMIT/Makefile b/test/TEST-60-MOUNT-RATELIMIT/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-60-MOUNT-RATELIMIT/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-60-MOUNT-RATELIMIT/test.sh b/test/TEST-60-MOUNT-RATELIMIT/test.sh +new file mode 100755 +index 0000000000..e3c9288546 +--- /dev/null ++++ b/test/TEST-60-MOUNT-RATELIMIT/test.sh +@@ -0,0 +1,48 @@ ++#!/usr/bin/env bash ++set -e ++TEST_DESCRIPTION="Test that mount/unmount storms can enter/exit rate limit state and will not leak units" ++ ++. $TEST_BASE_DIR/test-functions ++ ++test_setup() { ++ create_empty_image ++ mkdir -p $TESTDIR/root ++ mount ${LOOPDEV}p1 $TESTDIR/root ++ ++ ( ++ LOG_LEVEL=5 ++ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) ++ ++ setup_basic_environment ++ ++ # mask some services that we do not want to run in these tests ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service ++ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service ++ ++ # setup the testsuite service ++ cat >$initdir/etc/systemd/system/testsuite.service </testok ++ ++exit 0 diff --git a/SOURCES/0765-tests-add-test-case-for-long-unit-names.patch b/SOURCES/0765-tests-add-test-case-for-long-unit-names.patch new file mode 100644 index 0000000..a6c458a --- /dev/null +++ b/SOURCES/0765-tests-add-test-case-for-long-unit-names.patch @@ -0,0 +1,42 @@ +From 7363f240c0bb9032c0c615934d5fe4d1eaa56077 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 23 Mar 2022 13:35:44 +0100 +Subject: [PATCH] tests: add test case for long unit names + +(cherry picked from commit 2ef0101e0b2813e8c99fc8f137dbaa763ca16057) + +Related: #2094712 +--- + test/TEST-60-MOUNT-RATELIMIT/testsuite.sh | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/test/TEST-60-MOUNT-RATELIMIT/testsuite.sh b/test/TEST-60-MOUNT-RATELIMIT/testsuite.sh +index 8158754667..6211050faf 100755 +--- a/test/TEST-60-MOUNT-RATELIMIT/testsuite.sh ++++ b/test/TEST-60-MOUNT-RATELIMIT/testsuite.sh +@@ -7,6 +7,25 @@ systemd-analyze log-target journal + + NUM_DIRS=20 + ++# make sure we can handle mounts at very long paths such that mount unit name must be hashed to fall within our unit name limit ++LONGPATH="$(printf "/$(printf "x%0.s" {1..255})%0.s" {1..7})" ++LONGMNT="$(systemd-escape --suffix=mount --path "$LONGPATH")" ++TS="$(date '+%H:%M:%S')" ++ ++mkdir -p "$LONGPATH" ++mount -t tmpfs tmpfs "$LONGPATH" ++systemctl daemon-reload ++ ++# check that unit is active(mounted) ++systemctl --no-pager show -p SubState --value "$LONGPATH" | grep -q mounted ++ ++# check that relevant part of journal doesn't contain any errors related to unit ++[ "$(journalctl -b --since="$TS" --priority=err | grep -c "$LONGMNT")" = "0" ] ++ ++# check that we can successfully stop the mount unit ++systemctl stop "$LONGPATH" ++rm -rf "$LONGPATH" ++ + # mount/unmount enough times to trigger the /proc/self/mountinfo parsing rate limiting + + for ((i = 0; i < NUM_DIRS; i++)); do diff --git a/SOURCES/0766-Revert-core-Propagate-condition-failed-state-to-trig.patch b/SOURCES/0766-Revert-core-Propagate-condition-failed-state-to-trig.patch new file mode 100644 index 0000000..40b8971 --- /dev/null +++ b/SOURCES/0766-Revert-core-Propagate-condition-failed-state-to-trig.patch @@ -0,0 +1,255 @@ +From eef171ea21cf4b77f62269aabfd8bf0fdd92b7bf Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Fri, 17 Dec 2021 19:39:29 +0100 +Subject: [PATCH] Revert "core: Propagate condition failed state to triggering + units." + +This reverts commit 12ab94a1e4961a39c32efb60b71866ab588d3ea2. + +(cherry picked from commit 40f41f34d4af15d0147b5b2525f0b87ff62eae9a) + +Related: #2123801 +--- + src/core/automount.c | 14 ++++---------- + src/core/automount.h | 1 - + src/core/path.c | 16 +++++----------- + src/core/path.h | 1 - + src/core/socket.c | 28 +++++++++------------------- + src/core/socket.h | 1 - + src/core/timer.c | 12 +++--------- + src/core/timer.h | 1 - + src/core/unit.c | 10 ---------- + src/core/unit.h | 2 -- + 10 files changed, 21 insertions(+), 65 deletions(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index bac3b2fab7..c1c513d4a5 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -776,11 +776,6 @@ static void automount_enter_running(Automount *a) { + goto fail; + } + +- if (unit_has_failed_condition_or_assert(trigger)) { +- automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED); +- return; +- } +- + r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL); + if (r < 0) { + log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r)); +@@ -1092,11 +1087,10 @@ static int automount_can_start(Unit *u) { + } + + static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { +- [AUTOMOUNT_SUCCESS] = "success", +- [AUTOMOUNT_FAILURE_RESOURCES] = "resources", +- [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", +- [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", +- [AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED] = "mount-condition-failed", ++ [AUTOMOUNT_SUCCESS] = "success", ++ [AUTOMOUNT_FAILURE_RESOURCES] = "resources", ++ [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", ++ [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", + }; + + DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); +diff --git a/src/core/automount.h b/src/core/automount.h +index a7417d195c..21dd1c0774 100644 +--- a/src/core/automount.h ++++ b/src/core/automount.h +@@ -10,7 +10,6 @@ typedef enum AutomountResult { + AUTOMOUNT_FAILURE_RESOURCES, + AUTOMOUNT_FAILURE_START_LIMIT_HIT, + AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT, +- AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED, + _AUTOMOUNT_RESULT_MAX, + _AUTOMOUNT_RESULT_INVALID = -1 + } AutomountResult; +diff --git a/src/core/path.c b/src/core/path.c +index bf7e1bf3c2..c2facf0b16 100644 +--- a/src/core/path.c ++++ b/src/core/path.c +@@ -453,7 +453,7 @@ static void path_enter_dead(Path *p, PathResult f) { + else + unit_log_failure(UNIT(p), path_result_to_string(p->result)); + +- path_set_state(p, p->result == PATH_SUCCESS ? PATH_DEAD : PATH_FAILED); ++ path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD); + } + + static void path_enter_running(Path *p) { +@@ -711,11 +711,6 @@ static void path_trigger_notify(Unit *u, Unit *other) { + return; + } + +- if (unit_has_failed_condition_or_assert(other)) { +- path_enter_dead(p, PATH_FAILURE_UNIT_CONDITION_FAILED); +- return; +- } +- + /* Don't propagate anything if there's still a job queued */ + if (other->job) + return; +@@ -768,11 +763,10 @@ static const char* const path_type_table[_PATH_TYPE_MAX] = { + DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); + + static const char* const path_result_table[_PATH_RESULT_MAX] = { +- [PATH_SUCCESS] = "success", +- [PATH_FAILURE_RESOURCES] = "resources", +- [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", +- [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", +- [PATH_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed", ++ [PATH_SUCCESS] = "success", ++ [PATH_FAILURE_RESOURCES] = "resources", ++ [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", ++ [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", + }; + + DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult); +diff --git a/src/core/path.h b/src/core/path.h +index 0ad6bd12c6..8a69f06c13 100644 +--- a/src/core/path.h ++++ b/src/core/path.h +@@ -46,7 +46,6 @@ typedef enum PathResult { + PATH_FAILURE_RESOURCES, + PATH_FAILURE_START_LIMIT_HIT, + PATH_FAILURE_UNIT_START_LIMIT_HIT, +- PATH_FAILURE_UNIT_CONDITION_FAILED, + _PATH_RESULT_MAX, + _PATH_RESULT_INVALID = -1 + } PathResult; +diff --git a/src/core/socket.c b/src/core/socket.c +index 6f9a0f7575..74c1cc70cb 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -2272,15 +2272,6 @@ static void socket_enter_running(Socket *s, int cfd) { + goto refuse; + } + +- if (UNIT_ISSET(s->service) && cfd < 0) { +- Unit *service = UNIT_DEREF(s->service); +- +- if (unit_has_failed_condition_or_assert(service)) { +- socket_enter_dead(s, SOCKET_FAILURE_SERVICE_CONDITION_FAILED); +- return; +- } +- } +- + if (cfd < 0) { + bool pending = false; + Unit *other; +@@ -3296,16 +3287,15 @@ static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { + DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand); + + static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { +- [SOCKET_SUCCESS] = "success", +- [SOCKET_FAILURE_RESOURCES] = "resources", +- [SOCKET_FAILURE_TIMEOUT] = "timeout", +- [SOCKET_FAILURE_EXIT_CODE] = "exit-code", +- [SOCKET_FAILURE_SIGNAL] = "signal", +- [SOCKET_FAILURE_CORE_DUMP] = "core-dump", +- [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", +- [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", +- [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit", +- [SOCKET_FAILURE_SERVICE_CONDITION_FAILED] = "service-condition-failed", ++ [SOCKET_SUCCESS] = "success", ++ [SOCKET_FAILURE_RESOURCES] = "resources", ++ [SOCKET_FAILURE_TIMEOUT] = "timeout", ++ [SOCKET_FAILURE_EXIT_CODE] = "exit-code", ++ [SOCKET_FAILURE_SIGNAL] = "signal", ++ [SOCKET_FAILURE_CORE_DUMP] = "core-dump", ++ [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", ++ [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", ++ [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit" + }; + + DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult); +diff --git a/src/core/socket.h b/src/core/socket.h +index b171b94316..2409dbf2a0 100644 +--- a/src/core/socket.h ++++ b/src/core/socket.h +@@ -39,7 +39,6 @@ typedef enum SocketResult { + SOCKET_FAILURE_START_LIMIT_HIT, + SOCKET_FAILURE_TRIGGER_LIMIT_HIT, + SOCKET_FAILURE_SERVICE_START_LIMIT_HIT, +- SOCKET_FAILURE_SERVICE_CONDITION_FAILED, + _SOCKET_RESULT_MAX, + _SOCKET_RESULT_INVALID = -1 + } SocketResult; +diff --git a/src/core/timer.c b/src/core/timer.c +index 3c8d89771d..990f05fee4 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -567,11 +567,6 @@ static void timer_enter_running(Timer *t) { + return; + } + +- if (unit_has_failed_condition_or_assert(trigger)) { +- timer_enter_dead(t, TIMER_FAILURE_UNIT_CONDITION_FAILED); +- return; +- } +- + r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL); + if (r < 0) + goto fail; +@@ -855,10 +850,9 @@ static const char* const timer_base_table[_TIMER_BASE_MAX] = { + DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); + + static const char* const timer_result_table[_TIMER_RESULT_MAX] = { +- [TIMER_SUCCESS] = "success", +- [TIMER_FAILURE_RESOURCES] = "resources", +- [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit", +- [TIMER_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed", ++ [TIMER_SUCCESS] = "success", ++ [TIMER_FAILURE_RESOURCES] = "resources", ++ [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + }; + + DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult); +diff --git a/src/core/timer.h b/src/core/timer.h +index d23e19d622..833aadb0b8 100644 +--- a/src/core/timer.h ++++ b/src/core/timer.h +@@ -32,7 +32,6 @@ typedef enum TimerResult { + TIMER_SUCCESS, + TIMER_FAILURE_RESOURCES, + TIMER_FAILURE_START_LIMIT_HIT, +- TIMER_FAILURE_UNIT_CONDITION_FAILED, + _TIMER_RESULT_MAX, + _TIMER_RESULT_INVALID = -1 + } TimerResult; +diff --git a/src/core/unit.c b/src/core/unit.c +index 0810bf5a58..dfe0c243ef 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -5661,16 +5661,6 @@ int unit_thaw_vtable_common(Unit *u) { + return unit_cgroup_freezer_action(u, FREEZER_THAW); + } + +-bool unit_has_failed_condition_or_assert(Unit *u) { +- if (dual_timestamp_is_set(&u->condition_timestamp) && !u->condition_result) +- return true; +- +- if (dual_timestamp_is_set(&u->assert_timestamp) && !u->assert_result) +- return true; +- +- return false; +-} +- + static const char* const collect_mode_table[_COLLECT_MODE_MAX] = { + [COLLECT_INACTIVE] = "inactive", + [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed", +diff --git a/src/core/unit.h b/src/core/unit.h +index a924bd2e83..b8b914711f 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -847,8 +847,6 @@ void unit_thawed(Unit *u); + int unit_freeze_vtable_common(Unit *u); + int unit_thaw_vtable_common(Unit *u); + +-bool unit_has_failed_condition_or_assert(Unit *u); +- + /* Macros which append UNIT= or USER_UNIT= to the message */ + + #define log_unit_full(unit, level, error, ...) \ diff --git a/SOURCES/0767-core-Check-unit-start-rate-limiting-earlier.patch b/SOURCES/0767-core-Check-unit-start-rate-limiting-earlier.patch new file mode 100644 index 0000000..b575710 --- /dev/null +++ b/SOURCES/0767-core-Check-unit-start-rate-limiting-earlier.patch @@ -0,0 +1,137 @@ +From 6ec2c387cd4fe081e6a5561b5c7e66ec0555c353 Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Tue, 24 Aug 2021 16:46:47 +0100 +Subject: [PATCH] core: Check unit start rate limiting earlier + +[dtardon: This adds the test that's been left out by commit +471eda89a25a3ceac91a2d05e39a54aae78038ed] + +(cherry picked from commit 9727f2427ff6b2e1f4ab927cc57ad8e888f04e95) + +Related: #2123801 +--- + test/TEST-10-ISSUE-2467/test.sh | 3 ++ + test/TEST-63-ISSUE-17433/Makefile | 1 + + test/TEST-63-ISSUE-17433/test.sh | 42 ++++++++++++++++++++++ + test/TEST-63-ISSUE-17433/test63.path | 2 ++ + test/TEST-63-ISSUE-17433/test63.service | 5 +++ + test/TEST-63-ISSUE-17433/testsuite.service | 17 +++++++++ + 6 files changed, 70 insertions(+) + create mode 120000 test/TEST-63-ISSUE-17433/Makefile + create mode 100755 test/TEST-63-ISSUE-17433/test.sh + create mode 100644 test/TEST-63-ISSUE-17433/test63.path + create mode 100644 test/TEST-63-ISSUE-17433/test63.service + create mode 100644 test/TEST-63-ISSUE-17433/testsuite.service + +diff --git a/test/TEST-10-ISSUE-2467/test.sh b/test/TEST-10-ISSUE-2467/test.sh +index 0e61236686..a839ef79de 100755 +--- a/test/TEST-10-ISSUE-2467/test.sh ++++ b/test/TEST-10-ISSUE-2467/test.sh +@@ -42,6 +42,9 @@ EOF + [Unit] + Requires=test.socket + ConditionPathExistsGlob=/tmp/nonexistent ++# Make sure we hit the socket trigger limit in the test and not the service start limit. ++StartLimitInterval=1000 ++StartLimitBurst=1000 + + [Service] + ExecStart=/bin/true +diff --git a/test/TEST-63-ISSUE-17433/Makefile b/test/TEST-63-ISSUE-17433/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-63-ISSUE-17433/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-63-ISSUE-17433/test.sh b/test/TEST-63-ISSUE-17433/test.sh +new file mode 100755 +index 0000000000..406a1e214c +--- /dev/null ++++ b/test/TEST-63-ISSUE-17433/test.sh +@@ -0,0 +1,42 @@ ++#!/usr/bin/env bash ++set -e ++ ++TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/17433" ++ ++# shellcheck source=test/test-functions ++. "${TEST_BASE_DIR:?}/test-functions" ++ ++test_setup() { ++ create_empty_image ++ mkdir -p $TESTDIR/root ++ mount ${LOOPDEV}p1 $TESTDIR/root ++ ++ # Create what will eventually be our root filesystem onto an overlay ++ ( ++ LOG_LEVEL=5 ++ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) ++ ++ setup_basic_environment ++ ++ # setup the testsuite service ++ cp testsuite.service $initdir/etc/systemd/system/testsuite.service ++ ++ cp test63.path $initdir/etc/systemd/system/test63.path ++ cp test63.service $initdir/etc/systemd/system/test63.service ++ ++ setup_testsuite ++ ) || return 1 ++ setup_nspawn_root ++ ++ # mask some services that we do not want to run in these tests ++ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service ++ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service ++ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service ++ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket ++ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service ++ ++ ddebug "umount $TESTDIR/root" ++ umount $TESTDIR/root ++} ++ ++do_test "$@" +diff --git a/test/TEST-63-ISSUE-17433/test63.path b/test/TEST-63-ISSUE-17433/test63.path +new file mode 100644 +index 0000000000..a6573bda0a +--- /dev/null ++++ b/test/TEST-63-ISSUE-17433/test63.path +@@ -0,0 +1,2 @@ ++[Path] ++PathExists=/tmp/test63 +diff --git a/test/TEST-63-ISSUE-17433/test63.service b/test/TEST-63-ISSUE-17433/test63.service +new file mode 100644 +index 0000000000..c83801874d +--- /dev/null ++++ b/test/TEST-63-ISSUE-17433/test63.service +@@ -0,0 +1,5 @@ ++[Unit] ++ConditionPathExists=!/tmp/nonexistent ++ ++[Service] ++ExecStart=true +diff --git a/test/TEST-63-ISSUE-17433/testsuite.service b/test/TEST-63-ISSUE-17433/testsuite.service +new file mode 100644 +index 0000000000..d3ca5b002b +--- /dev/null ++++ b/test/TEST-63-ISSUE-17433/testsuite.service +@@ -0,0 +1,17 @@ ++[Unit] ++Description=TEST-63-ISSUE-17433 ++ ++[Service] ++ExecStartPre=rm -f /failed /testok ++Type=oneshot ++ExecStart=rm -f /tmp/nonexistent ++ExecStart=systemctl start test63.path ++ExecStart=touch /tmp/test63 ++# Make sure systemd has sufficient time to hit the start limit for test63.service. ++ExecStart=sleep 2 ++ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p ActiveState)" = failed' ++ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p Result)" = start-limit-hit' ++# FIXME: The path remains active, which it should not ++# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p ActiveState)" = failed' ++# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p Result)" = unit-start-limit-hit' ++ExecStart=sh -x -c 'echo OK >/testok' diff --git a/SOURCES/0768-core-Add-trigger-limit-for-path-units.patch b/SOURCES/0768-core-Add-trigger-limit-for-path-units.patch new file mode 100644 index 0000000..7307dfe --- /dev/null +++ b/SOURCES/0768-core-Add-trigger-limit-for-path-units.patch @@ -0,0 +1,127 @@ +From d61bd956e599dd747490d36ff793b63fb6a9fedc Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Fri, 17 Dec 2021 20:01:31 +0100 +Subject: [PATCH] core: Add trigger limit for path units + +When conditions fail on a service unit, a path unit can cause +PID 1 to busy loop as it keeps trying to activate the service unit. +To avoid this from happening, add a trigger limit to the path unit, +identical to the trigger limit we have for socket units. + +Initially, let's start with a high limit and not make it configurable. +If needed, we can add properties to configure the rate limit similar +to the ones we have for socket units. + +(cherry picked from commit aaae822b37aa3ca39aebb516fdc6bef36d730c25) + +Resolves: #2123801 +--- + src/core/path.c | 10 ++++++++++ + src/core/path.h | 3 +++ + test/TEST-63-ISSUE-17433/test63.service | 2 +- + test/TEST-63-ISSUE-17433/testsuite.service | 21 +++++++++++++++++---- + 4 files changed, 31 insertions(+), 5 deletions(-) + +diff --git a/src/core/path.c b/src/core/path.c +index c2facf0b16..b899bde0de 100644 +--- a/src/core/path.c ++++ b/src/core/path.c +@@ -238,6 +238,9 @@ static void path_init(Unit *u) { + assert(u->load_state == UNIT_STUB); + + p->directory_mode = 0755; ++ ++ p->trigger_limit.interval = 2 * USEC_PER_SEC; ++ p->trigger_limit.burst = 200; + } + + void path_free_specs(Path *p) { +@@ -467,6 +470,12 @@ static void path_enter_running(Path *p) { + if (unit_stop_pending(UNIT(p))) + return; + ++ if (!ratelimit_below(&p->trigger_limit)) { ++ log_unit_warning(UNIT(p), "Trigger limit hit, refusing further activation."); ++ path_enter_dead(p, PATH_FAILURE_TRIGGER_LIMIT_HIT); ++ return; ++ } ++ + trigger = UNIT_TRIGGER(UNIT(p)); + if (!trigger) { + log_unit_error(UNIT(p), "Unit to trigger vanished."); +@@ -767,6 +776,7 @@ static const char* const path_result_table[_PATH_RESULT_MAX] = { + [PATH_FAILURE_RESOURCES] = "resources", + [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", ++ [PATH_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", + }; + + DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult); +diff --git a/src/core/path.h b/src/core/path.h +index 8a69f06c13..12fd13fbe3 100644 +--- a/src/core/path.h ++++ b/src/core/path.h +@@ -46,6 +46,7 @@ typedef enum PathResult { + PATH_FAILURE_RESOURCES, + PATH_FAILURE_START_LIMIT_HIT, + PATH_FAILURE_UNIT_START_LIMIT_HIT, ++ PATH_FAILURE_TRIGGER_LIMIT_HIT, + _PATH_RESULT_MAX, + _PATH_RESULT_INVALID = -1 + } PathResult; +@@ -63,6 +64,8 @@ struct Path { + mode_t directory_mode; + + PathResult result; ++ ++ RateLimit trigger_limit; + }; + + void path_free_specs(Path *p); +diff --git a/test/TEST-63-ISSUE-17433/test63.service b/test/TEST-63-ISSUE-17433/test63.service +index c83801874d..6292434c5c 100644 +--- a/test/TEST-63-ISSUE-17433/test63.service ++++ b/test/TEST-63-ISSUE-17433/test63.service +@@ -1,5 +1,5 @@ + [Unit] +-ConditionPathExists=!/tmp/nonexistent ++ConditionPathExists=/tmp/nonexistent + + [Service] + ExecStart=true +diff --git a/test/TEST-63-ISSUE-17433/testsuite.service b/test/TEST-63-ISSUE-17433/testsuite.service +index d3ca5b002b..39f9643890 100644 +--- a/test/TEST-63-ISSUE-17433/testsuite.service ++++ b/test/TEST-63-ISSUE-17433/testsuite.service +@@ -4,14 +4,27 @@ Description=TEST-63-ISSUE-17433 + [Service] + ExecStartPre=rm -f /failed /testok + Type=oneshot ++ ++# Test that a path unit continuously triggering a service that fails condition checks eventually fails with ++# the trigger-limit-hit error. + ExecStart=rm -f /tmp/nonexistent + ExecStart=systemctl start test63.path + ExecStart=touch /tmp/test63 +-# Make sure systemd has sufficient time to hit the start limit for test63.service. ++# Make sure systemd has sufficient time to hit the trigger limit for test63.path. + ExecStart=sleep 2 +-ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p ActiveState)" = failed' +-ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p Result)" = start-limit-hit' ++ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p ActiveState)" = inactive' ++ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p Result)" = success' + # FIXME: The path remains active, which it should not + # ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p ActiveState)" = failed' +-# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p Result)" = unit-start-limit-hit' ++# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p Result)" = trigger-limit-hit' ++ ++# Test that starting the service manually doesn't affect the path unit. ++ExecStart=rm -f /tmp/test63 ++ExecStart=systemctl reset-failed ++ExecStart=systemctl start test63.path ++ExecStart=systemctl start test63.service ++ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p ActiveState)" = inactive' ++ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p Result)" = success' ++ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p ActiveState)" = active' ++ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p Result)" = success' + ExecStart=sh -x -c 'echo OK >/testok' diff --git a/SOURCES/0769-resolved-pin-stream-while-calling-callbacks-for-it.patch b/SOURCES/0769-resolved-pin-stream-while-calling-callbacks-for-it.patch new file mode 100644 index 0000000..9bf0eb6 --- /dev/null +++ b/SOURCES/0769-resolved-pin-stream-while-calling-callbacks-for-it.patch @@ -0,0 +1,39 @@ +From b92fae31236301ba1fcca604c68bb4e908318c49 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 4 Dec 2018 22:13:39 +0100 +Subject: [PATCH] resolved: pin stream while calling callbacks for it + +These callbacks might unref the stream, but we still have to access it, +let's hence ref it explicitly. + +Maybe fixes: #10725 + +(cherry picked from commit d973d94dec349fb676fdd844f6fe2ada3538f27c) + +Resolves: #2110548 +--- + src/resolve/resolved-dns-stream.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c +index 555e200a23..ca0313d1d7 100644 +--- a/src/resolve/resolved-dns-stream.c ++++ b/src/resolve/resolved-dns-stream.c +@@ -42,6 +42,8 @@ static int dns_stream_update_io(DnsStream *s) { + } + + static int dns_stream_complete(DnsStream *s, int error) { ++ _cleanup_(dns_stream_unrefp) _unused_ DnsStream *ref = dns_stream_ref(s); /* Protect stream while we process it */ ++ + assert(s); + + #if ENABLE_DNS_OVER_TLS +@@ -316,7 +318,7 @@ static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) { + } + + static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) { +- DnsStream *s = userdata; ++ _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */ + int r; + + assert(s); diff --git a/SOURCES/0770-core-move-reset_arguments-to-the-end-of-main-s-finis.patch b/SOURCES/0770-core-move-reset_arguments-to-the-end-of-main-s-finis.patch new file mode 100644 index 0000000..e61aa01 --- /dev/null +++ b/SOURCES/0770-core-move-reset_arguments-to-the-end-of-main-s-finis.patch @@ -0,0 +1,49 @@ +From 34aeec27c86917e7284ea562f62e46384d5da5ba Mon Sep 17 00:00:00 2001 +From: Anita Zhang +Date: Thu, 17 Sep 2020 01:49:17 -0700 +Subject: [PATCH] core: move reset_arguments() to the end of main's finish + +Fixes #16991 + +fb39af4ce42d7ef9af63009f271f404038703704 replaced `free_arguments()` with +`reset_arguments()`, which frees arg_* variables as before, but also resets all +of them to the default values. `reset_arguments()` was positioned +in such a way that it overrode some arg_* values still in use at shutdown. + +To avoid further unintentional resets, I moved `reset_arguments()` +right before the return, when nothing else will be using the arg_* variables. + +(cherry picked from commit 7d9eea2bd3d4f83668c7a78754d201b226acbf1e) + +Resolves: #2127171 +--- + src/core/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/core/main.c b/src/core/main.c +index d897155644..a4cdb28884 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -2622,7 +2622,6 @@ finish: + m = manager_free(m); + } + +- reset_arguments(); + mac_selinux_finish(); + + if (reexecute) +@@ -2647,6 +2646,7 @@ finish: + * in become_shutdown() so normally we cannot free them yet. */ + watchdog_free_device(); + arg_watchdog_device = mfree(arg_watchdog_device); ++ reset_arguments(); + return retval; + } + #endif +@@ -2668,5 +2668,6 @@ finish: + freeze_or_reboot(); + } + ++ reset_arguments(); + return retval; + } diff --git a/SOURCES/9000-resolved-pin-stream-while-calling-callbacks-for-it.patch b/SOURCES/9000-resolved-pin-stream-while-calling-callbacks-for-it.patch deleted file mode 100644 index 9b82d08..0000000 --- a/SOURCES/9000-resolved-pin-stream-while-calling-callbacks-for-it.patch +++ /dev/null @@ -1,42 +0,0 @@ -From a4f08c798cabd5c43f2578a9e2b048fa1ad4a52c Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Tue, 4 Dec 2018 22:13:39 +0100 -Subject: [PATCH] resolved: pin stream while calling callbacks for it - -These callbacks might unref the stream, but we still have to access it, -let's hence ref it explicitly. - -Maybe fixes: #10725 - -(cherry picked from commit d973d94dec349fb676fdd844f6fe2ada3538f27c) - -Resolves: #2110548 ---- - src/resolve/resolved-dns-stream.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c -index 066daef96e..2d0162483a 100644 ---- a/src/resolve/resolved-dns-stream.c -+++ b/src/resolve/resolved-dns-stream.c -@@ -42,6 +42,8 @@ static int dns_stream_update_io(DnsStream *s) { - } - - static int dns_stream_complete(DnsStream *s, int error) { -+ _cleanup_(dns_stream_unrefp) _unused_ DnsStream *ref = dns_stream_ref(s); /* Protect stream while we process it */ -+ - assert(s); - - #if ENABLE_DNS_OVER_TLS -@@ -315,7 +317,7 @@ static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) { - } - - static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) { -- DnsStream *s = userdata; -+ _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */ - int r; - - assert(s); --- -2.37.1 - diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index 605bd40..2027214 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -13,7 +13,7 @@ Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd Version: 239 -Release: 58%{?dist}.7 +Release: 58%{?dist}.8 # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -811,8 +811,16 @@ Patch0758: 0758-sd-event-don-t-invalidate-source-type-on-disconnect.patch Patch0759: 0759-test-procfs-util-skip-test-on-certain-errors.patch Patch0760: 0760-Try-stopping-MD-RAID-devices-in-shutdown-too.patch Patch0761: 0761-shutdown-get-only-active-md-arrays.patch +Patch0762: 0762-unit-name-tighten-checks-for-building-valid-unit-nam.patch +Patch0763: 0763-core-shorten-long-unit-names-that-are-based-on-paths.patch +Patch0764: 0764-test-add-extended-test-for-triggering-mount-rate-lim.patch +Patch0765: 0765-tests-add-test-case-for-long-unit-names.patch +Patch0766: 0766-Revert-core-Propagate-condition-failed-state-to-trig.patch +Patch0767: 0767-core-Check-unit-start-rate-limiting-earlier.patch +Patch0768: 0768-core-Add-trigger-limit-for-path-units.patch +Patch0769: 0769-resolved-pin-stream-while-calling-callbacks-for-it.patch +Patch0770: 0770-core-move-reset_arguments-to-the-end-of-main-s-finis.patch -Patch9000: 9000-resolved-pin-stream-while-calling-callbacks-for-it.patch %ifarch %{ix86} x86_64 aarch64 %global have_gnu_efi 1 @@ -1442,6 +1450,17 @@ fi %files tests -f .file-list-tests %changelog +* Wed Sep 21 2022 systemd maintenance team - 239-58.8 +- unit-name: tighten checks for building valid unit names (#2094712) +- core: shorten long unit names that are based on paths and append path hash at the end (#2094712) +- test: add extended test for triggering mount rate limit (#2094712) +- tests: add test case for long unit names (#2094712) +- Revert "core: Propagate condition failed state to triggering units." (#2123801) +- core: Check unit start rate limiting earlier (#2123801) +- core: Add trigger limit for path units (#2123801) +- resolved: pin stream while calling callbacks for it (#2110548) +- core: move reset_arguments() to the end of main's finish (#2127171) + * Thu Aug 25 2022 systemd maintenance team - 239-58.7 - sd-event: don't invalidate source type on disconnect (#2116892) - test-procfs-util: skip test on certain errors (#2087152)