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