All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Hildenbrand <david@redhat.com>
To: qemu-devel@nongnu.org
Cc: qemu-ppc@nongnu.org, "David Hildenbrand" <david@redhat.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Peter Xu" <peterx@redhat.com>,
	"Igor Mammedov" <imammedo@redhat.com>,
	"Thiner Logoer" <logoerthiner1@163.com>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Daniel P . Berrangé" <berrange@redhat.com>,
	"Stefan Hajnoczi" <stefanha@redhat.com>,
	"Elena Ufimtseva" <elena.ufimtseva@oracle.com>,
	"Jagannathan Raman" <jag.raman@oracle.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Ani Sinha" <anisinha@redhat.com>,
	"Xiao Guangrong" <xiaoguangrong.eric@gmail.com>,
	"Daniel Henrique Barboza" <danielhb413@gmail.com>,
	"Greg Kurz" <groug@kaod.org>, "Eric Blake" <eblake@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>,
	"Eduardo Habkost" <eduardo@habkost.net>
Subject: [PATCH v2 1/9] nvdimm: Reject writing label data to ROM instead of crashing QEMU
Date: Tue, 22 Aug 2023 13:44:49 +0200	[thread overview]
Message-ID: <20230822114504.239505-2-david@redhat.com> (raw)
In-Reply-To: <20230822114504.239505-1-david@redhat.com>

Currently, when using a true R/O NVDIMM (ROM memory backend) with a label
area, the VM can easily crash QEMU by trying to write to the label area,
because the ROM memory is mmap'ed without PROT_WRITE.

    [root@vm-0 ~]# ndctl disable-region region0
    disabled 1 region
    [root@vm-0 ~]# ndctl zero-labels nmem0
    -> QEMU segfaults

Let's remember whether we have a ROM memory backend and properly
reject the write request:

    [root@vm-0 ~]# ndctl disable-region region0
    disabled 1 region
    [root@vm-0 ~]# ndctl zero-labels nmem0
    zeroed 0 nmem

In comparison, on a system with a R/W NVDIMM:

    [root@vm-0 ~]# ndctl disable-region region0
    disabled 1 region
    [root@vm-0 ~]# ndctl zero-labels nmem0
    zeroed 1 nmem

For ACPI, just return "unsupported", like if no label exists. For spapr,
return "H_P2", similar to when no label area exists.

Could we rely on the "unarmed" property? Maybe, but it looks cleaner to
only disallow what certainly cannot work.

After all "unarmed=on" primarily means: cannot accept persistent writes. In
theory, there might be setups where devices with "unarmed=on" set could
be used to host non-persistent data (temporary files, system RAM, ...); for
example, in Linux, admins can overwrite the "readonly" setting and still
write to the device -- which will work as long as we're not using ROM.
Allowing writing label data in such configurations can make sense.

Fixes: dbd730e85987 ("nvdimm: check -object memory-backend-file, readonly=on option")
Signed-off-by: David Hildenbrand <david@redhat.com>
---
 hw/acpi/nvdimm.c        | 11 ++++++++---
 hw/mem/nvdimm.c         | 10 +++++++---
 hw/ppc/spapr_nvdimm.c   |  3 ++-
 include/hw/mem/nvdimm.h |  6 ++++++
 4 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
index a3b25a92f3..3cbd41629d 100644
--- a/hw/acpi/nvdimm.c
+++ b/hw/acpi/nvdimm.c
@@ -670,7 +670,8 @@ static void nvdimm_dsm_label_size(NVDIMMDevice *nvdimm, hwaddr dsm_mem_addr)
 }
 
 static uint32_t nvdimm_rw_label_data_check(NVDIMMDevice *nvdimm,
-                                           uint32_t offset, uint32_t length)
+                                           uint32_t offset, uint32_t length,
+                                           bool is_write)
 {
     uint32_t ret = NVDIMM_DSM_RET_STATUS_INVALID;
 
@@ -690,6 +691,10 @@ static uint32_t nvdimm_rw_label_data_check(NVDIMMDevice *nvdimm,
         return ret;
     }
 
+    if (is_write && nvdimm->readonly) {
+        return NVDIMM_DSM_RET_STATUS_UNSUPPORT;
+    }
+
     return NVDIMM_DSM_RET_STATUS_SUCCESS;
 }
 
@@ -713,7 +718,7 @@ static void nvdimm_dsm_get_label_data(NVDIMMDevice *nvdimm, NvdimmDsmIn *in,
                                  get_label_data->length);
 
     status = nvdimm_rw_label_data_check(nvdimm, get_label_data->offset,
-                                        get_label_data->length);
+                                        get_label_data->length, false);
     if (status != NVDIMM_DSM_RET_STATUS_SUCCESS) {
         nvdimm_dsm_no_payload(status, dsm_mem_addr);
         return;
@@ -752,7 +757,7 @@ static void nvdimm_dsm_set_label_data(NVDIMMDevice *nvdimm, NvdimmDsmIn *in,
                                   set_label_data->length);
 
     status = nvdimm_rw_label_data_check(nvdimm, set_label_data->offset,
-                                        set_label_data->length);
+                                        set_label_data->length, true);
     if (status != NVDIMM_DSM_RET_STATUS_SUCCESS) {
         nvdimm_dsm_no_payload(status, dsm_mem_addr);
         return;
diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index 31080c22c9..1631a7d13f 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -154,6 +154,9 @@ static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp)
                    object_get_canonical_path_component(OBJECT(hostmem)));
         return;
     }
