From nobody Thu Apr 9 12:58:01 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3A7D3939D2; Mon, 9 Mar 2026 11:15:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773054931; cv=none; b=M1S7ZHUX/nT3EjJIroqGft/V/YhcecxfSzzH3Huq7sQO0oUmyy2qp2fzRz1V4S+9C4CfMKujPZkcvQQhx3TSUw6u/7G1Jpud8uaaG69QlUqbMJZxGlss1JwNM6fCByxv3/nObk6ZMkAsSbodmboAMPBKUEkIt560rkhaEEQQRoc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773054931; c=relaxed/simple; bh=PoqZDprkyG97xhHd0xAhB5NUCone+g6NoPGHHatVjlw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=li5SRQR9t8JVP3uFic/HGsaxG8qmS13r0P6taZd/gh1kR2rQoc1gOgclENHyLlqxL8309i/Ue4NCkEIq5AKiyCBOXcbKqM0EAUUGgTcy3LccmfuXWtKBQSAfwIby9L3gpleG4MWy3l9RE5ok+0dwa3yr5JtefghisaY3aH65EPw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UOPvBKEx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UOPvBKEx" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 05C44C2BC9E; Mon, 9 Mar 2026 11:15:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773054931; bh=PoqZDprkyG97xhHd0xAhB5NUCone+g6NoPGHHatVjlw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UOPvBKExj/tOZiQXJCY0WqA337vztYbTXpIv6XkFbKvDgxbn3Us5XcAgKPmIZdzgO PQXKGbwhe3nT0ymhLQZWEvbdghOrMl2myltS2Slk43BMSODmqJgYWlDe3Spb/wuLkH yVVJpauYglzEXR8yoB49+w4VeNeLQQT/FYXOz4yRPTc43alOlGW42TYXTKJYWJ2I7L jkf4C+v35lYIxitbZpdo1tgMlO/ILy4i5xZylCLVilBds71Bb5rxGsFfYgiO5hSL51 X7tNwqHwUeXa4r2G8UIYq+bAAwWr/kSIKHAlEzGEZ2vjGLGB69DGt/8LvpgyydrJkg aKIFdJqk8fxbA== From: Leon Romanovsky To: Paul Moore , James Morris , "Serge E. Hallyn" , Leon Romanovsky , Jason Gunthorpe , Saeed Mahameed , Itay Avraham , Dave Jiang , Jonathan Cameron Cc: linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, linux-rdma@vger.kernel.org, Chiara Meiohas , Maher Sanalla , Edward Srouji Subject: [PATCH 1/3] lsm: add hook for firmware command validation Date: Mon, 9 Mar 2026 13:15:18 +0200 Message-ID: <20260309-fw-lsm-hook-v1-1-4a6422e63725@nvidia.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260309-fw-lsm-hook-v1-0-4a6422e63725@nvidia.com> References: <20260309-fw-lsm-hook-v1-0-4a6422e63725@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Chiara Meiohas Drivers typically communicate with device firmware either via register-based commands (writing parameters into device registers) or by passing a command buffer using shared-memory mechanisms. This hook targets the command buffer mechanism, which is commonly used on modern, complex devices. Add the LSM hook fw_validate_cmd. 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 security modules 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). Signed-off-by: Chiara Meiohas Reviewed-by: Maher Sanalla Signed-off-by: Edward Srouji Signed-off-by: Leon Romanovsky Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron --- include/linux/lsm_hook_defs.h | 2 ++ include/linux/security.h | 25 +++++++++++++++++++++++++ security/security.c | 26 ++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 8c42b4bde09c0..93da090384ea1 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -445,6 +445,8 @@ LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_to= ken *token, int cap) #endif /* CONFIG_BPF_SYSCALL */ =20 LSM_HOOK(int, 0, locked_down, enum lockdown_reason what) +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) =20 #ifdef CONFIG_PERF_EVENTS LSM_HOOK(int, 0, perf_event_open, int type) diff --git a/include/linux/security.h b/include/linux/security.h index 83a646d72f6f8..64786d013207a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -67,6 +67,7 @@ enum fs_value_type; struct watch; struct watch_notification; struct lsm_ctx; +struct device; =20 /* Default (no) options for the capable function */ #define CAP_OPT_NONE 0x0 @@ -157,6 +158,21 @@ enum lockdown_reason { LOCKDOWN_CONFIDENTIALITY_MAX, }; =20 +/* + * enum fw_cmd_class - Class of the firmware command passed to + * security_fw_validate_cmd. + * This allows security modules 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, + FW_CMD_CLASS_MAX, +}; + /* * Data exported by the security modules */ @@ -575,6 +591,9 @@ int security_inode_notifysecctx(struct inode *inode, vo= id *ctx, u32 ctxlen); int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); int security_inode_getsecctx(struct inode *inode, struct lsm_context *cp); int security_locked_down(enum lockdown_reason what); +int security_fw_validate_cmd(const void *in, size_t in_len, + const struct device *dev, + enum fw_cmd_class class_id, u32 id); int lsm_fill_user_ctx(struct lsm_ctx __user *uctx, u32 *uctx_len, void *val, size_t val_len, u64 id, u64 flags); int security_bdev_alloc(struct block_device *bdev); @@ -1589,6 +1608,12 @@ static inline int security_locked_down(enum lockdown= _reason what) { return 0; } +static inline int security_fw_validate_cmd(const void *in, size_t in_len, + const struct device *dev, + enum fw_cmd_class class_id, u32 id) +{ + return 0; +} static inline int lsm_fill_user_ctx(struct lsm_ctx __user *uctx, u32 *uctx_len, void *val, size_t val_len, u64 id, u64 flags) diff --git a/security/security.c b/security/security.c index 67af9228c4e94..d05941fe89a48 100644 --- a/security/security.c +++ b/security/security.c @@ -5373,6 +5373,32 @@ int security_locked_down(enum lockdown_reason what) } EXPORT_SYMBOL(security_locked_down); =20 +/** + * security_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. + */ +int security_fw_validate_cmd(const void *in, size_t in_len, + const struct device *dev, + enum fw_cmd_class class_id, + u32 id) +{ + if (class_id >=3D FW_CMD_CLASS_MAX) + return -EINVAL; + + return call_int_hook(fw_validate_cmd, in, in_len, + dev, class_id, id); +} +EXPORT_SYMBOL_GPL(security_fw_validate_cmd); + /** * security_bdev_alloc() - Allocate a block device LSM blob * @bdev: block device --=20 2.53.0