[RFC 1/2] nvme : Add dynamic whitelisting for passthru
Joel Granados
j.granados at samsung.com
Fri Oct 7 06:22:55 PDT 2022
Drive information such as block size and total usable LBAs are needed to
send IO down the nvme passthru path. Currently only privileged users can
get these parameters. This patch implements a dynamic whitelist that
allows the privileged user to define what nvme opcodes are available for
the unprivileged.
A bitmap is added at the nvme driver level that controls what opcodes are
allowed. The unprivileged user will be able to execute an nvme opcode
(using passthru) when it is whitelisted and if mode matches FMODE_WRITE.
This contains only the whitelist implementation and is a preparation commit
for the ioctl calls.
Signed-off-by: Joel Granados <j.granados at samsung.com>
---
drivers/nvme/host/core.c | 10 ++++++++++
drivers/nvme/host/ioctl.c | 11 +++++++++--
drivers/nvme/host/nvme.h | 1 +
include/linux/nvme.h | 1 +
4 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 13080a017ecf..05d1e6fd633d 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -107,6 +107,8 @@ EXPORT_SYMBOL_GPL(nvme_reset_wq);
struct workqueue_struct *nvme_delete_wq;
EXPORT_SYMBOL_GPL(nvme_delete_wq);
+DECLARE_BITMAP(nvme_admin_whitelist, nvme_admin_last);
+
static LIST_HEAD(nvme_subsystems);
static DEFINE_MUTEX(nvme_subsystems_lock);
@@ -125,6 +127,12 @@ static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
static void nvme_update_keep_alive(struct nvme_ctrl *ctrl,
struct nvme_command *cmd);
+static void nvme_init_admin_whitelist(void)
+{
+ bitmap_zero(nvme_admin_whitelist, nvme_admin_last);
+ __set_bit(nvme_admin_identify, nvme_admin_whitelist);
+}
+
void nvme_queue_scan(struct nvme_ctrl *ctrl)
{
/*
@@ -5231,6 +5239,8 @@ static int __init nvme_core_init(void)
goto unregister_generic_ns;
}
+ nvme_init_admin_whitelist();
+
return 0;
unregister_generic_ns:
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index ebe04e977baa..73e4287d2c44 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -20,6 +20,14 @@ static void __user *nvme_to_user_ptr(uintptr_t ptrval)
return (void __user *)ptrval;
}
+
+bool nvme_admin_cmd_allowed(u8 opcode, fmode_t mode)
+{
+ if (test_bit(opcode, nvme_admin_whitelist))
+ return (mode & FMODE_WRITE);
+ return false;
+}
+
bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c, fmode_t mode)
{
u8 opcode = c->common.opcode;
@@ -27,9 +35,8 @@ bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c, fmode_t mode)
if (capable(CAP_SYS_ADMIN))
return true;
- /* admin commands are not allowed */
if (ns == NULL)
- return false;
+ return nvme_admin_cmd_allowed(opcode, mode);
/* exclude vendor-specific io and fabrics commands */
if (opcode >= nvme_cmd_vendor_start || opcode == nvme_fabrics_command)
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 216acbe953b3..18a55e3483bd 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -46,6 +46,7 @@ extern unsigned int admin_timeout;
extern struct workqueue_struct *nvme_wq;
extern struct workqueue_struct *nvme_reset_wq;
extern struct workqueue_struct *nvme_delete_wq;
+extern unsigned long nvme_admin_whitelist[];
/*
* List of workarounds for devices that required behavior not specified in
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 8396eb7ecb68..18a75496299c 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -1123,6 +1123,7 @@ enum nvme_admin_opcode {
nvme_admin_sanitize_nvm = 0x84,
nvme_admin_get_lba_status = 0x86,
nvme_admin_vendor_start = 0xC0,
+ nvme_admin_last,
};
#define nvme_admin_opcode_name(opcode) { opcode, #opcode }
--
2.30.2
More information about the Linux-nvme
mailing list