raise() implementation in freebsd libc vs musl libc

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

raise() implementation in freebsd libc vs musl libc

Andrew Kelley
Howdy,

I noticed that musl-libc blocks signals in raise() to prevent a race
condition, but freebsd libc does not. is there a reason it's necessary
on linux and not freebsd?

musl
int raise(int sig)
{
        sigset_t set;
        __block_app_sigs(&set);
        int ret = syscall(SYS_tkill, __pthread_self()->tid, sig);
        __restore_sigs(&set);
        return ret;
}

freebsd
int
__raise(int s)
{
        long id;

        if (__sys_thr_self(&id) == -1)
                return (-1);
        return (__sys_thr_kill(id, s));
}

Regards,
Andrew


signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: raise() implementation in freebsd libc vs musl libc

Conrad Meyer-2
Hi Andrew,

The musl signal blocking dates to this commit:

https://git.musl-libc.org/cgit/musl/commit/?id=0bed7e0acfd34e3fb63ca0e4d99b7592571355a9

The concern raised in that commit was that raise(3) could
theoretically be interrupted by a concurrently running signal handler
which invokes fork() (also sighandler-safe), resulting in
inconsistent/stale values from gettid(2)/getpid(2) on Linux (at the
time).

On both systems, gettid(2) / thr_self(2) returns a unique thread
identifier that cannot be reused until the thread it identifies has
exited.  So, I don't know.  I guess if fork happens between thr_self()
and thr_kill(), the parent process may have already exited and had its
tid recycled by the time the child process invokes thr_kill().

OTOH, that seems like a pretty byzantine / broken application?  I'm
not sure it's libc's job to prevent applications from shooting
themselves in the foot.  Forking in a signal handler is already
somewhat dicey, and especially so if the child does not immediately
exec() or _exit(2).

Anyway, that's just my guess.  I am not a libthr expert on either BSD
nor Linux, so take this with a big grain of salt.  Signals were a
mistake ;-).

Best,
Conrad

P.S., Zig looks quite promising, I am excited to see where it goes.


On Wed, Dec 12, 2018 at 9:12 PM Andrew Kelley <[hidden email]> wrote:

>
> Howdy,
>
> I noticed that musl-libc blocks signals in raise() to prevent a race
> condition, but freebsd libc does not. is there a reason it's necessary
> on linux and not freebsd?
>
> musl
> int raise(int sig)
> {
>         sigset_t set;
>         __block_app_sigs(&set);
>         int ret = syscall(SYS_tkill, __pthread_self()->tid, sig);
>         __restore_sigs(&set);
>         return ret;
> }
>
> freebsd
> int
> __raise(int s)
> {
>         long id;
>
>         if (__sys_thr_self(&id) == -1)
>                 return (-1);
>         return (__sys_thr_kill(id, s));
> }
>
> Regards,
> Andrew
>
_______________________________________________
[hidden email] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[hidden email]"
Reply | Threaded
Open this post in threaded view
|

Re: raise() implementation in freebsd libc vs musl libc

Steve Kargl
In reply to this post by Andrew Kelley
On Thu, Dec 13, 2018 at 12:11:21AM -0500, Andrew Kelley wrote:
>
> I noticed that musl-libc blocks signals in raise() to prevent a race
> condition, but freebsd libc does not. is there a reason it's necessary
> on linux and not freebsd?
>
> if (__sys_thr_self(&id) == -1)
> return (-1);
> return (__sys_thr_kill(id, s));

The answer probably lies in the meaining of '_thr_' in the
above function names.  See src/sys/kern/kern_thr.c.

--
Steve
_______________________________________________
[hidden email] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[hidden email]"
Reply | Threaded
Open this post in threaded view
|

Re: raise() implementation in freebsd libc vs musl libc

Konstantin Belousov
In reply to this post by Conrad Meyer-2
On Wed, Dec 12, 2018 at 10:00:56PM -0800, Conrad Meyer wrote:

> Hi Andrew,
>
> The musl signal blocking dates to this commit:
>
> https://git.musl-libc.org/cgit/musl/commit/?id=0bed7e0acfd34e3fb63ca0e4d99b7592571355a9
>
> The concern raised in that commit was that raise(3) could
> theoretically be interrupted by a concurrently running signal handler
> which invokes fork() (also sighandler-safe), resulting in
> inconsistent/stale values from gettid(2)/getpid(2) on Linux (at the
> time).
But even then, for the child to signal wrong thread, it must return from
the signal frame to the interrupted frame executing raise().  This would
be really weird design.

>
> On both systems, gettid(2) / thr_self(2) returns a unique thread
> identifier that cannot be reused until the thread it identifies has
> exited.  So, I don't know.  I guess if fork happens between thr_self()
> and thr_kill(), the parent process may have already exited and had its
> tid recycled by the time the child process invokes thr_kill().
The difference between Linux and FreeBSD there, as I see it, is that
thr_kill() only allows to send signals to the threads in the current
process.  So when the forked child sends a signal to the thread identified
by the parent' thread id, nothing happens except an error code returned.

>
> OTOH, that seems like a pretty byzantine / broken application?  I'm
> not sure it's libc's job to prevent applications from shooting
> themselves in the foot.  Forking in a signal handler is already
> somewhat dicey, and especially so if the child does not immediately
> exec() or _exit(2).
Forking in a signal handler is fine, assuming that the signal handler
only uses async-signal safe functions, regardless of exec/_exit.
Problem there is that atfork handlers must only use async-safe functions,
which means that the author of the signal handler must be aware of the
whole application code, including all libraries.

>
> Anyway, that's just my guess.  I am not a libthr expert on either BSD
> nor Linux, so take this with a big grain of salt.  Signals were a
> mistake ;-).
>
> Best,
> Conrad
>
> P.S., Zig looks quite promising, I am excited to see where it goes.
>
>
> On Wed, Dec 12, 2018 at 9:12 PM Andrew Kelley <[hidden email]> wrote:
> >
> > Howdy,
> >
> > I noticed that musl-libc blocks signals in raise() to prevent a race
> > condition, but freebsd libc does not. is there a reason it's necessary
> > on linux and not freebsd?
> >
> > musl
> > int raise(int sig)
> > {
> >         sigset_t set;
> >         __block_app_sigs(&set);
> >         int ret = syscall(SYS_tkill, __pthread_self()->tid, sig);
> >         __restore_sigs(&set);
> >         return ret;
> > }
> >
> > freebsd
> > int
> > __raise(int s)
> > {
> >         long id;
> >
> >         if (__sys_thr_self(&id) == -1)
> >                 return (-1);
> >         return (__sys_thr_kill(id, s));
> > }
> >
> > Regards,
> > Andrew
> >
> _______________________________________________
> [hidden email] mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
> To unsubscribe, send any mail to "[hidden email]"
_______________________________________________
[hidden email] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[hidden email]"