From nobody Wed Apr 1 12:38: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 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 From nobody Wed Apr 1 12:38: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 699D0371890; Tue, 31 Mar 2026 05:56:54 +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=1774936614; cv=none; b=UBVLa8mpXzkgMp3afh64U9qy4LD6xGtA+AIDcEWEnOeBk1Nff1qKUpSxAk6q/a1qnHB9g61BDTBf8ge59sn2s/4XcwI7PscgIcRRHVjlKwceLgaT6M0H/T/gmA+ukGnqdz5O9F33f4WYNf3hg7VCJu5AnFPKuR+RnHFxPRjANrY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774936614; c=relaxed/simple; bh=8PCIPCDnlGfi9fRYFfkIETHKvqA/mw9m2S1aONNRJdQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=a4o7KCuJQ9uIYYrpDHg6ulYOWeG6hq68dD/wKOHfoLKGmwJsqgfqmCAhCsOpg1v5qA0eInv6064mwPVMyMg64aZ6cIXjHYnlX3t8C6gqo0DKuXcx71JYTxeL8GNpy/4rfSR1yssB7zxRpkz/u8nj3/Q1YPdL1+IfpYJ2ZQLu1Xs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FEDlhw7V; 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="FEDlhw7V" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 69E68C19424; Tue, 31 Mar 2026 05:56:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774936614; bh=8PCIPCDnlGfi9fRYFfkIETHKvqA/mw9m2S1aONNRJdQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FEDlhw7VVzT/CYwpIFBHeexNZr3ySdv6Q6DFNCI6hRvVoRs448+dEJWih0bXjsHVW 5HnhMQ2/qutuLUfw6oHPWRr8ywJ9aFQa4ncfBYUvae+bNS8H/lo7qWeGjFSmrkk1b1 OQ90B3YryNMfu2cC8upcdvjd19qix0+awhiM4ttAA6BrLPNL6zyxSHfAvebRbxYU5s 0QdrDTbr0BZbLaJN2w3NrEkU3rSvr6s7hWeAUcZDQut6OJCpdFENnK5asilqh7uuPB Pxr6UlLob6z+Gm6ajWWU5VwZB6BhnIhNYoDQ95JX0avI7AAnbziAvlzKNOLHO5bD0T KDcvkpWxhaEaw== 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 2/4] selftests/bpf: add test cases for fw_validate_cmd hook Date: Tue, 31 Mar 2026 08:56:34 +0300 Message-ID: <20260331-fw-lsm-hook-v2-2-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 The first test validates that the BPF verifier accepts a program that accesses the hook parameters (in_len) and returns values in the valid errno range. The second test validates that the BPF verifier rejects a program that returns a positive value, which is outside the valid [-4095, 0] return range for BPF-LSM hooks. Signed-off-by: Chiara Meiohas Reviewed-by: Maher Sanalla Signed-off-by: Leon Romanovsky --- tools/testing/selftests/bpf/progs/verifier_lsm.c | 23 ++++++++++++++++++++= +++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_lsm.c b/tools/testi= ng/selftests/bpf/progs/verifier_lsm.c index 38e8e91768620..9b2487948f8cb 100644 --- a/tools/testing/selftests/bpf/progs/verifier_lsm.c +++ b/tools/testing/selftests/bpf/progs/verifier_lsm.c @@ -188,4 +188,27 @@ int BPF_PROG(null_check, struct file *file) return 0; } =20 +SEC("lsm/fw_validate_cmd") +__description("lsm fw_validate_cmd: validate hook parameters") +__success +int BPF_PROG(fw_validate_cmd_test, const void *in, size_t in_len, + const struct device *dev, enum fw_cmd_class class_id, u32 id) +{ + if (!in_len) + return -22; + + return 0; +} + +SEC("lsm/fw_validate_cmd") +__description("lsm fw_validate_cmd: invalid positive return") +__failure __msg("R0 has smin=3D1 smax=3D1 should have been in [-4095, 0]") +__naked int fw_validate_cmd_fail(void *ctx) +{ + asm volatile ( + "r0 =3D 1;" + "exit;" + ::: __clobber_all); +} + char _license[] SEC("license") =3D "GPL"; --=20 2.53.0 From nobody Wed Apr 1 12:38: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 C591B28002B; Tue, 31 Mar 2026 05:57:01 +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=1774936621; cv=none; b=MBcdqDyJXbdbfZgWTy2c+FbBSSCBBMkphi9hFKooGpkMCM1dqRq+85QBc4uAqFZAlq167joTr6UT0oY4xzGVjl1UlYDLYdDNgPKJKmNyxVGq9NsMKegGka4rVXilXvZJ/05NR09YwjjTrohEvlsGdjWk2eQd7jlwBljBIGgjHLw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774936621; c=relaxed/simple; bh=2sUVXWm6gNzbVe8kaPMIgxN7RRU36ux1iye5UqtO5zY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iCeiQ23xA60bBzs7eblNRcSjI7ZhTakfXCBOHhIk2wJZUn6KFaW7Hynlk6m4fEOVHDMIxwUOhxKIt5T5gIj4u5gnyoJpxU0n8FyQHGpJbROAjAqSLSVVS6kxQNCmPlYQT0zBXXx9tBtWQAfK+3TnTDyUWYHwm5UfHZ7X0yW4Bf0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=b8H84but; 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="b8H84but" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D21EFC2BCB2; Tue, 31 Mar 2026 05:57:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774936621; bh=2sUVXWm6gNzbVe8kaPMIgxN7RRU36ux1iye5UqtO5zY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=b8H84butCoPCRLEFvp8G0bCPS9e/YZqXvfcgpLlYxU8v0Q2hb9g2cQrGUEBxjOoQK v6kqvevV2I22huT1MSDikjrDpi5lN2aUjU6u8nXblALEoExcZ6ZHZQzm/hhkJP0v8a SHIncaR3H+a0IZAhk5WMueCzUUAbmG7xxZWDhoUQM0tUMF1/O6B1voDl5ozOnX0yJW xWj4mIK/thjVdMF2aOVCQBZ2DrXI+hDa/CKniLrY9v6PDuasX8RlU6vwC1XjOiCSc/ /YkcC7XHb+oMDBNtxMkpyh6MuutaDDJn7rcsh2BKn8cX6N5A1pWheExXoiLMujfqBX Y27YV0xzQmHWg== 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 , Jonathan Cameron Subject: [PATCH v2 3/4] RDMA/mlx5: Externally validate FW commands supplied in DEVX interface Date: Tue, 31 Mar 2026 08:56:35 +0300 Message-ID: <20260331-fw-lsm-hook-v2-3-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 DEVX is an RDMA uverbs extension that allows userspace to submit firmware command buffers. The driver inspects the command and then passes the buffer through for firmware execution. Call bpf_lsm_fw_validate_cmd() before dispatching firmware commands through DEVX. This allows BPF programs to implement custom policies and enforce per-command security policy on user-triggered firmware commands. For example, a BPF program could restrict specific firmware operations to privileged users. Signed-off-by: Chiara Meiohas Reviewed-by: Maher Sanalla Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx5/devx.c | 49 +++++++++++++++++++++++++++++------= ---- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5= /devx.c index 0066b2738ac89..b7a2e19987018 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -18,6 +18,7 @@ #include "devx.h" #include "qp.h" #include +#include =20 #define UVERBS_MODULE_NAME mlx5_ib #include @@ -1111,6 +1112,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)( struct mlx5_ib_dev *dev; void *cmd_in =3D uverbs_attr_get_alloced_ptr( attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN); + int cmd_in_len =3D uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_DEVX_OTHER_CMD_IN); int cmd_out_len =3D uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT); void *cmd_out; @@ -1135,9 +1138,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)( return PTR_ERR(cmd_out); =20 MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid); - err =3D mlx5_cmd_do(dev->mdev, cmd_in, - uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN), - cmd_out, cmd_out_len); + err =3D bpf_lsm_fw_validate_cmd(cmd_in, cmd_in_len, &dev->ib_dev.dev, + FW_CMD_CLASS_UVERBS, RDMA_DRIVER_MLX5); + if (err) + return err; + + err =3D mlx5_cmd_do(dev->mdev, cmd_in, cmd_in_len, cmd_out, cmd_out_len); if (err && err !=3D -EREMOTEIO) return err; =20 @@ -1570,6 +1576,11 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CR= EATE)( devx_set_umem_valid(cmd_in); } =20 + err =3D bpf_lsm_fw_validate_cmd(cmd_in, cmd_in_len, &dev->ib_dev.dev, + FW_CMD_CLASS_UVERBS, RDMA_DRIVER_MLX5); + if (err) + goto obj_free; + if (opcode =3D=3D MLX5_CMD_OP_CREATE_DCT) { obj->flags |=3D DEVX_OBJ_FLAGS_DCT; err =3D mlx5_core_create_dct(dev, &obj->core_dct, cmd_in, @@ -1646,6 +1657,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MOD= IFY)( struct uverbs_attr_bundle *attrs) { void *cmd_in =3D uverbs_attr_get_alloced_ptr(attrs, MLX5_IB_ATTR_DEVX_OBJ= _MODIFY_CMD_IN); + int cmd_in_len =3D uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN); int cmd_out_len =3D uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT); struct ib_uobject *uobj =3D uverbs_attr_get_uobject(attrs, @@ -1676,10 +1689,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_M= ODIFY)( =20 MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid); devx_set_umem_valid(cmd_in); + err =3D bpf_lsm_fw_validate_cmd(cmd_in, cmd_in_len, &mdev->ib_dev.dev, + FW_CMD_CLASS_UVERBS, RDMA_DRIVER_MLX5); + if (err) + return err; =20 - err =3D mlx5_cmd_do(mdev->mdev, cmd_in, - uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN), - cmd_out, cmd_out_len); + err =3D mlx5_cmd_do(mdev->mdev, cmd_in, cmd_in_len, cmd_out, cmd_out_len); if (err && err !=3D -EREMOTEIO) return err; =20 @@ -1693,6 +1708,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUE= RY)( struct uverbs_attr_bundle *attrs) { void *cmd_in =3D uverbs_attr_get_alloced_ptr(attrs, MLX5_IB_ATTR_DEVX_OBJ= _QUERY_CMD_IN); + int cmd_in_len =3D uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN); int cmd_out_len =3D uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT); struct ib_uobject *uobj =3D uverbs_attr_get_uobject(attrs, @@ -1722,9 +1739,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QU= ERY)( return PTR_ERR(cmd_out); =20 MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid); - err =3D mlx5_cmd_do(mdev->mdev, cmd_in, - uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN), - cmd_out, cmd_out_len); + err =3D bpf_lsm_fw_validate_cmd(cmd_in, cmd_in_len, &mdev->ib_dev.dev, + FW_CMD_CLASS_UVERBS, RDMA_DRIVER_MLX5); + if (err) + return err; + + err =3D mlx5_cmd_do(mdev->mdev, cmd_in, cmd_in_len, cmd_out, cmd_out_len); if (err && err !=3D -EREMOTEIO) return err; =20 @@ -1832,6 +1852,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_ASY= NC_QUERY)( { void *cmd_in =3D uverbs_attr_get_alloced_ptr(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_ASYNC_CMD_IN); + int cmd_in_len =3D uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_DEVX_OBJ_QUERY_ASYNC_CMD_IN); struct ib_uobject *uobj =3D uverbs_attr_get_uobject( attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_ASYNC_HANDLE); @@ -1894,9 +1916,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_AS= YNC_QUERY)( async_data->ev_file =3D ev_file; =20 MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid); - err =3D mlx5_cmd_exec_cb(&ev_file->async_ctx, cmd_in, - uverbs_attr_get_len(attrs, - MLX5_IB_ATTR_DEVX_OBJ_QUERY_ASYNC_CMD_IN), + err =3D bpf_lsm_fw_validate_cmd(cmd_in, cmd_in_len, &mdev->ib_dev.dev, + FW_CMD_CLASS_UVERBS, RDMA_DRIVER_MLX5); + if (err) + goto free_async; + + err =3D mlx5_cmd_exec_cb(&ev_file->async_ctx, cmd_in, cmd_in_len, async_data->hdr.out_data, async_data->cmd_out_len, devx_query_callback, &async_data->cb_work); --=20 2.53.0 From nobody Wed Apr 1 12:38: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 26307371888; Tue, 31 Mar 2026 05:56:57 +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=1774936618; cv=none; b=f+P9b2hsVmMA/nfCdjp43vNPwczC7UpV9piATV+k55sDV6Gnmg37YnVV14YqLR0XQCfTIQAryKzVxBHCy0wntrW0HHVnpqzK9BV9xv3Nk6vYye8otd5rbGKLMdM5+h4scyNWMzksBuGv5foG8R0B/82aHHJFDUxwVtgCPwCLSLw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774936618; c=relaxed/simple; bh=5k4T59VFMXQz4OG6JuaoBzpu2XM/Crd28cH9bMwomqg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KofVrVJ3RmeAAKDdBXqT7/bdgyaEXvQzpOz3ZA5oZ7VByaSPj5ocJRYs8Lla3gCNIkyFlwRukV/5eagX7VxLF9btmGnW3uP2wQhoB9vieBMSgdRnw99bNoruE3tTkUF0aAFANFMk2ujro9n0YMVPwtfNlEj9+ZoAbqvf3UrDBi4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mQB++NZ7; 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="mQB++NZ7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 09719C19423; Tue, 31 Mar 2026 05:56:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774936617; bh=5k4T59VFMXQz4OG6JuaoBzpu2XM/Crd28cH9bMwomqg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mQB++NZ7favTt7zBJAmAee27yfICYaVMXGS3znVvRwI+zSm4HOdxscrw/IoIqHWfR PjkZXfY2urp0+wtffL5e8OgaHdqH+we7dT73ogipnwzkUs4im9hG/8gEDDX5T7fcoC Tq9F8lVpgMJlwW5LuUatq1ZPi7MBY9XUOU5UGklFGMogahi61m1X4XLlq7w1BuA/eo cc0xKcYlHgzMOS/8c25bHpjhDqu2wHNOZQbHYcVqsEQkeqZpbzOBrJ+7ZYdAu87opO vadPPXXxliFaLMBwqwVDrSbkT78BbcKtL+NrpaojzcxTucsctkZtzTdQf48jOK8WDZ ffBnqz9lggytQ== 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 , Jonathan Cameron Subject: [PATCH v2 4/4] fwctl/mlx5: Externally validate FW commands supplied in fwctl Date: Tue, 31 Mar 2026 08:56:36 +0300 Message-ID: <20260331-fw-lsm-hook-v2-4-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 fwctl is subsystem which exposes a firmware interface directly to userspace: it allows userspace to send device specific command buffers to firmware. fwctl is focused on debugging, configuration and provisioning of the device. Call bpf_lsm_fw_validate_cmd() before dispatching the user-provided firmware command. This allows BPF programs to implement custom policies and enforce per-command security policy on user-triggered firmware commands. For example, a BPF program could filter firmware commands based on their opcode. Signed-off-by: Chiara Meiohas Reviewed-by: Maher Sanalla Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Signed-off-by: Leon Romanovsky --- drivers/fwctl/mlx5/main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/fwctl/mlx5/main.c b/drivers/fwctl/mlx5/main.c index e86ab703c767a..c49dfa1d172d9 100644 --- a/drivers/fwctl/mlx5/main.c +++ b/drivers/fwctl/mlx5/main.c @@ -7,6 +7,7 @@ #include #include #include +#include =20 #define mlx5ctl_err(mcdev, format, ...) \ dev_err(&mcdev->fwctl.dev, format, ##__VA_ARGS__) @@ -324,6 +325,15 @@ static void *mlx5ctl_fw_rpc(struct fwctl_uctx *uctx, e= num fwctl_rpc_scope scope, if (!mlx5ctl_validate_rpc(rpc_in, scope)) return ERR_PTR(-EBADMSG); =20 + /* Enforce the user context for the command */ + MLX5_SET(mbox_in_hdr, rpc_in, uid, mfd->uctx_uid); + + ret =3D bpf_lsm_fw_validate_cmd(rpc_in, in_len, &mcdev->fwctl.dev, + FW_CMD_CLASS_FWCTL, + FWCTL_DEVICE_TYPE_MLX5); + if (ret) + return ERR_PTR(ret); + /* * mlx5_cmd_do() copies the input message to its own buffer before * executing it, so we can reuse the allocation for the output. @@ -336,8 +346,6 @@ static void *mlx5ctl_fw_rpc(struct fwctl_uctx *uctx, en= um fwctl_rpc_scope scope, return ERR_PTR(-ENOMEM); } =20 - /* Enforce the user context for the command */ - MLX5_SET(mbox_in_hdr, rpc_in, uid, mfd->uctx_uid); ret =3D mlx5_cmd_do(mcdev->mdev, rpc_in, in_len, rpc_out, *out_len); =20 mlx5ctl_dbg(mcdev, --=20 2.53.0