~ubuntu-branches/ubuntu/wily/spice/wily-proposed

« back to all changes in this revision

Viewing changes to .pc/CVE-2015-526x/0056-Prevent-data_size-to-be-set-independently-from-data.patch/server/red_parse_qxl.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2015-10-19 12:29:46 UTC
  • Revision ID: package-import@ubuntu.com-20151019122946-fmblwx9b49kd2msx
Tags: 0.12.5-1.1ubuntu2
* SECURITY UPDATE: multiple security issues
  - debian/patches/CVE-2015-526x/*.patch: apply series of patches from
    Red Hat to fix overflows, race conditions, memory leaks and denial of
    service issues.
  - CVE-2015-5260
  - CVE-2015-5261

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 
2
/*
 
3
   Copyright (C) 2009,2010 Red Hat, Inc.
 
4
 
 
5
   This library is free software; you can redistribute it and/or
 
6
   modify it under the terms of the GNU Lesser General Public
 
7
   License as published by the Free Software Foundation; either
 
8
   version 2.1 of the License, or (at your option) any later version.
 
9
 
 
10
   This library is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
   Lesser General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU Lesser General Public
 
16
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
 
17
*/
 
18
#ifdef HAVE_CONFIG_H
 
19
#include <config.h>
 
20
#endif
 
21
 
 
22
#include <stdbool.h>
 
23
#include <inttypes.h>
 
24
#include <glib.h>
 
25
#include "common/lz_common.h"
 
26
#include "red_common.h"
 
27
#include "red_memslots.h"
 
28
#include "red_parse_qxl.h"
 
29
 
 
30
/* Max size in bytes for any data field used in a QXL command.
 
31
 * This will for example be useful to prevent the guest from saturating the
 
32
 * host memory if it tries to send overlapping chunks.
 
33
 * This value should be big enough for all requests but limited
 
34
 * to 32 bits. Even better if it fits on 31 bits to detect integer overflows.
 
35
 */
 
36
#define MAX_DATA_CHUNK 0x7ffffffflu
 
37
 
 
38
G_STATIC_ASSERT(MAX_DATA_CHUNK <= G_MAXINT32);
 
39
 
 
40
/* Limit number of chunks.
 
41
 * The guest can attempt to make host allocate too much memory
 
42
 * just with a large number of small chunks.
 
43
 * Prevent that the chunk list take more memory than the data itself.
 
44
 */
 
45
#define MAX_CHUNKS (MAX_DATA_CHUNK/1024u)
 
46
 
 
47
#if 0
 
48
static void hexdump_qxl(RedMemSlotInfo *slots, int group_id,
 
49
                        QXLPHYSICAL addr, uint8_t bytes)
 
50
{
 
51
    uint8_t *hex;
 
52
    int i;
 
53
 
 
54
    hex = (uint8_t*)get_virt(slots, addr, bytes, group_id);
 
55
    for (i = 0; i < bytes; i++) {
 
56
        if (0 == i % 16) {
 
57
            fprintf(stderr, "%lx: ", addr+i);
 
58
        }
 
59
        if (0 == i % 4) {
 
60
            fprintf(stderr, " ");
 
61
        }
 
62
        fprintf(stderr, " %02x", hex[i]);
 
63
        if (15 == i % 16) {
 
64
            fprintf(stderr, "\n");
 
65
        }
 
66
    }
 
67
}
 
68
#endif
 
69
 
 
70
static inline uint32_t color_16_to_32(uint32_t color)
 
71
{
 
72
    uint32_t ret;
 
73
 
 
74
    ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
 
75
    ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
 
76
    ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
 
77
 
 
78
    return ret;
 
79
}
 
80
 
 
81
static uint8_t *red_linearize_chunk(RedDataChunk *head, size_t size, bool *free_chunk)
 
82
{
 
83
    uint8_t *data, *ptr;
 
84
    RedDataChunk *chunk;
 
85
    uint32_t copy;
 
86
 
 
87
    if (head->next_chunk == NULL) {
 
88
        spice_assert(size <= head->data_size);
 
89
        *free_chunk = false;
 
90
        return head->data;
 
91
    }
 
92
 
 
93
    ptr = data = spice_malloc(size);
 
94
    *free_chunk = true;
 
95
    for (chunk = head; chunk != NULL && size > 0; chunk = chunk->next_chunk) {
 
96
        copy = MIN(chunk->data_size, size);
 
97
        memcpy(ptr, chunk->data, copy);
 
98
        ptr += copy;
 
99
        size -= copy;
 
100
    }
 
101
    spice_assert(size == 0);
 
102
    return data;
 
103
}
 
104
 
 
105
static size_t red_get_data_chunks_ptr(RedMemSlotInfo *slots, int group_id,
 
106
                                      int memslot_id,
 
107
                                      RedDataChunk *red, QXLDataChunk *qxl)
 
108
{
 
109
    RedDataChunk *red_prev;
 
110
    uint64_t data_size = 0;
 
111
    uint32_t chunk_data_size;
 
112
    int error;
 
113
    QXLPHYSICAL next_chunk;
 
114
    unsigned num_chunks = 0;
 
115
 
 
116
    red->data_size = qxl->data_size;
 
117
    data_size += red->data_size;
 
118
    red->data = qxl->data;
 
119
    red->prev_chunk = red->next_chunk = NULL;
 
120
    if (!validate_virt(slots, (intptr_t)red->data, memslot_id, red->data_size, group_id)) {
 
121
        red->data = NULL;
 
122
        return 0;
 
123
    }
 
124
 
 
125
    while ((next_chunk = qxl->next_chunk) != 0) {
 
126
        /* somebody is trying to use too much memory using a lot of chunks.
 
127
         * Or made a circular list of chunks
 
128
         */
 
129
        if (++num_chunks >= MAX_CHUNKS) {
 
130
            spice_warning("data split in too many chunks, avoiding DoS\n");
 
131
            goto error;
 
132
        }
 
133
 
 
134
        memslot_id = get_memslot_id(slots, next_chunk);
 
135
        qxl = (QXLDataChunk *)get_virt(slots, next_chunk, sizeof(*qxl),
 
136
                                       group_id, &error);
 
137
        if (error)
 
138
            goto error;
 
139
 
 
140
        /* do not waste space for empty chunks.
 
141
         * This could be just a driver issue or an attempt
 
142
         * to allocate too much memory or a circular list.
 
143
         * All above cases are handled by the check for number
 
144
         * of chunks.
 
145
         */
 
146
        chunk_data_size = qxl->data_size;
 
147
        if (chunk_data_size == 0)
 
148
            continue;
 
149
 
 
150
        red_prev = red;
 
151
        red = spice_new0(RedDataChunk, 1);
 
152
        red->data_size = chunk_data_size;
 
153
        red->prev_chunk = red_prev;
 
154
        red->data = qxl->data;
 
155
        red_prev->next_chunk = red;
 
156
 
 
157
        data_size += chunk_data_size;
 
158
        /* this can happen if client is sending nested chunks */
 
159
        if (data_size > MAX_DATA_CHUNK) {
 
160
            spice_warning("too much data inside chunks, avoiding DoS\n");
 
161
            goto error;
 
162
        }
 
163
        if (!validate_virt(slots, (intptr_t)red->data, memslot_id, red->data_size, group_id))
 
164
            goto error;
 
165
    }
 
166
 
 
167
    red->next_chunk = NULL;
 
168
    return data_size;
 
169
 
 
170
error:
 
171
    while (red->prev_chunk) {
 
172
        red_prev = red->prev_chunk;
 
173
        free(red);
 
174
        red = red_prev;
 
175
    }
 
176
    red->data_size = 0;
 
177
    red->next_chunk = NULL;
 
178
    red->data = NULL;
 
179
    return 0;
 
180
}
 
181
 
 
182
static size_t red_get_data_chunks(RedMemSlotInfo *slots, int group_id,
 
183
                                  RedDataChunk *red, QXLPHYSICAL addr)
 
