[PATCH v2 1/4] bpf: add firmware command validation hook

Leon Romanovsky posted 4 patches 1 day, 6 hours ago
[PATCH v2 1/4] bpf: add firmware command validation hook
Posted by Leon Romanovsky 1 day, 6 hours ago
From: Chiara Meiohas <cmeiohas@nvidia.com>

Drivers communicate with device firmware either via register-based
commands (writing parameters into device registers) or by passing
a command buffer using shared-memory mechanisms.

The proposed fw_validate_cmd hook is intended for the command buffer
mechanism, which is commonly used on modern, complex devices.

This hook allows inspecting firmware command buffers before they are
sent to the device.
The hook receives the command buffer, device, command class, and a
class-specific id:
  - class_id (enum fw_cmd_class) allows BPF programs to
    differentiate between classes of firmware commands.
    In this series, class_id distinguishes between commands from the
    RDMA uverbs interface and from fwctl.
  - id is a class-specific device identifier. For uverbs, id is the
    RDMA driver identifier (enum rdma_driver_id). For fwctl, id is the
    device type (enum fwctl_device_type).

The mailbox format varies across vendors and may even differ between
firmware versions, so policy authors must be familiar with the
specific device's mailbox format. BPF programs can be tailored to
inspect the mailbox accordingly, making BPF the natural fit.
Therefore, the hook is defined using the LSM_HOOK macro in bpf_lsm.c
rather than in lsm_hook_defs.h, as it is a BPF-only hook.

Signed-off-by: Chiara Meiohas <cmeiohas@nvidia.com>
Reviewed-by: Maher Sanalla <msanalla@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
 include/linux/bpf_lsm.h | 41 +++++++++++++++++++++++++++++++++++++++++
 kernel/bpf/bpf_lsm.c    | 11 +++++++++++
 2 files changed, 52 insertions(+)

diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
index 643809cc78c33..7ad7e153f486c 100644
--- a/include/linux/bpf_lsm.h
+++ b/include/linux/bpf_lsm.h
@@ -12,6 +12,21 @@
 #include <linux/bpf_verifier.h>
 #include <linux/lsm_hooks.h>
 
+struct device;
+
+/**
+ * enum fw_cmd_class - Class of the firmware command passed to
+ * bpf_lsm_fw_validate_cmd.
+ * This allows BPF programs to distinguish between different command classes.
+ *
+ * @FW_CMD_CLASS_UVERBS: Command originated from the RDMA uverbs interface
+ * @FW_CMD_CLASS_FWCTL: Command originated from the fwctl interface
+ */
+enum fw_cmd_class {
+	FW_CMD_CLASS_UVERBS,
+	FW_CMD_CLASS_FWCTL,
+};
+
 #ifdef CONFIG_BPF_LSM
 
 #define LSM_HOOK(RET, DEFAULT, NAME, ...) \
@@ -53,6 +68,24 @@ int bpf_set_dentry_xattr_locked(struct dentry *dentry, const char *name__str,
 int bpf_remove_dentry_xattr_locked(struct dentry *dentry, const char *name__str);
 bool bpf_lsm_has_d_inode_locked(const struct bpf_prog *prog);
 
+/**
+ * bpf_lsm_fw_validate_cmd() - Validate a firmware command
+ * @in: pointer to the firmware command input buffer
+ * @in_len: length of the firmware command input buffer
+ * @dev: device associated with the command
+ * @class_id: class of the firmware command
+ * @id: device identifier, specific to the command @class_id
+ *
+ * Check permissions before sending a firmware command generated by
+ * userspace to the device.
+ *
+ * Return: Returns 0 if permission is granted, or a negative errno
+ * value to deny the operation.
+ */
+int bpf_lsm_fw_validate_cmd(const void *in, size_t in_len,
+			    const struct device *dev,
+			    enum fw_cmd_class class_id, u32 id);
+
 #else /* !CONFIG_BPF_LSM */
 
 static inline bool bpf_lsm_is_sleepable_hook(u32 btf_id)
@@ -104,6 +137,14 @@ static inline bool bpf_lsm_has_d_inode_locked(const struct bpf_prog *prog)
 {
 	return false;
 }
+
+static inline int bpf_lsm_fw_validate_cmd(const void *in, size_t in_len,
+					  const struct device *dev,
+					  enum fw_cmd_class class_id, u32 id)
+{
+	return 0;
+}
+
 #endif /* CONFIG_BPF_LSM */
 
 #endif /* _LINUX_BPF_LSM_H */
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 0c4a0c8e6f703..fbdc056995fee 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -28,12 +28,23 @@ __weak noinline RET bpf_lsm_##NAME(__VA_ARGS__)	\
 }
 
 #include <linux/lsm_hook_defs.h>
+
+/*
+ * fw_validate_cmd is not in lsm_hook_defs.h because it is a BPF-only
+ * hook — mailbox formats are device-specific, making BPF the natural
+ * fit for inspection.
+ */
+LSM_HOOK(int, 0, fw_validate_cmd, const void *in, size_t in_len,
+	 const struct device *dev, enum fw_cmd_class class_id, u32 id)
+EXPORT_SYMBOL_GPL(bpf_lsm_fw_validate_cmd);
+
 #undef LSM_HOOK
 
 #define LSM_HOOK(RET, DEFAULT, NAME, ...) BTF_ID(func, bpf_lsm_##NAME)
 BTF_SET_START(bpf_lsm_hooks)
 #include <linux/lsm_hook_defs.h>
 #undef LSM_HOOK
+BTF_ID(func, bpf_lsm_fw_validate_cmd)
 BTF_SET_END(bpf_lsm_hooks)
 
 BTF_SET_START(bpf_lsm_disabled_hooks)

-- 
2.53.0