aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Freeland <jfree@FreeBSD.org>2026-03-20 06:33:38 +0000
committerJake Freeland <jfree@FreeBSD.org>2026-03-20 07:15:08 +0000
commit0e8f351be7935729bf67dc1b7aa4d178cf154931 (patch)
treeb7f7d4d245ac0dc80a1361e5e842339b1d8487ae
parente3799530b3ba38567f8052b9e107884609fc71ea (diff)
timerfd: Use saturating sbintime conversions
Some timerfd consumers set expirations with timespec tv_sec components larger than 2^31 - 1. In such cases, converting that timespec to sbintime results in data loss or sign flip, yielding a shorter expiration than desired. To avoid this problem, use saturating timespec-to-sbintime conversion functions. These will clamp the converted sbintime to SBT_MAX under circumstances where the normal conversion functions would overflow. Saturating conversions still result in data loss, but the consequences are less severe, causing problems only after SBT_MAX (~68 years) of system uptime elapses. Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D55792 MFC after: 2 weeks
-rw-r--r--sys/kern/sys_timerfd.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/sys/kern/sys_timerfd.c b/sys/kern/sys_timerfd.c
index 236dfe8bb96a..f2a66e21cd63 100644
--- a/sys/kern/sys_timerfd.c
+++ b/sys/kern/sys_timerfd.c
@@ -165,7 +165,7 @@ timerfd_jumped(void)
&diff, &tfd->tfd_time.it_value);
if (callout_stop(&tfd->tfd_callout) == 1) {
callout_schedule_sbt(&tfd->tfd_callout,
- tstosbt(tfd->tfd_time.it_value),
+ tstosbt_sat(tfd->tfd_time.it_value),
0, C_ABSOLUTE);
}
}
@@ -398,10 +398,10 @@ timerfd_expire(void *arg)
++tfd->tfd_count;
tfd->tfd_expired = true;
if (timespecisset(&tfd->tfd_time.it_interval)) {
- exp = tstosbt(tfd->tfd_time.it_value);
- interval = tstosbt(tfd->tfd_time.it_interval);
+ exp = tstosbt_sat(tfd->tfd_time.it_value);
+ interval = tstosbt_sat(tfd->tfd_time.it_interval);
now = sbinuptime();
- next = now + interval;
+ next = now > SBT_MAX - interval ? SBT_MAX : now + interval;
/* Count missed events. */
if (now > exp) {
@@ -553,7 +553,7 @@ kern_timerfd_settime(struct thread *td, int fd, int flags,
&tfd->tfd_time.it_value);
}
callout_reset_sbt(&tfd->tfd_callout,
- tstosbt(tfd->tfd_time.it_value),
+ tstosbt_sat(tfd->tfd_time.it_value),
0, timerfd_expire, tfd, C_ABSOLUTE);
} else {
callout_stop(&tfd->tfd_callout);