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

Kanchan Joshi joshi.k at samsung.com
Wed Dec 14 23:14:05 PST 2022


On Wed, Dec 14, 2022 at 05:13:47PM +0100, Christoph Hellwig wrote:
>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 at 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 a371209ee5e6d4..90e3a4a711bd17 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.

nit: trailing whitespace at the end of above line.

> 	 */
>-	if (nvme_is_write(c))
>+	if (nvme_is_write(c) || nvme_command_effects(ns->ctrl, ns, opcode))
> 		return mode & FMODE_WRITE;

So even for operation that do not alter anything (e.g. nvme_cmd_read)
nvme_is_write will return false, but nvme_command_effects will return
true and we will ask for FMODE_WRITE. Is that intentional?

I think doing 
"nvme_command_effects(ctrl, ns, opcode) & ~NVME_CMD_EFFECTS_CSUPP"
is better to avoid that?


More information about the Linux-nvme mailing list