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