migration/vmstate: Add VMState support for GByteArray

In GLib, GByteArray is an object managed by the library. Currently,
migrating a GByteArray requires treating it as a raw C struct and using
VMSTATE_VBUFFER_ALLOC_UINT32. For example, see vmstate_vdba in
ui/vdagent.c

QEMU cannot pretend that GByteArray is a C struct and simply use
VMS_ALLOC to g_malloc() the buffer. This is because, VMS_ALLOC blindly
overwrites the data pointer with a newly allocated buffer, thereby
leaking the previous memory. Besides, GLib tracks the array's capacity
in a hidden alloc field. Bypassing GLib APIs leave this capacity out of
sync with the newly allocated buffer, potentially leading to heap buffer
overflows during subsequent g_byte_array_append() calls.

This commit introduces VMSTATE_GBYTEARRAY which uses specific library
API calls (g_byte_array_set_size()) to safely resize and populate the
buffer.

Signed-off-by: Arun Menon <armenon@redhat.com>
Suggested-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260423105733.113046-2-armenon@redhat.com
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Arun Menon
2026-04-23 16:27:32 +05:30
committed by Stefan Berger
parent a94f1c2eff
commit 1d9688c074
2 changed files with 38 additions and 0 deletions

View File

@@ -308,6 +308,7 @@ extern const VMStateInfo vmstate_info_bitmap;
extern const VMStateInfo vmstate_info_qtailq; extern const VMStateInfo vmstate_info_qtailq;
extern const VMStateInfo vmstate_info_gtree; extern const VMStateInfo vmstate_info_gtree;
extern const VMStateInfo vmstate_info_qlist; extern const VMStateInfo vmstate_info_qlist;
extern const VMStateInfo vmstate_info_g_byte_array;
#define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0) #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
/* /*
@@ -957,6 +958,15 @@ extern const VMStateInfo vmstate_info_qlist;
.start = offsetof(_type, _next), \ .start = offsetof(_type, _next), \
} }
#define VMSTATE_GBYTEARRAY(_field, _state, _version) { \
.name = (stringify(_field)), \
.version_id = (_version), \
.size = sizeof(GByteArray), \
.info = &vmstate_info_g_byte_array, \
.flags = VMS_SINGLE, \
.offset = vmstate_offset_pointer(_state, _field, GByteArray), \
}
/* _f : field name /* _f : field name
_f_n : num of elements field_name _f_n : num of elements field_name
_n : num of elements _n : num of elements

View File

@@ -924,3 +924,31 @@ const VMStateInfo vmstate_info_qlist = {
.load = load_qlist, .load = load_qlist,
.save = save_qlist, .save = save_qlist,
}; };
static int get_g_byte_array(QEMUFile *f, void *pv, size_t size,
const VMStateField *field)
{
GByteArray *byte_array = *(GByteArray **)pv;
uint32_t len = qemu_get_be32(f);
g_byte_array_set_size(byte_array, len);
qemu_get_buffer(f, byte_array->data, len);
return 0;
}
static int put_g_byte_array(QEMUFile *f, void *pv, size_t size,
const VMStateField *field, JSONWriter *vmdesc)
{
GByteArray *byte_array = *(GByteArray **)pv;
qemu_put_be32(f, byte_array->len);
qemu_put_buffer(f, byte_array->data, byte_array->len);
return 0;
}
const VMStateInfo vmstate_info_g_byte_array = {
.name = "GByteArray",
.get = get_g_byte_array,
.put = put_g_byte_array,
};