DF-4158 / vgafuzz.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 | /* * DF-4158 supporting evidence: hostile-input exerciser for the vga.c ioctl * surface reachable through syscons (/dev/ttyvN) and (when compiled with * FB_INSTALL_CDEV) /dev/vgaN. * * Not a crasher: it asserts that every user-fed scalar (mode number, display * start, line width, palette index/count) is rejected or clamped by the * kernel instead of being used as an index/length. * * build: cc -O -o vgafuzz vgafuzz.c * run: ./vgafuzz /dev/ttyv0 */ #include <sys/ioctl.h> #include <sys/fbio.h> #include <fcntl.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> static int fd; static int fails; static void expect_reject(const char *what, unsigned long cmd, void *arg) { int rv = ioctl(fd, cmd, arg); if (rv == 0) { printf("FAIL %-38s : accepted (rv=0) -- needs review\n", what); fails++; } else { printf("ok %-38s : rejected (%s)\n", what, strerror(errno)); } } int main(int argc, char **argv) { const char *dev = argc > 1 ? argv[1] : "/dev/ttyv0"; int i, mode; video_display_start_t start; video_color_palette_t pal; struct fbcmap cmap; video_info_t vinfo; unsigned char palbuf[768]; fd = open(dev, O_RDWR); if (fd < 0) { printf("open %s: %s\n", dev, strerror(errno)); return (1); } printf("opened %s\n", dev); /* --- (a) user-fed mode number as table index ------------------- */ int modes[] = {INT_MIN, -1, -100, 29, 64, 256, 65535, 0x40000000, INT_MAX}; for (i = 0; i < (int)(sizeof(modes) / sizeof(modes[0])); i++) { mode = modes[i]; char buf[64]; snprintf(buf, sizeof(buf), "FBIO_SETMODE mode=%d", mode); expect_reject(buf, FBIO_SETMODE, &mode); } /* MODEINFO with hostile vi_mode (fb.c passes it as get_info index) */ memset(&vinfo, 0, sizeof(vinfo)); vinfo.vi_mode = INT_MAX; expect_reject("FBIO_MODEINFO vi_mode=INT_MAX", FBIO_MODEINFO, &vinfo); vinfo.vi_mode = -1; expect_reject("FBIO_MODEINFO vi_mode=-1", FBIO_MODEINFO, &vinfo); vinfo.vi_mode = 29; expect_reject("FBIO_MODEINFO vi_mode=29", FBIO_MODEINFO, &vinfo); /* sanity: current mode must be reported fine */ if (ioctl(fd, FBIO_GETMODE, &mode) == 0) printf("ok %-38s : %d\n", "FBIO_GETMODE (sanity)", mode); else { printf("note FBIO_GETMODE: %s\n", strerror(errno)); } /* --- (b) display start / line width ----------------------------- */ start.x = INT_MAX; start.y = INT_MAX; if (ioctl(fd, FBIO_SETDISPSTART, &start) == 0) printf("ok %-38s : accepted (hw regs only)\n", "FBIO_SETDISPSTART INT_MAX/INT_MAX"); else printf("ok %-38s : %s\n", "FBIO_SETDISPSTART INT_MAX", strerror(errno)); start.x = INT_MIN; start.y = INT_MIN; (void)ioctl(fd, FBIO_SETDISPSTART, &start); printf("ok %-38s : survived\n", "FBIO_SETDISPSTART INT_MIN"); i = INT_MAX; expect_reject("FBIO_SETLINEWIDTH INT_MAX", FBIO_SETLINEWIDTH, &i); i = 0; (void)ioctl(fd, FBIO_SETLINEWIDTH, &i); printf("ok %-38s : survived\n", "FBIO_SETLINEWIDTH 0"); i = -1; /* becomes 0xffffffff via *(u_int *)arg */ (void)ioctl(fd, FBIO_SETLINEWIDTH, &i); printf("ok %-38s : survived\n", "FBIO_SETLINEWIDTH -1"); /* --- (c) palette index/count arithmetic ------------------------- */ memset(&pal, 0, sizeof(pal)); pal.index = 0; pal.count = 256; /* valid boundary */ pal.red = palbuf; pal.green = palbuf + 256; pal.blue = palbuf + 512; if (ioctl(fd, FBIO_GETPALETTE, &pal) == 0) printf("ok %-38s : index=0 count=256 served\n", "FBIO_GETPALETTE boundary"); else printf("note FBIO_GETPALETTE 0/256: %s\n", strerror(errno)); pal.index = 255; pal.count = 2; /* valid boundary */ if (ioctl(fd, FBIO_GETPALETTE, &pal) == 0) printf("ok %-38s : index=255 count=2 served\n", "FBIO_GETPALETTE boundary"); else printf("note FBIO_GETPALETTE 255/2: %s\n", strerror(errno)); pal.index = 255; pal.count = 255; /* base+count > 256 */ expect_reject("FBIO_GETPALETTE 255/255", FBIO_GETPALETTE, &pal); pal.index = -1; pal.count = 1; expect_reject("FBIO_GETPALETTE index=-1", FBIO_GETPALETTE, &pal); pal.index = 0; pal.count = INT_MAX; expect_reject("FBIO_GETPALETTE count=INT_MAX", FBIO_GETPALETTE, &pal); pal.index = 0; pal.count = -1; expect_reject("FBIO_GETPALETTE count=-1", FBIO_GETPALETTE, &pal); pal.index = INT_MAX; pal.count = 1; expect_reject("FBIO_GETPALETTE index=INT_MAX", FBIO_GETPALETTE, &pal); /* copyin variant */ pal.index = 0; pal.count = 0x40000000; expect_reject("FBIO_SETPALETTE count=2^30", FBIO_SETPALETTE, &pal); pal.index = 300; pal.count = 1; expect_reject("FBIO_SETPALETTE index=300", FBIO_SETPALETTE, &pal); memset(&cmap, 0, sizeof(cmap)); cmap.index = 0; cmap.count = INT_MAX; cmap.red = palbuf; cmap.green = palbuf; cmap.blue = palbuf; expect_reject("FBIOGETCMAP count=INT_MAX", FBIOGETCMAP, &cmap); cmap.index = -5; cmap.count = 4; expect_reject("FBIOGETCMAP index=-5", FBIOGETCMAP, &cmap); cmap.index = 0; cmap.count = 0x7fffffff; expect_reject("FBIOPUTCMAP count=INT_MAX", FBIOPUTCMAP, &cmap); printf("%s: %d unexpected accept(s)\n", dev, fails); return (fails ? 2 : 0); } |