> Date: Fri, 8 Nov 2013 12:34:42 +0100
> From: Martin Pieuchot <mpieuc...@nolizard.org>
> 
> On 20/06/13(Thu) 15:18, Martin Pelikan wrote:
> > > And p_sigmask is copied during fork, so that needs a bit of thought.
> > > I guess it doesn't matter for the new child, as it isn't running yet
> > > and therefore can't invoke sigprocmask(2).  And the parent should be
> > > safe as well, as it is in fork(2) and therefore can't call
> > > sigprocmask(2) either.
> > 
> > memcpy(p_startcopy) which is, tadaaa, p_sigmask!  From implementations
> > of memcpy I've seen (usage of SSE or non-temporal instructions to begin
> > with) it seems that no guarantee about how big a chunk does it copy
> > atomically can be assumed...
> > 
> > So a multithreaded process doing sigprocmask(2) in one thread and
> > simultaneously fork(2) in the other?  Not a problem either, because
> > 1003.1 2004 edition says that sigprocmask(2) is equivalent to
> > pthread_sigmask(3) and the fork only copies the other thread, not
> > bothering with the sigprocmask-ing one.
> > I haven't checked the code that thoroughly but this is what POSIX says.
> > 
> > > There's also a couple of additional p->p_sigmask |= ... in kern_sig.c.
> > > 
> > > All of these need to become atomic_setbits_int/atomic_clearbits_int calls.
> > 
> > Does the third one do the charm?  I haven't compiled the other arch's,
> > but i386 is running fine.
> 
> So what's going on with this diff?  fwiw I tried it on macppc and amd64.
> 
> I'm also wondering, don't you think ptsignal() needs to be modified as
> well?  Because it might access p_sigmask various times, so are you sure
> your diff won't introduce any side effect if the mask is modified in
> between?  Or is it simply impossible?

