DF-3347 / df3347.c
/* * DF-3347 harness -- lagg_lacp_attach ignores lacp_port_create failure * (if_lagg.c:2081-2082): * * SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) * lacp_port_create(lp); <-- return value dropped * * A failing lacp_port_create (if_addmulti failure or its * kmalloc(M_NOWAIT)) leaves ports in sc_ports with lp_psc == NULL; * every later LACP operation that walks sc_ports and derefs * LACP_PORT(lp) NULL-derefs. Fault-injection harness. */ #include "guard.h" #include <stdio.h> #include <string.h> #include <stdlib.h> struct lagg_port { const char *ifname; void *lp_psc; }; struct lacp_port { int marker; }; static int create_fail; /* fault knob */ /* verbatim lacp_port_create shape (lacp.c:530-565) */ static int lacp_port_create(struct lagg_port *lp) { void *p; if (create_fail) /* if_addmulti/kmalloc failure */ return 12; /* ENOMEM */ p = calloc(1, sizeof(struct lacp_port)); ((struct lacp_port *)p)->marker = 1; lp->lp_psc = p; return 0; } /* verbatim lagg_lacp_attach loop (if_lagg.c:2081-2082) */ static void lagg_lacp_attach(struct lagg_port *ports, int n) { int i; for (i = 0; i < n; i++) lacp_port_create(&ports[i]); /* failure IGNORED */ } /* later LACP operation walking sc_ports (e.g. lacp_linkstate / tick) */ static void lacp_tick(struct lagg_port *ports, int n) { int i; for (i = 0; i < n; i++) ((struct lacp_port *)ports[i].lp_psc)->marker++; /* deref */ } static struct lagg_port ports[2]; static struct lagg_port ports[2]; int main(int argc, char **argv) { int poison = (argc > 1 && argv[1][0] == 'p'); printf("DF-3347 (lacp_port_create failure ignored, if_lagg.c:2081)\n"); memset(ports, 0, sizeof(ports)); ports[0].ifname = "tap0"; ports[1].ifname = "tap1"; create_fail = 0; lacp_port_create(&ports[0]); /* port 1 ok */ create_fail = poison; lacp_port_create(&ports[1]); /* port 2 fails, IGNORED */ printf(" port1 lp_psc=%p port2 lp_psc=%p (failure silently ignored)\n", ports[0].lp_psc, ports[1].lp_psc); if (!poison) { create_fail = 0; lacp_port_create(&ports[1]); lacp_tick(ports, 2); printf(" control: both ports attached, tick ok\n"); return 0; } printf(" later LACP op derefs NULL lp_psc:\n"); fflush(stdout); #ifdef FIXED /* DF-3347 fix: abort the attach loop on the first failure */ { int bad = 0, k; for (k = 0; k < 2; k++) if (ports[k].lp_psc == NULL) bad++; if (bad) { printf("FIXED: %d port(s) unattached, LACP ops" " suspended\n", bad); return 0; } } #endif lacp_tick(ports, 2); /* NULL deref -> SEGV */ printf(" ran?!\n"); return 0; } |