DF-3526 / iface_con.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | /* * DF-3526 / DF-3527 trigger -- create the first netgraph7 "iface" node. * * DF-3526: ng_iface_get_unit() (sys/netgraph7/iface/ng_iface.c:292-303) * passes the initially-NULL ng_iface_units to bcopy(); systm.h maps * bcopy onto __builtin_memmove and documents that GCC may then assume * the operand non-NULL and delete the later NULL test at :300, so the * first node creation calls kfree(NULL) -> "panic: trying to free * NULL pointer" (twin of the v1 DF-3485, same code, ng7 module). * * DF-3527: with the bcopy guard restored, creation proceeds to * if_attach(ifp, NULL) at ng_iface.c:624 from the ng7 control-message * (netisr) context -> ifnet-lock assert panic * (twin of the v1 DF-3486). * * modes: * create : mkpeer iface -> GET_IFNAME -> NGM_SHUTDOWN (full lifecycle) * unpriv : same, run as an unprivileged uid (expect EPERM on the * control socket: ng7 ngc_attach has caps_priv_check) * * Build: cc -O2 -o iface_con iface_con.c * Run: ./iface_con create */ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> /* ---- ng7 netgraph user ABI ---- */ #define AF_NG 32 #define NG_CONTROL 2 #define NG_VERSION 8 #define NGM_GENERIC_COOKIE 1137070366 #define NGM_SHUTDOWN 1 #define NGM_MKPEER 2 #define NGM_NODEINFO (6 | 0x10000000 | 0x20000000) #define NG_TYPESIZ 32 #define NG_HOOKSIZ 32 #define NG_NODESIZ 32 struct ngm_hdr_ { u_char version; u_char spare; u_short spare2; u_int arglen, cmd, flags, token, typecookie; char cmdstr[32]; }; struct ng_mesg_ { struct ngm_hdr_ header; char data[1024]; }; struct ngm_mkpeer_ { char type[NG_TYPESIZ]; char ourhook[NG_HOOKSIZ]; char peerhook[NG_HOOKSIZ]; }; struct nodeinfo_ { char name[NG_NODESIZ]; char type[NG_TYPESIZ]; u_int32_t id; u_int32_t hooks; }; struct sockaddr_ng_ { u_char sg_len; sa_family_t sg_family; char sg_data[64]; }; /* ---- ng_iface ABI ---- */ #define NGM_IFACE_COOKIE 1108312559 #define NGM_IFACE_GET_IFNAME 1 static u_int32_t tok = 0x2100; static int ng_send_msg2(int cs, const char *path, u_int cookie, u_int cmd, const void *arg, size_t arglen, struct ng_mesg_ *reply) { struct ng_mesg_ m; struct sockaddr_ng_ sa; ssize_t n; memset(&m, 0, sizeof(m)); m.header.version = NG_VERSION; m.header.arglen = arglen; m.header.cmd = cmd; m.header.token = ++tok; m.header.typecookie = cookie; if (arglen) memcpy(m.data, arg, arglen); memset(&sa, 0, sizeof(sa)); sa.sg_family = AF_NG; snprintf(sa.sg_data, sizeof(sa.sg_data), "%s", path); sa.sg_len = 2 + strlen(sa.sg_data) + 1; n = sendto(cs, &m, sizeof(m.header) + arglen, 0, (struct sockaddr *)&sa, sa.sg_len); if (n < 0) return (-1); if (reply) { u_int32_t mytok = m.header.token; int tries; for (tries = 0; tries < 64; tries++) { n = recv(cs, reply, sizeof(*reply), 0); if (n < 0) return (-1); if (reply->header.token != mytok) continue; if (reply->header.flags & 1 /* NGF_RESP */) { if (reply->header.arglen == 4) return (-((int)*(u_int32_t *)reply->data ? (int)*(u_int32_t *)reply->data : EIO)); return (0); } } return (-1); } return (0); } static int ng_send_msg(int cs, const char *path, u_int cmd, const void *arg, size_t arglen, struct ng_mesg_ *reply) { return (ng_send_msg2(cs, path, NGM_GENERIC_COOKIE, cmd, arg, arglen, reply)); } int main(int argc, char **argv) { struct ngm_mkpeer_ mkp; static struct ng_mesg_ reply; int cs; const char *mode = (argc > 1) ? argv[1] : "create"; printf("iface_con: uid=%d euid=%d mode=%s\n", getuid(), geteuid(), mode); fflush(stdout); cs = socket(AF_NG, SOCK_DGRAM, NG_CONTROL); if (cs < 0) { printf("RESULT control-socket errno=%d (%s)\n", errno, strerror(errno)); if (errno == EPERM) { printf("RESULT unpriv-gated: ng7 ngc_attach " "caps_priv_check -> EPERM (root-only trigger)\n"); exit(0); } exit(1); } printf("STEP control-socket ok\n"); fflush(stdout); /* DF-3526 / DF-3527 trigger: constructor runs HERE */ memset(&mkp, 0, sizeof(mkp)); strcpy(mkp.type, "iface"); strcpy(mkp.ourhook, "inet"); strcpy(mkp.peerhook, "inet"); if (ng_send_msg(cs, ".", NGM_MKPEER, &mkp, sizeof(mkp), NULL) < 0) { printf("RESULT mkpeer failed errno=%d (%s)\n", errno, strerror(errno)); exit(1); } printf("STEP mkpeer iface survived (no panic)\n"); fflush(stdout); if (ng_send_msg2(cs, "inet", NGM_IFACE_COOKIE, NGM_IFACE_GET_IFNAME, NULL, 0, &reply) < 0) printf("STEP get_ifname failed errno=%d\n", errno); else printf("STEP ifname=%s\n", reply.data); fflush(stdout); if (ng_send_msg(cs, "inet", NGM_SHUTDOWN, NULL, 0, NULL) < 0) printf("STEP shutdown failed errno=%d\n", errno); else printf("STEP shutdown ok\n"); fflush(stdout); printf("RESULT lifecycle-complete exit=0\n"); return (0); } |