From d75ea227b4ad8d54dcf1ded5bcfcd32ea4177cc8 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 29 Jun 2024 06:46:14 +0100 Subject: [PATCH] Fix GH-14709 overflow on recurrences for DatePeriod::__construct --- ext/date/php_date.c | 20 +++++++++++++---- ...eriod_wrong_recurrence_on_constructor.phpt | 6 ++--- .../tests/date_period_bad_iso_format.phpt | 6 ++--- ext/date/tests/gh14709.phpt | 22 +++++++++++++++++++ 4 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 ext/date/tests/gh14709.phpt diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 7cff8e13e23d5..4f874b229fb80 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -4903,19 +4903,31 @@ static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_en static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, zend_long recurrences) { - if (dpobj->end == NULL && recurrences < 1) { + const zend_long max_recurrences = (INT_MAX - 8); + + if (dpobj->end == NULL && (recurrences < 1 || recurrences > max_recurrences)) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func)); + zend_throw_exception_ex(NULL, 0, "%s(): Recurrence count must be greater or equal to 1 and lower than " ZEND_LONG_FMT, ZSTR_VAL(func), max_recurrences + 1); zend_string_release(func); return false; } + /* options */ dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE); dpobj->include_end_date = options & PHP_DATE_PERIOD_INCLUDE_END_DATE; - /* recurrrences */ - dpobj->recurrences = recurrences + dpobj->include_start_date + dpobj->include_end_date; + /* recurrences */ + recurrences += dpobj->include_start_date + dpobj->include_end_date; + + if (UNEXPECTED(recurrences > max_recurrences)) { + zend_string *func = get_active_function_or_method_name(); + zend_throw_exception_ex(NULL, 0, "%s(): Recurrence count must be greater or equal to 1 and lower than " ZEND_LONG_FMT " (including options)", ZSTR_VAL(func), max_recurrences + 1); + zend_string_release(func); + return false; + } + + dpobj->recurrences = (int)recurrences; dpobj->initialized = 1; diff --git a/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt b/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt index f2e121db389a3..31c6868d67fb2 100644 --- a/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt +++ b/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt @@ -15,6 +15,6 @@ try { } ?> ---EXPECT-- -DatePeriod::__construct(): Recurrence count must be greater than 0 -DatePeriod::__construct(): Recurrence count must be greater than 0 +--EXPECTF-- +DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d +DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d diff --git a/ext/date/tests/date_period_bad_iso_format.phpt b/ext/date/tests/date_period_bad_iso_format.phpt index dde177e739871..ab476cda4c913 100644 --- a/ext/date/tests/date_period_bad_iso_format.phpt +++ b/ext/date/tests/date_period_bad_iso_format.phpt @@ -40,10 +40,10 @@ try { } ?> ---EXPECT-- +--EXPECTF-- DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain a start date, "R4" given DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain a start date, "R4" given DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given -DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater than 0 -DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): Recurrence count must be greater than 0 +Exception: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d +Exception: DatePeriod::createFromISO8601String(): Recurrence count must be greater or equal to 1 and lower than %d diff --git a/ext/date/tests/gh14709.phpt b/ext/date/tests/gh14709.phpt new file mode 100644 index 0000000000000..8298ca6651790 --- /dev/null +++ b/ext/date/tests/gh14709.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug GH-14709 overflow on reccurences parameter +--FILE-- +getMessage() . PHP_EOL; +} + +try { + new DatePeriod($start, $interval, 2147483639, DatePeriod::EXCLUDE_START_DATE | DatePeriod::INCLUDE_END_DATE); +} catch (Exception $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d +DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d (including options)