DF-4893 / fix.diff
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 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | --- a/sys/dev/netif/ath/ath_hal/ah_osdep.c +++ b/sys/dev/netif/ath/ath_hal/ah_osdep.c @@ -185,184 +185,20 @@ #undef HAL_DEBUG_UNMASKABLE #endif /* AH_DEBUG */ -#ifdef AH_DEBUG_ALQ -/* - * ALQ register tracing support. - * - * Setting hw.ath.hal.alq=1 enables tracing of all register reads and - * writes to the file /tmp/ath_hal.log. The file format is a simple - * fixed-size array of records. When done logging set hw.ath.hal.alq=0 - * and then decode the file with the arcode program (that is part of the - * HAL). If you start+stop tracing the data will be appended to an - * existing file. +/* DF-4893: the AH_DEBUG_ALQ block (ALQ register tracing) was removed. * - * NB: doesn't handle multiple devices properly; only one DEVICE record - * is emitted and the different devices are not identified. - */ -/*#include <sys/alq.h> FreeBSD */ -/*#include <sys/pcpu.h> FreeBSD */ -#include <dev/netif/ath/ath_hal/ah_decode.h> - -static struct alq *ath_hal_alq; -static int ath_hal_alq_emitdev; /* need to emit DEVICE record */ -static u_int ath_hal_alq_lost; /* count of lost records */ -static char ath_hal_logfile[MAXPATHLEN] = "/tmp/ath_hal.log"; - -SYSCTL_STRING(_hw_ath_hal, OID_AUTO, alq_logfile, CTLFLAG_RW, - &ath_hal_logfile, sizeof(kernelname), "Name of ALQ logfile"); - -static u_int ath_hal_alq_qsize = 64*1024; - -static int -ath_hal_setlogging(int enable) -{ - int error; - - if (enable) { - error = alq_open(&ath_hal_alq, ath_hal_logfile, - curthread->td_ucred, ALQ_DEFAULT_CMODE, - sizeof (struct athregrec), ath_hal_alq_qsize); - ath_hal_alq_lost = 0; - ath_hal_alq_emitdev = 1; - kprintf("ath_hal: logging to %s enabled\n", - ath_hal_logfile); - } else { - if (ath_hal_alq) - alq_close(ath_hal_alq); - ath_hal_alq = NULL; - kprintf("ath_hal: logging disabled\n"); - error = 0; - } - return (error); -} - -static int -sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS) -{ - int error, enable; - - enable = (ath_hal_alq != NULL); - error = sysctl_handle_int(oidp, &enable, 0, req); - if (error || !req->newptr) - return (error); - else - return (ath_hal_setlogging(enable)); -} -SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW, - 0, 0, sysctl_hw_ath_hal_log, "I", "Enable HAL register logging"); -SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW, - &ath_hal_alq_qsize, 0, "In-memory log size (#records)"); -SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW, - &ath_hal_alq_lost, 0, "Register operations not logged"); - -static struct ale * -ath_hal_alq_get(struct ath_hal *ah) -{ - struct ale *ale; - - if (ath_hal_alq_emitdev) { - ale = alq_get(ath_hal_alq, ALQ_NOWAIT); - if (ale) { - struct athregrec *r = - (struct athregrec *) ale->ae_data; - r->op = OP_DEVICE; - r->reg = 0; - r->val = ah->ah_devid; - alq_post(ath_hal_alq, ale); - ath_hal_alq_emitdev = 0; - } else - ath_hal_alq_lost++; - } - ale = alq_get(ath_hal_alq, ALQ_NOWAIT); - if (!ale) - ath_hal_alq_lost++; - return ale; -} - -void -ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) -{ - bus_space_tag_t tag = BUSTAG(ah); - bus_space_handle_t h = ah->ah_sh; - -#ifdef AH_DEBUG - /* Debug - complain if we haven't fully waken things up */ - if (! ath_hal_reg_whilst_asleep(ah, reg) && - ah->ah_powerMode != HAL_PM_AWAKE) { - ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n", - __func__, reg, val, ah->ah_powerMode); - } -#endif - - if (ath_hal_alq) { - struct ale *ale = ath_hal_alq_get(ah); - if (ale) { - struct athregrec *r = (struct athregrec *) ale->ae_data; - r->threadid = curthread->td_tid; - r->op = OP_WRITE; - r->reg = reg; - r->val = val; - alq_post(ath_hal_alq, ale); - } - } - if (ah->ah_config.ah_serialise_reg_war) - lockmgr(&ah_regser_mtx, LK_EXCLUSIVE); - bus_space_write_4(tag, h, reg, val); - OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_WRITE); - if (ah->ah_config.ah_serialise_reg_war) - lockmgr(&ah_regser_mtx, LK_RELEASE); -} - -u_int32_t -ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) -{ - bus_space_tag_t tag = BUSTAG(ah); - bus_space_handle_t h = ah->ah_sh; - u_int32_t val; - - /* Debug - complain if we haven't fully waken things up */ - if (! ath_hal_reg_whilst_asleep(ah, reg) && - ah->ah_powerMode != HAL_PM_AWAKE) { - ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n", - __func__, reg, ah->ah_powerMode); - } - - if (ah->ah_config.ah_serialise_reg_war) - lockmgr(&ah_regser_mtx, LK_EXCLUSIVE); - OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_READ); - val = bus_space_read_4(tag, h, reg); - if (ah->ah_config.ah_serialise_reg_war) - lockmgr(&ah_regser_mtx, LK_RELEASE); - if (ath_hal_alq) { - struct ale *ale = ath_hal_alq_get(ah); - if (ale) { - struct athregrec *r = (struct athregrec *) ale->ae_data; - r->threadid = curthread->td_tid; - r->op = OP_READ; - r->reg = reg; - r->val = val; - alq_post(ath_hal_alq, ale); - } - } - return val; -} - -void -OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v) -{ - if (ath_hal_alq) { - struct ale *ale = ath_hal_alq_get(ah); - if (ale) { - struct athregrec *r = (struct athregrec *) ale->ae_data; - r->threadid = curthread->td_tid; - r->op = OP_MARK; - r->reg = id; - r->val = v; - alq_post(ath_hal_alq, ale); - } - } -} -#else /* AH_DEBUG_ALQ */ + * It was inherited FreeBSD glue that can never compile on DragonFly: + * - the AH_DEBUG_ALQ option mapping is commented out (sys/conf/options); + * - no alq(9) implementation or <sys/alq.h> exists in this tree + * (the include was commented out here); + * - its ath_hal_reg_read() called ath_hal_reg_whilst_asleep(), which is + * only defined under AH_DEBUG. + * The block also carried a TOCTOU: consumers checked the unlocked global + * `ath_hal_alq` (NULL test) and then passed it to alq_get()/alq_post() + * while the sysctl disable path ran alq_close() + NULL-store on it -- a + * use-after-free if the block is ever revived without locking. If alq(9) + * is imported later, re-add the block with the global protected by a mutex + * on BOTH the consumer and the sysctl closer paths. */ /* * Memory-mapped device register read/write. These are here @@ -422,7 +258,6 @@ lockmgr(&ah_regser_mtx, LK_RELEASE); return val; } -#endif /* AH_DEBUG_ALQ */ #ifdef AH_ASSERT void |