[Spice-devel] [PATCH spice-server v2] red-parse-qxl: Fix QUIC images from QXL
Uri Lublin
uril at redhat.com
Wed Jul 31 15:22:10 UTC 2019
On 7/24/19 2:37 PM, Frediano Ziglio wrote:
>>
>> Hi Frediano,
>>
>> On 7/23/19 11:21 PM, Frediano Ziglio wrote:
>>> The decoding is wrong, the Red and QXL structures are different so
>>> code is not doing what is expected. red-parse-qxl translate from QXL
>>> to Red structures, red-record-qxl saves Red structure to file,
>>> red-replay-qxl is supposed to read from file into QXL directly.
>>>
>>> If a Quic image is stored inside QXL memory the layout of the QXLImage
>>> in memory is:
>>> - QXLImageDescriptor
>>> - QXLQUICData
>>> - QXLDataChunk
>>> - first chunk data
>>> and all remaining data in linked QXLDataChunk.
>>> red_replay_image was reading the image as data was all contained in
>>> QXLImage->quic.data however "data" shoule store the first QXLDataChunk
>>
>> shoule -> should
>>
>
> I'll fix, thanks
>
>>> followed by QXLDataChunk data.
>>> Use proper base_size calling red_replay_data_chunks in order to
>>> initialise the image with the first data chunk correctly.
>>
>> I like this patch better then the first one.
>>
>>
>>
>>>
>>> Not easy to reproduce, the only driver is XDDM which means Windows XP
>>> or similars, I got no recording with such images.
>>>
>>> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
>>> ---
>>> server/red-replay-qxl.c | 17 ++++++++++-------
>>> 1 file changed, 10 insertions(+), 7 deletions(-)
>>>
>>> Changes v1:
>>> - realloc the buffer inside read_binary with the proper size.
>>> The proper size if not available in red_replay_image.
>>
>> Can we not just fix the above without moving the realloc call ?
>> Before only QUIC memory (which was malloc'ed) was realloc'ed.
>> With this other memory may be realloced.
>
> I checked all calls, only for QUIC the initial pointer is NULL
> so it will get reallocated.
>
>>
>> Allocate more memory (add sizeof(QXLDataChunk))
>> qxl = replay_realloc(replay, qxl, sizeof(QXLImageDescriptor)
>> + sizeof(QXLQUICData)
>> + sizeof(QXLDataChunk)
>> + qxl->quic.data_size);
>>
>
> No, I rather prefer patch version 1 instead. The replay code should
> attempt to allocate memory more like drivers. This will also help
> using sanitizer tools. In this specific case allocating a larger
> buffer will avoid some potential buffer overflow check.
>
> Looking more at the code I noted that in many places the "header"
> (information before chunks) are read into temporary variables
> then raw data is allocated with the structure than the structure
> header is filled (like red_replay_clip_rects for instance,
> another more complicated one is red_replay_cursor).
> The exception is red_replay_image where the "qxl" (in this case
> a QXLImage type) is allocated at the beginning. One difference
> between bitmap and quic is that "data" in QXLBitmap is a
> QXLPHYSICAL, not a uint8_t[0].
Yes, you are right. I think your V1 indeed fits better to
the code around.
I was able to reproduce with running windows XP guest and
setting -spice image-compression=quic on qemu-kvm command line.
It indeed crashes on master and fixed by V1 and V2.
>
>> Call red_replay_data_chunks as you do in this patch
>> Call red_replay_data_chunks_free as you do in this patch.
>>
>
> Surely the offset is wrong, is expected to be the offset of raw
> data to write.
Yes, the offset of original code is wrong but you fixed it in both
versions.
Uri.
>>
>>>
>>> diff --git a/server/red-replay-qxl.c b/server/red-replay-qxl.c
>>> index 674feae2f..1f1bd8c1d 100644
>>> --- a/server/red-replay-qxl.c
>>> +++ b/server/red-replay-qxl.c
>>> @@ -114,6 +114,9 @@ static inline void replay_free(SpiceReplay *replay,
>>> void *mem)
>>>
>>> static inline void *replay_realloc(SpiceReplay *replay, void *mem, size_t
>>> n_bytes)
>>> {
>>> + if (mem == NULL) {
>>> + return replay_malloc(replay, n_bytes);
>>> + }
>>> GList *elem = g_list_find(replay->allocated, mem);
>>> elem->data = g_realloc(mem, n_bytes);
>>> return elem->data;
>>> @@ -231,9 +234,7 @@ static replay_t read_binary(SpiceReplay *replay, const
>>> char *prefix, size_t *siz
>>> return REPLAY_ERROR;
>>> }
>>>
>>> - if (*buf == NULL) {
>>> - *buf = replay_malloc(replay, *size + base_size);
>>> - }
>>> + *buf = replay_realloc(replay, *buf, *size + base_size);
>>> #if 0
>>> {
>>> int num_read = fread(*buf + base_size, *size, 1, fd);
>>> @@ -497,9 +498,9 @@ static QXLImage *red_replay_image(SpiceReplay *replay,
>>> uint32_t flags)
>>> if (replay->error) {
>>> return NULL;
>>> }
>>> - qxl = replay_realloc(replay, qxl, sizeof(QXLImageDescriptor) +
>>> sizeof(QXLQUICData) +
>>> - qxl->quic.data_size);
>>> - size = red_replay_data_chunks(replay, "quic.data",
>>> (uint8_t**)&qxl->quic.data, 0);
>>> + size = red_replay_data_chunks(replay, "quic.data",
>>> (uint8_t**)&qxl,
>>> + sizeof(QXLImageDescriptor) +
>>> sizeof(QXLQUICData) +
>>> + sizeof(QXLDataChunk));
>>> spice_assert(size == qxl->quic.data_size);
>>> break;
>>> default:
>>> @@ -526,7 +527,9 @@ static void red_replay_image_free(SpiceReplay *replay,
>>> QXLPHYSICAL p, uint32_t f
>>> case SPICE_IMAGE_TYPE_SURFACE:
>>> break;
>>> case SPICE_IMAGE_TYPE_QUIC:
>>> - red_replay_data_chunks_free(replay, qxl, 0);
>>> + red_replay_data_chunks_free(replay, qxl,
>>> + sizeof(QXLImageDescriptor) +
>>> sizeof(QXLQUICData) +
>>> + sizeof(QXLDataChunk));
>>> qxl = NULL;
>>> break;
>>> default:
>>>
More information about the Spice-devel
mailing list