Fix etheriq()'s extra-data problems
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 21 Sep 2016 19:10:52 +0000 (15:10 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 21 Sep 2016 21:27:46 +0000 (17:27 -0400)
Or at least try to fix them.  The old code was clearly broken if you passed
in a block with extra data during tracing or any other snooping (including
virtio-net).

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/dev/ether.c

index 4f8e7b7..90a7d61 100644 (file)
@@ -306,7 +306,7 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
 {
        struct etherpkt *pkt;
        uint16_t type;
-       int len, multi, tome, fromme, vlanid, i;
+       int multi, tome, fromme, vlanid, i;
        struct netfile **ep, *f, **fp, *fx;
        struct block *xbp;
        struct ether *vlan;
@@ -314,7 +314,9 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
        ether->inpackets++;
 
        pkt = (struct etherpkt *)bp->rp;
-       len = BLEN(bp);
+       /* TODO: we might need to assert more for higher layers, or otherwise deal
+        * with extra data. */
+       assert(BHLEN(bp) >= offsetof(struct etherpkt, data));
        type = (pkt->type[0] << 8) | pkt->type[1];
        if (type == Type8021Q && ether->nvlan) {
                vlanid = nhgets(bp->rp + 2 * Eaddrlen + 2) & 0xFFF;
@@ -322,6 +324,8 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
                        for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
                                vlan = ether->vlans[i];
                                if (vlan != NULL && vlan->vlanid == vlanid) {
+                                       /* might have a problem with extra data here */
+                                       assert(BHLEN(bp) >= 4 + 2 * Eaddrlen);
                                        memmove(bp->rp + 4, bp->rp, 2 * Eaddrlen);
                                        bp->rp += 4;
                                        return etheriq(vlan, bp, fromwire);
@@ -364,20 +368,18 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
                                if (f->bridge && !fromwire && !fromme)
                                        continue;
                                if (f->headersonly) {
-                                       etherrtrace(f, pkt, len);
+                                       etherrtrace(f, pkt, BHLEN(bp));
                                        continue;
                                }
                                if (fromwire && fx == 0) {
                                        fx = f;
                                        continue;
                                }
-                               xbp = block_alloc(len, MEM_ATOMIC);
+                               xbp = copyblock(bp, MEM_ATOMIC);
                                if (xbp == 0) {
                                        ether->soverflows++;
                                        continue;
                                }
-                               memmove(xbp->wp, pkt, len);
-                               xbp->wp += len;
                                if (qpass(f->in, xbp) < 0)
                                        ether->soverflows++;
                        }