I'd like to protect bridge(4) data structures with a mutex.  Using a
mutex is necessary because bridge_output() is called from interrupt
handlers in wireless drivers.  This forces us to decouple data gathering
from copying to userland when executing some ioctl(2)s.  Diff below does
that by moving the copyout(9)s outside of the loops.

Ok?

Index: net/bridgectl.c
===================================================================
RCS file: /cvs/src/sys/net/bridgectl.c,v
retrieving revision 1.11
diff -u -p -r1.11 bridgectl.c
--- net/bridgectl.c     26 Oct 2018 14:55:27 -0000      1.11
+++ net/bridgectl.c     8 Nov 2018 18:17:37 -0000
@@ -470,40 +470,48 @@ bridge_rtdelete(struct bridge_softc *sc,
 int
 bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
 {
-       int i, error = 0, onlycnt = 0;
-       u_int32_t cnt = 0;
+       struct ifbareq *bareq, *bareqs = NULL;
        struct bridge_rtnode *n;
-       struct ifbareq bareq;
+       u_int32_t i = 0, total = 0;
+       int k, error = 0;
 
-       if (baconf->ifbac_len == 0)
-               onlycnt = 1;
+       for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) {
+               LIST_FOREACH(n, &sc->sc_rts[k], brt_next)
+                       total++;
+       }
 
-       for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
-               LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
-                       if (!onlycnt) {
-                               if (baconf->ifbac_len < sizeof(struct ifbareq))
-                                       goto done;
-                               bcopy(sc->sc_if.if_xname, bareq.ifba_name,
-                                   sizeof(bareq.ifba_name));
-                               bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
-                                   sizeof(bareq.ifba_ifsname));
-                               bcopy(&n->brt_addr, &bareq.ifba_dst,
-                                   sizeof(bareq.ifba_dst));
-                               bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
-                                   sstosa(&bareq.ifba_dstsa));
-                               bareq.ifba_age = n->brt_age;
-                               bareq.ifba_flags = n->brt_flags;
-                               error = copyout((caddr_t)&bareq,
-                                   (caddr_t)(baconf->ifbac_req + cnt), 
sizeof(bareq));
-                               if (error)
-                                       goto done;
-                               baconf->ifbac_len -= sizeof(struct ifbareq);
-                       }
-                       cnt++;
+       if (baconf->ifbac_len == 0) {
+               i = total;
+               goto done;
+       }
+
+       bareqs = mallocarray(total, sizeof(*bareqs), M_TEMP, M_WAITOK|M_ZERO);
+       if (bareqs == NULL)
+               goto done;
+
+       for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) {
+               LIST_FOREACH(n, &sc->sc_rts[k], brt_next) {
+                       if (baconf->ifbac_len < (i + 1) * sizeof(*bareqs))
+                               goto done;
+                       bareq = &bareqs[i];
+                       bcopy(sc->sc_if.if_xname, bareq->ifba_name,
+                           sizeof(bareq->ifba_name));
+                       bcopy(n->brt_if->if_xname, bareq->ifba_ifsname,
+                           sizeof(bareq->ifba_ifsname));
+                       bcopy(&n->brt_addr, &bareq->ifba_dst,
+                           sizeof(bareq->ifba_dst));
+                       bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
+                           sstosa(&bareq->ifba_dstsa));
+                       bareq->ifba_age = n->brt_age;
+                       bareq->ifba_flags = n->brt_flags;
+                       i++;
                }
        }
+
+       error = copyout(bareqs, baconf->ifbac_req, i * sizeof(*bareqs));
 done:
-       baconf->ifbac_len = cnt * sizeof(struct ifbareq);
+       free(bareqs, M_TEMP, total * sizeof(*bareqs));
+       baconf->ifbac_len = i * sizeof(struct ifbareq);
        return (error);
 }
 