184
{
 
185
    QXLDataChunk *qxl;
 
186
    int error;
 
187
    int memslot_id = get_memslot_id(slots, addr);
 
188
 
 
189
    qxl = (QXLDataChunk *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
190
    if (error) {
 
191
        return 0;
 
192
    }
 
193
    return red_get_data_chunks_ptr(slots, group_id, memslot_id, red, qxl);
 
194
}
 
195
 
 
196
static void red_put_data_chunks(RedDataChunk *red)
 
197
{
 
198
    RedDataChunk *tmp;
 
199
 
 
200
    red = red->next_chunk;
 
201
    while (red) {
 
202
        tmp = red;
 
203
        red = red->next_chunk;
 
204
        free(tmp);
 
205
    }
 
206
}
 
207
 
 
208
static void red_get_point_ptr(SpicePoint *red, QXLPoint *qxl)
 
209
{
 
210
    red->x = qxl->x;
 
211
    red->y = qxl->y;
 
212
}
 
213
 
 
214
static void red_get_point16_ptr(SpicePoint16 *red, QXLPoint16 *qxl)
 
215
{
 
216
    red->x = qxl->x;
 
217
    red->y = qxl->y;
 
218
}
 
219
 
 
220
void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl)
 
221
{
 
222
    red->top    = qxl->top;
 
223
    red->left   = qxl->left;
 
224
    red->bottom = qxl->bottom;
 
225
    red->right  = qxl->right;
 
226
}
 
227
 
 
228
static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
 
229
                               QXLPHYSICAL addr)
 