I came to the conclusion that in its current form, this diff is *not*
safe :(.  There is indeed a problem in ptsignal().  Essentially there
is a race between deciding to which thread to deliver the signal to
and the actual delivery.  This particularly applies to the case where
you are blocking a signal; unblocking a signal is probably safe.

> > Index: arch/hp300/hp300/trap.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/hp300/hp300/trap.c,v
> > retrieving revision 1.62
> > diff -u -p -r1.62 trap.c
> > --- arch/hp300/hp300/trap.c 31 Dec 2012 06:46:13 -0000      1.62
> > +++ arch/hp300/hp300/trap.c 20 Jun 2013 12:51:46 -0000
> > @@ -321,7 +321,7 @@ dopanic:
> >             i = sigmask(SIGILL);
> >             p->p_sigacts->ps_sigignore &= ~i;
> >             p->p_sigacts->ps_sigcatch &= ~i;
> > -           p->p_sigmask &= ~i;
> > +           atomic_clearbits_int(&p->p_sigmask, i);
> >             i = SIGILL;
> >             ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */
> >             typ = ILL_COPROC;
> > Index: arch/mvme68k/mvme68k/trap.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/mvme68k/mvme68k/trap.c,v
> > retrieving revision 1.77
> > diff -u -p -r1.77 trap.c
> > --- arch/mvme68k/mvme68k/trap.c     31 Dec 2012 06:46:13 -0000      1.77
> > +++ arch/mvme68k/mvme68k/trap.c     20 Jun 2013 12:51:47 -0000
> > @@ -260,7 +260,7 @@ copyfault:
> >             i = sigmask(SIGILL);
> >             p->p_sigacts->ps_sigignore &= ~i;
> >             p->p_sigacts->ps_sigcatch &= ~i;
> > -           p->p_sigmask &= ~i;
> > +           atomic_clearbits_int(&p->p_sigmask, i);
> >             i = SIGILL;
> >             ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */
> >             typ = ILL_COPROC;
> > Index: compat/linux/linux_signal.c
> > ===================================================================
> > RCS file: /cvs/src/sys/compat/linux/linux_signal.c,v
> > retrieving revision 1.15
> > diff -u -p -r1.15 linux_signal.c
> > --- compat/linux/linux_signal.c     19 Jun 2012 11:35:29 -0000      1.15
> > +++ compat/linux/linux_signal.c     20 Jun 2013 12:51:49 -0000
> > @@ -584,7 +584,6 @@ linux_sys_sigprocmask(p, v, retval)
> >     linux_old_sigset_t ss;
> >     sigset_t bs;
> >     int error = 0;
> > -   int s;
> >  
> >     *retval = 0;
> >  
> > @@ -604,19 +603,18 @@ linux_sys_sigprocmask(p, v, retval)
> >  
> >     linux_old_to_bsd_sigset(&ss, &bs);
> >  
> > -   s = splhigh();
> > -
> > +   bs &= ~sigcantmask;
> >     switch (SCARG(uap, how)) {
> >     case LINUX_SIG_BLOCK:
> > -           p->p_sigmask |= bs & ~sigcantmask;
> > +           atomic_setbits_int(&p->p_sigmask, bs);
> >             break;
> >  
> >     case LINUX_SIG_UNBLOCK:
> > -           p->p_sigmask &= ~bs;
> > +           atomic_clearbits_int(&p->p_sigmask, bs);
> >             break;
> >  
> >     case LINUX_SIG_SETMASK:
> > -           p->p_sigmask = bs & ~sigcantmask;
> > +           p->p_sigmask = bs;
> >             break;
> >  
> >     default:
> > @@ -624,8 +622,6 @@ linux_sys_sigprocmask(p, v, retval)
> >             break;
> >     }
> >  
> > -   splx(s);
> > -
> >     return (error);
> >  }
> >  
> > @@ -644,7 +640,6 @@ linux_sys_rt_sigprocmask(p, v, retval)
> >     linux_sigset_t ls;
> >     sigset_t bs;
> >     int error = 0;
> > -   int s;
> >  
> >     if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
> >             return (EINVAL);
> > @@ -667,19 +662,18 @@ linux_sys_rt_sigprocmask(p, v, retval)
> >  
> >     linux_to_bsd_sigset(&ls, &bs);
> >  
> > -   s = splhigh();
> > -
> > +   bs &= ~sigcantmask;
> >     switch (SCARG(uap, how)) {
> >     case LINUX_SIG_BLOCK:
> > -           p->p_sigmask |= bs & ~sigcantmask;
> > +           atomic_setbits_int(&p->p_sigmask, bs);
> >             break;
> >  
> >     case LINUX_SIG_UNBLOCK:
> > -           p->p_sigmask &= ~bs;
> > +           atomic_clearbits_int(&p->p_sigmask, bs);
> >             break;
> >  
> >     case LINUX_SIG_SETMASK:
> > -           p->p_sigmask = bs & ~sigcantmask;
> > +           p->p_sigmask = bs;
> >             break;
> >  
> >     default:
> > @@ -687,8 +681,6 @@ linux_sys_rt_sigprocmask(p, v, retval)
> >             break;
> >     }
> >  
> > -   splx(s);
> > -
> >     return (error);
> >  }
> >  
> > @@ -727,16 +719,13 @@ linux_sys_sigsetmask(p, v, retval)
> >     } */ *uap = v;
> >     linux_old_sigset_t mask;
> >     sigset_t bsdsig;
> > -   int s;
> >  
> >     bsd_to_linux_old_sigset(&p->p_sigmask, (linux_old_sigset_t *)retval);
> >  
> >     mask = SCARG(uap, mask);
> >     bsd_to_linux_old_sigset(&bsdsig, &mask);
> >  
> > -   s = splhigh();
> >     p->p_sigmask = bsdsig & ~sigcantmask;
> > -   splx(s);
> >  
> >     return (0);
> >  }
> > Index: kern/init_sysent.c
> > ===================================================================
> > RCS file: /cvs/src/sys/kern/init_sysent.c,v
> > retrieving revision 1.145
> > diff -u -p -r1.145 init_sysent.c
> > --- kern/init_sysent.c      9 Jun 2013 13:10:27 -0000       1.145
> > +++ kern/init_sysent.c      20 Jun 2013 12:51:49 -0000
> > @@ -136,7 +136,7 @@ struct sysent sysent[] = {
> >         sys_sigaction },                    /* 46 = sigaction */
> >     { 0, 0, 0,
> >         sys_getgid },                       /* 47 = getgid */
> > -   { 2, s(struct sys_sigprocmask_args), 0,
> > +   { 2, s(struct sys_sigprocmask_args), SY_NOLOCK | 0,
> >         sys_sigprocmask },                  /* 48 = sigprocmask */
> >     { 2, s(struct sys_getlogin_args), 0,
> >         sys_getlogin },                     /* 49 = getlogin */
> > Index: kern/kern_sig.c
> > ===================================================================
> > RCS file: /cvs/src/sys/kern/kern_sig.c,v
> > retrieving revision 1.152
> > diff -u -p -r1.152 kern_sig.c
> > --- kern/kern_sig.c 1 Jun 2013 04:05:26 -0000       1.152
> > +++ kern/kern_sig.c 20 Jun 2013 12:51:49 -0000
> > @@ -429,28 +429,25 @@ sys_sigprocmask(struct proc *p, void *v,
> >             syscallarg(sigset_t) mask;
> >     } */ *uap = v;
> >     int error = 0;
> > -   int s;
> >     sigset_t mask;
> >  
> >     *retval = p->p_sigmask;
> > -   mask = SCARG(uap, mask);
> > -   s = splhigh();
> > +   mask = SCARG(uap, mask) &~ sigcantmask;
> >  
> >     switch (SCARG(uap, how)) {
> >     case SIG_BLOCK:
> > -           p->p_sigmask |= mask &~ sigcantmask;
> > +           atomic_setbits_int(&p->p_sigmask, mask);
> >             break;
> >     case SIG_UNBLOCK:
> > -           p->p_sigmask &= ~mask;
> > +           atomic_clearbits_int(&p->p_sigmask, mask);
> >             break;
> >     case SIG_SETMASK:
> > -           p->p_sigmask = mask &~ sigcantmask;
> > +           p->p_sigmask = mask;
> >             break;
> >     default:
> >             error = EINVAL;
> >             break;
> >     }
> > -   splx(s);
> >     return (error);
> >  }
> >  
> > @@ -739,7 +736,7 @@ trapsignal(struct proc *p, int signum, u
> >             p->p_ru.ru_nsignals++;
> >             (*p->p_emul->e_sendsig)(ps->ps_sigact[signum], signum,
> >                 p->p_sigmask, trapno, code, sigval);
> > -           p->p_sigmask |= ps->ps_catchmask[signum];
> > +           atomic_setbits_int(&p->p_sigmask, ps->ps_catchmask[signum]);
> >             if ((ps->ps_sigreset & mask) != 0) {
> >                     ps->ps_sigcatch &= ~mask;
> >                     if (signum != SIGCONT && sigprop[signum] & SA_IGNORE)
> > @@ -1334,7 +1331,7 @@ postsig(int signum)
> >             } else {
> >                     returnmask = p->p_sigmask;
> >             }
> > -           p->p_sigmask |= ps->ps_catchmask[signum];
> > +           atomic_setbits_int(&p->p_sigmask, ps->ps_catchmask[signum]);
> >             if ((ps->ps_sigreset & mask) != 0) {
> >                     ps->ps_sigcatch &= ~mask;
> >                     if (signum != SIGCONT && sigprop[signum] & SA_IGNORE)
> > Index: kern/syscalls.master
> > ===================================================================
> > RCS file: /cvs/src/sys/kern/syscalls.master,v
> > retrieving revision 1.133
> > diff -u -p -r1.133 syscalls.master
> > --- kern/syscalls.master    9 Jun 2013 13:10:19 -0000       1.133
> > +++ kern/syscalls.master    20 Jun 2013 12:51:49 -0000
> > @@ -123,7 +123,7 @@
> >                         const struct sigaction *nsa, \
> >                         struct sigaction *osa); }
> >  47 STD             { gid_t sys_getgid(void); }
> > -48 STD             { int sys_sigprocmask(int how, sigset_t mask); }
> > +48 STD NOLOCK      { int sys_sigprocmask(int how, sigset_t mask); }
> >  49 STD             { int sys_getlogin(char *namebuf, u_int namelen); }
> >  50 STD             { int sys_setlogin(const char *namebuf); }
> >  #ifdef ACCOUNTING
> > 
> 

Reply via email to