The branch main has been updated by dchagin:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=4a700f3c329a48f3a20fd576900820e293c8cad7

commit 4a700f3c329a48f3a20fd576900820e293c8cad7
Author:     Dmitry Chagin <[email protected]>
AuthorDate: 2022-04-25 07:23:15 +0000
Commit:     Dmitry Chagin <[email protected]>
CommitDate: 2022-04-25 07:23:15 +0000

    sigtimedwait: Prevent timeout math overflows.
    
    Our kern_sigtimedwait() calculates absolute sleep timo value as 
'uptime+timeout'.
    So, when the user specifies a big timeout value (LONG_MAX), the calculated
    timo can be less the the current uptime value.
    In that case kern_sigtimedwait() returns EAGAIN instead of EINTR, if
    unblocked signal was caught.
    
    While here switch to a high-precision sleep method.
    
    Reviewed by:            mav, kib
    In collaboration with:  mav
    Differential revision:  https://reviews.freebsd.org/D34981
    MFC after:              2 weeks
---
 sys/kern/kern_sig.c | 49 ++++++++++++++++++++-----------------------------
 1 file changed, 20 insertions(+), 29 deletions(-)

diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 55b2957d163b..ce6f517262a4 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1258,15 +1258,13 @@ kern_sigtimedwait(struct thread *td, sigset_t waitset, 
ksiginfo_t *ksi,
        struct sigacts *ps;
        sigset_t saved_mask, new_block;
        struct proc *p;
-       int error, sig, timo, timevalid = 0;
-       struct timespec rts, ets, ts;
-       struct timeval tv;
+       int error, sig, timevalid = 0;
+       sbintime_t sbt, precision, tsbt;
+       struct timespec ts;
        bool traced;
 
        p = td->td_proc;
        error = 0;
-       ets.tv_sec = 0;
-       ets.tv_nsec = 0;
        traced = false;
 
        /* Ensure the sigfastblock value is up to date. */
@@ -1275,10 +1273,19 @@ kern_sigtimedwait(struct thread *td, sigset_t waitset, 
ksiginfo_t *ksi,
        if (timeout != NULL) {
                if (timeout->tv_nsec >= 0 && timeout->tv_nsec < 1000000000) {
                        timevalid = 1;
-                       getnanouptime(&rts);
-                       timespecadd(&rts, timeout, &ets);
+                       ts = *timeout;
+                       if (ts.tv_sec < INT32_MAX / 2) {
+                               tsbt = tstosbt(ts);
+                               precision = tsbt;
+                               precision >>= tc_precexp;
+                               if (TIMESEL(&sbt, tsbt))
+                                       sbt += tc_tick_sbt;
+                               sbt += tsbt;
+                       } else
+                               precision = sbt = 0;
                }
-       }
+       } else
+               precision = sbt = 0;
        ksiginfo_init(ksi);
        /* Some signals can not be waited for. */
        SIG_CANTMASK(waitset);
@@ -1312,21 +1319,9 @@ kern_sigtimedwait(struct thread *td, sigset_t waitset, 
ksiginfo_t *ksi,
                 * POSIX says this must be checked after looking for pending
                 * signals.
                 */
-               if (timeout != NULL) {
-                       if (!timevalid) {
-                               error = EINVAL;
-                               break;
-                       }
-                       getnanouptime(&rts);
-                       if (timespeccmp(&rts, &ets, >=)) {
-                               error = EAGAIN;
-                               break;
-                       }
-                       timespecsub(&ets, &rts, &ts);
-                       TIMESPEC_TO_TIMEVAL(&tv, &ts);
-                       timo = tvtohz(&tv);
-               } else {
-                       timo = 0;
+               if (timeout != NULL && !timevalid) {
+                       error = EINVAL;
+                       break;
                }
 
                if (traced) {
@@ -1334,17 +1329,13 @@ kern_sigtimedwait(struct thread *td, sigset_t waitset, 
ksiginfo_t *ksi,
                        break;
                }
 
-               error = msleep(&p->p_sigacts, &p->p_mtx, PPAUSE | PCATCH,
-                   "sigwait", timo);
+               error = msleep_sbt(&p->p_sigacts, &p->p_mtx, PPAUSE | PCATCH,
+                   "sigwait", sbt, precision, C_ABSOLUTE);
 
                /* The syscalls can not be restarted. */
                if (error == ERESTART)
                        error = EINTR;
 
-               /* We will calculate timeout by ourself. */
-               if (timeout != NULL && error == EAGAIN)
-                       error = 0;
-
                /*
                 * If PTRACE_SCE or PTRACE_SCX were set after
                 * userspace entered the syscall, return spurious

Reply via email to