On 10/07/20(Fri) 14:07, Vitaliy Makkoveev wrote:
> We have some races in pppac(4)
> 1. malloc(9) can sleep so we must check `sc' presence after malloc(9)

Makes sense.

> 2. we can sleep between `sc' insertion to `sc_entry' list and 
> `sc_pipex_iface' initialization. Concurrent pppacioctl() can touch
> this incomplete `sc'.

Why not insert the descriptor at the end?  Shouldn't the order of
operations be:

        pipex_iface_init();
        if_attach();
        LIST_INSERT_HEAD()

This way there's no need for a `ready' flag since the descriptor is only
added to global data structures once it is completely initialized.

Using a `sc_ready' or `sc_dead' approach is something that require
touching all drivers whereas serializing insertions to global data
structures can be done at once for all the kernel.

> Index: sys/net/if_pppx.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pppx.c,v
> retrieving revision 1.91
> diff -u -p -r1.91 if_pppx.c
> --- sys/net/if_pppx.c 6 Jul 2020 20:37:51 -0000       1.91
> +++ sys/net/if_pppx.c 10 Jul 2020 11:04:53 -0000
> @@ -1019,7 +1019,7 @@ RBT_GENERATE(pppx_ifs, pppx_if, pxi_entr
>  
>  struct pppac_softc {
>       struct ifnet    sc_if;
> -     unsigned int    sc_dead;
> +     unsigned int    sc_ready;
>       dev_t           sc_dev;
>       LIST_ENTRY(pppac_softc)
>                       sc_entry;
> @@ -1072,8 +1072,12 @@ pppac_lookup(dev_t dev)
>       struct pppac_softc *sc;
>  
>       LIST_FOREACH(sc, &pppac_devs, sc_entry) {
> -             if (sc->sc_dev == dev)
> -                     return (sc);
> +             if (sc->sc_dev == dev) {
> +                     if (sc->sc_ready)
> +                             return (sc);
> +                     else
> +                             break;
> +             }
>       }
>  
>       return (NULL);
> @@ -1088,22 +1092,25 @@ pppacattach(int n)
>  int
>  pppacopen(dev_t dev, int flags, int mode, struct proc *p)
>  {
> -     struct pppac_softc *sc;
> +     struct pppac_softc *sc, *sc_tmp;
>       struct ifnet *ifp;
>  
> -     sc = pppac_lookup(dev);
> -     if (sc != NULL)
> -             return (EBUSY);
> -
>       sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
> +
> +     LIST_FOREACH(sc_tmp, &pppac_devs, sc_entry) {
> +             if (sc_tmp->sc_dev == dev) {
> +                     free(sc, M_DEVBUF, sizeof(*sc));
> +                     return (EBUSY);
> +             }
> +     }
> +
>       sc->sc_dev = dev;
> +     LIST_INSERT_HEAD(&pppac_devs, sc, sc_entry);
>  
>       mtx_init(&sc->sc_rsel_mtx, IPL_SOFTNET);
>       mtx_init(&sc->sc_wsel_mtx, IPL_SOFTNET);
>       mq_init(&sc->sc_mq, IFQ_MAXLEN, IPL_SOFTNET);
>  
> -     LIST_INSERT_HEAD(&pppac_devs, sc, sc_entry);
> -
>       ifp = &sc->sc_if;
>       snprintf(ifp->if_xname, sizeof(ifp->if_xname), "pppac%u", minor(dev));
>  
> @@ -1129,6 +1136,7 @@ pppacopen(dev_t dev, int flags, int mode
>  #endif
>  
>       pipex_iface_init(&sc->sc_pipex_iface, ifp);
> +     sc->sc_ready = 1;
>  
>       return (0);
>  }
> @@ -1136,12 +1144,14 @@ pppacopen(dev_t dev, int flags, int mode
>  int
>  pppacread(dev_t dev, struct uio *uio, int ioflag)
>  {
> -     struct pppac_softc *sc = pppac_lookup(dev);
> +     struct pppac_softc *sc;
>       struct ifnet *ifp = &sc->sc_if;
>       struct mbuf *m0, *m;
>       int error = 0;
>       size_t len;
>  
> +     if ((sc = pppac_lookup(dev)) == NULL)
> +             return (EBADF);
>       if (!ISSET(ifp->if_flags, IFF_RUNNING))
>               return (EHOSTDOWN);
>  
> @@ -1181,12 +1191,14 @@ pppacread(dev_t dev, struct uio *uio, in
>  int
>  pppacwrite(dev_t dev, struct uio *uio, int ioflag)
>  {
> -     struct pppac_softc *sc = pppac_lookup(dev);
> +     struct pppac_softc *sc;
>       struct ifnet *ifp = &sc->sc_if;
>       uint32_t proto;
>       int error;
>       struct mbuf *m;
>  
> +     if ((sc = pppac_lookup(dev)) == NULL)
> +             return (EBADF);
>       if (!ISSET(ifp->if_flags, IFF_RUNNING))
>               return (EHOSTDOWN);
>  
> @@ -1258,9 +1270,12 @@ pppacwrite(dev_t dev, struct uio *uio, i
>  int
>  pppacioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
>  {
> -     struct pppac_softc *sc = pppac_lookup(dev);
> +     struct pppac_softc *sc;
>       int error = 0;
>  
> +     if ((sc = pppac_lookup(dev)) == NULL)
> +             return (EBADF);
> +
>       switch (cmd) {
>       case TUNSIFMODE: /* make npppd happy */
>               break;
> @@ -1282,9 +1297,12 @@ pppacioctl(dev_t dev, u_long cmd, caddr_
>  int
>  pppacpoll(dev_t dev, int events, struct proc *p)
>  {
> -     struct pppac_softc *sc = pppac_lookup(dev);
> +     struct pppac_softc *sc;
>       int revents = 0;
>  
> +     if ((sc = pppac_lookup(dev)) == NULL)
> +             goto out;
> +
>       if (events & (POLLIN | POLLRDNORM)) {
>               if (!mq_empty(&sc->sc_mq))
>                       revents |= events & (POLLIN | POLLRDNORM);
> @@ -1296,17 +1314,20 @@ pppacpoll(dev_t dev, int events, struct 
>               if (events & (POLLIN | POLLRDNORM))
>                       selrecord(p, &sc->sc_rsel);
>       }
> -
> +out:
>       return (revents);
>  }
>  
>  int
>  pppackqfilter(dev_t dev, struct knote *kn)
>  {
> -     struct pppac_softc *sc = pppac_lookup(dev);
> +     struct pppac_softc *sc;
>       struct mutex *mtx;
>       struct klist *klist;
>  
> +     if ((sc = pppac_lookup(dev)) == NULL)
> +             return (EBADF);
> +
>       switch (kn->kn_filter) {
>       case EVFILT_READ:
>               mtx = &sc->sc_rsel_mtx;
> @@ -1373,12 +1394,15 @@ filt_pppac_write(struct knote *kn, long 
>  int
>  pppacclose(dev_t dev, int flags, int mode, struct proc *p)
>  {
> -     struct pppac_softc *sc = pppac_lookup(dev);
> +     struct pppac_softc *sc;
>       struct ifnet *ifp = &sc->sc_if;
>       int s;
>  
> +     if ((sc = pppac_lookup(dev)) == NULL)
> +             return (EBADF);
> +
> +     sc->sc_ready = 0;
>       NET_LOCK();
> -     sc->sc_dead = 1;
>       CLR(ifp->if_flags, IFF_RUNNING);
>       NET_UNLOCK();
>  
> @@ -1404,7 +1428,7 @@ pppac_ioctl(struct ifnet *ifp, u_long cm
>       /* struct ifreq *ifr = (struct ifreq *)data; */
>       int error = 0;
>  
> -     if (sc->sc_dead)
> +     if (sc->sc_ready == 0)
>               return (ENXIO);
>  
>       switch (cmd) {
> 

Reply via email to