nvme: consult the CSE log page for unprivileged passthrough
authorChristoph Hellwig <hch@lst.de>
Tue, 13 Dec 2022 15:13:38 +0000 (16:13 +0100)
committerChristoph Hellwig <hch@lst.de>
Wed, 28 Dec 2022 16:26:31 +0000 (06:26 -1000)
Commands like Write Zeros can change the contents of a namespaces without
actually transferring data.  To protect against this, check the Commands
Supported and Effects log is supported by the controller for any
unprivileg command passthrough and refuse unprivileged passthrough if the
command has any effects that can change data or metadata.

Note: While the Commands Support and Effects log page has only been
mandatory since NVMe 2.0, it is widely supported because Windows requires
it for any command passthrough from userspace.

Fixes: e4fbcf32c860 ("nvme: identify-namespace without CAP_SYS_ADMIN")
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>
drivers/nvme/host/ioctl.c
include/linux/nvme.h

index 9ddda571f0461f2d699669a385f2d8a907ce927e..a8639919237e6aa3b089acd679fc098cfcdf0edb 100644 (file)
@@ -11,6 +11,8 @@
 static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,
                fmode_t mode)
 {
+       u32 effects;
+
        if (capable(CAP_SYS_ADMIN))
                return true;
 
@@ -43,11 +45,29 @@ static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,
        }
 
        /*
-        * Only allow I/O commands that transfer data to the controller if the
-        * special file is open for writing, but always allow I/O commands that
-        * transfer data from the controller.
+        * Check if the controller provides a Commands Supported and Effects log
+        * and marks this command as supported.  If not reject unprivileged
+        * passthrough.
+        */
+       effects = nvme_command_effects(ns->ctrl, ns, c->common.opcode);
+       if (!(effects & NVME_CMD_EFFECTS_CSUPP))
+               return false;
+
+       /*
+        * Don't allow passthrough for command that have intrusive (or unknown)
+        * effects.
+        */
+       if (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC |
+                       NVME_CMD_EFFECTS_UUID_SEL |
+                       NVME_CMD_EFFECTS_SCOPE_MASK))
+               return false;
+
+       /*
+        * Only allow I/O commands that transfer data to the controller or that
+        * change the logical block contents if the file descriptor is open for
+        * writing.
         */
-       if (nvme_is_write(c))
+       if (nvme_is_write(c) || (effects & NVME_CMD_EFFECTS_LBCC))
                return mode & FMODE_WRITE;
        return true;
 }
index d1cd53f2b6abd9dbabfacde6cfac2f2eb9cb024f..4fad4aa245fb0621ee3adbec1793981ae54f1ea7 100644 (file)
@@ -642,6 +642,7 @@ enum {
        NVME_CMD_EFFECTS_CCC            = 1 << 4,
        NVME_CMD_EFFECTS_CSE_MASK       = GENMASK(18, 16),
        NVME_CMD_EFFECTS_UUID_SEL       = 1 << 19,
+       NVME_CMD_EFFECTS_SCOPE_MASK     = GENMASK(31, 20),
 };
 
 struct nvme_effects_log {