230
{
 
231
    RedDataChunk chunks;
 
232
    QXLPathSeg *start, *end;
 
233
    SpicePathSeg *seg;
 
234
    uint8_t *data;
 
235
    bool free_data;
 
236
    QXLPath *qxl;
 
237
    SpicePath *red;
 
238
    size_t size, mem_size, mem_size2, dsize, segment_size;
 
239
    int n_segments;
 
240
    int i;
 
241
    uint32_t count;
 
242
    int error;
 
243
 
 
244
    qxl = (QXLPath *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
245
    if (error) {
 
246
        return NULL;
 
247
    }
 
248
    size = red_get_data_chunks_ptr(slots, group_id,
 
249
                                   get_memslot_id(slots, addr),
 
250
                                   &chunks, &qxl->chunk);
 
251
    data = red_linearize_chunk(&chunks, size, &free_data);
 
252
    red_put_data_chunks(&chunks);
 
253
 
 
254
    n_segments = 0;
 
255
    mem_size = sizeof(*red);
 
256
 
 
257
    start = (QXLPathSeg*)data;
 
258
    end = (QXLPathSeg*)(data + size);
 
259
    while (start+1 < end) {
 
260
        n_segments++;
 
261
        count = start->count;
 
262
        segment_size = sizeof(SpicePathSeg) + count * sizeof(SpicePointFix);
 
263
        mem_size += sizeof(SpicePathSeg *) + SPICE_ALIGN(segment_size, 4);
 
264
        start = (QXLPathSeg*)(&start->points[count]);
 
265
    }
 
266
 
 
267
    red = spice_malloc(mem_size);
 
268
    red->num_segments = n_segments;
 
269
 
 
270
    start = (QXLPathSeg*)data;
 
271
    end = (QXLPathSeg*)(data + size);
 
272
    seg = (SpicePathSeg*)&red->segments[n_segments];
 
273
    n_segments = 0;
 
274
    mem_size2 = sizeof(*red);
 
275
    while (start+1 < end && n_segments < red->num_segments) {
 
276
        red->segments[n_segments++] = seg;
 
277
        count = start->count;
 
278
 
 
279
        /* Protect against overflow in size calculations before
 
280
           writing to memory */
 
281
        spice_assert(mem_size2 + sizeof(SpicePathSeg) > mem_size2);
 
282
        mem_size2  += sizeof(SpicePathSeg);
 
283
        spice_assert(count < UINT32_MAX / sizeof(SpicePointFix));
 
284
        dsize = count * sizeof(SpicePointFix);
 
285
        spice_assert(mem_size2 + dsize > mem_size2);
 
286
        mem_size2  += dsize;
 
287
 
 
288
        /* Verify that we didn't overflow due to guest changing data */
 
289
        spice_assert(mem_size2 <= mem_size);
 
290
 
 
291
        seg->flags = start->flags;
 
292
        seg->count = count;
 
293
        for (i = 0; i < seg->count; i++) {
 
294
            seg->points[i].x = start->points[i].x;
 
295
            seg->points[i].y = start->points[i].y;
 
296
        }
 
297
        start = (QXLPathSeg*)(&start->points[i]);
 
298
        seg = (SpicePathSeg*)(&seg->points[i]);
 
299
    }
 
300
    /* Ensure guest didn't tamper with segment count */
 
301
    spice_assert(n_segments == red->num_segments);
 
302
 
 
303
    if (free_data) {
 
304
        free(data);
 
305
    }
 
306
    return red;
 
307
}
 
308
 
 
309
static SpiceClipRects *red_get_clip_rects(RedMemSlotInfo *slots, int group_id,
 
310
                                          QXLPHYSICAL addr)
 
311
{
 
312
    RedDataChunk chunks;
 
313
    QXLClipRects *qxl;
 
314
    SpiceClipRects *red;
 
315
    QXLRect *start;
 
316
    uint8_t *data;
 
317
    bool free_data;
 
318
    size_t size;
 
319
    int i;
 
320
    int error;
 
321
    uint32_t num_rects;
 
322
 
 
323
    qxl = (QXLClipRects *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
324
    if (error) {
 
325
        return NULL;
 
326
    }
 
327
    size = red_get_data_chunks_ptr(slots, group_id,
 
328
                                   get_memslot_id(slots, addr),
 
329
                                   &chunks, &qxl->chunk);
 
330
    data = red_linearize_chunk(&chunks, size, &free_data);
 
331
    red_put_data_chunks(&chunks);
 
332
 
 
333
    num_rects = qxl->num_rects;
 
334
    spice_assert(num_rects * sizeof(QXLRect) == size);
 
335
    red = spice_malloc(sizeof(*red) + num_rects * sizeof(SpiceRect));
 
336
    red->num_rects = num_rects;
 
337
 
 
338
    start = (QXLRect*)data;
 
339
    for (i = 0; i < red->num_rects; i++) {
 
340
        red_get_rect_ptr(red->rects + i, start++);
 
341
    }
 
342
 
 
343
    if (free_data) {
 
344
        free(data);
 
345
    }
 
346
    return red;
 
347
}
 
348
 
 
349
static SpiceChunks *red_get_image_data_flat(RedMemSlotInfo *slots, int group_id,
 
350
                                            QXLPHYSICAL addr, size_t size)
 
351
{
 
352
    SpiceChunks *data;
 
353
    int error;
 
354
 
 
355
    data = spice_chunks_new(1);
 
356
    data->data_size      = size;
 
357
    data->chunk[0].data  = (void*)get_virt(slots, addr, size, group_id, &error);
 
358
    if (error) {
 
359
        return 0;
 
360
    }
 
361
    data->chunk[0].len   = size;
 
362
    return data;
 
363
}
 
364
 
 
365
static SpiceChunks *red_get_image_data_chunked(RedMemSlotInfo *slots, int group_id,
 
366
                                               RedDataChunk *head)
 
367
{
 
368
    SpiceChunks *data;
 
369
    RedDataChunk *chunk;
 
370
    int i;
 
371
 
 
372
    for (i = 0, chunk = head; chunk != NULL; chunk = chunk->next_chunk) {
 
373
        i++;
 
374
    }
 
375
 
 
376
    data = spice_chunks_new(i);
 
377
    data->data_size = 0;
 
378
    for (i = 0, chunk = head;
 
379
         chunk != NULL && i < data->num_chunks;
 
380
         chunk = chunk->next_chunk, i++) {
 
381
        data->chunk[i].data  = chunk->data;
 
382
        data->chunk[i].len   = chunk->data_size;
 
383
        data->data_size     += chunk->data_size;
 
384
    }
 
385
    spice_assert(i == data->num_chunks);
 
386
    return data;
 
387
}
 
388
 
 
389
static const char *bitmap_format_to_string(int format)
 
390
{
 
391
    switch (format) {
 
392
    case SPICE_BITMAP_FMT_INVALID: return "SPICE_BITMAP_FMT_INVALID";
 
393
    case SPICE_BITMAP_FMT_1BIT_LE: return "SPICE_BITMAP_FMT_1BIT_LE";
 
394
    case SPICE_BITMAP_FMT_1BIT_BE: return "SPICE_BITMAP_FMT_1BIT_BE";
 
395
    case SPICE_BITMAP_FMT_4BIT_LE: return "SPICE_BITMAP_FMT_4BIT_LE";
 
396
    case SPICE_BITMAP_FMT_4BIT_BE: return "SPICE_BITMAP_FMT_4BIT_BE";
 
397
    case SPICE_BITMAP_FMT_8BIT: return "SPICE_BITMAP_FMT_8BIT";
 
398
    case SPICE_BITMAP_FMT_16BIT: return "SPICE_BITMAP_FMT_16BIT";
 
399
    case SPICE_BITMAP_FMT_24BIT: return "SPICE_BITMAP_FMT_24BIT";
 
400
    case SPICE_BITMAP_FMT_32BIT: return "SPICE_BITMAP_FMT_32BIT";
 
401
    case SPICE_BITMAP_FMT_RGBA: return "SPICE_BITMAP_FMT_RGBA";
 
402
    case SPICE_BITMAP_FMT_8BIT_A: return "SPICE_BITMAP_FMT_8BIT_A";
 
403
    }
 
404
    return "unknown";
 
405
}
 
406
 
 
407
static const unsigned int MAP_BITMAP_FMT_TO_BITS_PER_PIXEL[] =
 
408
    {0, 1, 1, 4, 4, 8, 16, 24, 32, 32, 8};
 
409
 
 
410
static int bitmap_consistent(SpiceBitmap *bitmap)
 
411
{
 
412
    unsigned int bpp;
 
413
 
 
414
    if (bitmap->format >= SPICE_N_ELEMENTS(MAP_BITMAP_FMT_TO_BITS_PER_PIXEL)) {
 
415
        spice_warning("wrong format specified for image\n");
 
416
        return FALSE;
 
417
    }
 
418
 
 
419
    bpp = MAP_BITMAP_FMT_TO_BITS_PER_PIXEL[bitmap->format];
 
420
 
 
421
    if (bitmap->stride < (((uint64_t) bitmap->x * bpp + 7u) / 8u)) {
 
422
        spice_warning("image stride too small for width: %d < ((%d * %d + 7) / 8) (%s=%d)\n",
 
423
                    bitmap->stride, bitmap->x, bpp,
 
424
                    bitmap_format_to_string(bitmap->format),
 
425
                    bitmap->format);
 
426
        return FALSE;
 
427
    }
 
428
    return TRUE;
 
429
}
 
430
 
 
431
// This is based on SPICE_BITMAP_FMT_*, copied from server/red_worker.c
 
432
// to avoid a possible unoptimization from making it non static.
 
433
static const int BITMAP_FMT_IS_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
 
434
 
 
435
static SpiceImage *red_get_image(RedMemSlotInfo *slots, int group_id,
 
436
                                 QXLPHYSICAL addr, uint32_t flags, int is_mask)
 
437
{
 
438
    RedDataChunk chunks;
 
439
    QXLImage *qxl;
 
440
    SpiceImage *red = NULL;
 
441
    SpicePalette *rp = NULL;
 
442
    uint64_t bitmap_size, size;
 
443
    uint8_t qxl_flags;
 
444
    int error;
 
445
    QXLPHYSICAL palette;
 
446
 
 
447
    if (addr == 0) {
 
448
        return NULL;
 
449
    }
 
450
 
 
451
    qxl = (QXLImage *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
452
    if (error) {
 
453
        return NULL;
 
454
    }
 
455
    red = spice_new0(SpiceImage, 1);
 
456
    red->descriptor.id     = qxl->descriptor.id;
 
457
    red->descriptor.type   = qxl->descriptor.type;
 
458
    red->descriptor.flags = 0;
 
459
    if (qxl->descriptor.flags & QXL_IMAGE_HIGH_BITS_SET) {
 
460
        red->descriptor.flags |= SPICE_IMAGE_FLAGS_HIGH_BITS_SET;
 
461
    }
 
462
    if (qxl->descriptor.flags & QXL_IMAGE_CACHE) {
 
463
        red->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
 
464
    }
 
465
    red->descriptor.width  = qxl->descriptor.width;
 
466
    red->descriptor.height = qxl->descriptor.height;
 
467
 
 
468
    switch (red->descriptor.type) {
 
469
    case SPICE_IMAGE_TYPE_BITMAP:
 
470
        red->u.bitmap.format = qxl->bitmap.format;
 
471
        red->u.bitmap.x      = qxl->bitmap.x;
 
472
        red->u.bitmap.y      = qxl->bitmap.y;
 
473
        red->u.bitmap.stride = qxl->bitmap.stride;
 
474
        palette = qxl->bitmap.palette;
 
475
        if (!bitmap_fmt_is_rgb(red->u.bitmap.format) && !palette && !is_mask) {
 
476
            spice_warning("guest error: missing palette on bitmap format=%d\n",
 
477
                          red->u.bitmap.format);
 
478
            goto error;
 
479
        }
 
480
        if (red->u.bitmap.x == 0 || red->u.bitmap.y == 0) {
 
481
            spice_warning("guest error: zero area bitmap\n");
 
482
            goto error;
 
483
        }
 
484
        qxl_flags = qxl->bitmap.flags;
 
485
        if (qxl_flags & QXL_BITMAP_TOP_DOWN) {
 
486
            red->u.bitmap.flags = SPICE_BITMAP_FLAGS_TOP_DOWN;
 
487
        }
 
488
        if (!bitmap_consistent(&red->u.bitmap)) {
 
489
            goto error;
 
490
        }
 
491
        if (palette) {
 
492
            QXLPalette *qp;
 
493
            int i, num_ents;
 
494
            qp = (QXLPalette *)get_virt(slots, palette,
 
495
                                        sizeof(*qp), group_id, &error);
 
496
            if (error) {
 
497
                goto error;
 
498
            }
 
499
            num_ents = qp->num_ents;
 
500
            if (!validate_virt(slots, (intptr_t)qp->ents,
 
501
                               get_memslot_id(slots, palette),
 
502
                               num_ents * sizeof(qp->ents[0]), group_id)) {
 
503
                goto error;
 
504
            }
 
505
            rp = spice_malloc_n_m(num_ents, sizeof(rp->ents[0]), sizeof(*rp));
 
506
            rp->unique   = qp->unique;
 
507
            rp->num_ents = num_ents;
 
508
            if (flags & QXL_COMMAND_FLAG_COMPAT_16BPP) {
 
509
                for (i = 0; i < num_ents; i++) {
 
510
                    rp->ents[i] = color_16_to_32(qp->ents[i]);
 
511
                }
 
512
            } else {
 
513
                for (i = 0; i < num_ents; i++) {
 
514
                    rp->ents[i] = qp->ents[i];
 
515
                }
 
516
            }
 
517
            red->u.bitmap.palette = rp;
 
518
            red->u.bitmap.palette_id = rp->unique;
 
519
        }
 
520
        bitmap_size = (uint64_t) red->u.bitmap.y * red->u.bitmap.stride;
 
521
        if (bitmap_size > MAX_DATA_CHUNK) {
 
522
            goto error;
 
523
        }
 
524
        if (qxl_flags & QXL_BITMAP_DIRECT) {
 
525
            red->u.bitmap.data = red_get_image_data_flat(slots, group_id,
 
526
                                                         qxl->bitmap.data,
 
527
                                                         bitmap_size);
 
528
        } else {
 
529
            size = red_get_data_chunks(slots, group_id,
 
530
                                       &chunks, qxl->bitmap.data);
 
531
            spice_assert(size == bitmap_size);
 
532
            if (size != bitmap_size) {
 
533
                goto error;
 
534
            }
 
535
            red->u.bitmap.data = red_get_image_data_chunked(slots, group_id,
 
536
                                                            &chunks);
 
537
            red_put_data_chunks(&chunks);
 
538
        }
 
539
        if (qxl_flags & QXL_BITMAP_UNSTABLE) {
 
540
            red->u.bitmap.data->flags |= SPICE_CHUNKS_FLAGS_UNSTABLE;
 
541
        }
 
542
        break;
 
543
    case SPICE_IMAGE_TYPE_SURFACE:
 
544
        red->u.surface.surface_id = qxl->surface_image.surface_id;
 
545
        break;
 
546
    case SPICE_IMAGE_TYPE_QUIC:
 
547
        red->u.quic.data_size = qxl->quic.data_size;
 
548
        size = red_get_data_chunks_ptr(slots, group_id,
 
549
                                       get_memslot_id(slots, addr),
 
550
                                       &chunks, (QXLDataChunk *)qxl->quic.data);
 
551
        spice_assert(size == red->u.quic.data_size);
 
552
        if (size != red->u.quic.data_size) {
 
553
            goto error;
 
554
        }
 
555
        red->u.quic.data = red_get_image_data_chunked(slots, group_id,
 
556
                                                      &chunks);
 
557
        red_put_data_chunks(&chunks);
 
558
        break;
 
559
    default:
 
560
        spice_warning("unknown type %d", red->descriptor.type);
 
561
        goto error;
 
562
    }
 
563
    return red;
 
564
error:
 
565
    free(red);
 
566
    free(rp);
 
567
    return NULL;
 
568
}
 
569
 
 
570
void red_put_image(SpiceImage *red)
 
571
{
 
572
    if (red == NULL)
 
573
        return;
 
574
 
 
575
    switch (red->descriptor.type) {
 
576
    case SPICE_IMAGE_TYPE_BITMAP:
 
577
        free(red->u.bitmap.palette);
 
578
        spice_chunks_destroy(red->u.bitmap.data);
 
579
        break;
 
580
    case SPICE_IMAGE_TYPE_QUIC:
 
581
        spice_chunks_destroy(red->u.quic.data);
 
582
        break;
 
583
    }
 
584
    free(red);
 
585
}
 
586
 
 
587
static void red_get_brush_ptr(RedMemSlotInfo *slots, int group_id,
 
588
                              SpiceBrush *red, QXLBrush *qxl, uint32_t flags)
 
589
{
 
590
    red->type = qxl->type;
 
591
    switch (red->type) {
 
592
    case SPICE_BRUSH_TYPE_SOLID:
 
593
        if (flags & QXL_COMMAND_FLAG_COMPAT_16BPP) {
 
594
            red->u.color = color_16_to_32(qxl->u.color);
 
595
        } else {
 
596
            red->u.color = qxl->u.color;
 
597
        }
 
598
        break;
 
599
    case SPICE_BRUSH_TYPE_PATTERN:
 
600
        red->u.pattern.pat = red_get_image(slots, group_id, qxl->u.pattern.pat, flags, FALSE);
 
601
        break;
 
602
    }
 
603
}
 
604
 
 
605
static void red_put_brush(SpiceBrush *red)
 
606
{
 
607
    switch (red->type) {
 
608
    case SPICE_BRUSH_TYPE_PATTERN:
 
609
        red_put_image(red->u.pattern.pat);
 
610
        break;
 
611
    }
 
612
}
 
613
 
 
614
static void red_get_qmask_ptr(RedMemSlotInfo *slots, int group_id,
 
615
                              SpiceQMask *red, QXLQMask *qxl, uint32_t flags)
 
616
{
 
617
    red->flags  = qxl->flags;
 
618
    red_get_point_ptr(&red->pos, &qxl->pos);
 
619
    red->bitmap = red_get_image(slots, group_id, qxl->bitmap, flags, TRUE);
 
620
}
 
621
 
 
622
static void red_put_qmask(SpiceQMask *red)
 
623
{
 
624
    red_put_image(red->bitmap);
 
625
}
 
626
 
 
627
static void red_get_fill_ptr(RedMemSlotInfo *slots, int group_id,
 
628
                             SpiceFill *red, QXLFill *qxl, uint32_t flags)
 
629
{
 
630
    red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
 
631
    red->rop_descriptor = qxl->rop_descriptor;
 
632
    red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
 
633
}
 
634
 
 
635
static void red_put_fill(SpiceFill *red)
 
636
{
 
637
    red_put_brush(&red->brush);
 
638
    red_put_qmask(&red->mask);
 
639
}
 
640
 
 
641
static void red_get_opaque_ptr(RedMemSlotInfo *slots, int group_id,
 
642
                               SpiceOpaque *red, QXLOpaque *qxl, uint32_t flags)
 
643
{
 
644
    red->src_bitmap     = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
 
645
   red_get_rect_ptr(&red->src_area, &qxl->src_area);
 
646
   red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
 
647
   red->rop_descriptor = qxl->rop_descriptor;
 
648
   red->scale_mode     = qxl->scale_mode;
 
649
   red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
 
650
}
 
651
 
 
652
static void red_put_opaque(SpiceOpaque *red)
 
653
{
 
654
    red_put_image(red->src_bitmap);
 
655
    red_put_brush(&red->brush);
 
656
    red_put_qmask(&red->mask);
 
657
}
 
658
 
 
659
static int red_get_copy_ptr(RedMemSlotInfo *slots, int group_id,
 
660
                            SpiceCopy *red, QXLCopy *qxl, uint32_t flags)
 
661
{
 
662
    red->src_bitmap      = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
 
663
    if (!red->src_bitmap) {
 
664
        return 1;
 
665
    }
 
666
    red_get_rect_ptr(&red->src_area, &qxl->src_area);
 
667
    red->rop_descriptor  = qxl->rop_descriptor;
 
668
    red->scale_mode      = qxl->scale_mode;
 
669
    red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
 
670
    return 0;
 
671
}
 
672
 
 
673
static void red_put_copy(SpiceCopy *red)
 
674
{
 
675
    red_put_image(red->src_bitmap);
 
676
    red_put_qmask(&red->mask);
 
677
}
 
678
 
 
679
static void red_get_blend_ptr(RedMemSlotInfo *slots, int group_id,
 
680
                             SpiceBlend *red, QXLBlend *qxl, uint32_t flags)
 
681
{
 
682
    red->src_bitmap      = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
 
683
   red_get_rect_ptr(&red->src_area, &qxl->src_area);
 
684
   red->rop_descriptor  = qxl->rop_descriptor;
 
685
   red->scale_mode      = qxl->scale_mode;
 
686
   red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
 
687
}
 
688
 
 
689
static void red_put_blend(SpiceBlend *red)
 
690
{
 
691
    red_put_image(red->src_bitmap);
 
692
    red_put_qmask(&red->mask);
 
693
}
 
694
 
 
695
static void red_get_transparent_ptr(RedMemSlotInfo *slots, int group_id,
 
696
                                    SpiceTransparent *red, QXLTransparent *qxl,
 
697
                                    uint32_t flags)
 
698
{
 
699
    red->src_bitmap      = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
 
700
   red_get_rect_ptr(&red->src_area, &qxl->src_area);
 
701
   red->src_color       = qxl->src_color;
 
702
   red->true_color      = qxl->true_color;
 
703
}
 
704
 
 
705
static void red_put_transparent(SpiceTransparent *red)
 
706
{
 
707
    red_put_image(red->src_bitmap);
 
708
}
 
709
 
 
710
static void red_get_alpha_blend_ptr(RedMemSlotInfo *slots, int group_id,
 
711
                                    SpiceAlphaBlend *red, QXLAlphaBlend *qxl,
 
712
                                    uint32_t flags)
 
713
{
 
714
    red->alpha_flags = qxl->alpha_flags;
 
715
    red->alpha       = qxl->alpha;
 
716
    red->src_bitmap  = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
 
717
    red_get_rect_ptr(&red->src_area, &qxl->src_area);
 
718
}
 
719
 
 
720
static void red_get_alpha_blend_ptr_compat(RedMemSlotInfo *slots, int group_id,
 
721
                                           SpiceAlphaBlend *red, QXLCompatAlphaBlend *qxl,
 
722
                                           uint32_t flags)
 
723
{
 
724
    red->alpha       = qxl->alpha;
 
725
    red->src_bitmap  = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
 
726
    red_get_rect_ptr(&red->src_area, &qxl->src_area);
 
727
}
 
728
 
 
729
static void red_put_alpha_blend(SpiceAlphaBlend *red)
 
730
{
 
731
    red_put_image(red->src_bitmap);
 
732
}
 
733
 
 
734
static bool get_transform(RedMemSlotInfo *slots,
 
735
                          int group_id,
 
736
                          QXLPHYSICAL qxl_transform,
 
737
                          SpiceTransform *dst_transform)
 
738
{
 
739
    const uint32_t *t = NULL;
 
740
    int error;
 
741
 
 
742
    if (qxl_transform == 0)
 
743
        return FALSE;
 
744
 
 
745
    t = (uint32_t *)get_virt(slots, qxl_transform, sizeof(*dst_transform), group_id, &error);
 
746
 
 
747
    if (!t || error)
 
748
        return FALSE;
 
749
 
 
750
    memcpy(dst_transform, t, sizeof(*dst_transform));
 
751
    return TRUE;
 
752
}
 
753
 
 
754
static void red_get_composite_ptr(RedMemSlotInfo *slots, int group_id,
 
755
                                  SpiceComposite *red, QXLComposite *qxl, uint32_t flags)
 
756
{
 
757
    red->flags = qxl->flags;
 
758
 
 
759
    red->src_bitmap = red_get_image(slots, group_id, qxl->src, flags, FALSE);
 
760
    if (get_transform(slots, group_id, qxl->src_transform, &red->src_transform))
 
761
        red->flags |= SPICE_COMPOSITE_HAS_SRC_TRANSFORM;
 
762
 
 
763
    if (qxl->mask) {
 
764
        red->mask_bitmap = red_get_image(slots, group_id, qxl->mask, flags, FALSE);
 
765
        red->flags |= SPICE_COMPOSITE_HAS_MASK;
 
766
        if (get_transform(slots, group_id, qxl->mask_transform, &red->mask_transform))
 
767
            red->flags |= SPICE_COMPOSITE_HAS_MASK_TRANSFORM;
 
768
    } else {
 
769
        red->mask_bitmap = NULL;
 
770
    }
 
771
    red->src_origin.x = qxl->src_origin.x;
 
772
    red->src_origin.y = qxl->src_origin.y;
 
773
    red->mask_origin.x = qxl->mask_origin.x;
 
774
    red->mask_origin.y = qxl->mask_origin.y;
 
775
}
 
776
 
 
777
static void red_put_composite(SpiceComposite *red)
 
778
{
 
779
    red_put_image(red->src_bitmap);
 
780
    if (red->mask_bitmap)
 
781
        red_put_image(red->mask_bitmap);
 
782
}
 
783
 
 
784
static void red_get_rop3_ptr(RedMemSlotInfo *slots, int group_id,
 
785
                             SpiceRop3 *red, QXLRop3 *qxl, uint32_t flags)
 
786
{
 
787
   red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
 
788
   red_get_rect_ptr(&red->src_area, &qxl->src_area);
 
789
   red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
 
790
   red->rop3       = qxl->rop3;
 
791
   red->scale_mode = qxl->scale_mode;
 
792
   red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
 
793
}
 
794
 
 
795
static void red_put_rop3(SpiceRop3 *red)
 
796
{
 
797
    red_put_image(red->src_bitmap);
 
798
    red_put_brush(&red->brush);
 
799
    red_put_qmask(&red->mask);
 
800
}
 
801
 
 
802
static int red_get_stroke_ptr(RedMemSlotInfo *slots, int group_id,
 
803
                              SpiceStroke *red, QXLStroke *qxl, uint32_t flags)
 
804
{
 
805
    int error;
 
806
 
 
807
    red->path = red_get_path(slots, group_id, qxl->path);
 
808
    if (!red->path) {
 
809
        return 1;
 
810
    }
 
811
    red->attr.flags       = qxl->attr.flags;
 
812
    if (red->attr.flags & SPICE_LINE_FLAGS_STYLED) {
 
813
        int style_nseg;
 
814
        uint8_t *buf;
 
815
 
 
816
        style_nseg = qxl->attr.style_nseg;
 
817
        red->attr.style = spice_malloc_n(style_nseg, sizeof(SPICE_FIXED28_4));
 
818
        red->attr.style_nseg  = style_nseg;
 
819
        spice_assert(qxl->attr.style);
 
820
        buf = (uint8_t *)get_virt(slots, qxl->attr.style,
 
821
                                  style_nseg * sizeof(QXLFIXED), group_id, &error);
 
822
        if (error) {
 
823
            return error;
 
824
        }
 
825
        memcpy(red->attr.style, buf, style_nseg * sizeof(QXLFIXED));
 
826
    } else {
 
827
        red->attr.style_nseg  = 0;
 
828
        red->attr.style       = NULL;
 
829
    }
 
830
    red_get_brush_ptr(slots, group_id, &red->brush, &qxl->brush, flags);
 
831
    red->fore_mode        = qxl->fore_mode;
 
832
    red->back_mode        = qxl->back_mode;
 
833
    return 0;
 
834
}
 
835
 
 
836
static void red_put_stroke(SpiceStroke *red)
 
837
{
 
838
    red_put_brush(&red->brush);
 
839
    free(red->path);
 
840
    if (red->attr.flags & SPICE_LINE_FLAGS_STYLED) {
 
841
        free(red->attr.style);
 
842
    }
 
843
}
 
844
 
 
845
static SpiceString *red_get_string(RedMemSlotInfo *slots, int group_id,
 
846
                                   QXLPHYSICAL addr)
 
847
{
 
848
    RedDataChunk chunks;
 
849
    QXLString *qxl;
 
850
    QXLRasterGlyph *start, *end;
 
851
    SpiceString *red;
 
852
    SpiceRasterGlyph *glyph;
 
853
    uint8_t *data;
 
854
    bool free_data;
 
855
    size_t chunk_size, qxl_size, red_size, glyph_size;
 
856
    int glyphs, i;
 
857
    /* use unsigned to prevent integer overflow in multiplication below */
 
858
    unsigned int bpp = 0;
 
859
    int error;
 
860
    uint16_t qxl_flags, qxl_length;
 
861
 
 
862
    qxl = (QXLString *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
863
    if (error) {
 
864
        return NULL;
 
865
    }
 
866
    chunk_size = red_get_data_chunks_ptr(slots, group_id,
 
867
                                         get_memslot_id(slots, addr),
 
868
                                         &chunks, &qxl->chunk);
 
869
    if (!chunk_size) {
 
870
        /* XXX could be a zero sized string.. */
 
871
        return NULL;
 
872
    }
 
873
    data = red_linearize_chunk(&chunks, chunk_size, &free_data);
 
874
    red_put_data_chunks(&chunks);
 
875
 
 
876
    qxl_size = qxl->data_size;
 
877
    qxl_flags = qxl->flags;
 
878
    qxl_length = qxl->length;
 
879
    spice_assert(chunk_size == qxl_size);
 
880
 
 
881
    if (qxl_flags & SPICE_STRING_FLAGS_RASTER_A1) {
 
882
        bpp = 1;
 
883
    } else if (qxl_flags & SPICE_STRING_FLAGS_RASTER_A4) {
 
884
        bpp = 4;
 
885
    } else if (qxl_flags & SPICE_STRING_FLAGS_RASTER_A8) {
 
886
        bpp = 8;
 
887
    }
 
888
    spice_assert(bpp != 0);
 
889
 
 
890
    start = (QXLRasterGlyph*)data;
 
891
    end = (QXLRasterGlyph*)(data + chunk_size);
 
892
    red_size = sizeof(SpiceString);
 
893
    glyphs = 0;
 
894
    while (start < end) {
 
895
        spice_assert((QXLRasterGlyph*)(&start->data[0]) <= end);
 
896
        glyphs++;
 
897
        glyph_size = start->height * ((start->width * bpp + 7u) / 8u);
 
898
        red_size += sizeof(SpiceRasterGlyph *) + SPICE_ALIGN(sizeof(SpiceRasterGlyph) + glyph_size, 4);
 
899
        /* do the test correctly, we know end - start->data[0] cannot
 
900
         * overflow, don't use start->data[glyph_size] to test for
 
901
         * buffer overflow as this on 32 bit can cause overflow
 
902
         * on the pointer arithmetic */
 
903
        spice_assert(glyph_size <= (char*) end - (char*) &start->data[0]);
 
904
        start = (QXLRasterGlyph*)(&start->data[glyph_size]);
 
905
    }
 
906
    spice_assert(start <= end);
 
907
    spice_assert(glyphs == qxl_length);
 
908
 
 
909
    red = spice_malloc(red_size);
 
910
    red->length = qxl_length;
 
911
    red->flags = qxl_flags;
 
912
 
 
913
    start = (QXLRasterGlyph*)data;
 
914
    end = (QXLRasterGlyph*)(data + chunk_size);
 
915
    glyph = (SpiceRasterGlyph *)&red->glyphs[red->length];
 
916
    for (i = 0; i < red->length; i++) {
 
917
        spice_assert((QXLRasterGlyph*)(&start->data[0]) <= end);
 
918
        red->glyphs[i] = glyph;
 
919
        glyph->width = start->width;
 
920
        glyph->height = start->height;
 
921
        red_get_point_ptr(&glyph->render_pos, &start->render_pos);
 
922
        red_get_point_ptr(&glyph->glyph_origin, &start->glyph_origin);
 
923
        glyph_size = glyph->height * ((glyph->width * bpp + 7u) / 8u);
 
924
        /* see above for similar test */
 
925
        spice_assert(glyph_size <= (char*) end - (char*) &start->data[0]);
 
926
        memcpy(glyph->data, start->data, glyph_size);
 
927
        start = (QXLRasterGlyph*)(&start->data[glyph_size]);
 
928
        glyph = (SpiceRasterGlyph*)
 
929
            (((uint8_t *)glyph) +
 
930
             SPICE_ALIGN(sizeof(SpiceRasterGlyph) + glyph_size, 4));
 
931
    }
 
932
 
 
933
    if (free_data) {
 
934
        free(data);
 
935
    }
 
936
    return red;
 
937
}
 
938
 
 
939
static void red_get_text_ptr(RedMemSlotInfo *slots, int group_id,
 
940
                             SpiceText *red, QXLText *qxl, uint32_t flags)
 
941
{
 
942
   red->str = red_get_string(slots, group_id, qxl->str);
 
943
   red_get_rect_ptr(&red->back_area, &qxl->back_area);
 
944
   red_get_brush_ptr(slots, group_id, &red->fore_brush, &qxl->fore_brush, flags);
 
945
   red_get_brush_ptr(slots, group_id, &red->back_brush, &qxl->back_brush, flags);
 
946
   red->fore_mode  = qxl->fore_mode;
 
947
   red->back_mode  = qxl->back_mode;
 
948
}
 
949
 
 
950
static void red_put_text_ptr(SpiceText *red)
 
951
{
 
952
    free(red->str);
 
953
    red_put_brush(&red->fore_brush);
 
954
    red_put_brush(&red->back_brush);
 
955
}
 
956
 
 
957
static void red_get_whiteness_ptr(RedMemSlotInfo *slots, int group_id,
 
958
                                  SpiceWhiteness *red, QXLWhiteness *qxl, uint32_t flags)
 
959
{
 
960
    red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
 
961
}
 
962
 
 
963
static void red_put_whiteness(SpiceWhiteness *red)
 
964
{
 
965
    red_put_qmask(&red->mask);
 
966
}
 
967
 
 
968
static void red_get_blackness_ptr(RedMemSlotInfo *slots, int group_id,
 
969
                                  SpiceBlackness *red, QXLBlackness *qxl, uint32_t flags)
 
970
{
 
971
    red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
 
972
}
 
973
 
 
974
static void red_put_blackness(SpiceWhiteness *red)
 
975
{
 
976
    red_put_qmask(&red->mask);
 
977
}
 
978
 
 
979
static void red_get_invers_ptr(RedMemSlotInfo *slots, int group_id,
 
980
                               SpiceInvers *red, QXLInvers *qxl, uint32_t flags)
 
981
{
 
982
    red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
 
983
}
 
984
 
 
985
static void red_put_invers(SpiceWhiteness *red)
 
986
{
 
987
    red_put_qmask(&red->mask);
 
988
}
 
989
 
 
990
static void red_get_clip_ptr(RedMemSlotInfo *slots, int group_id,
 
991
                             SpiceClip *red, QXLClip *qxl)
 
992
{
 
993
    red->type = qxl->type;
 
994
    switch (red->type) {
 
995
    case SPICE_CLIP_TYPE_RECTS:
 
996
        red->rects = red_get_clip_rects(slots, group_id, qxl->data);
 
997
        break;
 
998
    }
 
999
}
 
1000
 
 
1001
static void red_put_clip(SpiceClip *red)
 
1002
{
 
1003
    switch (red->type) {
 
1004
    case SPICE_CLIP_TYPE_RECTS:
 
1005
        free(red->rects);
 
1006
        break;
 
1007
    }
 
1008
}
 
1009
 
 
1010
static int red_get_native_drawable(RedMemSlotInfo *slots, int group_id,
 
1011
                                   RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
 
1012
{
 
1013
    QXLDrawable *qxl;
 
1014
    int i;
 
1015
    int error = 0;
 
1016
 
 
1017
    qxl = (QXLDrawable *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
1018
    if (error) {
 
1019
        return error;
 
1020
    }
 
1021
    red->release_info     = &qxl->release_info;
 
1022
 
 
1023
    red_get_rect_ptr(&red->bbox, &qxl->bbox);
 
1024
    red_get_clip_ptr(slots, group_id, &red->clip, &qxl->clip);
 
1025
    red->effect           = qxl->effect;
 
1026
    red->mm_time          = qxl->mm_time;
 
1027
    red->self_bitmap      = qxl->self_bitmap;
 
1028
    red_get_rect_ptr(&red->self_bitmap_area, &qxl->self_bitmap_area);
 
1029
    red->surface_id       = qxl->surface_id;
 
1030
 
 
1031
    for (i = 0; i < 3; i++) {
 
1032
        red->surfaces_dest[i] = qxl->surfaces_dest[i];
 
1033
        red_get_rect_ptr(&red->surfaces_rects[i], &qxl->surfaces_rects[i]);
 
1034
    }
 
1035
 
 
1036
    red->type = qxl->type;
 
1037
    switch (red->type) {
 
1038
    case QXL_DRAW_ALPHA_BLEND:
 
1039
        red_get_alpha_blend_ptr(slots, group_id,
 
1040
                                &red->u.alpha_blend, &qxl->u.alpha_blend, flags);
 
1041
        break;
 
1042
    case QXL_DRAW_BLACKNESS:
 
1043
        red_get_blackness_ptr(slots, group_id,
 
1044
                              &red->u.blackness, &qxl->u.blackness, flags);
 
1045
        break;
 
1046
    case QXL_DRAW_BLEND:
 
1047
        red_get_blend_ptr(slots, group_id, &red->u.blend, &qxl->u.blend, flags);
 
1048
        break;
 
1049
    case QXL_DRAW_COPY:
 
1050
        error = red_get_copy_ptr(slots, group_id, &red->u.copy, &qxl->u.copy, flags);
 
1051
        break;
 
1052
    case QXL_COPY_BITS:
 
1053
        red_get_point_ptr(&red->u.copy_bits.src_pos, &qxl->u.copy_bits.src_pos);
 
1054
        break;
 
1055
    case QXL_DRAW_FILL:
 
1056
        red_get_fill_ptr(slots, group_id, &red->u.fill, &qxl->u.fill, flags);
 
1057
        break;
 
1058
    case QXL_DRAW_OPAQUE:
 
1059
        red_get_opaque_ptr(slots, group_id, &red->u.opaque, &qxl->u.opaque, flags);
 
1060
        break;
 
1061
    case QXL_DRAW_INVERS:
 
1062
        red_get_invers_ptr(slots, group_id, &red->u.invers, &qxl->u.invers, flags);
 
1063
        break;
 
1064
    case QXL_DRAW_NOP:
 
1065
        break;
 
1066
    case QXL_DRAW_ROP3:
 
1067
        red_get_rop3_ptr(slots, group_id, &red->u.rop3, &qxl->u.rop3, flags);
 
1068
        break;
 
1069
    case QXL_DRAW_COMPOSITE:
 
1070
        red_get_composite_ptr(slots, group_id, &red->u.composite, &qxl->u.composite, flags);
 
1071
        break;
 
1072
    case QXL_DRAW_STROKE:
 
1073
        error = red_get_stroke_ptr(slots, group_id, &red->u.stroke, &qxl->u.stroke, flags);
 
1074
        break;
 
1075
    case QXL_DRAW_TEXT:
 
1076
        red_get_text_ptr(slots, group_id, &red->u.text, &qxl->u.text, flags);
 
1077
        break;
 
1078
    case QXL_DRAW_TRANSPARENT:
 
1079
        red_get_transparent_ptr(slots, group_id,
 
1080
                                &red->u.transparent, &qxl->u.transparent, flags);
 
1081
        break;
 
1082
    case QXL_DRAW_WHITENESS:
 
1083
        red_get_whiteness_ptr(slots, group_id,
 
1084
                              &red->u.whiteness, &qxl->u.whiteness, flags);
 
1085
        break;
 
1086
    default:
 
1087
        spice_warning("unknown type %d", red->type);
 
1088
        error = 1;
 
1089
        break;
 
1090
    };
 
1091
    return error;
 
1092
}
 
1093
 
 
1094
static int red_get_compat_drawable(RedMemSlotInfo *slots, int group_id,
 
1095
                                   RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
 
1096
{
 
1097
    QXLCompatDrawable *qxl;
 
1098
    int error;
 
1099
 
 
1100
    qxl = (QXLCompatDrawable *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
1101
    if (error) {
 
1102
        return error;
 
1103
    }
 
1104
    red->release_info     = &qxl->release_info;
 
1105
 
 
1106
    red_get_rect_ptr(&red->bbox, &qxl->bbox);
 
1107
    red_get_clip_ptr(slots, group_id, &red->clip, &qxl->clip);
 
1108
    red->effect           = qxl->effect;
 
1109
    red->mm_time          = qxl->mm_time;
 
1110
 
 
1111
    red->self_bitmap = (qxl->bitmap_offset != 0);
 
1112
    red_get_rect_ptr(&red->self_bitmap_area, &qxl->bitmap_area);
 
1113
 
 
1114
    red->surfaces_dest[0] = -1;
 
1115
    red->surfaces_dest[1] = -1;
 
1116
    red->surfaces_dest[2] = -1;
 
1117
 
 
1118
    red->type = qxl->type;
 
1119
    switch (red->type) {
 
1120
    case QXL_DRAW_ALPHA_BLEND:
 
1121
        red_get_alpha_blend_ptr_compat(slots, group_id,
 
1122
                                       &red->u.alpha_blend, &qxl->u.alpha_blend, flags);
 
1123
        break;
 
1124
    case QXL_DRAW_BLACKNESS:
 
1125
        red_get_blackness_ptr(slots, group_id,
 
1126
                              &red->u.blackness, &qxl->u.blackness, flags);
 
1127
        break;
 
1128
    case QXL_DRAW_BLEND:
 
1129
        red_get_blend_ptr(slots, group_id, &red->u.blend, &qxl->u.blend, flags);
 
1130
        break;
 
1131
    case QXL_DRAW_COPY:
 
1132
        error = red_get_copy_ptr(slots, group_id, &red->u.copy, &qxl->u.copy, flags);
 
1133
        break;
 
1134
    case QXL_COPY_BITS:
 
1135
        red_get_point_ptr(&red->u.copy_bits.src_pos, &qxl->u.copy_bits.src_pos);
 
1136
        red->surfaces_dest[0] = 0;
 
1137
        red->surfaces_rects[0].left   = red->u.copy_bits.src_pos.x;
 
1138
        red->surfaces_rects[0].right  = red->u.copy_bits.src_pos.x +
 
1139
            (red->bbox.right - red->bbox.left);
 
1140
        red->surfaces_rects[0].top    = red->u.copy_bits.src_pos.y;
 
1141
        red->surfaces_rects[0].bottom = red->u.copy_bits.src_pos.y +
 
1142
            (red->bbox.bottom - red->bbox.top);
 
1143
        break;
 
1144
    case QXL_DRAW_FILL:
 
1145
        red_get_fill_ptr(slots, group_id, &red->u.fill, &qxl->u.fill, flags);
 
1146
        break;
 
1147
    case QXL_DRAW_OPAQUE:
 
1148
        red_get_opaque_ptr(slots, group_id, &red->u.opaque, &qxl->u.opaque, flags);
 
1149
        break;
 
1150
    case QXL_DRAW_INVERS:
 
1151
        red_get_invers_ptr(slots, group_id, &red->u.invers, &qxl->u.invers, flags);
 
1152
        break;
 
1153
    case QXL_DRAW_NOP:
 
1154
        break;
 
1155
    case QXL_DRAW_ROP3:
 
1156
        red_get_rop3_ptr(slots, group_id, &red->u.rop3, &qxl->u.rop3, flags);
 
1157
        break;
 
1158
    case QXL_DRAW_STROKE:
 
1159
        error = red_get_stroke_ptr(slots, group_id, &red->u.stroke, &qxl->u.stroke, flags);
 
1160
        break;
 
1161
    case QXL_DRAW_TEXT:
 
1162
        red_get_text_ptr(slots, group_id, &red->u.text, &qxl->u.text, flags);
 
1163
        break;
 
1164
    case QXL_DRAW_TRANSPARENT:
 
1165
        red_get_transparent_ptr(slots, group_id,
 
1166
                                &red->u.transparent, &qxl->u.transparent, flags);
 
1167
        break;
 
1168
    case QXL_DRAW_WHITENESS:
 
1169
        red_get_whiteness_ptr(slots, group_id,
 
1170
                              &red->u.whiteness, &qxl->u.whiteness, flags);
 
1171
        break;
 
1172
    default:
 
1173
        spice_warning("unknown type %d", red->type);
 
1174
        error = 1;
 
1175
        break;
 
1176
    };
 
1177
    return error;
 
1178
}
 
1179
 
 
1180
int red_get_drawable(RedMemSlotInfo *slots, int group_id,
 
1181
                      RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
 
1182
{
 
1183
    int ret;
 
1184
 
 
1185
    if (flags & QXL_COMMAND_FLAG_COMPAT) {
 
1186
        ret = red_get_compat_drawable(slots, group_id, red, addr, flags);
 
1187
    } else {
 
1188
        ret = red_get_native_drawable(slots, group_id, red, addr, flags);
 
1189
    }
 
1190
    return ret;
 
1191
}
 
1192
 
 
1193
void red_put_drawable(RedDrawable *red)
 
1194
{
 
1195
    red_put_clip(&red->clip);
 
1196
    if (red->self_bitmap_image) {
 
1197
        red_put_image(red->self_bitmap_image);
 
1198
    }
 
1199
    switch (red->type) {
 
1200
    case QXL_DRAW_ALPHA_BLEND:
 
1201
        red_put_alpha_blend(&red->u.alpha_blend);
 
1202
        break;
 
1203
    case QXL_DRAW_BLACKNESS:
 
1204
        red_put_blackness(&red->u.blackness);
 
1205
        break;
 
1206
    case QXL_DRAW_BLEND:
 
1207
        red_put_blend(&red->u.blend);
 
1208
        break;
 
1209
    case QXL_DRAW_COPY:
 
1210
        red_put_copy(&red->u.copy);
 
1211
        break;
 
1212
    case QXL_DRAW_FILL:
 
1213
        red_put_fill(&red->u.fill);
 
1214
        break;
 
1215
    case QXL_DRAW_OPAQUE:
 
1216
        red_put_opaque(&red->u.opaque);
 
1217
        break;
 
1218
    case QXL_DRAW_INVERS:
 
1219
        red_put_invers(&red->u.invers);
 
1220
        break;
 
1221
    case QXL_DRAW_ROP3:
 
1222
        red_put_rop3(&red->u.rop3);
 
1223
        break;
 
1224
    case QXL_DRAW_COMPOSITE:
 
1225
        red_put_composite(&red->u.composite);
 
1226
        break;
 
1227
    case QXL_DRAW_STROKE:
 
1228
        red_put_stroke(&red->u.stroke);
 
1229
        break;
 
1230
    case QXL_DRAW_TEXT:
 
1231
        red_put_text_ptr(&red->u.text);
 
1232
        break;
 
1233
    case QXL_DRAW_TRANSPARENT:
 
1234
        red_put_transparent(&red->u.transparent);
 
1235
        break;
 
1236
    case QXL_DRAW_WHITENESS:
 
1237
        red_put_whiteness(&red->u.whiteness);
 
1238
        break;
 
1239
    }
 
1240
}
 
1241
 
 
1242
int red_get_update_cmd(RedMemSlotInfo *slots, int group_id,
 
1243
                       RedUpdateCmd *red, QXLPHYSICAL addr)
 
1244
{
 
1245
    QXLUpdateCmd *qxl;
 
1246
    int error;
 
1247
 
 
1248
    qxl = (QXLUpdateCmd *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
1249
    if (error) {
 
1250
        return 1;
 
1251
    }
 
1252
    red->release_info     = &qxl->release_info;
 
1253
 
 
1254
    red_get_rect_ptr(&red->area, &qxl->area);
 
1255
    red->update_id  = qxl->update_id;
 
1256
    red->surface_id = qxl->surface_id;
 
1257
    return 0;
 
1258
}
 
1259
 
 
1260
void red_put_update_cmd(RedUpdateCmd *red)
 
1261
{
 
1262
    /* nothing yet */
 
1263
}
 
1264
 
 
1265
int red_get_message(RedMemSlotInfo *slots, int group_id,
 
1266
                    RedMessage *red, QXLPHYSICAL addr)
 
1267
{
 
1268
    QXLMessage *qxl;
 
1269
    int error;
 
1270
 
 
1271
    /*
 
1272
     * security alert:
 
1273
     *   qxl->data[0] size isn't specified anywhere -> can't verify
 
1274
     *   luckily this is for debug logging only,
 
1275
     *   so we can just ignore it by default.
 
1276
     */
 
1277
    qxl = (QXLMessage *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
1278
    if (error) {
 
1279
        return 1;
 
1280
    }
 
1281
    red->release_info  = &qxl->release_info;
 
1282
    red->data          = qxl->data;
 
1283
    return 0;
 
1284
}
 
1285
 
 
1286
void red_put_message(RedMessage *red)
 
1287
{
 
1288
    /* nothing yet */
 
1289
}
 
1290
 
 
1291
static unsigned int surface_format_to_bpp(uint32_t format)
 
1292
{
 
1293
    switch (format) {
 
1294
    case SPICE_SURFACE_FMT_1_A:
 
1295
        return 1;
 
1296
    case SPICE_SURFACE_FMT_8_A:
 
1297
        return 8;
 
1298
    case SPICE_SURFACE_FMT_16_555:
 
1299
    case SPICE_SURFACE_FMT_16_565:
 
1300
        return 16;
 
1301
    case SPICE_SURFACE_FMT_32_xRGB:
 
1302
    case SPICE_SURFACE_FMT_32_ARGB:
 
1303
        return 32;
 
1304
    }
 
1305
    return 0;
 
1306
}
 
1307
 
 
1308
int red_get_surface_cmd(RedMemSlotInfo *slots, int group_id,
 
1309
                        RedSurfaceCmd *red, QXLPHYSICAL addr)
 
1310
{
 
1311
    QXLSurfaceCmd *qxl;
 
1312
    uint64_t size;
 
1313
    int error;
 
1314
    unsigned int bpp;
 
1315
 
 
1316
    qxl = (QXLSurfaceCmd *)get_virt(slots, addr, sizeof(*qxl), group_id,
 
1317
                                    &error);
 
1318
    if (error) {
 
1319
        return 1;
 
1320
    }
 
1321
    red->release_info     = &qxl->release_info;
 
1322
 
 
1323
    red->surface_id = qxl->surface_id;
 
1324
    red->type       = qxl->type;
 
1325
    red->flags      = qxl->flags;
 
1326
 
 
1327
    switch (red->type) {
 
1328
    case QXL_SURFACE_CMD_CREATE:
 
1329
        red->u.surface_create.format = qxl->u.surface_create.format;
 
1330
        red->u.surface_create.width  = qxl->u.surface_create.width;
 
1331
        red->u.surface_create.height = qxl->u.surface_create.height;
 
1332
        red->u.surface_create.stride = qxl->u.surface_create.stride;
 
1333
        bpp = surface_format_to_bpp(red->u.surface_create.format);
 
1334
 
 
1335
        /* check if format is valid */
 
1336
        if (!bpp) {
 
1337
            return 1;
 
1338
        }
 
1339
 
 
1340
        /* check stride is larger than required bytes */
 
1341
        size = ((uint64_t) red->u.surface_create.width * bpp + 7u) / 8u;
 
1342
        /* the uint32_t conversion is here to avoid problems with -2^31 value */
 
1343
        if (red->u.surface_create.stride == G_MININT32
 
1344
            || size > (uint32_t) abs(red->u.surface_create.stride)) {
 
1345
            return 1;
 
1346
        }
 
1347
 
 
1348
        /* the multiplication can overflow, also abs(-2^31) may return a negative value */
 
1349
        size = (uint64_t) red->u.surface_create.height * abs(red->u.surface_create.stride);
 
1350
        if (size > MAX_DATA_CHUNK) {
 
1351
            return 1;
 
1352
        }
 
1353
        red->u.surface_create.data =
 
1354
            (uint8_t*)get_virt(slots, qxl->u.surface_create.data, size, group_id, &error);
 
1355
        if (error) {
 
1356
            return 1;
 
1357
        }
 
1358
        break;
 
1359
    }
 
1360
    return 0;
 
1361
}
 
1362
 
 
1363
void red_put_surface_cmd(RedSurfaceCmd *red)
 
1364
{
 
1365
    /* nothing yet */
 
1366
}
 
1367
 
 
1368
static int red_get_cursor(RedMemSlotInfo *slots, int group_id,
 
1369
                          SpiceCursor *red, QXLPHYSICAL addr)
 
1370
{
 
1371
    QXLCursor *qxl;
 
1372
    RedDataChunk chunks;
 
1373
    size_t size;
 
1374
    uint8_t *data;
 
1375
    bool free_data;
 
1376
    int error;
 
1377
 
 
1378
    qxl = (QXLCursor *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
1379
    if (error) {
 
1380
        return 1;
 
1381
    }
 
1382
 
 
1383
    red->header.unique     = qxl->header.unique;
 
1384
    red->header.type       = qxl->header.type;
 
1385
    red->header.width      = qxl->header.width;
 
1386
    red->header.height     = qxl->header.height;
 
1387
    red->header.hot_spot_x = qxl->header.hot_spot_x;
 
1388
    red->header.hot_spot_y = qxl->header.hot_spot_y;
 
1389
 
 
1390
    red->flags = 0;
 
1391
    red->data_size = qxl->data_size;
 
1392
    size = red_get_data_chunks_ptr(slots, group_id,
 
1393
                                   get_memslot_id(slots, addr),
 
1394
                                   &chunks, &qxl->chunk);
 
1395
    data = red_linearize_chunk(&chunks, size, &free_data);
 
1396
    red_put_data_chunks(&chunks);
 
1397
    if (free_data) {
 
1398
        red->data = data;
 
1399
    } else {
 
1400
        red->data = spice_malloc(size);
 
1401
        memcpy(red->data, data, size);
 
1402
    }
 
1403
    return 0;
 
1404
}
 
1405
 
 
1406
static void red_put_cursor(SpiceCursor *red)
 
1407
{
 
1408
    free(red->data);
 
1409
}
 
1410
 
 
1411
int red_get_cursor_cmd(RedMemSlotInfo *slots, int group_id,
 
1412
                       RedCursorCmd *red, QXLPHYSICAL addr)
 
1413
{
 
1414
    QXLCursorCmd *qxl;
 
1415
    int error;
 
1416
 
 
1417
    qxl = (QXLCursorCmd *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
 
1418
    if (error) {
 
1419
        return error;
 
1420
    }
 
1421
    red->release_info     = &qxl->release_info;
 
1422
 
 
1423
    red->type = qxl->type;
 
1424
    switch (red->type) {
 
1425
    case QXL_CURSOR_SET:
 
1426
        red_get_point16_ptr(&red->u.set.position, &qxl->u.set.position);
 
1427
        red->u.set.visible  = qxl->u.set.visible;
 
1428
        error = red_get_cursor(slots, group_id,  &red->u.set.shape, qxl->u.set.shape);
 
1429
        break;
 
1430
    case QXL_CURSOR_MOVE:
 
1431
        red_get_point16_ptr(&red->u.position, &qxl->u.position);
 
1432
        break;
 
1433
    case QXL_CURSOR_TRAIL:
 
1434
        red->u.trail.length    = qxl->u.trail.length;
 
1435
        red->u.trail.frequency = qxl->u.trail.frequency;
 
1436
        break;
 
1437
    }
 
1438
    return error;
 
1439
}
 
1440
 
 
1441
void red_put_cursor_cmd(RedCursorCmd *red)
 
1442
{
 
1443
    switch (red->type) {
 
1444
    case QXL_CURSOR_SET:
 
1445
        red_put_cursor(&red->u.set.shape);
 
1446
        break;
 
1447
    }
 
1448
}