DF-2366 / rc4_keylen0.c
/* DF-2366: rc4_init (sys/crypto/rc4/rc4.c:58-77) lacks a keylen>0 guard. * The key-schedule loop is * * for (j = i = k = 0; i < 256; i++) { * j += state->perm[i] + key[k]; <-- reads key[0] ... * swap_bytes(&state->perm[i], &state->perm[j]); * if (++k >= keylen) <-- keylen<=0: k stays 0 * k = 0; * } * * so a non-positive keylen reads key[0] (and only key[0]) 256 times; if the * caller passed a zero-length key buffer, key[0] is out of bounds. * * This is a userland replica of the exact loop (no kernel headers needed) * with key[] placed at the very end of a page followed by a PROT_NONE page, * so the OOB read of key[0] faults deterministically. In the kernel the * same instruction reads one byte past the caller-supplied buffer. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/mman.h> struct rc4_state { u_char perm[256]; int index1, index2; }; static __inline void swap_bytes(u_char *a, u_char *b){ u_char t=*a; *a=*b; *b=t; } /* verbatim port of rc4_init loop with the guard REMOVED (as shipped) */ static void rc4_init_buggy(struct rc4_state *const state, const u_char *key, int keylen) { u_char j; int i, k; for (i = 0; i < 256; i++) state->perm[i] = (u_char)i; state->index1 = 0; state->index2 = 0; for (j = i = k = 0; i < 256; i++) { j += state->perm[i] + key[k]; /* <-- key[0] read */ swap_bytes(&state->perm[i], &state->perm[j]); if (++k >= keylen) k = 0; /* keylen<=0: k=0 */ } } int main(void) { struct rc4_state st; u_char *pageend; pageend = mmap(NULL, 2*4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (pageend == MAP_FAILED) { perror("mmap"); return 1; } if (mprotect(pageend + 4096, 4096, PROT_NONE) != 0) { perror("mprotect"); return 1; } printf("[*] zero-length key buffer modeled by a pointer whose first byte\n" " (key[0]) lies in a PROT_NONE guard page\n"); printf("[*] calling buggy rc4_init(state, key, keylen=0)...\n"); fflush(stdout); rc4_init_buggy(&st, pageend + 4096, 0); /* zero-length key: key[0] lands in the guard page */ printf("[-] returned without reading key[0]?? not reproduced\n"); return 1; } |