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