mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-10 00:58:20 +03:00
Merge pull request #12234 from yuwata/calendarspec-fix-oss-fuzz-14108
Calendarspec cleanups and fixes integer overflow
This commit is contained in:
commit
d855b2ab36
@ -33,7 +33,7 @@
|
||||
* linked compenents anyway. */
|
||||
#define CALENDARSPEC_COMPONENTS_MAX 240
|
||||
|
||||
static void free_chain(CalendarComponent *c) {
|
||||
static void chain_free(CalendarComponent *c) {
|
||||
CalendarComponent *n;
|
||||
|
||||
while (c) {
|
||||
@ -43,17 +43,19 @@ static void free_chain(CalendarComponent *c) {
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(CalendarComponent*, chain_free);
|
||||
|
||||
CalendarSpec* calendar_spec_free(CalendarSpec *c) {
|
||||
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
free_chain(c->year);
|
||||
free_chain(c->month);
|
||||
free_chain(c->day);
|
||||
free_chain(c->hour);
|
||||
free_chain(c->minute);
|
||||
free_chain(c->microsecond);
|
||||
chain_free(c->year);
|
||||
chain_free(c->month);
|
||||
chain_free(c->day);
|
||||
chain_free(c->hour);
|
||||
chain_free(c->minute);
|
||||
chain_free(c->microsecond);
|
||||
free(c->timezone);
|
||||
|
||||
return mfree(c);
|
||||
@ -551,14 +553,16 @@ static int const_chain(int value, CalendarComponent **c) {
|
||||
|
||||
assert(c);
|
||||
|
||||
cc = new0(CalendarComponent, 1);
|
||||
cc = new(CalendarComponent, 1);
|
||||
if (!cc)
|
||||
return -ENOMEM;
|
||||
|
||||
cc->start = value;
|
||||
cc->stop = -1;
|
||||
cc->repeat = 0;
|
||||
cc->next = *c;
|
||||
*cc = (CalendarComponent) {
|
||||
.start = value,
|
||||
.stop = -1,
|
||||
.repeat = 0,
|
||||
.next = *c,
|
||||
};
|
||||
|
||||
*c = cc;
|
||||
|
||||
@ -566,13 +570,18 @@ static int const_chain(int value, CalendarComponent **c) {
|
||||
}
|
||||
|
||||
static int calendarspec_from_time_t(CalendarSpec *c, time_t time) {
|
||||
_cleanup_(chain_freep) CalendarComponent
|
||||
*year = NULL, *month = NULL, *day = NULL,
|
||||
*hour = NULL, *minute = NULL, *us = NULL;
|
||||
struct tm tm;
|
||||
CalendarComponent *year = NULL, *month = NULL, *day = NULL, *hour = NULL, *minute = NULL, *us = NULL;
|
||||
int r;
|
||||
|
||||
if (!gmtime_r(&time, &tm))
|
||||
return -ERANGE;
|
||||
|
||||
if (tm.tm_year > INT_MAX - 1900)
|
||||
return -ERANGE;
|
||||
|
||||
r = const_chain(tm.tm_year + 1900, &year);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -598,12 +607,12 @@ static int calendarspec_from_time_t(CalendarSpec *c, time_t time) {
|
||||
return r;
|
||||
|
||||
c->utc = true;
|
||||
c->year = year;
|
||||
c->month = month;
|
||||
c->day = day;
|
||||
c->hour = hour;
|
||||
c->minute = minute;
|
||||
c->microsecond = us;
|
||||
c->year = TAKE_PTR(year);
|
||||
c->month = TAKE_PTR(month);
|
||||
c->day = TAKE_PTR(day);
|
||||
c->hour = TAKE_PTR(hour);
|
||||
c->minute = TAKE_PTR(minute);
|
||||
c->microsecond = TAKE_PTR(us);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -644,14 +653,16 @@ static int prepend_component(const char **p, bool usec, unsigned nesting, Calend
|
||||
if (!IN_SET(*e, 0, ' ', ',', '-', '~', ':'))
|
||||
return -EINVAL;
|
||||
|
||||
cc = new0(CalendarComponent, 1);
|
||||
cc = new(CalendarComponent, 1);
|
||||
if (!cc)
|
||||
return -ENOMEM;
|
||||
|
||||
cc->start = start;
|
||||
cc->stop = stop;
|
||||
cc->repeat = repeat;
|
||||
cc->next = *c;
|
||||
*cc = (CalendarComponent) {
|
||||
.start = start,
|
||||
.stop = stop,
|
||||
.repeat = repeat,
|
||||
.next = *c,
|
||||
};
|
||||
|
||||
*p = e;
|
||||
*c = cc;
|
||||
@ -665,8 +676,8 @@ static int prepend_component(const char **p, bool usec, unsigned nesting, Calend
|
||||
}
|
||||
|
||||
static int parse_chain(const char **p, bool usec, CalendarComponent **c) {
|
||||
_cleanup_(chain_freep) CalendarComponent *cc = NULL;
|
||||
const char *t;
|
||||
CalendarComponent *cc = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
@ -688,20 +699,18 @@ static int parse_chain(const char **p, bool usec, CalendarComponent **c) {
|
||||
}
|
||||
|
||||
r = prepend_component(&t, usec, 0, &cc);
|
||||
if (r < 0) {
|
||||
free_chain(cc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*p = t;
|
||||
*c = cc;
|
||||
*c = TAKE_PTR(cc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_date(const char **p, CalendarSpec *c) {
|
||||
_cleanup_(chain_freep) CalendarComponent *first = NULL, *second = NULL, *third = NULL;
|
||||
const char *t;
|
||||
int r;
|
||||
CalendarComponent *first, *second, *third;
|
||||
|
||||
assert(p);
|
||||
assert(*p);
|
||||
@ -738,70 +747,51 @@ static int parse_date(const char **p, CalendarSpec *c) {
|
||||
return r;
|
||||
|
||||
/* Already the end? A ':' as separator? In that case this was a time, not a date */
|
||||
if (IN_SET(*t, 0, ':')) {
|
||||
free_chain(first);
|
||||
if (IN_SET(*t, 0, ':'))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*t == '~')
|
||||
c->end_of_month = true;
|
||||
else if (*t != '-') {
|
||||
free_chain(first);
|
||||
else if (*t != '-')
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
t++;
|
||||
r = parse_chain(&t, false, &second);
|
||||
if (r < 0) {
|
||||
free_chain(first);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Got two parts, hence it's month and day */
|
||||
if (IN_SET(*t, 0, ' ')) {
|
||||
*p = t + strspn(t, " ");
|
||||
c->month = first;
|
||||
c->day = second;
|
||||
c->month = TAKE_PTR(first);
|
||||
c->day = TAKE_PTR(second);
|
||||
return 0;
|
||||
} else if (c->end_of_month) {
|
||||
free_chain(first);
|
||||
free_chain(second);
|
||||
} else if (c->end_of_month)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (*t == '~')
|
||||
c->end_of_month = true;
|
||||
else if (*t != '-') {
|
||||
free_chain(first);
|
||||
free_chain(second);
|
||||
else if (*t != '-')
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
t++;
|
||||
r = parse_chain(&t, false, &third);
|
||||
if (r < 0) {
|
||||
free_chain(first);
|
||||
free_chain(second);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!IN_SET(*t, 0, ' '))
|
||||
return -EINVAL;
|
||||
|
||||
/* Got three parts, hence it is year, month and day */
|
||||
if (IN_SET(*t, 0, ' ')) {
|
||||
*p = t + strspn(t, " ");
|
||||
c->year = first;
|
||||
c->month = second;
|
||||
c->day = third;
|
||||
return 0;
|
||||
}
|
||||
|
||||
free_chain(first);
|
||||
free_chain(second);
|
||||
free_chain(third);
|
||||
return -EINVAL;
|
||||
*p = t + strspn(t, " ");
|
||||
c->year = TAKE_PTR(first);
|
||||
c->month = TAKE_PTR(second);
|
||||
c->day = TAKE_PTR(third);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_calendar_time(const char **p, CalendarSpec *c) {
|
||||
CalendarComponent *h = NULL, *m = NULL, *s = NULL;
|
||||
_cleanup_(chain_freep) CalendarComponent *h = NULL, *m = NULL, *s = NULL;
|
||||
const char *t;
|
||||
int r;
|
||||
|
||||
@ -817,66 +807,55 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
|
||||
|
||||
r = parse_chain(&t, false, &h);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
if (*t != ':') {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (*t != ':')
|
||||
return -EINVAL;
|
||||
|
||||
t++;
|
||||
r = parse_chain(&t, false, &m);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
/* Already at the end? Then it's hours and minutes, and seconds are 0 */
|
||||
if (*t == 0)
|
||||
goto null_second;
|
||||
|
||||
if (*t != ':') {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (*t != ':')
|
||||
return -EINVAL;
|
||||
|
||||
t++;
|
||||
r = parse_chain(&t, true, &s);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
/* At the end? Then it's hours, minutes and seconds */
|
||||
if (*t == 0)
|
||||
goto finish;
|
||||
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
return -EINVAL;
|
||||
|
||||
null_hour:
|
||||
r = const_chain(0, &h);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = const_chain(0, &m);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
null_second:
|
||||
r = const_chain(0, &s);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
finish:
|
||||
*p = t;
|
||||
c->hour = h;
|
||||
c->minute = m;
|
||||
c->microsecond = s;
|
||||
c->hour = TAKE_PTR(h);
|
||||
c->minute = TAKE_PTR(m);
|
||||
c->microsecond = TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free_chain(h);
|
||||
free_chain(m);
|
||||
free_chain(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
@ -888,11 +867,14 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
assert(p);
|
||||
assert(spec);
|
||||
|
||||
c = new0(CalendarSpec, 1);
|
||||
c = new(CalendarSpec, 1);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
c->dst = -1;
|
||||
c->timezone = NULL;
|
||||
|
||||
*c = (CalendarSpec) {
|
||||
.dst = -1,
|
||||
.timezone = NULL,
|
||||
};
|
||||
|
||||
utc = endswith_no_case(p, " UTC");
|
||||
if (utc) {
|
||||
|
1
test/fuzz/fuzz-calendarspec/oss-fuzz-14108
Normal file
1
test/fuzz/fuzz-calendarspec/oss-fuzz-14108
Normal file
@ -0,0 +1 @@
|
||||
@67767992554749550
|
Loading…
x
Reference in New Issue
Block a user