1 /* 2 * QEMU dbus-vmstate 3 * 4 * Copyright (C) 2019 Red Hat Inc 5 * 6 * Authors: 7 * Marc-André Lureau <marcandre.lureau@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qemu/units.h" 15 #include "qemu/dbus.h" 16 #include "qemu/error-report.h" 17 #include "qapi/error.h" 18 #include "qom/object_interfaces.h" 19 #include "qapi/qmp/qerror.h" 20 #include "migration/vmstate.h" 21 #include "trace.h" 22 #include "qom/object.h" 23 24 typedef struct DBusVMState DBusVMState; 25 typedef struct DBusVMStateClass DBusVMStateClass; 26 27 #define TYPE_DBUS_VMSTATE "dbus-vmstate" 28 #define DBUS_VMSTATE(obj) \ 29 OBJECT_CHECK(DBusVMState, (obj), TYPE_DBUS_VMSTATE) 30 #define DBUS_VMSTATE_GET_CLASS(obj) \ 31 OBJECT_GET_CLASS(DBusVMStateClass, (obj), TYPE_DBUS_VMSTATE) 32 #define DBUS_VMSTATE_CLASS(klass) \ 33 OBJECT_CLASS_CHECK(DBusVMStateClass, (klass), TYPE_DBUS_VMSTATE) 34 35 struct DBusVMStateClass { 36 ObjectClass parent_class; 37 }; 38 39 struct DBusVMState { 40 Object parent; 41 42 GDBusConnection *bus; 43 char *dbus_addr; 44 char *id_list; 45 46 uint32_t data_size; 47 uint8_t *data; 48 }; 49 50 static const GDBusPropertyInfo vmstate_property_info[] = { 51 { -1, (char *) "Id", (char *) "s", 52 G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL }, 53 }; 54 55 static const GDBusPropertyInfo * const vmstate_property_info_pointers[] = { 56 &vmstate_property_info[0], 57 NULL 58 }; 59 60 static const GDBusInterfaceInfo vmstate1_interface_info = { 61 -1, 62 (char *) "org.qemu.VMState1", 63 (GDBusMethodInfo **) NULL, 64 (GDBusSignalInfo **) NULL, 65 (GDBusPropertyInfo **) &vmstate_property_info_pointers, 66 NULL, 67 }; 68 69 #define DBUS_VMSTATE_SIZE_LIMIT (1 * MiB) 70 71 static GHashTable * 72 get_id_list_set(DBusVMState *self) 73 { 74 g_auto(GStrv) ids = NULL; 75 g_autoptr(GHashTable) set = NULL; 76 int i; 77 78 if (!self->id_list) { 79 return NULL; 80 } 81 82 ids = g_strsplit(self->id_list, ",", -1); 83 set = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); 84 for (i = 0; ids[i]; i++) { 85 g_hash_table_add(set, ids[i]); 86 ids[i] = NULL; 87 } 88 89 return g_steal_pointer(&set); 90 } 91 92 static GHashTable * 93 dbus_get_proxies(DBusVMState *self, GError **err) 94 { 95 g_autoptr(GHashTable) proxies = NULL; 96 g_autoptr(GHashTable) ids = NULL; 97 g_auto(GStrv) names = NULL; 98 Error *error = NULL; 99 size_t i; 100 101 ids = get_id_list_set(self); 102 proxies = g_hash_table_new_full(g_str_hash, g_str_equal, 103 g_free, g_object_unref); 104 105 names = qemu_dbus_get_queued_owners(self->bus, "org.qemu.VMState1", &error); 106 if (!names) { 107 g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, "%s", 108 error_get_pretty(error)); 109 error_free(error); 110 return NULL; 111 } 112 113 for (i = 0; names[i]; i++) { 114 g_autoptr(GDBusProxy) proxy = NULL; 115 g_autoptr(GVariant) result = NULL; 116 g_autofree char *id = NULL; 117 size_t size; 118 119 proxy = g_dbus_proxy_new_sync(self->bus, G_DBUS_PROXY_FLAGS_NONE, 120 (GDBusInterfaceInfo *) &vmstate1_interface_info, 121 names[i], 122 "/org/qemu/VMState1", 123 "org.qemu.VMState1", 124 NULL, err); 125 if (!proxy) { 126 return NULL; 127 } 128 129 result = g_dbus_proxy_get_cached_property(proxy, "Id"); 130 if (!result) { 131 g_set_error_literal(err, G_IO_ERROR, G_IO_ERROR_FAILED, 132 "VMState Id property is missing."); 133 return NULL; 134 } 135 136 id = g_variant_dup_string(result, &size); 137 if (ids && !g_hash_table_remove(ids, id)) { 138 g_clear_pointer(&id, g_free); 139 g_clear_object(&proxy); 140 continue; 141 } 142 if (size == 0 || size >= 256) { 143 g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, 144 "VMState Id '%s' is invalid.", id); 145 return NULL; 146 } 147 148 if (!g_hash_table_insert(proxies, id, proxy)) { 149 g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, 150 "Duplicated VMState Id '%s'", id); 151 return NULL; 152 } 153 id = NULL; 154 proxy = NULL; 155 156 g_clear_pointer(&result, g_variant_unref); 157 } 158 159 if (ids) { 160 g_autofree char **left = NULL; 161 162 left = (char **)g_hash_table_get_keys_as_array(ids, NULL); 163 if (*left) { 164 g_autofree char *leftids = g_strjoinv(",", left); 165 g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, 166 "Required VMState Id are missing: %s", leftids); 167 return NULL; 168 } 169 } 170 171 return g_steal_pointer(&proxies); 172 } 173 174 static int 175 dbus_load_state_proxy(GDBusProxy *proxy, const uint8_t *data, size_t size) 176 { 177 g_autoptr(GError) err = NULL; 178 g_autoptr(GVariant) result = NULL; 179 g_autoptr(GVariant) value = NULL; 180 181 value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, 182 data, size, sizeof(char)); 183 result = g_dbus_proxy_call_sync(proxy, "Load", 184 g_variant_new("(@ay)", 185 g_steal_pointer(&value)), 186 G_DBUS_CALL_FLAGS_NO_AUTO_START, 187 -1, NULL, &err); 188 if (!result) { 189 error_report("%s: Failed to Load: %s", __func__, err->message); 190 return -1; 191 } 192 193 return 0; 194 } 195 196 static int dbus_vmstate_post_load(void *opaque, int version_id) 197 { 198 DBusVMState *self = DBUS_VMSTATE(opaque); 199 g_autoptr(GInputStream) m = NULL; 200 g_autoptr(GDataInputStream) s = NULL; 201 g_autoptr(GError) err = NULL; 202 g_autoptr(GHashTable) proxies = NULL; 203 uint32_t nelem; 204 205 trace_dbus_vmstate_post_load(version_id); 206 207 proxies = dbus_get_proxies(self, &err); 208 if (!proxies) { 209 error_report("%s: Failed to get proxies: %s", __func__, err->message); 210 return -1; 211 } 212 213 m = g_memory_input_stream_new_from_data(self->data, self->data_size, NULL); 214 s = g_data_input_stream_new(m); 215 g_data_input_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); 216 217 nelem = g_data_input_stream_read_uint32(s, NULL, &err); 218 if (err) { 219 goto error; 220 } 221 222 while (nelem > 0) { 223 GDBusProxy *proxy = NULL; 224 uint32_t len; 225 gsize bytes_read, avail; 226 char id[256]; 227 228 len = g_data_input_stream_read_uint32(s, NULL, &err); 229 if (err) { 230 goto error; 231 } 232 if (len >= 256) { 233 error_report("%s: Invalid DBus vmstate proxy name %u", 234 __func__, len); 235 return -1; 236 } 237 if (!g_input_stream_read_all(G_INPUT_STREAM(s), id, len, 238 &bytes_read, NULL, &err)) { 239 goto error; 240 } 241 g_return_val_if_fail(bytes_read == len, -1); 242 id[len] = 0; 243 244 trace_dbus_vmstate_loading(id); 245 246 proxy = g_hash_table_lookup(proxies, id); 247 if (!proxy) { 248 error_report("%s: Failed to find proxy Id '%s'", __func__, id); 249 return -1; 250 } 251 252 len = g_data_input_stream_read_uint32(s, NULL, &err); 253 avail = g_buffered_input_stream_get_available( 254 G_BUFFERED_INPUT_STREAM(s)); 255 256 if (len > DBUS_VMSTATE_SIZE_LIMIT || len > avail) { 257 error_report("%s: Invalid vmstate size: %u", __func__, len); 258 return -1; 259 } 260 261 if (dbus_load_state_proxy(proxy, 262 g_buffered_input_stream_peek_buffer(G_BUFFERED_INPUT_STREAM(s), 263 NULL), 264 len) < 0) { 265 error_report("%s: Failed to restore Id '%s'", __func__, id); 266 return -1; 267 } 268 269 if (!g_seekable_seek(G_SEEKABLE(s), len, G_SEEK_CUR, NULL, &err)) { 270 goto error; 271 } 272 273 nelem -= 1; 274 } 275 276 return 0; 277 278 error: 279 error_report("%s: Failed to read from stream: %s", __func__, err->message); 280 return -1; 281 } 282 283 static void 284 dbus_save_state_proxy(gpointer key, 285 gpointer value, 286 gpointer user_data) 287 { 288 GDataOutputStream *s = user_data; 289 const char *id = key; 290 GDBusProxy *proxy = value; 291 g_autoptr(GVariant) result = NULL; 292 g_autoptr(GVariant) child = NULL; 293 g_autoptr(GError) err = NULL; 294 const uint8_t *data; 295 gsize size; 296 297 trace_dbus_vmstate_saving(id); 298 299 result = g_dbus_proxy_call_sync(proxy, "Save", 300 NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, 301 -1, NULL, &err); 302 if (!result) { 303 error_report("%s: Failed to Save: %s", __func__, err->message); 304 return; 305 } 306 307 child = g_variant_get_child_value(result, 0); 308 data = g_variant_get_fixed_array(child, &size, sizeof(char)); 309 if (!data) { 310 error_report("%s: Failed to Save: not a byte array", __func__); 311 return; 312 } 313 if (size > DBUS_VMSTATE_SIZE_LIMIT) { 314 error_report("%s: Too large vmstate data to save: %zu", 315 __func__, (size_t)size); 316 return; 317 } 318 319 if (!g_data_output_stream_put_uint32(s, strlen(id), NULL, &err) || 320 !g_data_output_stream_put_string(s, id, NULL, &err) || 321 !g_data_output_stream_put_uint32(s, size, NULL, &err) || 322 !g_output_stream_write_all(G_OUTPUT_STREAM(s), 323 data, size, NULL, NULL, &err)) { 324 error_report("%s: Failed to write to stream: %s", 325 __func__, err->message); 326 } 327 } 328 329 static int dbus_vmstate_pre_save(void *opaque) 330 { 331 DBusVMState *self = DBUS_VMSTATE(opaque); 332 g_autoptr(GOutputStream) m = NULL; 333 g_autoptr(GDataOutputStream) s = NULL; 334 g_autoptr(GHashTable) proxies = NULL; 335 g_autoptr(GError) err = NULL; 336 337 trace_dbus_vmstate_pre_save(); 338 339 proxies = dbus_get_proxies(self, &err); 340 if (!proxies) { 341 error_report("%s: Failed to get proxies: %s", __func__, err->message); 342 return -1; 343 } 344 345 m = g_memory_output_stream_new_resizable(); 346 s = g_data_output_stream_new(m); 347 g_data_output_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); 348 349 if (!g_data_output_stream_put_uint32(s, g_hash_table_size(proxies), 350 NULL, &err)) { 351 error_report("%s: Failed to write to stream: %s", 352 __func__, err->message); 353 return -1; 354 } 355 356 g_hash_table_foreach(proxies, dbus_save_state_proxy, s); 357 358 if (g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m)) 359 > UINT32_MAX) { 360 error_report("%s: DBus vmstate buffer is too large", __func__); 361 return -1; 362 } 363 364 if (!g_output_stream_close(G_OUTPUT_STREAM(m), NULL, &err)) { 365 error_report("%s: Failed to close stream: %s", __func__, err->message); 366 return -1; 367 } 368 369 g_free(self->data); 370 self->data_size = 371 g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m)); 372 self->data = 373 g_memory_output_stream_steal_data(G_MEMORY_OUTPUT_STREAM(m)); 374 375 return 0; 376 } 377 378 static const VMStateDescription dbus_vmstate = { 379 .name = TYPE_DBUS_VMSTATE, 380 .version_id = 0, 381 .pre_save = dbus_vmstate_pre_save, 382 .post_load = dbus_vmstate_post_load, 383 .fields = (VMStateField[]) { 384 VMSTATE_UINT32(data_size, DBusVMState), 385 VMSTATE_VBUFFER_ALLOC_UINT32(data, DBusVMState, 0, 0, data_size), 386 VMSTATE_END_OF_LIST() 387 } 388 }; 389 390 static void 391 dbus_vmstate_complete(UserCreatable *uc, Error **errp) 392 { 393 DBusVMState *self = DBUS_VMSTATE(uc); 394 g_autoptr(GError) err = NULL; 395 396 if (!object_resolve_path_type("", TYPE_DBUS_VMSTATE, NULL)) { 397 error_setg(errp, "There is already an instance of %s", 398 TYPE_DBUS_VMSTATE); 399 return; 400 } 401 402 if (!self->dbus_addr) { 403 error_setg(errp, QERR_MISSING_PARAMETER, "addr"); 404 return; 405 } 406 407 self->bus = g_dbus_connection_new_for_address_sync(self->dbus_addr, 408 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | 409 G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, 410 NULL, NULL, &err); 411 if (err) { 412 error_setg(errp, "failed to connect to DBus: '%s'", err->message); 413 return; 414 } 415 416 if (vmstate_register(VMSTATE_IF(self), VMSTATE_INSTANCE_ID_ANY, 417 &dbus_vmstate, self) < 0) { 418 error_setg(errp, "Failed to register vmstate"); 419 } 420 } 421 422 static void 423 dbus_vmstate_finalize(Object *o) 424 { 425 DBusVMState *self = DBUS_VMSTATE(o); 426 427 vmstate_unregister(VMSTATE_IF(self), &dbus_vmstate, self); 428 429 g_clear_object(&self->bus); 430 g_free(self->dbus_addr); 431 g_free(self->id_list); 432 g_free(self->data); 433 } 434 435 static char * 436 get_dbus_addr(Object *o, Error **errp) 437 { 438 DBusVMState *self = DBUS_VMSTATE(o); 439 440 return g_strdup(self->dbus_addr); 441 } 442 443 static void 444 set_dbus_addr(Object *o, const char *str, Error **errp) 445 { 446 DBusVMState *self = DBUS_VMSTATE(o); 447 448 g_free(self->dbus_addr); 449 self->dbus_addr = g_strdup(str); 450 } 451 452 static char * 453 get_id_list(Object *o, Error **errp) 454 { 455 DBusVMState *self = DBUS_VMSTATE(o); 456 457 return g_strdup(self->id_list); 458 } 459 460 static void 461 set_id_list(Object *o, const char *str, Error **errp) 462 { 463 DBusVMState *self = DBUS_VMSTATE(o); 464 465 g_free(self->id_list); 466 self->id_list = g_strdup(str); 467 } 468 469 static char * 470 dbus_vmstate_get_id(VMStateIf *vmif) 471 { 472 return g_strdup(TYPE_DBUS_VMSTATE); 473 } 474 475 static void 476 dbus_vmstate_class_init(ObjectClass *oc, void *data) 477 { 478 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 479 VMStateIfClass *vc = VMSTATE_IF_CLASS(oc); 480 481 ucc->complete = dbus_vmstate_complete; 482 vc->get_id = dbus_vmstate_get_id; 483 484 object_class_property_add_str(oc, "addr", 485 get_dbus_addr, set_dbus_addr); 486 object_class_property_add_str(oc, "id-list", 487 get_id_list, set_id_list); 488 } 489 490 static const TypeInfo dbus_vmstate_info = { 491 .name = TYPE_DBUS_VMSTATE, 492 .parent = TYPE_OBJECT, 493 .instance_size = sizeof(DBusVMState), 494 .instance_finalize = dbus_vmstate_finalize, 495 .class_size = sizeof(DBusVMStateClass), 496 .class_init = dbus_vmstate_class_init, 497 .interfaces = (InterfaceInfo[]) { 498 { TYPE_USER_CREATABLE }, 499 { TYPE_VMSTATE_IF }, 500 { } 501 } 502 }; 503 504 static void 505 register_types(void) 506 { 507 type_register_static(&dbus_vmstate_info); 508 } 509 510 type_init(register_types); 511