memsave and pmemsave read guest memory and write it to a file, with no
guard at all. They run on the main thread with the BQL held, so on a
postcopy destination touching a not-yet-received page deadlocks: the
thread blocks on the userfault while the postcopy incoming path waits for
the BQL to install that page. During precopy the read returns incomplete
state instead.

Refuse both while guest RAM is still being received, using the same
migration_guest_ram_loading() check as dump-guest-memory.

Signed-off-by: Denis V. Lunev <[email protected]>
---
 system/cpus.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/system/cpus.c b/system/cpus.c
index bded87feb1..ba9da4ee06 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -42,6 +42,7 @@
 #include "hw/core/nmi.h"
 #include "system/replay.h"
 #include "system/runstate.h"
+#include "migration/misc.h"
 #include "system/cpu-timers.h"
 #include "system/whpx.h"
 #include "hw/core/boards.h"
@@ -841,6 +842,11 @@ void qmp_memsave(uint64_t addr, uint64_t size, const char 
*filename,
     uint8_t buf[1024];
     uint64_t orig_addr = addr, orig_size = size;
 
+    if (migration_guest_ram_loading()) {
+        error_setg(errp, "Guest memory access not allowed during migration");
+        return;
+    }
+
     if (!has_cpu) {
         cpu_index = 0;
     }
@@ -887,6 +893,11 @@ void qmp_pmemsave(uint64_t addr, uint64_t size, const char 
*filename,
     uint64_t l;
     uint8_t buf[1024];
 
+    if (migration_guest_ram_loading()) {
+        error_setg(errp, "Guest memory access not allowed during migration");
+        return;
+    }
+
     f = fopen(filename, "wb");
     if (!f) {
         error_setg_file_open(errp, errno, filename);
-- 
2.53.0


Reply via email to