+    if (memory_region_is_rom(mr)) {
+        nvdimm->readonly = true;
+    }
 
     nvdimm->nvdimm_mr = g_new(MemoryRegion, 1);
     memory_region_init_alias(nvdimm->nvdimm_mr, OBJECT(dimm),
@@ -207,15 +210,16 @@ static void nvdimm_unrealize(PCDIMMDevice *dimm)
  * label read/write functions.
  */
 static void nvdimm_validate_rw_label_data(NVDIMMDevice *nvdimm, uint64_t size,
-                                        uint64_t offset)
+                                        uint64_t offset, bool is_write)
 {
     assert((nvdimm->label_size >= size + offset) && (offset + size > offset));
+    assert(!is_write || !nvdimm->readonly);
 }
 
 static void nvdimm_read_label_data(NVDIMMDevice *nvdimm, void *buf,
                                    uint64_t size, uint64_t offset)
 {
-    nvdimm_validate_rw_label_data(nvdimm, size, offset);
+    nvdimm_validate_rw_label_data(nvdimm, size, offset, false);
 
     memcpy(buf, nvdimm->label_data + offset, size);
 }
@@ -229,7 +233,7 @@ static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf,
                                             "pmem", NULL);
     uint64_t backend_offset;
 
-    nvdimm_validate_rw_label_data(nvdimm, size, offset);
+    nvdimm_validate_rw_label_data(nvdimm, size, offset, true);
 
     if (!is_pmem) {
         memcpy(nvdimm->label_data + offset, buf, size);
diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c
index a8688243a6..60d6d0acc0 100644
--- a/hw/ppc/spapr_nvdimm.c
+++ b/hw/ppc/spapr_nvdimm.c
@@ -320,7 +320,8 @@ static target_ulong h_scm_write_metadata(PowerPCCPU *cpu,
 
     nvdimm = NVDIMM(drc->dev);
     if ((offset + len < offset) ||
-        (nvdimm->label_size < len + offset)) {
+        (nvdimm->label_size < len + offset) ||
+        nvdimm->readonly) {
         return H_P2;
     }
 
diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h
index acf887c83d..d3b763453a 100644
--- a/include/hw/mem/nvdimm.h
+++ b/include/hw/mem/nvdimm.h
@@ -77,6 +77,12 @@ struct NVDIMMDevice {
      */
     bool unarmed;
 
+    /*
+     * Whether our DIMM is backed by ROM, and even label data cannot be
+     * written. If set, implies that "unarmed" is also set.
+     */
+    bool readonly;
+
     /*
      * The PPC64 - spapr requires each nvdimm device have a uuid.
      */
-- 
2.41.0



  reply	other threads:[~2023-08-22 11:46 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-22 11:44 [PATCH v2 0/9] memory-backend-file related improvements and VM templating support David Hildenbrand
2023-08-22 11:44 ` David Hildenbrand [this message]
2023-08-22 19:25   ` [PATCH v2 1/9] nvdimm: Reject writing label data to ROM instead of crashing QEMU Stefan Hajnoczi
2023-08-22 11:44 ` [PATCH v2 2/9] softmmu/physmem: Distinguish between file access mode and mmap protection David Hildenbrand
2023-08-22 13:13   ` ThinerLogoer
2023-08-22 13:25     ` [PATCH " David Hildenbrand
2023-08-22 11:44 ` [PATCH v2 3/9] backends/hostmem-file: Add "rom" property to support VM templating with R/O files David Hildenbrand
2023-08-22 13:27   ` Markus Armbruster
2023-08-22 13:29     ` David Hildenbrand
2023-08-22 14:26   ` ThinerLogoer
2023-08-23 12:43     ` [PATCH " David Hildenbrand
2023-08-23 14:47       ` ThinerLogoer
2023-08-23 14:59         ` David Hildenbrand
2023-08-22 11:44 ` [PATCH v2 4/9] softmmu/physmem: Remap with proper protection in qemu_ram_remap() David Hildenbrand
2023-08-22 11:44 ` [PATCH v2 5/9] softmmu/physmem: Bail out early in ram_block_discard_range() with readonly files David Hildenbrand
2023-08-22 11:44 ` [PATCH v2 6/9] softmmu/physmem: Fail creation of new files in file_ram_open() with readonly=true David Hildenbrand
2023-08-22 11:44 ` [PATCH v2 7/9] softmmu/physmem: Never return directories from file_ram_open() David Hildenbrand
2023-08-22 11:44 ` [PATCH v2 8/9] docs: Don't mention "-mem-path" in multi-process.rst David Hildenbrand
2023-08-22 13:21   ` ThinerLogoer
2023-08-22 13:24     ` [PATCH " David Hildenbrand
2023-08-22 11:44 ` [PATCH v2 9/9] docs: Start documenting VM templating David Hildenbrand
2023-08-22 13:47   ` Daniel P. Berrangé
2023-08-22 14:04     ` David Hildenbrand
2023-08-22 14:23   ` Peter Maydell
2023-08-22 14:31     ` David Hildenbrand

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230822114504.239505-2-david@redhat.com \
    --to=david@redhat.com \
    --cc=anisinha@redhat.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=danielhb413@gmail.com \
    --cc=eblake@redhat.com \
    --cc=eduardo@habkost.net \
    --cc=elena.ufimtseva@oracle.com \
    --cc=groug@kaod.org \
    --cc=imammedo@redhat.com \
    --cc=jag.raman@oracle.com \
    --cc=logoerthiner1@163.com \
    --cc=mst@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peterx@redhat.com \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=xiaoguangrong.eric@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.