mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
fix(esp_libc): reject out-of-range adjtime() deltas instead of overflowing
The adjtime() wrapper stored the microsecond offset into the 32-bit `long` timex.offset field without checking for overflow. A large delta (e.g. 400 days) was computed in 64-bit and silently truncated when assigned, wrapping into a small value that passed the ~35 minute range check. adjtime() then returned 0 instead of the expected -1. Compute the offset in int64_t and reject values that do not fit in the timex.offset field with EINVAL. Add a regression test for a multi-day delta. Closes https://github.com/espressif/esp-idf/issues/19051
This commit is contained in:
@@ -189,8 +189,15 @@ WEAK_UNLESS_TIMEFUNC_IMPL int adjtime(const struct timeval *delta, struct timeva
|
|||||||
struct timex tx = {0};
|
struct timex tx = {0};
|
||||||
|
|
||||||
if (delta != NULL) {
|
if (delta != NULL) {
|
||||||
|
// Reject deltas that do not fit in the 32-bit struct timex.offset (µs) field,
|
||||||
|
// otherwise the value would be silently truncated and pass the range check.
|
||||||
|
int64_t offset_us = (int64_t)delta->tv_sec * 1000000LL + delta->tv_usec;
|
||||||
|
if (offset_us > LONG_MAX || offset_us < LONG_MIN) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
tx.modes = ADJ_OFFSET_SINGLESHOT;
|
tx.modes = ADJ_OFFSET_SINGLESHOT;
|
||||||
tx.offset = delta->tv_sec * 1000000L + delta->tv_usec;
|
tx.offset = (long)offset_us;
|
||||||
} else {
|
} else {
|
||||||
tx.modes = ADJ_OFFSET_SS_READ;
|
tx.modes = ADJ_OFFSET_SS_READ;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,18 @@ void test_adjtime_function(test_adjtime_mode_t mode, test_clock_adjtime_units_t
|
|||||||
TEST_ASSERT_EQUAL(realtime_adjtime_wrapper(&tv_delta, &tv_outdelta, mode, units), -1);
|
TEST_ASSERT_EQUAL(realtime_adjtime_wrapper(&tv_delta, &tv_outdelta, mode, units), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a multi-day delta must be rejected, not silently
|
||||||
|
// truncated into the 32-bit timex.offset (µs) field and applied as a small slew.
|
||||||
|
if (mode == TEST_ADJTIME_MODE_LEGACY) {
|
||||||
|
tv_delta.tv_sec = 400L * 24 * 60 * 60; // 400 days
|
||||||
|
tv_delta.tv_usec = 123456;
|
||||||
|
TEST_ASSERT_EQUAL(realtime_adjtime_wrapper(&tv_delta, NULL, mode, units), -1);
|
||||||
|
|
||||||
|
tv_delta.tv_sec = -400L * 24 * 60 * 60;
|
||||||
|
tv_delta.tv_usec = -123456;
|
||||||
|
TEST_ASSERT_EQUAL(realtime_adjtime_wrapper(&tv_delta, NULL, mode, units), -1);
|
||||||
|
}
|
||||||
|
|
||||||
tv_delta.tv_sec = 0;
|
tv_delta.tv_sec = 0;
|
||||||
tv_delta.tv_usec = -900000;
|
tv_delta.tv_usec = -900000;
|
||||||
TEST_ASSERT_EQUAL(realtime_adjtime_wrapper(&tv_delta, &tv_outdelta, mode, units), 0);
|
TEST_ASSERT_EQUAL(realtime_adjtime_wrapper(&tv_delta, &tv_outdelta, mode, units), 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user