[PATCH 7/7] nvme: don't allow unprivileged passthrough of commands that have effects

Christoph Hellwig
2022-12-13T16:25:38Z

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 and refuse unprivileged passthrough if the
command has any effects. This also includes more intrusive effects which
currently can't happen for I/O commands.

Fixes: e4fbcf32c860 ("nvme: identify-namespace without CAP_SYS_ADMIN")
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/nvme/host/ioctl.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index 2ed8fdd09bb35a..e71d136816eae0 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -11,6 +11,8 @@
static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,
fmode_t mode)
{
+ u8 opcode = c->common.opcode;
+
if (capable(CAP_SYS_ADMIN))
return true;

@@ -18,8 +20,7 @@ static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,
* Do not allow unprivileged processes to send vendor specific or fabrics
* commands as we can't be sure about their effects.
*/
- if (c->common.opcode >= nvme_cmd_vendor_start ||
- c->common.opcode == nvme_fabrics_command)
+ if (opcode >= nvme_cmd_vendor_start || opcode == nvme_fabrics_command)
return false;

/*
@@ -29,7 +30,7 @@ static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,
* potentially sensitive information.
*/
if (!ns) {
- if (c->common.opcode == nvme_admin_identify) {
+ if (opcode == nvme_admin_identify) {
switch (c->identify.cns) {
case NVME_ID_CNS_NS:
case NVME_ID_CNS_CS_NS:
@@ -43,11 +44,11 @@ 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.
+ * Only allow I/O commands that transfer data to the controller, change
+ * the logical block content or have any other intrusive effects if the
+ * special file is open for writing.
*/
- if (nvme_is_write(c))
+ if (nvme_is_write(c) || nvme_command_effects(ns->ctrl, ns, opcode))
return mode & FMODE_WRITE;
return true;
}
--
2.35.1