1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-03-10 00:58:20 +03:00

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.

(cherry picked from commit 169615c9a8cdc54d748d4dfc8279be9b3c2bec44)
(cherry picked from commit f14b80e09e225ccf7cfd8a85578b7e64c3fdebb9)
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-03-21 20:59:32 +01:00
parent 3bfa393198
commit 822d39cad4

View File

@ -1211,6 +1211,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;
@ -1224,7 +1228,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;
@ -1321,6 +1325,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) {