From 6384abb1d17a75465ed516b0e1b1611f36f57d8e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mar 23 2021 00:08:51 +0000 Subject: A few more patches --- diff --git a/0001-sd-event-do-not-use-epoll_pwait2-tentatively.patch b/0001-sd-event-do-not-use-epoll_pwait2-tentatively.patch deleted file mode 100644 index 4baf338..0000000 --- a/0001-sd-event-do-not-use-epoll_pwait2-tentatively.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 829e2b5cd552c5ea33a8ccc43e118ba87bbda206 Mon Sep 17 00:00:00 2001 -From: Yu Watanabe -Date: Fri, 19 Mar 2021 04:13:59 +0900 -Subject: [PATCH] sd-event: do not use epoll_pwait2() tentatively - ---- - src/libsystemd/sd-event/sd-event.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c -index 8f74b14101..14bed4f854 100644 ---- a/src/libsystemd/sd-event/sd-event.c -+++ b/src/libsystemd/sd-event/sd-event.c -@@ -3808,8 +3808,9 @@ static int epoll_wait_usec( - int maxevents, - usec_t timeout) { - -- static bool epoll_pwait2_absent = false; - int r, msec; -+#if 0 -+ static bool epoll_pwait2_absent = false; - - /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not */ - -@@ -3829,6 +3830,7 @@ static int epoll_wait_usec( - - epoll_pwait2_absent = true; - } -+#endif - - if (timeout == USEC_INFINITY) - msec = -1; --- -2.30.2 - diff --git a/0e557eef37c9ebcc8f5c19fc6fc44b6fd617cc5d.patch b/0e557eef37c9ebcc8f5c19fc6fc44b6fd617cc5d.patch new file mode 100644 index 0000000..5c5317f --- /dev/null +++ b/0e557eef37c9ebcc8f5c19fc6fc44b6fd617cc5d.patch @@ -0,0 +1,36 @@ +From 0e557eef37c9ebcc8f5c19fc6fc44b6fd617cc5d Mon Sep 17 00:00:00 2001 +From: Sergey Bugaev +Date: Mon, 22 Mar 2021 18:31:12 +0300 +Subject: [PATCH] log: protect errno in log_open() + +Commit 0b1f3c768ce1bd1490a5e53f539976dcef8ca765 has introduced log_open() +calls after exec fails post-fork. However, the log_open() call itself could +change the value of errno, which, for me, manifested in: + +$ coredumpctl gdb +... +Failed to invoke gdb: Success + +Fix this by using PROTECT_ERRNO in log_open(). +--- + src/basic/log.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/basic/log.c b/src/basic/log.c +index c8cca96bca4..0e6023cff22 100644 +--- a/src/basic/log.c ++++ b/src/basic/log.c +@@ -252,6 +252,13 @@ int log_open(void) { + + /* Do not call from library code. */ + ++ /* This function is often called in preparation for being able ++ * to log. Let's make sure we don't clobber errno, so that a call ++ * to a logging function immediately following a log_open() call ++ * can still easily reference an error that happened immediately ++ * before the log_open() call. */ ++ PROTECT_ERRNO; ++ + /* If we don't use the console we close it here, to not get + * killed by SAK. If we don't use syslog we close it here so + * that we are not confused by somebody deleting the socket in diff --git a/19075.patch b/19075.patch new file mode 100644 index 0000000..10f391e --- /dev/null +++ b/19075.patch @@ -0,0 +1,415 @@ +From 169615c9a8cdc54d748d4dfc8279be9b3c2bec44 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 21 Mar 2021 20:59:32 +0100 +Subject: [PATCH 1/5] shared/calendarspec: abort calculation after 1000 + iterations + +We have a bug where we seem to enter an infinite loop when running in the +Europe/Dublin timezone. The timezone is "special" because it has negative SAVE +values. The handling of this should obviously be fixed, but let's use a +belt-and-suspenders approach, and gracefully fail if we fail to find an answer +within a specific number of attempts. The code in this function is rather +complex, and it's hard to rule out another bug in the future. +--- + src/shared/calendarspec.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c +index 4f68a570b52..feb43efdcda 100644 +--- a/src/shared/calendarspec.c ++++ b/src/shared/calendarspec.c +@@ -1210,6 +1210,10 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) { + return (weekdays_bits & (1 << k)); + } + ++/* A safety valve: if we get stuck in the calculation, return an error. ++ * C.f. https://bugzilla.redhat.com/show_bug.cgi?id=1941335. */ ++#define MAX_CALENDAR_ITERATIONS 1000 ++ + static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { + struct tm c; + int tm_usec; +@@ -1223,7 +1227,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { + c = *tm; + tm_usec = *usec; + +- for (;;) { ++ for (unsigned iteration = 0; iteration < MAX_CALENDAR_ITERATIONS; iteration++) { + /* Normalize the current date */ + (void) mktime_or_timegm(&c, spec->utc); + c.tm_isdst = spec->dst; +@@ -1320,6 +1324,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { + *usec = tm_usec; + return 0; + } ++ ++ /* It seems we entered an infinite loop. Let's gracefully return an error instead of hanging or ++ * aborting. This code is also exercised when timers.target is brought up during early boot, so ++ * aborting here is problematic and hard to diagnose for users. */ ++ _cleanup_free_ char *s = NULL; ++ (void) calendar_spec_to_string(spec, &s); ++ return log_warning_errno(SYNTHETIC_ERRNO(EDEADLK), ++ "Infinite loop in calendar calculation: %s", strna(s)); + } + + static int calendar_spec_next_usec_impl(const CalendarSpec *spec, usec_t usec, usec_t *ret_next) { + +From 462f15d92d35f812d7d77edd486ca63236cffe83 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 22 Mar 2021 09:20:47 +0100 +Subject: [PATCH 2/5] shared/calendarspec: constify parameter and simplify + assignments to variable + +The scope of start & stop is narrowed down, and they are assigned only once. +No functional change, but I think the code is easier to read this way. +Also add a comment to make the code easier to read. +--- + src/shared/calendarspec.c | 33 ++++++++++++++++++++++----------- + 1 file changed, 22 insertions(+), 11 deletions(-) + +diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c +index feb43efdcda..5c666412946 100644 +--- a/src/shared/calendarspec.c ++++ b/src/shared/calendarspec.c +@@ -1101,7 +1101,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { + return 0; + } + +-static int find_end_of_month(struct tm *tm, bool utc, int day) { ++static int find_end_of_month(const struct tm *tm, bool utc, int day) { + struct tm t = *tm; + + t.tm_mon++; +@@ -1114,28 +1114,39 @@ static int find_end_of_month(struct tm *tm, bool utc, int day) { + return t.tm_mday; + } + +-static int find_matching_component(const CalendarSpec *spec, const CalendarComponent *c, +- struct tm *tm, int *val) { +- const CalendarComponent *p = c; +- int start, stop, d = -1; ++static int find_matching_component( ++ const CalendarSpec *spec, ++ const CalendarComponent *c, ++ const struct tm *tm, /* tm is only used for end-of-month calculations */ ++ int *val) { ++ ++ int d = -1, r; + bool d_set = false; +- int r; + + assert(val); + ++ /* Finds the *earliest* matching time specified by one of the CalendarCompoment items in chain c. ++ * If no matches can be found, returns -ENOENT. ++ * Otherwise, updates *val to the matching time. 1 is returned if *val was changed, 0 otherwise. ++ */ ++ + if (!c) + return 0; + ++ bool end_of_month = spec->end_of_month && c == spec->day; ++ + while (c) { +- start = c->start; +- stop = c->stop; ++ int start, stop; + +- if (spec->end_of_month && p == spec->day) { +- start = find_end_of_month(tm, spec->utc, start); +- stop = find_end_of_month(tm, spec->utc, stop); ++ if (end_of_month) { ++ start = find_end_of_month(tm, spec->utc, c->start); ++ stop = find_end_of_month(tm, spec->utc, c->stop); + + if (stop > 0) + SWAP_TWO(start, stop); ++ } else { ++ start = c->start; ++ stop = c->stop; + } + + if (start >= *val) { + +From f035bb1b7a5900439640f267db881c60d042e450 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 22 Mar 2021 11:10:22 +0100 +Subject: [PATCH 3/5] test-calendarspec: print offending line in output + +The output is rather long at this makes it easier to jump to the right place. +Also use normal output routines and set_unset_env() to make things more +compact. +--- + src/test/test-calendarspec.c | 48 +++++++++++++++++------------------- + 1 file changed, 22 insertions(+), 26 deletions(-) + +diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c +index 01ec7f87704..152ce879f8a 100644 +--- a/src/test/test-calendarspec.c ++++ b/src/test/test-calendarspec.c +@@ -2,11 +2,11 @@ + + #include "alloc-util.h" + #include "calendarspec.h" ++#include "env-util.h" + #include "errno-util.h" + #include "string-util.h" +-#include "util.h" + +-static void test_one(const char *input, const char *output) { ++static void _test_one(int line, const char *input, const char *output) { + CalendarSpec *c; + _cleanup_free_ char *p = NULL, *q = NULL; + usec_t u; +@@ -16,13 +16,13 @@ static void test_one(const char *input, const char *output) { + assert_se(calendar_spec_from_string(input, &c) >= 0); + + assert_se(calendar_spec_to_string(c, &p) >= 0); +- printf("\"%s\" → \"%s\"\n", input, p); ++ log_info("line %d: \"%s\" → \"%s\"", line, input, p); + + assert_se(streq(p, output)); + + u = now(CLOCK_REALTIME); + r = calendar_spec_next_usec(c, u, &u); +- printf("Next: %s\n", r < 0 ? strerror_safe(r) : format_timestamp(buf, sizeof(buf), u)); ++ log_info("Next: %s", r < 0 ? strerror_safe(r) : format_timestamp(buf, sizeof buf, u)); + calendar_spec_free(c); + + assert_se(calendar_spec_from_string(p, &c) >= 0); +@@ -31,8 +31,9 @@ static void test_one(const char *input, const char *output) { + + assert_se(streq(q, p)); + } ++#define test_one(input, output) _test_one(__LINE__, input, output) + +-static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) { ++static void _test_next(int line, const char *input, const char *new_tz, usec_t after, usec_t expect) { + CalendarSpec *c; + usec_t u; + char *old_tz; +@@ -43,22 +44,19 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_ + if (old_tz) + old_tz = strdupa(old_tz); + +- if (new_tz) { +- char *colon_tz; ++ if (new_tz) ++ new_tz = strjoina(":", new_tz); + +- colon_tz = strjoina(":", new_tz); +- assert_se(setenv("TZ", colon_tz, 1) >= 0); +- } else +- assert_se(unsetenv("TZ") >= 0); ++ assert_se(set_unset_env("TZ", new_tz, true) == 0); + tzset(); + + assert_se(calendar_spec_from_string(input, &c) >= 0); + +- printf("\"%s\"\n", input); ++ log_info("line %d: \"%s\" new_tz=%s", line, input, strnull(new_tz)); + + u = after; + r = calendar_spec_next_usec(c, after, &u); +- printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US)); ++ log_info("At: %s", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US)); + if (expect != USEC_INFINITY) + assert_se(r >= 0 && u == expect); + else +@@ -66,12 +64,10 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_ + + calendar_spec_free(c); + +- if (old_tz) +- assert_se(setenv("TZ", old_tz, 1) >= 0); +- else +- assert_se(unsetenv("TZ") >= 0); ++ assert_se(set_unset_env("TZ", old_tz, true) == 0); + tzset(); + } ++#define test_next(input, new_tz, after, expect) _test_next(__LINE__, input,new_tz,after,expect) + + static void test_timestamp(void) { + char buf[FORMAT_TIMESTAMP_MAX]; +@@ -83,12 +79,12 @@ static void test_timestamp(void) { + + x = now(CLOCK_REALTIME); + +- assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US)); +- printf("%s\n", buf); ++ assert_se(format_timestamp_style(buf, sizeof buf, x, TIMESTAMP_US)); ++ log_info("%s", buf); + assert_se(calendar_spec_from_string(buf, &c) >= 0); + assert_se(calendar_spec_to_string(c, &t) >= 0); + calendar_spec_free(c); +- printf("%s\n", t); ++ log_info("%s", t); + + assert_se(parse_timestamp(t, &y) >= 0); + assert_se(y == x); +@@ -104,11 +100,11 @@ static void test_hourly_bug_4031(void) { + n = now(CLOCK_REALTIME); + assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0); + +- printf("Now: %s (%"PRIu64")\n", format_timestamp_style(buf, sizeof buf, n, TIMESTAMP_US), n); +- printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US), u); ++ log_info("Now: %s (%"PRIu64")", format_timestamp_style(buf, sizeof buf, n, TIMESTAMP_US), n); ++ log_info("Next hourly: %s (%"PRIu64")", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US), u); + + assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0); +- printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w); ++ log_info("Next hourly: %s (%"PRIu64")", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w); + + assert_se(n < u); + assert_se(u <= n + USEC_PER_HOUR); +@@ -209,13 +205,13 @@ int main(int argc, char* argv[]) { + test_next("2017-08-06 9..17/2:00 UTC", "", 1502029800000000, 1502031600000000); + test_next("2016-12-* 3..21/6:00 UTC", "", 1482613200000001, 1482634800000000); + test_next("2017-09-24 03:30:00 Pacific/Auckland", "", 12345, 1506177000000000); +- // Due to daylight saving time - 2017-09-24 02:30:00 does not exist ++ /* Due to daylight saving time - 2017-09-24 02:30:00 does not exist */ + test_next("2017-09-24 02:30:00 Pacific/Auckland", "", 12345, -1); + test_next("2017-04-02 02:30:00 Pacific/Auckland", "", 12345, 1491053400000000); +- // Confirm that even though it's a time change here (backward) 02:30 happens only once ++ /* Confirm that even though it's a time change here (backward) 02:30 happens only once */ + test_next("2017-04-02 02:30:00 Pacific/Auckland", "", 1491053400000000, -1); + test_next("2017-04-02 03:30:00 Pacific/Auckland", "", 12345, 1491060600000000); +- // Confirm that timezones in the Spec work regardless of current timezone ++ /* Confirm that timezones in the Spec work regardless of current timezone */ + test_next("2017-09-09 20:42:00 Pacific/Auckland", "", 12345, 1504946520000000); + test_next("2017-09-09 20:42:00 Pacific/Auckland", "EET", 12345, 1504946520000000); + + +From 47b0b65766229a18921a3ce831ef708ef408a34c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 22 Mar 2021 11:29:35 +0100 +Subject: [PATCH 4/5] test-calendarspec: do not convert timezone "" to ":" + +I *think* it doesn't actually make any difference, because ":" will be ignored. +437f48a471f51ac9dd2697ee3b848a71b4f101df added prefixing with ":", but didn't +take into account the fact that we also use "" with a different meaning than +NULL here. But let's restore the original behaviour of specifying the empty +string. +--- + src/test/test-calendarspec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c +index 152ce879f8a..c62e6860cf9 100644 +--- a/src/test/test-calendarspec.c ++++ b/src/test/test-calendarspec.c +@@ -44,7 +44,7 @@ static void _test_next(int line, const char *input, const char *new_tz, usec_t a + if (old_tz) + old_tz = strdupa(old_tz); + +- if (new_tz) ++ if (!isempty(new_tz)) + new_tz = strjoina(":", new_tz); + + assert_se(set_unset_env("TZ", new_tz, true) == 0); + +From 129cb6e249bef30dc33e08f98f0b27a6de976f6f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 22 Mar 2021 12:51:47 +0100 +Subject: [PATCH 5/5] shared/calendarspec: when mktime() moves us backwards, + jump forward +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When trying to calculate the next firing of 'Sun *-*-* 01:00:00', we'd fall +into an infinite loop, because mktime() moves us "backwards": + +Before this patch: +tm_within_bounds: good=0 2021-03-29 01:00:00 → 2021-03-29 00:00:00 +tm_within_bounds: good=0 2021-03-29 01:00:00 → 2021-03-29 00:00:00 +tm_within_bounds: good=0 2021-03-29 01:00:00 → 2021-03-29 00:00:00 +... + +We rely on mktime() normalizing the time. The man page does not say that it'll +move the time forward, but our algorithm relies on this. So let's catch this +case explicitly. + +With this patch: +$ TZ=Europe/Dublin faketime 2021-03-21 build/systemd-analyze calendar --iterations=5 'Sun *-*-* 01:00:00' +Normalized form: Sun *-*-* 01:00:00 + Next elapse: Sun 2021-03-21 01:00:00 GMT + (in UTC): Sun 2021-03-21 01:00:00 UTC + From now: 59min left + Iter. #2: Sun 2021-04-04 01:00:00 IST + (in UTC): Sun 2021-04-04 00:00:00 UTC + From now: 1 weeks 6 days left <---- note the 2 week jump here + Iter. #3: Sun 2021-04-11 01:00:00 IST + (in UTC): Sun 2021-04-11 00:00:00 UTC + From now: 2 weeks 6 days left + Iter. #4: Sun 2021-04-18 01:00:00 IST + (in UTC): Sun 2021-04-18 00:00:00 UTC + From now: 3 weeks 6 days left + Iter. #5: Sun 2021-04-25 01:00:00 IST + (in UTC): Sun 2021-04-25 00:00:00 UTC + From now: 1 months 4 days left + +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1941335. +--- + src/shared/calendarspec.c | 19 +++++++++++-------- + src/test/test-calendarspec.c | 3 +++ + test/test-functions | 1 + + 3 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c +index 5c666412946..bf24d8d5bbb 100644 +--- a/src/shared/calendarspec.c ++++ b/src/shared/calendarspec.c +@@ -1195,15 +1195,18 @@ static int tm_within_bounds(struct tm *tm, bool utc) { + return negative_errno(); + + /* Did any normalization take place? If so, it was out of bounds before */ +- bool good = t.tm_year == tm->tm_year && +- t.tm_mon == tm->tm_mon && +- t.tm_mday == tm->tm_mday && +- t.tm_hour == tm->tm_hour && +- t.tm_min == tm->tm_min && +- t.tm_sec == tm->tm_sec; +- if (!good) ++ int cmp = CMP(t.tm_year, tm->tm_year) ?: ++ CMP(t.tm_mon, tm->tm_mon) ?: ++ CMP(t.tm_mday, tm->tm_mday) ?: ++ CMP(t.tm_hour, tm->tm_hour) ?: ++ CMP(t.tm_min, tm->tm_min) ?: ++ CMP(t.tm_sec, tm->tm_sec); ++ ++ if (cmp < 0) ++ return -EDEADLK; /* Refuse to go backward */ ++ if (cmp > 0) + *tm = t; +- return good; ++ return cmp == 0; + } + + static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) { +diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c +index c62e6860cf9..4f1d0f64d57 100644 +--- a/src/test/test-calendarspec.c ++++ b/src/test/test-calendarspec.c +@@ -214,6 +214,9 @@ int main(int argc, char* argv[]) { + /* Confirm that timezones in the Spec work regardless of current timezone */ + test_next("2017-09-09 20:42:00 Pacific/Auckland", "", 12345, 1504946520000000); + test_next("2017-09-09 20:42:00 Pacific/Auckland", "EET", 12345, 1504946520000000); ++ /* Check that we don't start looping if mktime() moves us backwards */ ++ test_next("Sun *-*-* 01:00:00 Europe/Dublin", "", 1616412478000000, 1617494400000000); ++ test_next("Sun *-*-* 01:00:00 Europe/Dublin", "IST", 1616412478000000, 1617494400000000); + + assert_se(calendar_spec_from_string("test", &c) < 0); + assert_se(calendar_spec_from_string(" utc", &c) < 0); +diff --git a/test/test-functions b/test/test-functions +index d7f7967e2ff..6b94058fd36 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1340,6 +1340,7 @@ install_zoneinfo() { + inst_any /usr/share/zoneinfo/Asia/Vladivostok + inst_any /usr/share/zoneinfo/Australia/Sydney + inst_any /usr/share/zoneinfo/Europe/Berlin ++ inst_any /usr/share/zoneinfo/Europe/Dublin + inst_any /usr/share/zoneinfo/Europe/Kiev + inst_any /usr/share/zoneinfo/Pacific/Auckland + inst_any /usr/share/zoneinfo/Pacific/Honolulu diff --git a/19079.patch b/19079.patch new file mode 100644 index 0000000..0f5c23e --- /dev/null +++ b/19079.patch @@ -0,0 +1,178 @@ +From 4cba52cc7a2191d0b38e605801c60d8648bc67e2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 22 Mar 2021 18:27:36 +0100 +Subject: [PATCH 1/2] resolved: propagate correct error variable + +--- + src/resolve/resolved-dns-query.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c +index e4386c402ac..c5805111d21 100644 +--- a/src/resolve/resolved-dns-query.c ++++ b/src/resolve/resolved-dns-query.c +@@ -982,12 +982,12 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) + r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna); + if (r < 0) + return r; +- else if (r > 0) ++ if (r > 0) + log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna)); + + k = dns_question_is_equal(q->question_idna, q->question_utf8); + if (k < 0) +- return r; ++ return k; + if (k > 0) { + /* Same question? Shortcut new question generation */ + nq_utf8 = dns_question_ref(nq_idna); +@@ -996,7 +996,7 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) + k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8); + if (k < 0) + return k; +- else if (k > 0) ++ if (k > 0) + log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8)); + } + + +From 1a71fe4ee5248140f2395a7daedfad8f8b9ad291 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 22 Mar 2021 18:27:46 +0100 +Subject: [PATCH 2/2] resolved: don't accept responses to query unless they + completely answer our questions + +When we checking if the responses we collected for a DnsQuery are +sufficient to complete it we previously only check if one of the +collected response RRs matches at least one of the question RR keys. + +This changes the logic to require that there must be at least one +response RR matched *each* of the question RR keys before considering +the answer complete. + +Otherwise we might end up accepting an A reply as complete answer for an +A/AAAA query and vice versa, but we want to make sure we wait until we +get a reply on both types before returning this to the user in all +cases. + +This has been broken for basically forever, but didn't surface until +b1eea703e01da1e280e179fb119449436a0c9b8e since until then we'd basically +ignore the auxiliary RRs included in CNAME/DNAME replies. Once that +commit was made we'd start using the auxiliary RRs included in +CNAME/DNAME replies but those typically included only A or only AAAA +which we then took for complete. + +Fixe: #19049 +--- + src/resolve/resolved-dns-query.c | 55 ++++++++++++++++++++++++++++---- + src/resolve/resolved-dns-query.h | 9 +++++- + 2 files changed, 56 insertions(+), 8 deletions(-) + +diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c +index c5805111d21..8bc06079830 100644 +--- a/src/resolve/resolved-dns-query.c ++++ b/src/resolve/resolved-dns-query.c +@@ -433,6 +433,14 @@ int dns_query_new( + } else { + bool good = false; + ++ /* This (primarily) checks two things: ++ * ++ * 1. That the question is not empty ++ * 2. That all RR keys in the question objects are for the same domain ++ * ++ * Or in other words, a single DnsQuery object may be used to look up A+AAAA combination for ++ * the same domain name, or SRV+TXT (for DNS-SD services), but not for unrelated lookups. */ ++ + if (dns_question_size(question_utf8) > 0) { + r = dns_question_is_valid_for_query(question_utf8); + if (r < 0) +@@ -1032,6 +1040,8 @@ int dns_query_process_cname(DnsQuery *q) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL; + DnsQuestion *question; + DnsResourceRecord *rr; ++ bool full_match = true; ++ DnsResourceKey *k; + int r; + + assert(q); +@@ -1041,13 +1051,44 @@ int dns_query_process_cname(DnsQuery *q) { + + question = dns_query_question_for_protocol(q, q->answer_protocol); + +- DNS_ANSWER_FOREACH(rr, q->answer) { +- r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); +- if (r < 0) +- return r; +- if (r > 0) +- return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */ ++ /* Small reminder: our question will consist of one or more RR keys that match in name, but not in ++ * record type. Specifically, when we do an address lookup the question will typically consist of one ++ * A and one AAAA key lookup for the same domain name. When we get a response from a server we need ++ * to check if the answer answers all our questions to use it. Note that a response of CNAME/DNAME ++ * can answer both an A and the AAAA question for us, but an A/AAAA response only the relevant ++ * type. ++ * ++ * Hence we first check of the answers we collected are sufficient to answer all our questions ++ * directly. If one question wasn't answered we go on, waiting for more replies. However, if there's ++ * a CNAME/DNAME response we use it, and redirect to it, regardless if it was a response to the A or ++ * the AAAA query.*/ ++ ++ DNS_QUESTION_FOREACH(k, question) { ++ bool match = false; ++ ++ DNS_ANSWER_FOREACH(rr, q->answer) { ++ r = dns_resource_key_match_rr(k, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); ++ if (r < 0) ++ return r; ++ if (r > 0) { ++ match = true; /* Yay, we found an RR that matches the key we are looking for */ ++ break; ++ } ++ } ++ ++ if (!match) { ++ /* Hmm. :-( there's no response for this key. This doesn't match. */ ++ full_match = false; ++ break; ++ } ++ } + ++ if (full_match) ++ return DNS_QUERY_MATCH; /* The answer can answer our question in full, no need to follow CNAMEs/DNAMEs */ ++ ++ /* Let's see if there is a CNAME/DNAME to match. This case is simpler: we accept the CNAME/DNAME that ++ * matches any of our questions. */ ++ DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); + if (r < 0) + return r; +@@ -1056,7 +1097,7 @@ int dns_query_process_cname(DnsQuery *q) { + } + + if (!cname) +- return DNS_QUERY_NOMATCH; /* No match and no cname to follow */ ++ return DNS_QUERY_NOMATCH; /* No match and no CNAME/DNAME to follow */ + + if (q->flags & SD_RESOLVED_NO_CNAME) + return -ELOOP; +diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h +index 5d12171b0a1..5d96cc06f84 100644 +--- a/src/resolve/resolved-dns-query.h ++++ b/src/resolve/resolved-dns-query.h +@@ -45,7 +45,14 @@ struct DnsQuery { + * that even on classic DNS some labels might use UTF8 encoding. Specifically, DNS-SD service names + * (in contrast to their domain suffixes) use UTF-8 encoding even on DNS. Thus, the difference + * between these two fields is mostly relevant only for explicit *hostname* lookups as well as the +- * domain suffixes of service lookups. */ ++ * domain suffixes of service lookups. ++ * ++ * Note that questions may consist of multiple RR keys at once, but they must be for the same domain ++ * name. This is used for A+AAAA and TXT+SRV lookups: we'll allocate a single DnsQuery object for ++ * them instead of two separate ones. That allows us minor optimizations with response handling: ++ * CNAME/DNAMEs of the first reply we get can already be used to follow the CNAME/DNAME chain for ++ * both, and we can take benefit of server replies that oftentimes put A responses into AAAA queries ++ * and vice versa (in the additional section). */ + DnsQuestion *question_idna; + DnsQuestion *question_utf8; + diff --git a/19080.patch b/19080.patch new file mode 100644 index 0000000..c8e1db4 --- /dev/null +++ b/19080.patch @@ -0,0 +1,67 @@ +From fce5b2ac2a51b9ecbfb258ff7e62f4e67a38d4c8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 12 Mar 2021 10:20:38 +0100 +Subject: [PATCH] sd-event: disable epoll_pwait2 for now + +This reverts the gist of commit 798445ab84cff51bde7fcf936f0fb19c37cf858c. + +Unfortunately the new syscall causes test-event to hang. 32 bit architectures +seem affected: i686 and arm32 in fedora koji. 32 bit build of test-event hangs +reliably under valgrind: + +$ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig meson build-32 -Dc_args=-m32 -Dc_link_args=-m32 -Dcpp_args=-m32 -Dcpp_link_args=-m32 && ninja -C build-32 test-event && valgrind build/test-event + +If I set epoll_pwait2_absent=true, so the new function is never called, then +the issue does not reproduce. It seems to be strictly tied to the syscall. + +On amd64, the syscall is not used, at least with the kernel that Fedora +provides. The kernel patch 58169a52ebc9a733aeb5bea857bc5daa71a301bb says: + + For timespec, only support this new interface on 2038 aware platforms + that define __kernel_timespec_t. So no CONFIG_COMPAT_32BIT_TIME. + +And Fedora sets CONFIG_COMPAT_32BIT_TIME=y. I expect most other distros will too. + +On amd64: epoll_wait_usec: epoll_pwait2: ret=-1 / errno=38 +On i686 (same kernel): epoll_wait_usec: epoll_pwait2: ret=2 / errno=0 + +Is this some kind of emulation? Anyway, it seems that this is what is going wrong. + +So let's disable the syscall until it becomes more widely available and the +kinks have been ironed out. + +Fixes test-event issue in #19052. +--- + src/libsystemd/sd-event/sd-event.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 8f74b141015..b76b0623fe3 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -3808,10 +3808,15 @@ static int epoll_wait_usec( + int maxevents, + usec_t timeout) { + +- static bool epoll_pwait2_absent = false; + int r, msec; ++#if 0 ++ static bool epoll_pwait2_absent = false; + +- /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not */ ++ /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not. ++ * ++ * FIXME: this is temporarily disabled until epoll_pwait2() becomes more widely available. ++ * See https://github.com/systemd/systemd/pull/18973 and ++ * https://github.com/systemd/systemd/issues/19052. */ + + if (!epoll_pwait2_absent && timeout != USEC_INFINITY) { + struct timespec ts; +@@ -3829,6 +3834,7 @@ static int epoll_wait_usec( + + epoll_pwait2_absent = true; + } ++#endif + + if (timeout == USEC_INFINITY) + msec = -1; diff --git a/5cdb3f70ebe035323f4f079028a262669a2bbbf6.patch b/5cdb3f70ebe035323f4f079028a262669a2bbbf6.patch new file mode 100644 index 0000000..9e737ea --- /dev/null +++ b/5cdb3f70ebe035323f4f079028a262669a2bbbf6.patch @@ -0,0 +1,55 @@ +From 5cdb3f70ebe035323f4f079028a262669a2bbbf6 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 19 Mar 2021 06:26:53 +0900 +Subject: [PATCH] udev: do not try to assign invalid ifname + +Fixes #19038. +--- + src/udev/net/link-config.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index f06ecd455df..31e5d0cd673 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -441,8 +441,6 @@ static int link_config_apply_rtnl_settings(sd_netlink **rtnl, const link_config + + static int link_config_generate_new_name(const link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) { + unsigned name_type = NET_NAME_UNKNOWN; +- const char *new_name = NULL; +- NamePolicy policy; + int r; + + assert(ctx); +@@ -460,7 +458,8 @@ static int link_config_generate_new_name(const link_config_ctx *ctx, const link_ + + if (ctx->enable_name_policy && config->name_policy) + for (NamePolicy *p = config->name_policy; *p != _NAMEPOLICY_INVALID; p++) { +- policy = *p; ++ const char *new_name = NULL; ++ NamePolicy policy = *p; + + switch (policy) { + case NAMEPOLICY_KERNEL: +@@ -496,16 +495,13 @@ static int link_config_generate_new_name(const link_config_ctx *ctx, const link_ + default: + assert_not_reached("invalid policy"); + } +- if (ifname_valid(new_name)) +- break; ++ if (ifname_valid(new_name)) { ++ log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name); ++ *ret_name = new_name; ++ return 0; ++ } + } + +- if (new_name) { +- log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name); +- *ret_name = new_name; +- return 0; +- } +- + if (config->name) { + log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", config->name); + *ret_name = config->name; diff --git a/f9b3afae96c72564cd4cd766555845f17e3c12a9.patch b/f9b3afae96c72564cd4cd766555845f17e3c12a9.patch new file mode 100644 index 0000000..9bbab91 --- /dev/null +++ b/f9b3afae96c72564cd4cd766555845f17e3c12a9.patch @@ -0,0 +1,85 @@ +From f9b3afae96c72564cd4cd766555845f17e3c12a9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 19 Mar 2021 10:36:48 +0100 +Subject: [PATCH] repart: make sure to grow partition table after growing + backing loopback file + +This fixes the --size= switch, i.e. where we grow a disk image: after +growing it we need to expand the partition table so that its idea of the +the medium size matches the new reality. Otherwise our disk size +calculations in the subsequent steps might still use the original +ungrown size. + +(This used to work, I guess this was borked when libfdisk learnt the +concept of "minimized" partition tables) +--- + src/partition/repart.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/src/partition/repart.c b/src/partition/repart.c +index be16f5a067b..7b6201efa83 100644 +--- a/src/partition/repart.c ++++ b/src/partition/repart.c +@@ -3977,6 +3977,40 @@ static int find_root(char **ret, int *ret_fd) { + return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Failed to discover root block device."); + } + ++static int resize_pt(int fd) { ++ char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; ++ _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL; ++ int r; ++ ++ /* After resizing the backing file we need to resize the partition table itself too, so that it takes ++ * possession of the enlarged backing file. For this it suffices to open the device with libfdisk and ++ * immediately write it again, with no changes. */ ++ ++ c = fdisk_new_context(); ++ if (!c) ++ return log_oom(); ++ ++ xsprintf(procfs_path, "/proc/self/fd/%i", fd); ++ r = fdisk_assign_device(c, procfs_path, 0); ++ if (r < 0) ++ return log_error_errno(r, "Failed to open device '%s': %m", procfs_path); ++ ++ r = fdisk_has_label(c); ++ if (r < 0) ++ return log_error_errno(r, "Failed to determine whether disk '%s' has a disk label: %m", procfs_path); ++ if (r == 0) { ++ log_debug("Not resizing partition table, as there currently is none."); ++ return 0; ++ } ++ ++ r = fdisk_write_disklabel(c); ++ if (r < 0) ++ return log_error_errno(r, "Failed to write resized partition table: %m"); ++ ++ log_info("Resized partition table."); ++ return 1; ++} ++ + static int resize_backing_fd(const char *node, int *fd) { + char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX]; + _cleanup_close_ int writable_fd = -1; +@@ -4029,6 +4063,10 @@ static int resize_backing_fd(const char *node, int *fd) { + /* Fallback to truncation, if fallocate() is not supported. */ + log_debug("Backing file system does not support fallocate(), falling back to ftruncate()."); + } else { ++ r = resize_pt(writable_fd); ++ if (r < 0) ++ return r; ++ + if (st.st_size == 0) /* Likely regular file just created by us */ + log_info("Allocated %s for '%s'.", buf2, node); + else +@@ -4042,6 +4080,10 @@ static int resize_backing_fd(const char *node, int *fd) { + return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m", + node, buf1, buf2); + ++ r = resize_pt(writable_fd); ++ if (r < 0) ++ return r; ++ + if (st.st_size == 0) /* Likely regular file just created by us */ + log_info("Sized '%s' to %s.", node, buf2); + else diff --git a/systemd.spec b/systemd.spec index c31c136..8e30310 100644 --- a/systemd.spec +++ b/systemd.spec @@ -21,7 +21,7 @@ Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd Version: 248~rc4 -Release: 2%{?dist} +Release: 3%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -74,6 +74,20 @@ GIT_DIR=../../src/systemd/.git git diffab -M v233..master@{2017-06-15} -- hwdb/[ %endif # Backports of patches from upstream (0000–0499) +# +# Any patches which are "in preparation" upstream should be listed +# here, rather than in the next section. Packit CI will drop any +# patches in this range before applying upstream pull requests. + +# https://bugzilla.redhat.com/show_bug.cgi?id=1941335 +Patch0001: https://github.com/systemd/systemd/pull/19075.patch + +Patch0002: https://github.com/systemd/systemd/pull/19079.patch +Patch0003: https://github.com/systemd/systemd/pull/19080.patch + +Patch0004: https://github.com/systemd/systemd/commit/5cdb3f70ebe035323f4f079028a262669a2bbbf6.patch +Patch0005: https://github.com/systemd/systemd/commit/f9b3afae96c72564cd4cd766555845f17e3c12a9.patch +Patch0006: https://github.com/systemd/systemd/commit/0e557eef37c9ebcc8f5c19fc6fc44b6fd617cc5d.patch # Downstream-only patches (5000–9999) # https://bugzilla.redhat.com/show_bug.cgi?id=1738828 @@ -82,9 +96,6 @@ Patch0500: use-bfq-scheduler.patch # https://github.com/systemd/systemd/pull/17050 Patch0501: https://github.com/systemd/systemd/pull/17050/commits/f58b96d3e8d1cb0dd3666bc74fa673918b586612.patch -# https://github.com/systemd/systemd/pull/18973 -Patch0502: 0001-sd-event-do-not-use-epoll_pwait2-tentatively.patch - %ifarch %{ix86} x86_64 aarch64 %global have_gnu_efi 1 %endif @@ -955,6 +966,14 @@ getent passwd systemd-network &>/dev/null || useradd -r -u 192 -l -g systemd-net %files standalone-sysusers -f .file-list-standalone-sysusers %changelog +* Mon Mar 22 2021 Zbigniew Jędrzejewski-Szmek - 248~rc4-3 +- Fix hang when processing timers during DST switch in Europe/Dublin timezone (#1941335) +- Fix returning combined IPv4/IPv6 responses from systemd-resolved cache (#1940715) + (But note that the disablement of caching added previously is + retained until we can do more testing.) +- Minor fix to interface naming by udev +- Fix for systemd-repart --size + * Fri Mar 19 2021 Adam Williamson - 248~rc4-2 - Disable resolved cache via config snippet (#1940715)