On Mon, Jul 24, 2017 at 11:56:20AM +0200, Martin Pieuchot wrote:
> Updated diff addressing your comments.

Yes, previous issues are fixed.  But static code analysis shows
that you missed a lock in sys_socketpair() for soconnect2().

Analyzing locks for soconnect2
No lock: [soconnect2, sys_socketpair]

I could convince Zaur Molotnikov to publish his tool:
https://github.com/qutorial/lockfish

bluhm

> Index: kern/uipc_socket.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/uipc_socket.c,v
> retrieving revision 1.196
> diff -u -p -r1.196 uipc_socket.c
> --- kern/uipc_socket.c        20 Jul 2017 09:49:45 -0000      1.196
> +++ kern/uipc_socket.c        24 Jul 2017 09:52:01 -0000
> @@ -311,11 +311,12 @@ soaccept(struct socket *so, struct mbuf 
>  int
>  soconnect(struct socket *so, struct mbuf *nam)
>  {
> -     int s, error;
> +     int error;
> +
> +     soassertlocked(so);
>  
>       if (so->so_options & SO_ACCEPTCONN)
>               return (EOPNOTSUPP);
> -     s = solock(so);
>       /*
>        * If protocol is connection-based, can only connect once.
>        * Otherwise, if connected, try to disconnect first.
> @@ -329,19 +330,17 @@ soconnect(struct socket *so, struct mbuf
>       else
>               error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
>                   NULL, nam, NULL, curproc);
> -     sounlock(s);
>       return (error);
>  }
>  
>  int
>  soconnect2(struct socket *so1, struct socket *so2)
>  {
> -     int s, error;
> +     int error;
>  
> -     s = solock(so1);
> +     soassertlocked(so1);
>       error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, NULL,
>           (struct mbuf *)so2, NULL, curproc);
> -     sounlock(s);
>       return (error);
>  }
>  
> Index: kern/uipc_syscalls.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
> retrieving revision 1.155
> diff -u -p -r1.155 uipc_syscalls.c
> --- kern/uipc_syscalls.c      20 Jul 2017 18:40:16 -0000      1.155
> +++ kern/uipc_syscalls.c      24 Jul 2017 09:53:13 -0000
> @@ -373,18 +373,19 @@ sys_connect(struct proc *p, void *v, reg
>       if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
>               return (error);
>       so = fp->f_data;
> +     s = solock(so);
>       if (so->so_state & SS_ISCONNECTING) {
> -             FRELE(fp, p);
> -             return (EALREADY);
> +             error = EALREADY;
> +             goto out;
>       }
>       error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
>           MT_SONAME);
>       if (error)
> -             goto bad;
> +             goto out;
>       error = pledge_socket(p, so->so_proto->pr_domain->dom_family,
>           so->so_state);
>       if (error)
> -             goto bad;
> +             goto out;
>  #ifdef KTRACE
>       if (KTRPOINT(p, KTR_STRUCT))
>               ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
> @@ -393,11 +394,8 @@ sys_connect(struct proc *p, void *v, reg
>       if (isdnssocket(so)) {
>               u_int namelen = nam->m_len;
>               error = dns_portcheck(p, so, mtod(nam, void *), &namelen);
> -             if (error) {
> -                     FRELE(fp, p);
> -                     m_freem(nam);
> -                     return (error);
> -             }
> +             if (error)
> +                     goto out;
>               nam->m_len = namelen;
>       }
>  
> @@ -405,11 +403,9 @@ sys_connect(struct proc *p, void *v, reg
>       if (error)
>               goto bad;
>       if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
> -             FRELE(fp, p);
> -             m_freem(nam);
> -             return (EINPROGRESS);
> +             error = EINPROGRESS;
> +             goto out;
>       }
> -     s = solock(so);
>       while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
>               error = sosleep(so, &so->so_timeo, PSOCK | PCATCH,
>                   "netcon2", 0);
> @@ -423,10 +419,11 @@ sys_connect(struct proc *p, void *v, reg
>               error = so->so_error;
>               so->so_error = 0;
>       }
> -     sounlock(s);
>  bad:
>       if (!interrupted)
>               so->so_state &= ~SS_ISCONNECTING;
> +out:
> +     sounlock(s);
>       FRELE(fp, p);
>       m_freem(nam);
>       if (error == ERESTART)
> Index: miscfs/fifofs/fifo_vnops.c
> ===================================================================
> RCS file: /cvs/src/sys/miscfs/fifofs/fifo_vnops.c,v
> retrieving revision 1.57
> diff -u -p -r1.57 fifo_vnops.c
> --- miscfs/fifofs/fifo_vnops.c        8 Jul 2017 09:19:02 -0000       1.57
> +++ miscfs/fifofs/fifo_vnops.c        24 Jul 2017 09:54:45 -0000
> @@ -124,7 +124,7 @@ fifo_open(void *v)
>       struct fifoinfo *fip;
>       struct proc *p = ap->a_p;
>       struct socket *rso, *wso;
> -     int error;
> +     int s, error;
>  
>       if ((fip = vp->v_fifoinfo) == NULL) {
>               fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK);
> @@ -142,7 +142,14 @@ fifo_open(void *v)
>                       return (error);
>               }
>               fip->fi_writesock = wso;
> +             /*
> +              * XXXSMP
> +              * We only lock `wso' because AF_LOCAL sockets are
> +              * still relying on the KERNEL_LOCK().
> +              */
> +             s = solock(wso);
>               if ((error = soconnect2(wso, rso)) != 0) {
> +                     sounlock(s);
>                       (void)soclose(wso);
>                       (void)soclose(rso);
>                       free(fip, M_VNODE, sizeof *fip);
> @@ -152,11 +159,15 @@ fifo_open(void *v)
>               fip->fi_readers = fip->fi_writers = 0;
>               wso->so_state |= SS_CANTSENDMORE;
>               wso->so_snd.sb_lowat = PIPE_BUF;
> +     } else {
> +             rso = fip->fi_readsock;
> +             wso = fip->fi_writesock;
> +             s = solock(wso);
>       }
>       if (ap->a_mode & FREAD) {
>               fip->fi_readers++;
>               if (fip->fi_readers == 1) {
> -                     fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
> +                     wso->so_state &= ~SS_CANTSENDMORE;
>                       if (fip->fi_writers > 0)
>                               wakeup(&fip->fi_writers);
>               }
> @@ -165,14 +176,16 @@ fifo_open(void *v)
>               fip->fi_writers++;
>               if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
>                       error = ENXIO;
> +                     sounlock(s);
>                       goto bad;
>               }
>               if (fip->fi_writers == 1) {
> -                     fip->fi_readsock->so_state &= 
> ~(SS_CANTRCVMORE|SS_ISDISCONNECTED);
> +                     rso->so_state &= ~(SS_CANTRCVMORE|SS_ISDISCONNECTED);
>                       if (fip->fi_readers > 0)
>                               wakeup(&fip->fi_readers);
>               }
>       }
> +     sounlock(s);
>       if ((ap->a_mode & O_NONBLOCK) == 0) {
>               if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
>                       VOP_UNLOCK(vp, p);
> @@ -246,6 +259,7 @@ fifo_write(void *v)
>       if (ap->a_uio->uio_rw != UIO_WRITE)
>               panic("fifo_write mode");
>  #endif
> +     /* XXXSMP changing state w/o lock isn't safe. */
>       if (ap->a_ioflag & IO_NDELAY)
>               wso->so_state |= SS_NBIO;
>       VOP_UNLOCK(ap->a_vp, p);
> Index: nfs/nfs_socket.c
> ===================================================================
> RCS file: /cvs/src/sys/nfs/nfs_socket.c,v
> retrieving revision 1.119
> diff -u -p -r1.119 nfs_socket.c
> --- nfs/nfs_socket.c  27 Jun 2017 12:02:43 -0000      1.119
> +++ nfs/nfs_socket.c  24 Jul 2017 09:52:01 -0000
> @@ -297,16 +297,18 @@ nfs_connect(struct nfsmount *nmp, struct
>                       goto bad;
>               }
>       } else {
> +             s = solock(so);
>               error = soconnect(so, nmp->nm_nam);
> -             if (error)
> +             if (error) {
> +                     sounlock(s);
>                       goto bad;
> +             }
>  
>               /*
>                * Wait for the connection to complete. Cribbed from the
>                * connect system call but with the wait timing out so
>                * that interruptible mounts don't hang here for a long time.
>                */
> -             s = solock(so);
>               while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
>                       sosleep(so, &so->so_timeo, PSOCK, "nfscon", 2 * hz);
>                       if ((so->so_state & SS_ISCONNECTING) &&

Reply via email to