From nobody Wed Apr 1 14:14:55 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 08CB1370D41; Tue, 31 Mar 2026 05:56:50 +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=1774936611; cv=none; b=RKy+/ASTPHAUnUNw00mJwlmc2b85RK/z4Dy6QDefetTA2e8w5+wikii3/XCFYbGbNqpd51uwzj3XoaAYShsWXd+Slae4iLnj24mt3ctee3DWebTPymtAuPSuqtvxg+12t9W/32OWgWF1Qin6ghleENCRMGyFVF7RPejd3A/kpDM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774936611; c=relaxed/simple; bh=TVEuGbcfHGfDo71N8+nkdQbDv4dUqR/rzcqGcfeN0ps=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Z5xQ8aUH7QXMy1U2Vbn9jKQr04i8bP6+uN7SlAnQioyXjllFojV/qaeYPWqRwMRG+xtukl37OxH6pf8+ZqPok/NLlj02Ymxq3SAe2OEqGvFEz/ij7hgeFZD/lLhHTsL8TmY+RzWLOMse0zpRrNL8es1LtYaBO2UvK2vY+scx9+Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Q3BkhowZ; 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="Q3BkhowZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A8638C19423; Tue, 31 Mar 2026 05:56:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774936610; bh=TVEuGbcfHGfDo71N8+nkdQbDv4dUqR/rzcqGcfeN0ps=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Q3BkhowZcNR4BZl7MGNRtnmYLaUXC9NpHSiB8fdoYtWvfaJvCJa2I08aDDVnCgs1g JmSBhKNNR+8lszsK0rvch5LvYps9zl4Jj7i4UY/nqEFgoWdNkJdSlDb+NexTo/YgHJ D9+8sQRlTkXYpGBrjmy+IkxBWTf8f0KUG9gArYHvGIEmRnyQAAUcrEFH/ijwj90CTI bQYG4T6KSBOXmhT79AbGQRNhOj4ttaGtB90PsEKACL8RdAbBcmk7UrnrL5cQdWyMzx RD5Qdl/+EfsVUI7DHJ5Ad4PylKXv39VnBHKRAFNDWi4U1Pws2D4unIRpqh1qOMr1S3 97k9yHc+YQLSw== From: Leon Romanovsky To: KP Singh , Matt Bobrowski , Alexei Starovoitov , Daniel Borkmann , John Fastabend , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , Stanislav Fomichev , Hao Luo , Jiri Olsa , Shuah Khan , Leon Romanovsky , Jason Gunthorpe , Saeed Mahameed , Itay Avraham , Dave Jiang , Jonathan Cameron Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-rdma@vger.kernel.org, Chiara Meiohas , Maher Sanalla Subject: [PATCH v2 1/4] bpf: add firmware command validation hook Date: Tue, 31 Mar 2026 08:56:33 +0300 Message-ID: <20260331-fw-lsm-hook-v2-1-78504703df1f@nvidia.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260331-fw-lsm-hook-v2-0-78504703df1f@nvidia.com> References: <20260331-fw-lsm-hook-v2-0-78504703df1f@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 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 Reviewed-by: Maher Sanalla Signed-off-by: Leon Romanovsky --- 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 #include =20 +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 class= es. + * + * @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 =20 #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ @@ -53,6 +68,24 @@ int bpf_set_dentry_xattr_locked(struct dentry *dentry, c= onst 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); =20 +/** + * 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 */ =20 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 st= ruct 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 */ =20 #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__) \ } =20 #include + +/* + * fw_validate_cmd is not in lsm_hook_defs.h because it is a BPF-only + * hook =E2=80=94 mailbox formats are device-specific, making BPF the natu= ral + * 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 =20 #define LSM_HOOK(RET, DEFAULT, NAME, ...) BTF_ID(func, bpf_lsm_##NAME) BTF_SET_START(bpf_lsm_hooks) #include #undef LSM_HOOK +BTF_ID(func, bpf_lsm_fw_validate_cmd) BTF_SET_END(bpf_lsm_hooks) =20 BTF_SET_START(bpf_lsm_disabled_hooks) --=20 2.53.0