@samitouri / QOSamiQemu / commits / 1d9688c074

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>

Arun Menon committed Apr 23, 2026 at 16:27 UTC 1d9688c07408c33e8a684f79fd1294326c3bda5b
2 files changed +38
include/migration/vmstate.h
+10
@@ -308,6 +308,7 @@ extern const VMStateInfo vmstate_info_bitmap;
308 extern const VMStateInfo vmstate_info_qtailq;
309 extern const VMStateInfo vmstate_info_gtree;
310 extern const VMStateInfo vmstate_info_qlist;
311 +extern const VMStateInfo vmstate_info_g_byte_array;
312
313 #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
314 /*
@@ -957,6 +958,15 @@ extern const VMStateInfo vmstate_info_qlist;
958 .start = offsetof(_type, _next), \
959 }
960
961 +#define VMSTATE_GBYTEARRAY(_field, _state, _version) { \
962 + .name = (stringify(_field)), \
963 + .version_id = (_version), \
964 + .size = sizeof(GByteArray), \
965 + .info = &vmstate_info_g_byte_array, \
966 + .flags = VMS_SINGLE, \
967 + .offset = vmstate_offset_pointer(_state, _field, GByteArray), \
968 +}
969 +
970 /* _f : field name
971 _f_n : num of elements field_name
972 _n : num of elements
migration/vmstate-types.c
+28
@@ -924,3 +924,31 @@ const VMStateInfo vmstate_info_qlist = {
924 .load = load_qlist,
925 .save = save_qlist,
926 };
927 +
928 +static int get_g_byte_array(QEMUFile *f, void *pv, size_t size,
929 + const VMStateField *field)
930 +{
931 + GByteArray *byte_array = *(GByteArray **)pv;
932 + uint32_t len = qemu_get_be32(f);
933 +
934 + g_byte_array_set_size(byte_array, len);
935 + qemu_get_buffer(f, byte_array->data, len);
936 + return 0;
937 +}
938 +
939 +static int put_g_byte_array(QEMUFile *f, void *pv, size_t size,
940 + const VMStateField *field, JSONWriter *vmdesc)
941 +{
942 + GByteArray *byte_array = *(GByteArray **)pv;
943 +
944 + qemu_put_be32(f, byte_array->len);
945 + qemu_put_buffer(f, byte_array->data, byte_array->len);
946 +
947 + return 0;
948 +}
949 +
950 +const VMStateInfo vmstate_info_g_byte_array = {
951 + .name = "GByteArray",
952 + .get = get_g_byte_array,
953 + .put = put_g_byte_array,
954 +};