Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAMbhsRTrqwB98Jo2kUmt33J=0oA6wTJ9e_+Mr6a8P=yj8HtQxg@mail.gmail.com>
Date: Thu, 3 Sep 2026 18:24:19 -0700
From: Colin Cross <ccross@...roid.com>
To: musl@...ts.openwall.com
Subject: Re: Fix deadlock in timer_create when syscall fails

On Thu, Sep 3, 2026 at 4:27 PM Szabolcs Nagy <nsz@...t70.net> wrote:
>
> * Colin Cross <ccross@...roid.com> [2026-09-03 10:26:12 -0700]:
> > Subject: [PATCH] SIGEV_THREAD timers: fix deadlock when timer_create syscall
> >  fails
> >
> > sem_wait is a cancellation point.  If the parent thread in timer_create
> > sets td->cancel = 1 before the child thread reaches sem_wait then
> > the thread will exit and sem_post will never be called, causing
> > the parent thread to deadlock in sem_wait.
> >
> > 3ad3fa962efee12067d68c3405a537dce156a7ac set td->cancel = 1 to fix
> > a thread leak when the syscall failed.  The switch to two-way semaphores
> > cde213f9c3ac1aa168581222edee6a6642113323 allows checking if self->timer_id
> > is -1 instead of self->cancel because timer_delete can't have been called
> > before the sem_post allows the parent thread to return from timer_create.
>
> this looks ok, i have minor comments only
>
> your orig mail had
>
>   This was observed in a test that called
>   timer_create(CLOCK_BOOTTIME_ALARM, SIGEV_THREAD, ...) without
>   CAP_WAKE_ALARM, causing the kernel to return EPERM.
>
> i prefer to include such details in the commit.
>
> > ---
> >  src/time/timer_create.c | 22 +++++++++++++++-------
> >  1 file changed, 15 insertions(+), 7 deletions(-)
> >
> > diff --git a/src/time/timer_create.c b/src/time/timer_create.c
> > index cc6c2236..a89f45af 100644
> > --- a/src/time/timer_create.c
> > +++ b/src/time/timer_create.c
> > @@ -45,19 +45,28 @@ static void *start(void *arg)
> >       pthread_t self = __pthread_self();
> >       struct start_args *args = arg;
> >       jmp_buf jb;
> > +     int cs;
>
> not needed.

Oops, I'll drop that in the next version.

> >
> >       void (*notify)(union sigval) = args->sev->sigev_notify_function;
> >       union sigval val = args->sev->sigev_value;
> > +     int cancel = 0;
> >
> > -     /* The two-way semaphore synchronization ensures that we see
> > -      * self->cancel set by the parent if timer creation failed or
> > -      * self->timer_id if it succeeded, and informs the parent that
> > -      * we are done accessing the arguments so that the parent can
> > -      * proceed past their block lifetime. */
> > +     /* Waiting on sem1 ensures we see self->timer_id. */
> >       while (sem_wait(&args->sem1));
> > +
> > +     /* If self->timer_id is -1 while the parent thread is still in
> > +      * timer_create (before the sem_post to sem2) then the timer was
> > +      * never created.  If it is -1 later after the sem_post then
> > +      * it was cancelled via timer_delete. */
> > +     if (self->timer_id < 0)
> > +             cancel = 1;
> > +
> > +     /* Incrementing sem2 informs the parent that we are done checking
> > +      * the initial value of self->timer_id, and accessing the arguments
> > +      * so that the parent can proceed past their block lifetime. */
> >       sem_post(&args->sem2);
> >
> > -     if (self->cancel)
> > +     if (cancel)
> >               return 0;
>
> or
>
>   int timerid;
>   while (sem_wait(...));
>   timerid = self->timer_id; // only one if this way
>   sem_post(...);
>   if (timerid < 0) return 0;

I considered that, but it seemed confusing to create a local timerid
variable when the later loop needs to re-read self->timer_id each
time.

> >       for (;;) {
> >               siginfo_t si;
> > @@ -135,7 +144,6 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
> >               ksev.sigev_tid = td->tid;
> >               if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) {
> >                       timerid = -1;
> > -                     td->cancel = 1;
> >               }
> >               td->timer_id = timerid;
> >               sem_post(&args.sem1);
> > --
> > 2.55.0.979.g7e5102b832-goog
> >
>

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.