1
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3
Copyright (C) 2009,2010 Red Hat, Inc.
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.
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.
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/>.
25
#include "common/lz_common.h"
26
#include "red_common.h"
27
#include "red_memslots.h"
28
#include "red_parse_qxl.h"
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.
36
#define MAX_DATA_CHUNK 0x7ffffffflu
38
G_STATIC_ASSERT(MAX_DATA_CHUNK <= G_MAXINT32);
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.
45
#define MAX_CHUNKS (MAX_DATA_CHUNK/1024u)
48
static void hexdump_qxl(RedMemSlotInfo *slots, int group_id,
49
QXLPHYSICAL addr, uint8_t bytes)
54
hex = (uint8_t*)get_virt(slots, addr, bytes, group_id);
55
for (i = 0; i < bytes; i++) {
57
fprintf(stderr, "%lx: ", addr+i);
62
fprintf(stderr, " %02x", hex[i]);
64
fprintf(stderr, "\n");
70
static inline uint32_t color_16_to_32(uint32_t color)
74
ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
75
ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
76
ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
81
static uint8_t *red_linearize_chunk(RedDataChunk *head, size_t size, bool *free_chunk)
87
if (head->next_chunk == NULL) {
88
spice_assert(size <= head->data_size);
93
ptr = data = spice_malloc(size);
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);
101
spice_assert(size == 0);
105
static size_t red_get_data_chunks_ptr(RedMemSlotInfo *slots, int group_id,
107
RedDataChunk *red, QXLDataChunk *qxl)
109
RedDataChunk *red_prev;
110
uint64_t data_size = 0;
111
uint32_t chunk_data_size;
113
QXLPHYSICAL next_chunk;
114
unsigned num_chunks = 0;
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)) {
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
129
if (++num_chunks >= MAX_CHUNKS) {
130
spice_warning("data split in too many chunks, avoiding DoS\n");
134
memslot_id = get_memslot_id(slots, next_chunk);
135
qxl = (QXLDataChunk *)get_virt(slots, next_chunk, sizeof(*qxl),
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
146
chunk_data_size = qxl->data_size;
147
if (chunk_data_size == 0)
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;
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");
163
if (!validate_virt(slots, (intptr_t)red->data, memslot_id, red->data_size, group_id))
167
red->next_chunk = NULL;
171
while (red->prev_chunk) {
172
red_prev = red->prev_chunk;
177
red->next_chunk = NULL;
182
static size_t red_get_data_chunks(RedMemSlotInfo *slots, int group_id,
183
RedDataChunk *red, QXLPHYSICAL addr)
187
int memslot_id = get_memslot_id(slots, addr);
189
qxl = (QXLDataChunk *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
193
return red_get_data_chunks_ptr(slots, group_id, memslot_id, red, qxl);
196
static void red_put_data_chunks(RedDataChunk *red)
200
red = red->next_chunk;
203
red = red->next_chunk;
208
static void red_get_point_ptr(SpicePoint *red, QXLPoint *qxl)
214
static void red_get_point16_ptr(SpicePoint16 *red, QXLPoint16 *qxl)
220
void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl)
223
red->left = qxl->left;
224
red->bottom = qxl->bottom;
225
red->right = qxl->right;
228
static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
232
QXLPathSeg *start, *end;
238
size_t size, mem_size, mem_size2, dsize, segment_size;
244
qxl = (QXLPath *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
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);
255
mem_size = sizeof(*red);
257
start = (QXLPathSeg*)data;
258
end = (QXLPathSeg*)(data + size);
259
while (start+1 < end) {
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]);
267
red = spice_malloc(mem_size);
268
red->num_segments = n_segments;
270
start = (QXLPathSeg*)data;
271
end = (QXLPathSeg*)(data + size);
272
seg = (SpicePathSeg*)&red->segments[n_segments];
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;
279
/* Protect against overflow in size calculations before
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);
288
/* Verify that we didn't overflow due to guest changing data */
289
spice_assert(mem_size2 <= mem_size);
291
seg->flags = start->flags;
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;
297
start = (QXLPathSeg*)(&start->points[i]);
298
seg = (SpicePathSeg*)(&seg->points[i]);
300
/* Ensure guest didn't tamper with segment count */
301
spice_assert(n_segments == red->num_segments);
309
static SpiceClipRects *red_get_clip_rects(RedMemSlotInfo *slots, int group_id,
323
qxl = (QXLClipRects *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
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);
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;
338
start = (QXLRect*)data;
339
for (i = 0; i < red->num_rects; i++) {
340
red_get_rect_ptr(red->rects + i, start++);
349
static SpiceChunks *red_get_image_data_flat(RedMemSlotInfo *slots, int group_id,
350
QXLPHYSICAL addr, size_t size)
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);
361
data->chunk[0].len = size;
365
static SpiceChunks *red_get_image_data_chunked(RedMemSlotInfo *slots, int group_id,
372
for (i = 0, chunk = head; chunk != NULL; chunk = chunk->next_chunk) {
376
data = spice_chunks_new(i);
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;
385
spice_assert(i == data->num_chunks);
389
static const char *bitmap_format_to_string(int 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";
407
static const unsigned int MAP_BITMAP_FMT_TO_BITS_PER_PIXEL[] =
408
{0, 1, 1, 4, 4, 8, 16, 24, 32, 32, 8};
410
static int bitmap_consistent(SpiceBitmap *bitmap)
414
if (bitmap->format >= SPICE_N_ELEMENTS(MAP_BITMAP_FMT_TO_BITS_PER_PIXEL)) {
415
spice_warning("wrong format specified for image\n");
419
bpp = MAP_BITMAP_FMT_TO_BITS_PER_PIXEL[bitmap->format];
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),
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};
435
static SpiceImage *red_get_image(RedMemSlotInfo *slots, int group_id,
436
QXLPHYSICAL addr, uint32_t flags, int is_mask)
440
SpiceImage *red = NULL;
441
SpicePalette *rp = NULL;
442
uint64_t bitmap_size, size;
451
qxl = (QXLImage *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
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;
462
if (qxl->descriptor.flags & QXL_IMAGE_CACHE) {
463
red->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
465
red->descriptor.width = qxl->descriptor.width;
466
red->descriptor.height = qxl->descriptor.height;
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);
480
if (red->u.bitmap.x == 0 || red->u.bitmap.y == 0) {
481
spice_warning("guest error: zero area bitmap\n");
484
qxl_flags = qxl->bitmap.flags;
485
if (qxl_flags & QXL_BITMAP_TOP_DOWN) {
486
red->u.bitmap.flags = SPICE_BITMAP_FLAGS_TOP_DOWN;
488
if (!bitmap_consistent(&red->u.bitmap)) {
494
qp = (QXLPalette *)get_virt(slots, palette,
495
sizeof(*qp), group_id, &error);
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)) {
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]);
513
for (i = 0; i < num_ents; i++) {
514
rp->ents[i] = qp->ents[i];
517
red->u.bitmap.palette = rp;
518
red->u.bitmap.palette_id = rp->unique;
520
bitmap_size = (uint64_t) red->u.bitmap.y * red->u.bitmap.stride;
521
if (bitmap_size > MAX_DATA_CHUNK) {
524
if (qxl_flags & QXL_BITMAP_DIRECT) {
525
red->u.bitmap.data = red_get_image_data_flat(slots, group_id,
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) {
535
red->u.bitmap.data = red_get_image_data_chunked(slots, group_id,
537
red_put_data_chunks(&chunks);
539
if (qxl_flags & QXL_BITMAP_UNSTABLE) {
540
red->u.bitmap.data->flags |= SPICE_CHUNKS_FLAGS_UNSTABLE;
543
case SPICE_IMAGE_TYPE_SURFACE:
544
red->u.surface.surface_id = qxl->surface_image.surface_id;
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) {
555
red->u.quic.data = red_get_image_data_chunked(slots, group_id,
557
red_put_data_chunks(&chunks);
560
spice_warning("unknown type %d", red->descriptor.type);
570
void red_put_image(SpiceImage *red)
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);
580
case SPICE_IMAGE_TYPE_QUIC:
581
spice_chunks_destroy(red->u.quic.data);
587
static void red_get_brush_ptr(RedMemSlotInfo *slots, int group_id,
588
SpiceBrush *red, QXLBrush *qxl, uint32_t flags)
590
red->type = qxl->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);
596
red->u.color = qxl->u.color;
599
case SPICE_BRUSH_TYPE_PATTERN:
600
red->u.pattern.pat = red_get_image(slots, group_id, qxl->u.pattern.pat, flags, FALSE);
605
static void red_put_brush(SpiceBrush *red)
608
case SPICE_BRUSH_TYPE_PATTERN:
609
red_put_image(red->u.pattern.pat);
614
static void red_get_qmask_ptr(RedMemSlotInfo *slots, int group_id,
615
SpiceQMask *red, QXLQMask *qxl, uint32_t flags)
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);
622
static void red_put_qmask(SpiceQMask *red)
624
red_put_image(red->bitmap);
627
static void red_get_fill_ptr(RedMemSlotInfo *slots, int group_id,
628
SpiceFill *red, QXLFill *qxl, uint32_t flags)
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);
635
static void red_put_fill(SpiceFill *red)
637
red_put_brush(&red->brush);
638
red_put_qmask(&red->mask);
641
static void red_get_opaque_ptr(RedMemSlotInfo *slots, int group_id,
642
SpiceOpaque *red, QXLOpaque *qxl, uint32_t flags)
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);
652
static void red_put_opaque(SpiceOpaque *red)
654
red_put_image(red->src_bitmap);
655
red_put_brush(&red->brush);
656
red_put_qmask(&red->mask);
659
static int red_get_copy_ptr(RedMemSlotInfo *slots, int group_id,
660
SpiceCopy *red, QXLCopy *qxl, uint32_t flags)
662
red->src_bitmap = red_get_image(slots, group_id, qxl->src_bitmap, flags, FALSE);
663
if (!red->src_bitmap) {
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);
673
static void red_put_copy(SpiceCopy *red)
675
red_put_image(red->src_bitmap);
676
red_put_qmask(&red->mask);
679
static void red_get_blend_ptr(RedMemSlotInfo *slots, int group_id,
680
SpiceBlend *red, QXLBlend *qxl, uint32_t flags)
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);
689
static void red_put_blend(SpiceBlend *red)
691
red_put_image(red->src_bitmap);
692
red_put_qmask(&red->mask);
695
static void red_get_transparent_ptr(RedMemSlotInfo *slots, int group_id,
696
SpiceTransparent *red, QXLTransparent *qxl,
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;
705
static void red_put_transparent(SpiceTransparent *red)
707
red_put_image(red->src_bitmap);
710
static void red_get_alpha_blend_ptr(RedMemSlotInfo *slots, int group_id,
711
SpiceAlphaBlend *red, QXLAlphaBlend *qxl,
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);
720
static void red_get_alpha_blend_ptr_compat(RedMemSlotInfo *slots, int group_id,
721
SpiceAlphaBlend *red, QXLCompatAlphaBlend *qxl,
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);
729
static void red_put_alpha_blend(SpiceAlphaBlend *red)
731
red_put_image(red->src_bitmap);
734
static bool get_transform(RedMemSlotInfo *slots,
736
QXLPHYSICAL qxl_transform,
737
SpiceTransform *dst_transform)
739
const uint32_t *t = NULL;
742
if (qxl_transform == 0)
745
t = (uint32_t *)get_virt(slots, qxl_transform, sizeof(*dst_transform), group_id, &error);
750
memcpy(dst_transform, t, sizeof(*dst_transform));
754
static void red_get_composite_ptr(RedMemSlotInfo *slots, int group_id,
755
SpiceComposite *red, QXLComposite *qxl, uint32_t flags)
757
red->flags = qxl->flags;
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;
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;
769
red->mask_bitmap = NULL;
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;
777
static void red_put_composite(SpiceComposite *red)
779
red_put_image(red->src_bitmap);
780
if (red->mask_bitmap)
781
red_put_image(red->mask_bitmap);
784
static void red_get_rop3_ptr(RedMemSlotInfo *slots, int group_id,
785
SpiceRop3 *red, QXLRop3 *qxl, uint32_t flags)
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);
795
static void red_put_rop3(SpiceRop3 *red)
797
red_put_image(red->src_bitmap);
798
red_put_brush(&red->brush);
799
red_put_qmask(&red->mask);
802
static int red_get_stroke_ptr(RedMemSlotInfo *slots, int group_id,
803
SpiceStroke *red, QXLStroke *qxl, uint32_t flags)
807
red->path = red_get_path(slots, group_id, qxl->path);
811
red->attr.flags = qxl->attr.flags;
812
if (red->attr.flags & SPICE_LINE_FLAGS_STYLED) {
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);
825
memcpy(red->attr.style, buf, style_nseg * sizeof(QXLFIXED));
827
red->attr.style_nseg = 0;
828
red->attr.style = NULL;
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;
836
static void red_put_stroke(SpiceStroke *red)
838
red_put_brush(&red->brush);
840
if (red->attr.flags & SPICE_LINE_FLAGS_STYLED) {
841
free(red->attr.style);
845
static SpiceString *red_get_string(RedMemSlotInfo *slots, int group_id,
850
QXLRasterGlyph *start, *end;
852
SpiceRasterGlyph *glyph;
855
size_t chunk_size, qxl_size, red_size, glyph_size;
857
/* use unsigned to prevent integer overflow in multiplication below */
858
unsigned int bpp = 0;
860
uint16_t qxl_flags, qxl_length;
862
qxl = (QXLString *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
866
chunk_size = red_get_data_chunks_ptr(slots, group_id,
867
get_memslot_id(slots, addr),
868
&chunks, &qxl->chunk);
870
/* XXX could be a zero sized string.. */
873
data = red_linearize_chunk(&chunks, chunk_size, &free_data);
874
red_put_data_chunks(&chunks);
876
qxl_size = qxl->data_size;
877
qxl_flags = qxl->flags;
878
qxl_length = qxl->length;
879
spice_assert(chunk_size == qxl_size);
881
if (qxl_flags & SPICE_STRING_FLAGS_RASTER_A1) {
883
} else if (qxl_flags & SPICE_STRING_FLAGS_RASTER_A4) {
885
} else if (qxl_flags & SPICE_STRING_FLAGS_RASTER_A8) {
888
spice_assert(bpp != 0);
890
start = (QXLRasterGlyph*)data;
891
end = (QXLRasterGlyph*)(data + chunk_size);
892
red_size = sizeof(SpiceString);
894
while (start < end) {
895
spice_assert((QXLRasterGlyph*)(&start->data[0]) <= end);
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]);
906
spice_assert(start <= end);
907
spice_assert(glyphs == qxl_length);
909
red = spice_malloc(red_size);
910
red->length = qxl_length;
911
red->flags = qxl_flags;
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));
939
static void red_get_text_ptr(RedMemSlotInfo *slots, int group_id,
940
SpiceText *red, QXLText *qxl, uint32_t flags)
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;
950
static void red_put_text_ptr(SpiceText *red)
953
red_put_brush(&red->fore_brush);
954
red_put_brush(&red->back_brush);
957
static void red_get_whiteness_ptr(RedMemSlotInfo *slots, int group_id,
958
SpiceWhiteness *red, QXLWhiteness *qxl, uint32_t flags)
960
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
963
static void red_put_whiteness(SpiceWhiteness *red)
965
red_put_qmask(&red->mask);
968
static void red_get_blackness_ptr(RedMemSlotInfo *slots, int group_id,
969
SpiceBlackness *red, QXLBlackness *qxl, uint32_t flags)
971
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
974
static void red_put_blackness(SpiceWhiteness *red)
976
red_put_qmask(&red->mask);
979
static void red_get_invers_ptr(RedMemSlotInfo *slots, int group_id,
980
SpiceInvers *red, QXLInvers *qxl, uint32_t flags)
982
red_get_qmask_ptr(slots, group_id, &red->mask, &qxl->mask, flags);
985
static void red_put_invers(SpiceWhiteness *red)
987
red_put_qmask(&red->mask);
990
static void red_get_clip_ptr(RedMemSlotInfo *slots, int group_id,
991
SpiceClip *red, QXLClip *qxl)
993
red->type = qxl->type;
995
case SPICE_CLIP_TYPE_RECTS:
996
red->rects = red_get_clip_rects(slots, group_id, qxl->data);
1001
static void red_put_clip(SpiceClip *red)
1003
switch (red->type) {
1004
case SPICE_CLIP_TYPE_RECTS:
1010
static int red_get_native_drawable(RedMemSlotInfo *slots, int group_id,
1011
RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
1017
qxl = (QXLDrawable *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1021
red->release_info = &qxl->release_info;
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;
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]);
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);
1042
case QXL_DRAW_BLACKNESS:
1043
red_get_blackness_ptr(slots, group_id,
1044
&red->u.blackness, &qxl->u.blackness, flags);
1046
case QXL_DRAW_BLEND:
1047
red_get_blend_ptr(slots, group_id, &red->u.blend, &qxl->u.blend, flags);
1050
error = red_get_copy_ptr(slots, group_id, &red->u.copy, &qxl->u.copy, flags);
1053
red_get_point_ptr(&red->u.copy_bits.src_pos, &qxl->u.copy_bits.src_pos);
1056
red_get_fill_ptr(slots, group_id, &red->u.fill, &qxl->u.fill, flags);
1058
case QXL_DRAW_OPAQUE:
1059
red_get_opaque_ptr(slots, group_id, &red->u.opaque, &qxl->u.opaque, flags);
1061
case QXL_DRAW_INVERS:
1062
red_get_invers_ptr(slots, group_id, &red->u.invers, &qxl->u.invers, flags);
1067
red_get_rop3_ptr(slots, group_id, &red->u.rop3, &qxl->u.rop3, flags);
1069
case QXL_DRAW_COMPOSITE:
1070
red_get_composite_ptr(slots, group_id, &red->u.composite, &qxl->u.composite, flags);
1072
case QXL_DRAW_STROKE:
1073
error = red_get_stroke_ptr(slots, group_id, &red->u.stroke, &qxl->u.stroke, flags);
1076
red_get_text_ptr(slots, group_id, &red->u.text, &qxl->u.text, flags);
1078
case QXL_DRAW_TRANSPARENT:
1079
red_get_transparent_ptr(slots, group_id,
1080
&red->u.transparent, &qxl->u.transparent, flags);
1082
case QXL_DRAW_WHITENESS:
1083
red_get_whiteness_ptr(slots, group_id,
1084
&red->u.whiteness, &qxl->u.whiteness, flags);
1087
spice_warning("unknown type %d", red->type);
1094
static int red_get_compat_drawable(RedMemSlotInfo *slots, int group_id,
1095
RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
1097
QXLCompatDrawable *qxl;
1100
qxl = (QXLCompatDrawable *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1104
red->release_info = &qxl->release_info;
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;
1111
red->self_bitmap = (qxl->bitmap_offset != 0);
1112
red_get_rect_ptr(&red->self_bitmap_area, &qxl->bitmap_area);
1114
red->surfaces_dest[0] = -1;
1115
red->surfaces_dest[1] = -1;
1116
red->surfaces_dest[2] = -1;
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);
1124
case QXL_DRAW_BLACKNESS:
1125
red_get_blackness_ptr(slots, group_id,
1126
&red->u.blackness, &qxl->u.blackness, flags);
1128
case QXL_DRAW_BLEND:
1129
red_get_blend_ptr(slots, group_id, &red->u.blend, &qxl->u.blend, flags);
1132
error = red_get_copy_ptr(slots, group_id, &red->u.copy, &qxl->u.copy, flags);
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);
1145
red_get_fill_ptr(slots, group_id, &red->u.fill, &qxl->u.fill, flags);
1147
case QXL_DRAW_OPAQUE:
1148
red_get_opaque_ptr(slots, group_id, &red->u.opaque, &qxl->u.opaque, flags);
1150
case QXL_DRAW_INVERS:
1151
red_get_invers_ptr(slots, group_id, &red->u.invers, &qxl->u.invers, flags);
1156
red_get_rop3_ptr(slots, group_id, &red->u.rop3, &qxl->u.rop3, flags);
1158
case QXL_DRAW_STROKE:
1159
error = red_get_stroke_ptr(slots, group_id, &red->u.stroke, &qxl->u.stroke, flags);
1162
red_get_text_ptr(slots, group_id, &red->u.text, &qxl->u.text, flags);
1164
case QXL_DRAW_TRANSPARENT:
1165
red_get_transparent_ptr(slots, group_id,
1166
&red->u.transparent, &qxl->u.transparent, flags);
1168
case QXL_DRAW_WHITENESS:
1169
red_get_whiteness_ptr(slots, group_id,
1170
&red->u.whiteness, &qxl->u.whiteness, flags);
1173
spice_warning("unknown type %d", red->type);
1180
int red_get_drawable(RedMemSlotInfo *slots, int group_id,
1181
RedDrawable *red, QXLPHYSICAL addr, uint32_t flags)
1185
if (flags & QXL_COMMAND_FLAG_COMPAT) {
1186
ret = red_get_compat_drawable(slots, group_id, red, addr, flags);
1188
ret = red_get_native_drawable(slots, group_id, red, addr, flags);
1193
void red_put_drawable(RedDrawable *red)
1195
red_put_clip(&red->clip);
1196
if (red->self_bitmap_image) {
1197
red_put_image(red->self_bitmap_image);
1199
switch (red->type) {
1200
case QXL_DRAW_ALPHA_BLEND:
1201
red_put_alpha_blend(&red->u.alpha_blend);
1203
case QXL_DRAW_BLACKNESS:
1204
red_put_blackness(&red->u.blackness);
1206
case QXL_DRAW_BLEND:
1207
red_put_blend(&red->u.blend);
1210
red_put_copy(&red->u.copy);
1213
red_put_fill(&red->u.fill);
1215
case QXL_DRAW_OPAQUE:
1216
red_put_opaque(&red->u.opaque);
1218
case QXL_DRAW_INVERS:
1219
red_put_invers(&red->u.invers);
1222
red_put_rop3(&red->u.rop3);
1224
case QXL_DRAW_COMPOSITE:
1225
red_put_composite(&red->u.composite);
1227
case QXL_DRAW_STROKE:
1228
red_put_stroke(&red->u.stroke);
1231
red_put_text_ptr(&red->u.text);
1233
case QXL_DRAW_TRANSPARENT:
1234
red_put_transparent(&red->u.transparent);
1236
case QXL_DRAW_WHITENESS:
1237
red_put_whiteness(&red->u.whiteness);
1242
int red_get_update_cmd(RedMemSlotInfo *slots, int group_id,
1243
RedUpdateCmd *red, QXLPHYSICAL addr)
1248
qxl = (QXLUpdateCmd *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1252
red->release_info = &qxl->release_info;
1254
red_get_rect_ptr(&red->area, &qxl->area);
1255
red->update_id = qxl->update_id;
1256
red->surface_id = qxl->surface_id;
1260
void red_put_update_cmd(RedUpdateCmd *red)
1265
int red_get_message(RedMemSlotInfo *slots, int group_id,
1266
RedMessage *red, QXLPHYSICAL addr)
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.
1277
qxl = (QXLMessage *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1281
red->release_info = &qxl->release_info;
1282
red->data = qxl->data;
1286
void red_put_message(RedMessage *red)
1291
static unsigned int surface_format_to_bpp(uint32_t format)
1294
case SPICE_SURFACE_FMT_1_A:
1296
case SPICE_SURFACE_FMT_8_A:
1298
case SPICE_SURFACE_FMT_16_555:
1299
case SPICE_SURFACE_FMT_16_565:
1301
case SPICE_SURFACE_FMT_32_xRGB:
1302
case SPICE_SURFACE_FMT_32_ARGB:
1308
int red_get_surface_cmd(RedMemSlotInfo *slots, int group_id,
1309
RedSurfaceCmd *red, QXLPHYSICAL addr)
1316
qxl = (QXLSurfaceCmd *)get_virt(slots, addr, sizeof(*qxl), group_id,
1321
red->release_info = &qxl->release_info;
1323
red->surface_id = qxl->surface_id;
1324
red->type = qxl->type;
1325
red->flags = qxl->flags;
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);
1335
/* check if format is valid */
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)) {
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) {
1353
red->u.surface_create.data =
1354
(uint8_t*)get_virt(slots, qxl->u.surface_create.data, size, group_id, &error);
1363
void red_put_surface_cmd(RedSurfaceCmd *red)
1368
static int red_get_cursor(RedMemSlotInfo *slots, int group_id,
1369
SpiceCursor *red, QXLPHYSICAL addr)
1372
RedDataChunk chunks;
1378
qxl = (QXLCursor *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
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;
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);
1400
red->data = spice_malloc(size);
1401
memcpy(red->data, data, size);
1406
static void red_put_cursor(SpiceCursor *red)
1411
int red_get_cursor_cmd(RedMemSlotInfo *slots, int group_id,
1412
RedCursorCmd *red, QXLPHYSICAL addr)
1417
qxl = (QXLCursorCmd *)get_virt(slots, addr, sizeof(*qxl), group_id, &error);
1421
red->release_info = &qxl->release_info;
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);
1430
case QXL_CURSOR_MOVE:
1431
red_get_point16_ptr(&red->u.position, &qxl->u.position);
1433
case QXL_CURSOR_TRAIL:
1434
red->u.trail.length = qxl->u.trail.length;
1435
red->u.trail.frequency = qxl->u.trail.frequency;
1441
void red_put_cursor_cmd(RedCursorCmd *red)
1443
switch (red->type) {
1444
case QXL_CURSOR_SET:
1445
red_put_cursor(&red->u.set.shape);