DF-2807 / udev_short.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 | /* DF-2807: short-buffer read() on /dev/udev silently drops the event * and reports ENOMEM. * * Run as root. Open /dev/udev, generate two distinctive events: * e1 = vn0 CREATE (vnconfig -c vn0 on a blank image) * e2 = h41 CREATE (h41 module make_dev via debug.h41.cmd=4) * then read(fd, 1 byte): * expect (vulnerable): -1 ENOMEM, e1 consumed silently; follow-up big * read returns e2 (h41) first -> e1 (vn0) lost forever. * expect (patched): -1 EMSGSIZE, e1 NOT consumed; follow-up big read * returns e1 (vn0) first. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> static void dump_event(const char *tag, const char *buf, int rv) { int i; printf("DF2807 %-22s rv=%d errno=%d\n", tag, rv, errno); if (rv <= 0) return; printf("DF2807 %-22s event: ", ""); for (i = 0; i < rv; i++) putchar((buf[i] >= 32 && buf[i] < 127) ? buf[i] : '.'); putchar('\n'); } static int has(const char *xml, const char *key) { return strstr(xml, key) != NULL; } int main(void) { static char big[65536]; int fd, rv; char one; system("dd if=/dev/zero of=/tmp/df2807.img bs=1m count=2 2>/dev/null"); fd = open("/dev/udev", O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("open /dev/udev"); return 1; } printf("DF2807 opened /dev/udev fd=%d\n", fd); /* initiate the reader: first read arms the marker (kern_udev.c:826) */ { char c; errno = 0; rv = read(fd, &c, 1); printf("DF2807 initiation read rv=%d errno=%d (35/EAGAIN expected)\n", rv, errno); } /* e1: vn0 attach */ system("vnconfig -c vn0 /tmp/df2807.img 2>/dev/null"); /* e2: h41 create */ system("sysctl -w debug.h41.cmd=4 >/dev/null 2>&1"); sleep(1); one = 0; errno = 0; rv = read(fd, &one, 1); dump_event("short read(1B)", &one, rv); errno = 0; rv = read(fd, big, sizeof(big)); dump_event("full read #1", big, rv); if (rv > 0) { char *nm = strstr(big, "<key>name</key>"); char namev[64] = "?"; if (nm) { char *s1 = strstr(nm, "<string>"); char *e1; if (s1) { s1 += 8; e1 = strstr(s1, "</string>"); if (e1 && e1 - s1 < 63) { memcpy(namev, s1, e1 - s1); namev[e1 - s1] = 0; } } } printf("DF2807 first surviving event name=\"%s\" " "(vn0 = e1 kept -> patched; anything else -> e1 DROPPED)\n", namev); } /* drain one more to show what remains */ errno = 0; rv = read(fd, big, sizeof(big)); dump_event("full read #2", big, rv); system("vnconfig -u vn0 2>/dev/null"); return 0; } |