@@ -550,7 +558,7 @@ bridge_brlconf(struct bridge_iflist *bif
 {
        struct bridge_softc *sc = bif->bridge_sc;
        struct brl_node *n;
-       struct ifbrlreq req;
+       struct ifbrlreq *req, *reqs = NULL;
        int error = 0;
        u_int32_t i = 0, total = 0;
 
@@ -566,56 +574,52 @@ bridge_brlconf(struct bridge_iflist *bif
                goto done;
        }
 
+       reqs = mallocarray(total, sizeof(*reqs), M_TEMP, M_WAITOK|M_ZERO);
+       if (reqs == NULL)
+               goto done;
+
        SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) {
-               bzero(&req, sizeof req);
-               if (bc->ifbrl_len < sizeof(req))
+               if (bc->ifbrl_len < (i + 1) * sizeof(*reqs))
                        goto done;
-               strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
-               strlcpy(req.ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ);
-               req.ifbr_action = n->brl_action;
-               req.ifbr_flags = n->brl_flags;
-               req.ifbr_src = n->brl_src;
-               req.ifbr_dst = n->brl_dst;
-               req.ifbr_arpf = n->brl_arpf;
+               req = &reqs[i];
+               strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
+               strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ);
+               req->ifbr_action = n->brl_action;
+               req->ifbr_flags = n->brl_flags;
+               req->ifbr_src = n->brl_src;
+               req->ifbr_dst = n->brl_dst;
+               req->ifbr_arpf = n->brl_arpf;
 #if NPF > 0
-               req.ifbr_tagname[0] = '\0';
+               req->ifbr_tagname[0] = '\0';
                if (n->brl_tag)
-                       pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
+                       pf_tag2tagname(n->brl_tag, req->ifbr_tagname);
 #endif
-               error = copyout((caddr_t)&req,
-                   (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
-               if (error)
-                       goto done;
                i++;
-               bc->ifbrl_len -= sizeof(req);
        }
 
        SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) {
-               bzero(&req, sizeof req);
-               if (bc->ifbrl_len < sizeof(req))
+               if (bc->ifbrl_len < (i + 1) * sizeof(*reqs))
                        goto done;
-               strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
-               strlcpy(req.ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ);
-               req.ifbr_action = n->brl_action;
-               req.ifbr_flags = n->brl_flags;
-               req.ifbr_src = n->brl_src;
-               req.ifbr_dst = n->brl_dst;
-               req.ifbr_arpf = n->brl_arpf;
+               req = &reqs[i];
+               strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
+               strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ);
+               req->ifbr_action = n->brl_action;
+               req->ifbr_flags = n->brl_flags;
+               req->ifbr_src = n->brl_src;
+               req->ifbr_dst = n->brl_dst;
+               req->ifbr_arpf = n->brl_arpf;
 #if NPF > 0
-               req.ifbr_tagname[0] = '\0';
+               req->ifbr_tagname[0] = '\0';
                if (n->brl_tag)
-                       pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
+                       pf_tag2tagname(n->brl_tag, req->ifbr_tagname);
 #endif
-               error = copyout((caddr_t)&req,
-                   (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
-               if (error)
-                       goto done;
                i++;
-               bc->ifbrl_len -= sizeof(req);
        }
 
+       error = copyout(reqs, bc->ifbrl_buf, i * sizeof(*reqs));
 done:
-       bc->ifbrl_len = i * sizeof(req);
+       free(reqs, M_TEMP, total * sizeof(*reqs));
+       bc->ifbrl_len = i * sizeof(*reqs);
        return (error);
 }
 
Index: net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.312
diff -u -p -r1.312 if_bridge.c
--- net/if_bridge.c     1 Oct 2018 12:38:32 -0000       1.312
+++ net/if_bridge.c     8 Nov 2018 18:16:44 -0000
@@ -594,7 +594,7 @@ bridge_bifconf(struct bridge_softc *sc, 
        struct bstp_state *bs = sc->sc_stp;
        u_int32_t total = 0, i = 0;
        int error = 0;
-       struct ifbreq *breq = NULL;
+       struct ifbreq *breq, *breqs = NULL;
 
        TAILQ_FOREACH(bif, &sc->sc_iflist, next)
                total++;
@@ -605,16 +605,17 @@ bridge_bifconf(struct bridge_softc *sc, 
        if (bifc->ifbic_len == 0) {
                i = total;
                goto done;
+
        }
 
-       if ((breq = (struct ifbreq *)
-           malloc(sizeof(*breq), M_DEVBUF, M_NOWAIT)) == NULL)
+       breqs = mallocarray(total, sizeof(*breqs), M_TEMP, M_WAITOK|M_ZERO);
+       if (breqs == NULL)
                goto done;
 
        TAILQ_FOREACH(bif, &sc->sc_iflist, next) {
-               bzero(breq, sizeof(*breq));
-               if (bifc->ifbic_len < sizeof(*breq))
+               if (bifc->ifbic_len < (i + 1) * sizeof(*breqs))
                        break;
+               breq = &breqs[i];
                strlcpy(breq->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
                strlcpy(breq->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ);
                breq->ifbr_ifsflags = bif->bif_flags;
@@ -645,32 +646,22 @@ bridge_bifconf(struct bridge_softc *sc, 
                        if (bp->bp_flags & BSTP_PORT_AUTOPTP)
                                breq->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP;
                }
-               error = copyout((caddr_t)breq,
-                   (caddr_t)(bifc->ifbic_req + i), sizeof(*breq));
-               if (error)
-                       goto done;
                i++;
-               bifc->ifbic_len -= sizeof(*breq);
        }
        TAILQ_FOREACH(bif, &sc->sc_spanlist, next) {
-               bzero(breq, sizeof(*breq));
-               if (bifc->ifbic_len < sizeof(*breq))
+               if (bifc->ifbic_len < (i + 1) * sizeof(*breqs))
                        break;
+               breq = &breqs[i];
                strlcpy(breq->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
                strlcpy(breq->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ);
                breq->ifbr_ifsflags = bif->bif_flags | IFBIF_SPAN;
                breq->ifbr_portno = bif->ifp->if_index & 0xfff;
-               error = copyout((caddr_t)breq,
-                   (caddr_t)(bifc->ifbic_req + i), sizeof(*breq));
-               if (error)
-                       goto done;
                i++;
-               bifc->ifbic_len -= sizeof(*breq);
        }
 
+       error = copyout(breqs, bifc->ifbic_req, i * sizeof(*breqs));
 done:
-       if (breq != NULL)
-               free(breq, M_DEVBUF, sizeof *breq);
+       free(breqs, M_TEMP, total * sizeof(*breq));
        bifc->ifbic_len = i * sizeof(*breq);
        return (error);
 }

Reply via email to