On 07/07/14(Mon) 13:46, Matthew Dempsky wrote:
> p_sigmask is only modified by the owning thread from process context
> (e.g., sys_sigprocmask(), sys_sigreturn(), userret(), or postsig()),
> but it can be accessed anywhere (e.g., interrupts or threads on other
> CPUs).  Currently sys_sigprocmask() protects p_sigmask with splhigh(),
> but that's not MP-safe.
>
> 
> The simpler solution is to take advantage of our atomics APIs.
> Unfortunately for implementing SIG_SETMASK, we don't have an
> atomic_store_int() function, and I can't bring myself to abuse
> "volatile" for this purpose, so I've resorted to atomic_swap_uint().
> 
> While here, I also refactored the P_SIGSUSPEND code a bit so there's
> less code duplication.
> 
> I've included just amd64 and i386's machdep.c for now, because those
> were the only ones I'm readily able to test.  The others should be
> easy to similarly fix though, and I can send a followup diff for them.

There was a previous attempt to mark sigpromask(2) as nolock but if I
recall properly setting p_sigmask atomically is not enough and there's
still a possible race in ptsignal().

Have you looked into this function, is it safe now?

> Index: sys/proc.h
> ===================================================================
> RCS file: /home/matthew/cvs-mirror/cvs/src/sys/sys/proc.h,v
> retrieving revision 1.186
> diff -u -p -r1.186 proc.h
> --- sys/proc.h        15 May 2014 03:52:25 -0000      1.186
> +++ sys/proc.h        7 Jul 2014 19:23:06 -0000
> @@ -520,6 +520,8 @@ int       proc_cansugid(struct proc *);
>  void proc_finish_wait(struct proc *, struct proc *);
>  void process_zap(struct process *);
>  void proc_free(struct proc *);
> +void proc_sigsetmask(struct proc *, sigset_t);
> +void proc_sigsuspend(struct proc *, sigset_t);
>  
>  struct sleep_state {
>       int sls_s;
> @@ -559,4 +561,3 @@ struct cpu_info *cpuset_first(struct cpu
>  
>  #endif       /* _KERNEL */
>  #endif       /* !_SYS_PROC_H_ */
> -
> Index: kern/kern_sig.c
> ===================================================================
> RCS file: /home/matthew/cvs-mirror/cvs/src/sys/kern/kern_sig.c,v
> retrieving revision 1.166
> diff -u -p -r1.166 kern_sig.c
> --- kern/kern_sig.c   4 May 2014 05:03:26 -0000       1.166
> +++ kern/kern_sig.c   7 Jul 2014 19:24:07 -0000
> @@ -62,6 +62,7 @@
>  #include <sys/ptrace.h>
>  #include <sys/sched.h>
>  #include <sys/user.h>
> +#include <sys/atomic.h>
>  
>  #include <sys/mount.h>
>  #include <sys/syscallargs.h>
> @@ -439,37 +440,55 @@ sys_sigprocmask(struct proc *p, void *v,
>               syscallarg(int) how;
>               syscallarg(sigset_t) mask;
>       } */ *uap = v;
> -     int error = 0;
> -     int s;
> -     sigset_t mask;
> +     sigset_t mask = SCARG(uap, mask);
>  
>       *retval = p->p_sigmask;
> -     mask = SCARG(uap, mask);
> -     s = splhigh();
>  
>       switch (SCARG(uap, how)) {
>       case SIG_BLOCK:
> -             p->p_sigmask |= mask &~ sigcantmask;
> +             atomic_setbits_int(&p->p_sigmask, mask &~ sigcantmask);
>               break;
>       case SIG_UNBLOCK:
> -             p->p_sigmask &= ~mask;
> +             atomic_clearbits_int(&p->p_sigmask, mask);
>               break;
>       case SIG_SETMASK:
> -             p->p_sigmask = mask &~ sigcantmask;
> +             proc_sigsetmask(p, mask &~ sigcantmask);
>               break;
>       default:
> -             error = EINVAL;
> -             break;
> +             return (EINVAL);
>       }
> -     splx(s);
> -     return (error);
> +
> +     return (0);
> +}
> +
> +void
> +proc_sigsetmask(struct proc *p, sigset_t mask)
> +{
> +     KASSERT(p == curproc);
> +
> +     /* XXX: An atomic store would suffice here. */
> +     (void)atomic_swap_uint(&p->p_sigmask, mask);
> +}
> +
> +/*
> + * Temporarily replace calling proc's signal mask for the duration of a
> + * system call.  Original signal mask will be restored by userret().
> + */
> +void
> +proc_sigsuspend(struct proc *p, sigset_t mask)
> +{
> +     KASSERT(p == curproc);
> +     KASSERT(!(p->p_flag & P_SIGSUSPEND));
> +
> +     p->p_oldmask = p->p_sigmask;
> +     atomic_setbits_int(&p->p_flag, P_SIGSUSPEND);
> +     proc_sigsetmask(p, mask);
>  }
>  
>  /* ARGSUSED */
>  int
>  sys_sigpending(struct proc *p, void *v, register_t *retval)
>  {
> -
>       *retval = p->p_siglist;
>       return (0);
>  }
> @@ -489,16 +508,7 @@ sys_sigsuspend(struct proc *p, void *v, 
>       struct process *pr = p->p_p;
>       struct sigacts *ps = pr->ps_sigacts;
>  
> -     /*
> -      * When returning from sigpause, we want
> -      * the old mask to be restored after the
> -      * signal handler has finished.  Thus, we
> -      * save it here and mark the sigacts structure
> -      * to indicate this.
> -      */
> -     p->p_oldmask = p->p_sigmask;
> -     atomic_setbits_int(&p->p_flag, P_SIGSUSPEND);
> -     p->p_sigmask = SCARG(uap, mask) &~ sigcantmask;
> +     proc_sigsuspend(p, SCARG(uap, mask) &~ sigcantmask);
>       while (tsleep(ps, PPAUSE|PCATCH, "pause", 0) == 0)
>               /* void */;
>       /* always return EINTR rather than ERESTART... */
> Index: kern/sys_generic.c
> ===================================================================
> RCS file: /home/matthew/cvs-mirror/cvs/src/sys/kern/sys_generic.c,v
> retrieving revision 1.86
> diff -u -p -r1.86 sys_generic.c
> --- kern/sys_generic.c        30 Mar 2014 21:54:48 -0000      1.86
> +++ kern/sys_generic.c        7 Jul 2014 19:24:07 -0000
> @@ -658,9 +620,7 @@ dopselect(struct proc *p, int nd, fd_set
>       timo = 0;
>  
>       if (sigmask) {
> -             p->p_oldmask = p->p_sigmask;
> -             atomic_setbits_int(&p->p_flag, P_SIGSUSPEND);
> -             p->p_sigmask = *sigmask &~ sigcantmask;
> +             proc_sigsuspend(p, *sigmask &~ sigcantmask);
>       }
>  
>  retry:
> @@ -966,9 +926,7 @@ doppoll(struct proc *p, struct pollfd *f
>       timo = 0;
>  
>       if (sigmask) {
> -             p->p_oldmask = p->p_sigmask;
> -             atomic_setbits_int(&p->p_flag, P_SIGSUSPEND);
> -             p->p_sigmask = *sigmask &~ sigcantmask;
> +             proc_sigsuspend(p, *sigmask &~ sigcantmask);
>       }
>  
>  retry:
> Index: compat/linux/linux_signal.c
> ===================================================================
> RCS file: /home/matthew/cvs-mirror/cvs/src/sys/compat/linux/linux_signal.c,v
> retrieving revision 1.17
> diff -u -p -r1.17 linux_signal.c
> --- compat/linux/linux_signal.c       26 Mar 2014 05:23:42 -0000      1.17
> +++ compat/linux/linux_signal.c       7 Jul 2014 19:24:07 -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,17 @@ linux_sys_sigprocmask(p, v, retval)
>  
>       linux_old_to_bsd_sigset(&ss, &bs);
>  
> -     s = splhigh();
> -
>       switch (SCARG(uap, how)) {
>       case LINUX_SIG_BLOCK:
> -             p->p_sigmask |= bs & ~sigcantmask;
> +             atomic_setbits_int(&p->p_sigmask, bs &~ sigcantmask);
>               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;
> +             proc_sigsetmask(p, bs &~ sigcantmask);
>               break;
>  
>       default:
> @@ -624,8 +621,6 @@ linux_sys_sigprocmask(p, v, retval)
>               break;
>       }
>  
> -     splx(s);
> -
>       return (error);
>  }
>  
> @@ -644,7 +639,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 +661,17 @@ linux_sys_rt_sigprocmask(p, v, retval)
>  
>       linux_to_bsd_sigset(&ls, &bs);
>  
> -     s = splhigh();
> -
>       switch (SCARG(uap, how)) {
>       case LINUX_SIG_BLOCK:
> -             p->p_sigmask |= bs & ~sigcantmask;
> +             atomic_setbits_int(&p->p_sigmask, bs &~ sigcantmask);
>               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;
> +             proc_sigsetmask(p, bs &~ sigcantmask);
>               break;
>  
>       default:
> @@ -687,8 +679,6 @@ linux_sys_rt_sigprocmask(p, v, retval)
>               break;
>       }
>  
> -     splx(s);
> -
>       return (error);
>  }
>  
> @@ -727,16 +717,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);
> +     proc_sigsetmask(p, bsdsig &~ sigcantmask);
>  
>       return (0);
>  }
> Index: arch/amd64/amd64/machdep.c
> ===================================================================
> RCS file: /home/matthew/cvs-mirror/cvs/src/sys/arch/amd64/amd64/machdep.c,v
> retrieving revision 1.180
> diff -u -p -r1.180 machdep.c
> --- arch/amd64/amd64/machdep.c        15 Jun 2014 11:43:24 -0000      1.180
> +++ arch/amd64/amd64/machdep.c        7 Jul 2014 19:24:07 -0000
> @@ -670,7 +670,7 @@ sys_sigreturn(struct proc *p, void *v, r
>       bcopy(&ksc, tf, sizeof(*tf));
>  
>       /* Restore signal mask. */
> -     p->p_sigmask = ksc.sc_mask & ~sigcantmask;
> +     proc_sigsetmask(p, ksc.sc_mask & ~sigcantmask);
>  
>       /*
>        * sigreturn() needs to return to userspace via the 'iretq'
> Index: arch/i386/i386/machdep.c
> ===================================================================
> RCS file: /home/matthew/cvs-mirror/cvs/src/sys/arch/i386/i386/machdep.c,v
> retrieving revision 1.539
> diff -u -p -r1.539 machdep.c
> --- arch/i386/i386/machdep.c  15 Jun 2014 11:43:24 -0000      1.539
> +++ arch/i386/i386/machdep.c  7 Jul 2014 19:24:07 -0000
> @@ -2491,7 +2491,7 @@ sys_sigreturn(struct proc *p, void *v, r
>               p->p_md.md_flags |= MDP_USEDFPU;
>       }
>  
> -     p->p_sigmask = context.sc_mask & ~sigcantmask;
> +     proc_sigsetmask(p, context.sc_mask & ~sigcantmask);
>  
>       return (EJUSTRETURN);
>  }
> @@ -3990,4 +3990,3 @@ intr_handler(struct intrframe *frame, st
>  #endif
>       return rc;
>  }
> -
> 

Reply via email to