* Re: [PATCH 1/3] lsm: add hook for firmware command validation
From: Jonathan Cameron @ 2026-03-09 15:02 UTC (permalink / raw)
To: Leon Romanovsky
Cc: Paul Moore, James Morris, Serge E. Hallyn, Jason Gunthorpe,
Saeed Mahameed, Itay Avraham, Dave Jiang, linux-security-module,
linux-kernel, linux-rdma, Chiara Meiohas, Maher Sanalla,
Edward Srouji
In-Reply-To: <20260309-fw-lsm-hook-v1-1-4a6422e63725@nvidia.com>
On Mon, 9 Mar 2026 13:15:18 +0200
Leon Romanovsky <leon@kernel.org> wrote:
> From: Chiara Meiohas <cmeiohas@nvidia.com>
>
> 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 <cmeiohas@nvidia.com>
> Reviewed-by: Maher Sanalla <msanalla@nvidia.com>
> Signed-off-by: Edward Srouji <edwards@nvidia.com>
> Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Hi Leon,
To me this seems sensible, but LSM isn't an area I know that much about.
With that in mind:
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
A few formatting related comments inline.
> 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;
>
> /* Default (no) options for the capable function */
> #define CAP_OPT_NONE 0x0
> @@ -157,6 +158,21 @@ enum lockdown_reason {
> LOCKDOWN_CONFIDENTIALITY_MAX,
> };
>
> +/*
Could add the MAX entry and making this /**
The file is a bit inconsistent on that.
> + * 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,
Nitpick. Drop the trailing comma to make it a tiny bit more obvious if
someone accidentally adds anything after this counting entry.
> +};
> +
> /*
> * Data exported by the security modules
> */
> @@ -575,6 +591,9 @@ int security_inode_notifysecctx(struct inode *inode, void *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);
>
> +/**
> + * 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)
I'd follow the wrapping you have in the header and have id on the line
above.
> +{
> + if (class_id >= FW_CMD_CLASS_MAX)
> + return -EINVAL;
> +
> + return call_int_hook(fw_validate_cmd, in, in_len,
> + dev, class_id, id);
Fits on one line < 80 chars.
> +}
> +EXPORT_SYMBOL_GPL(security_fw_validate_cmd);
> +
> /**
> * security_bdev_alloc() - Allocate a block device LSM blob
> * @bdev: block device
>
^ permalink raw reply
* Subject: x86/msr + lockdown: allow access to **documented** RAPL/TCC controls under Secure Boot
From: Artem S. Tashkinov @ 2026-03-09 12:24 UTC (permalink / raw)
To: x86; +Cc: Linux Kernel Mailing List, linux-pm, linux-efi,
linux-security-module
Hello,
When Secure Boot is enabled and kernel lockdown is active, the x86 MSR
driver blocks all raw MSR access from user space via `/dev/cpu/*/msr`.
This effectively prevents legitimate use of documented CPU power and
thermal management interfaces such as RAPL power limits (PL1/PL2) and
the TCC/TjOffset control. These registers are part of Intel’s
**publicly** documented architectural interface and have been stable
across many generations of processors.
As a result, under Secure Boot Linux users lose the ability to read or
adjust **standard** power-management controls that remain available
through equivalent tooling on other operating systems.
The current all-or-nothing restriction appears broader than necessary
for the stated goal of protecting kernel integrity. MSRs associated with
power limits and TCC offset are not privileged debugging or microcode
interfaces but standard hardware configuration knobs intended for
platform power and thermal management.
It would be useful if the kernel either allowed access to a small
whitelist of such documented registers under lockdown or exposed a
mediated kernel interface for adjusting them. Without such a mechanism,
Secure Boot effectively disables legitimate and widely used
power/thermal tuning functionality on modern Intel laptops.
Most (if not all) Intel laptops don't expose or allow to configure
PL1/PL2 limits in BIOS/EFI either.
This is being tracked here:
https://bugzilla.kernel.org/show_bug.cgi?id=221192
Regards,
Artem
^ permalink raw reply
* Re: [PATCH v2] docs: security: ipe: fix typos and grammar
From: Bagas Sanjaya @ 2026-03-09 12:15 UTC (permalink / raw)
To: Evan Ducas, wufan, corbet, skhan
Cc: rdunlap, linux-security-module, linux-doc, linux-kernel
In-Reply-To: <20260308180734.5792-1-evan.j.ducas@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 247 bytes --]
On Sun, Mar 08, 2026 at 02:07:34PM -0400, Evan Ducas wrote:
> Fix several spelling and grammar mistakes in the IPE
> documentation.
Acked-by: Bagas Sanjaya <bagasdotme@gmail.com>
--
An old man doll... just what I always wanted! - Clara
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* [PATCH 2/3] RDMA/mlx5: Invoke fw_validate_cmd LSM hook for DEVX commands
From: Leon Romanovsky @ 2026-03-09 11:15 UTC (permalink / raw)
To: Paul Moore, James Morris, Serge E. Hallyn, Leon Romanovsky,
Jason Gunthorpe, Saeed Mahameed, Itay Avraham, Dave Jiang,
Jonathan Cameron
Cc: linux-security-module, linux-kernel, linux-rdma, Chiara Meiohas,
Maher Sanalla, Edward Srouji
In-Reply-To: <20260309-fw-lsm-hook-v1-0-4a6422e63725@nvidia.com>
From: Chiara Meiohas <cmeiohas@nvidia.com>
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 security_fw_validate_cmd() before dispatching firmware commands
through DEVX.
This allows security modules to implement custom policies and
enforce per-command security policy on user-triggered firmware
commands. For example, a BPF LSM program could restrict specific
firmware operations to privileged users.
Signed-off-by: Chiara Meiohas <cmeiohas@nvidia.com>
Reviewed-by: Maher Sanalla <msanalla@nvidia.com>
Signed-off-by: Edward Srouji <edwards@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
drivers/infiniband/hw/mlx5/devx.c | 52 ++++++++++++++++++++++++++++++---------
1 file changed, 40 insertions(+), 12 deletions(-)
diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c
index 0066b2738ac89..48a2c4b4ad4eb 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 <linux/xarray.h>
+#include <linux/security.h>
#define UVERBS_MODULE_NAME mlx5_ib
#include <rdma/uverbs_named_ioctl.h>
@@ -1111,6 +1112,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)(
struct mlx5_ib_dev *dev;
void *cmd_in = uverbs_attr_get_alloced_ptr(
attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN);
+ int cmd_in_len = uverbs_attr_get_len(attrs,
+ MLX5_IB_ATTR_DEVX_OTHER_CMD_IN);
int cmd_out_len = 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);
MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
- err = 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 = security_fw_validate_cmd(cmd_in, cmd_in_len, &dev->ib_dev.dev,
+ FW_CMD_CLASS_UVERBS, RDMA_DRIVER_MLX5);
+ if (err)
+ return err;
+
+ err = mlx5_cmd_do(dev->mdev, cmd_in, cmd_in_len, cmd_out, cmd_out_len);
if (err && err != -EREMOTEIO)
return err;
@@ -1570,6 +1576,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
devx_set_umem_valid(cmd_in);
}
+ err = security_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 == MLX5_CMD_OP_CREATE_DCT) {
obj->flags |= DEVX_OBJ_FLAGS_DCT;
err = mlx5_core_create_dct(dev, &obj->core_dct, cmd_in,
@@ -1582,8 +1594,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
cmd_in, cmd_in_len, cmd_out,
cmd_out_len);
} else {
- err = mlx5_cmd_do(dev->mdev, cmd_in, cmd_in_len,
- cmd_out, cmd_out_len);
+ err = mlx5_cmd_do(dev->mdev, cmd_in, cmd_in_len, cmd_out,
+ cmd_out_len);
}
if (err == -EREMOTEIO)
@@ -1646,6 +1658,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(
struct uverbs_attr_bundle *attrs)
{
void *cmd_in = uverbs_attr_get_alloced_ptr(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN);
+ int cmd_in_len = uverbs_attr_get_len(attrs,
+ MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN);
int cmd_out_len = uverbs_attr_get_len(attrs,
MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT);
struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs,
@@ -1676,9 +1690,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(
MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
devx_set_umem_valid(cmd_in);
+ err = security_fw_validate_cmd(cmd_in, cmd_in_len, &mdev->ib_dev.dev,
+ FW_CMD_CLASS_UVERBS, RDMA_DRIVER_MLX5);
+ if (err)
+ return err;
- err = mlx5_cmd_do(mdev->mdev, cmd_in,
- uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN),
+ err = mlx5_cmd_do(mdev->mdev, cmd_in, cmd_in_len,
cmd_out, cmd_out_len);
if (err && err != -EREMOTEIO)
return err;
@@ -1693,6 +1710,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(
struct uverbs_attr_bundle *attrs)
{
void *cmd_in = uverbs_attr_get_alloced_ptr(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN);
+ int cmd_in_len = uverbs_attr_get_len(attrs,
+ MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN);
int cmd_out_len = uverbs_attr_get_len(attrs,
MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT);
struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs,
@@ -1722,8 +1741,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(
return PTR_ERR(cmd_out);
MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
- err = mlx5_cmd_do(mdev->mdev, cmd_in,
- uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN),
+ err = security_fw_validate_cmd(cmd_in, cmd_in_len, &mdev->ib_dev.dev,
+ FW_CMD_CLASS_UVERBS, RDMA_DRIVER_MLX5);
+ if (err)
+ return err;
+
+ err = mlx5_cmd_do(mdev->mdev, cmd_in, cmd_in_len,
cmd_out, cmd_out_len);
if (err && err != -EREMOTEIO)
return err;
@@ -1832,6 +1855,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_ASYNC_QUERY)(
{
void *cmd_in = uverbs_attr_get_alloced_ptr(attrs,
MLX5_IB_ATTR_DEVX_OBJ_QUERY_ASYNC_CMD_IN);
+ int cmd_in_len = uverbs_attr_get_len(attrs,
+ MLX5_IB_ATTR_DEVX_OBJ_QUERY_ASYNC_CMD_IN);
struct ib_uobject *uobj = uverbs_attr_get_uobject(
attrs,
MLX5_IB_ATTR_DEVX_OBJ_QUERY_ASYNC_HANDLE);
@@ -1894,9 +1919,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_ASYNC_QUERY)(
async_data->ev_file = ev_file;
MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
- err = 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 = security_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 = 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);
--
2.53.0
^ permalink raw reply related
* [PATCH 3/3] fwctl/mlx5: Invoke fw_validate_cmd LSM hook for fwctl commands
From: Leon Romanovsky @ 2026-03-09 11:15 UTC (permalink / raw)
To: Paul Moore, James Morris, Serge E. Hallyn, Leon Romanovsky,
Jason Gunthorpe, Saeed Mahameed, Itay Avraham, Dave Jiang,
Jonathan Cameron
Cc: linux-security-module, linux-kernel, linux-rdma, Chiara Meiohas,
Maher Sanalla, Edward Srouji
In-Reply-To: <20260309-fw-lsm-hook-v1-0-4a6422e63725@nvidia.com>
From: Chiara Meiohas <cmeiohas@nvidia.com>
fwctl is subsystem which exposes a firmware interface directly to
userspace: it allows userspace to send device specific command
buffers to firmware.
Call security_fw_validate_cmd() before dispatching the user-provided
firmware command.
This allows security modules to implement custom policies and
enforce per-command security policy on user-triggered firmware
commands. For example, a BPF LSM program could filter firmware
commands based on their opcode.
Signed-off-by: Chiara Meiohas <cmeiohas@nvidia.com>
Reviewed-by: Maher Sanalla <msanalla@nvidia.com>
Signed-off-by: Edward Srouji <edwards@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
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..8ed17aaf48f1f 100644
--- a/drivers/fwctl/mlx5/main.c
+++ b/drivers/fwctl/mlx5/main.c
@@ -7,6 +7,7 @@
#include <linux/mlx5/device.h>
#include <linux/mlx5/driver.h>
#include <uapi/fwctl/mlx5.h>
+#include <linux/security.h>
#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, enum fwctl_rpc_scope scope,
if (!mlx5ctl_validate_rpc(rpc_in, scope))
return ERR_PTR(-EBADMSG);
+ /* Enforce the user context for the command */
+ MLX5_SET(mbox_in_hdr, rpc_in, uid, mfd->uctx_uid);
+
+ ret = security_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, enum fwctl_rpc_scope scope,
return ERR_PTR(-ENOMEM);
}
- /* Enforce the user context for the command */
- MLX5_SET(mbox_in_hdr, rpc_in, uid, mfd->uctx_uid);
ret = mlx5_cmd_do(mcdev->mdev, rpc_in, in_len, rpc_out, *out_len);
mlx5ctl_dbg(mcdev,
--
2.53.0
^ permalink raw reply related
* [PATCH 1/3] lsm: add hook for firmware command validation
From: Leon Romanovsky @ 2026-03-09 11:15 UTC (permalink / raw)
To: Paul Moore, James Morris, Serge E. Hallyn, Leon Romanovsky,
Jason Gunthorpe, Saeed Mahameed, Itay Avraham, Dave Jiang,
Jonathan Cameron
Cc: linux-security-module, linux-kernel, linux-rdma, Chiara Meiohas,
Maher Sanalla, Edward Srouji
In-Reply-To: <20260309-fw-lsm-hook-v1-0-4a6422e63725@nvidia.com>
From: Chiara Meiohas <cmeiohas@nvidia.com>
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 <cmeiohas@nvidia.com>
Reviewed-by: Maher Sanalla <msanalla@nvidia.com>
Signed-off-by: Edward Srouji <edwards@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
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_token *token, int cap)
#endif /* CONFIG_BPF_SYSCALL */
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)
#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;
/* Default (no) options for the capable function */
#define CAP_OPT_NONE 0x0
@@ -157,6 +158,21 @@ enum lockdown_reason {
LOCKDOWN_CONFIDENTIALITY_MAX,
};
+/*
+ * 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, void *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);
+/**
+ * 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 >= 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
--
2.53.0
^ permalink raw reply related
* [PATCH 0/3] Firmware LSM hook
From: Leon Romanovsky @ 2026-03-09 11:15 UTC (permalink / raw)
To: Paul Moore, James Morris, Serge E. Hallyn, Leon Romanovsky,
Jason Gunthorpe, Saeed Mahameed, Itay Avraham, Dave Jiang,
Jonathan Cameron
Cc: linux-security-module, linux-kernel, linux-rdma, Chiara Meiohas,
Maher Sanalla, Edward Srouji
From Chiara:
This patch set introduces a new LSM hook to validate firmware commands
triggered by userspace before they are submitted to the device. The hook
runs after the command buffer is constructed, right before it is sent
to firmware.
The goal is to allow a security module to allow or deny a given command
before it is submitted to firmware. BPF LSM can attach to this hook
to implement such policies. This allows fine-grained policies for different
firmware commands.
In this series, the new hook is called from RDMA uverbs and from the fwctl
subsystem. Both the uverbs and fwctl interfaces use ioctl, so an obvious
candidate would seem to be the file_ioctl hook. However, the userspace
attributes used to build the firmware command buffer are copied from
userspace (copy_from_user()) deep in the driver, depending on various
conditions. As a result, file_ioctl does not have the information required
to make a policy decision.
This newly introduced hook provides the command buffer together with relevant
metadata (device, command class, and a class-specific device identifier), so
security modules can distinguish between different command classes and devices.
The hook can be used by other drivers that submit firmware commands via a command
buffer.
Thanks
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
Chiara Meiohas (3):
lsm: add hook for firmware command validation
RDMA/mlx5: Invoke fw_validate_cmd LSM hook for DEVX commands
fwctl/mlx5: Invoke fw_validate_cmd LSM hook for fwctl commands
drivers/fwctl/mlx5/main.c | 12 +++++++--
drivers/infiniband/hw/mlx5/devx.c | 52 ++++++++++++++++++++++++++++++---------
include/linux/lsm_hook_defs.h | 2 ++
include/linux/security.h | 25 +++++++++++++++++++
security/security.c | 26 ++++++++++++++++++++
5 files changed, 103 insertions(+), 14 deletions(-)
---
base-commit: 11439c4635edd669ae435eec308f4ab8a0804808
change-id: 20260309-fw-lsm-hook-7c094f909ffc
Best regards,
--
Leon Romanovsky <leonro@nvidia.com>
^ permalink raw reply
* Re: [PATCH] FIXUP: cachefiles: change cachefiles_bury_object to use start_renaming_dentry()
From: Christian Brauner @ 2026-03-09 8:43 UTC (permalink / raw)
To: NeilBrown
Cc: Christian Brauner, Alexander Viro, David Howells, Jan Kara,
Chuck Lever, Jeff Layton, Miklos Szeredi, Amir Goldstein,
John Johansen, Paul Moore, James Morris, Serge E. Hallyn,
Stephen Smalley, Darrick J. Wong, linux-kernel, netfs,
linux-fsdevel, linux-nfs, linux-unionfs, apparmor,
linux-security-module, selinux
In-Reply-To: <177300347820.5556.314358492166337403@noble.neil.brown.name>
On Mon, 09 Mar 2026 07:57:58 +1100, NeilBrown wrote:
> [[This fixup for f242581e611e in vfs/vfs-7.1.directory provides a new
> commit description has preserves the error returns and log message, and
> importantly calls cachefiles_io_error() in exactly the same
> circumstances as the original - thanks]]
>
> Rather then using lock_rename() and lookup_one() etc we can use
> the new start_renaming_dentry(). This is part of centralising dir
> locking and lookup so that locking rules can be changed.
>
> [...]
Applied to the vfs-7.1.directory branch of the vfs/vfs.git tree.
Patches in the vfs-7.1.directory branch should appear in linux-next soon.
Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.
It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.
Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs-7.1.directory
[1/1] FIXUP: cachefiles: change cachefiles_bury_object to use start_renaming_dentry()
(fixup)
^ permalink raw reply
* 労基署対策も安心。従業員の健康管理
From: けんさぽ @ 2026-03-09 3:22 UTC (permalink / raw)
To: linux-security-module
ある日、突然
「労働基準監督署ですが、
従業員の健康管理の状況を・・・」とならない為に
事実、令和6年の厚労省の公表によると
労基署に「違反」とされたのは、21,201事業場。
忙しい、人事・労務担当者が後回しにしてしまう
「従業員の健康リスク対策」について
これまで1,000社以上の健康管理代行で気づいた
労基署対策につながるノウハウをお伝えする
Webセミナーのご案内です。
-------------------------------- Personal Health Tech ------
労基署対策につながる
〜健康管理の仕組み化セミナー〜
日 程:3月18日(水)14:00-15:00
3月25日(水)14:00-15:00
会 場:オンライン開催
定 員:15名
<視聴予約はこちら>
https://knsp.work/seminar2/
------------------------------------------------------------
いま、労働基準監督署が
企業への違反指摘の内容として注視している
「健康障害防止措置の不備」をご存じでしょうか?
「健康障害防止措置の不備」つまり、「従業員への健康リスク対策」は
システムやアプリでは対応しきれないため、
人の手間が多くかかり、対策が遅れている企業が多いため
労基署から目をつけられやすい項目になっているのです。
事実、令和6年の厚労省の発表によると、年間2.6万件が労基署の
立ち入り対象となり、その内2.1万件(約80%の確率)で
法令違反を指摘されています。
さらに注目するべきなのは、従業員100人以上への調査割合が多く、
従業員の「健康」に関する違反も22%と高い割合となっています。
しかし、健康管理業務の現場では──
・紙やExcelでは受診状況が追えない
・結果回収が遅れ、管理表がバラバラ
・労基署への申請のためのデータが揃わない
・業務が属人化し、担当者の負担が限界
という問題が深刻化しています。
そんな中でさらに、担当者に求められるのは、
「健康診断の受診管理」「ストレスチェック」「二次健診の勧奨」
「健康経営優良法人の申請」まで年々増え続けています。
では、会社を守るために経営層や人事・労務の担当者は
どのような対策をするべきなのでしょうか。
本セミナーでは、労基署の立ち入り状況を踏まえながら
手間のかかる、従業員の健診・健康管理・健康リスク対策を
ラクに、安く、簡単に仕組み化する「けんさぽ」をご紹介します。
知らない間に、労基署に駆け込まれる前に。
立ち入り調査で「違反」のレッテルを貼られる前に。
健康リスク対策の違反指摘を未然に防ぐための
ノウハウを得ることができますので
この機会にぜひご視聴ください。
<視聴予約はこちら>
https://knsp.work/seminar2/
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃株式会社Personal Health Tech
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
電話:0120-984-925
住所:大阪市中央区南本町2-2-3 本町UNICOビル4F
―――――――――――――――――――――――――――
本メールのご不要な方には大変ご迷惑をおかけいたしました。
配信不要の方はお手数ですが以下のURLから
ワンクリック解除をお願いいたします。
https://knsp.work/mail/
^ permalink raw reply
* Re: [PATCH] integrity: avoid using __weak functions
From: Mimi Zohar @ 2026-03-09 1:01 UTC (permalink / raw)
To: Nathan Chancellor, Arnd Bergmann
Cc: Madhavan Srinivasan, Michael Ellerman, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Arnd Bergmann, Roberto Sassu,
Dmitry Kasatkin, Paul Moore, James Morris, Serge E. Hallyn,
Jarkko Sakkinen, Ard Biesheuvel, Coiby Xu, Nicholas Piggin,
Christophe Leroy (CS GROUP), Christian Borntraeger, Sven Schnelle,
Eric Snowberg, Nick Desaulniers, Bill Wendling, Justin Stitt,
Andrew Donnellan, linuxppc-dev, linux-kernel, linux-s390,
linux-arch, linux-integrity, linux-security-module, keyrings,
llvm
In-Reply-To: <20260306225648.GC2746259@ax162>
On Fri, 2026-03-06 at 15:56 -0700, Nathan Chancellor wrote:
> On Fri, Mar 06, 2026 at 04:03:24PM +0100, Arnd Bergmann wrote:
> > From: Arnd Bergmann <arnd@arndb.de>
> >
> > The security/integrity/secure_boot.c file containing only a __weak function
> > leads to a build failure with clang:
> >
> > Cannot find symbol for section 2: .text.
> > security/integrity/secure_boot.o: failed
> >
> > Moving the function into another file that has at least one non-__weak
> > symbol would solve this, but this is always fragile.
> >
> > Avoid __weak definitions entirely and instead move the stub helper into
> > an asm-generic header that gets used by default on architectures that
> > do not provide their own version. This is consistent with how a lot
> > of other architecture specific functionality works, and is more reliable.
> >
> > Fixes: a0f87ede3bf4 ("integrity: Make arch_ima_get_secureboot integrity-wide")
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > ---
> > This is a larger change than I had hoped for.
> >
> > If you prefer a different way to address the build failure, please
> > treat this as a Reported-by when you apply your own fix
> > ---
> > arch/powerpc/include/asm/secure_boot.h | 6 +++
> > arch/powerpc/kernel/secure_boot.c | 1 -
> > arch/s390/include/asm/secure_boot.h | 9 +++++
> > include/asm-generic/Kbuild | 1 +
> > include/asm-generic/secure_boot.h | 37 +++++++++++++++++++
> > include/linux/secure_boot.h | 8 +---
> > security/integrity/Makefile | 2 +-
> > .../integrity/platform_certs/load_powerpc.c | 2 +-
> > security/integrity/secure_boot.c | 16 --------
> > 9 files changed, 56 insertions(+), 26 deletions(-)
> > create mode 100644 arch/s390/include/asm/secure_boot.h
> > create mode 100644 include/asm-generic/secure_boot.h
> > delete mode 100644 security/integrity/secure_boot.c
>
> Thanks, I noticed this as well. The version I came up with and have been
> locally testing is the following, which is a little bit more compact.
Thanks Arnd, Nathan. LGTM. Nathan, could you send a patch with a proper patch
description.
Mimi
>
> arch/Kconfig | 3 +++
> arch/powerpc/Kconfig | 1 +
> arch/s390/Kconfig | 1 +
> arch/s390/kernel/ipl.c | 10 +++++-----
> include/linux/secure_boot.h | 4 ++++
> security/integrity/Makefile | 2 +-
> security/integrity/secure_boot.c | 16 ----------------
> 7 files changed, 15 insertions(+), 22 deletions(-)
>
> diff --git a/arch/Kconfig b/arch/Kconfig
> index 102ddbd4298e..a6d1c8cc1d64 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -1841,4 +1841,7 @@ config ARCH_WANTS_PRE_LINK_VMLINUX
> config ARCH_HAS_CPU_ATTACK_VECTORS
> bool
>
> +config HAVE_ARCH_GET_SECUREBOOT
> + def_bool EFI
> +
> endmenu
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index c28776660246..e76d6cf0c403 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -1062,6 +1062,7 @@ config PPC_SECURE_BOOT
> depends on IMA_ARCH_POLICY
> imply IMA_SECURE_AND_OR_TRUSTED_BOOT
> select PSERIES_PLPKS if PPC_PSERIES
> + select HAVE_ARCH_GET_SECUREBOOT
> help
> Systems with firmware secure boot enabled need to define security
> policies to extend secure boot to the OS. This config allows a user
> diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
> index 24695ea29d5b..76f191dd208b 100644
> --- a/arch/s390/Kconfig
> +++ b/arch/s390/Kconfig
> @@ -181,6 +181,7 @@ config S390
> select GENERIC_IOREMAP if PCI
> select HAVE_ALIGNED_STRUCT_PAGE
> select HAVE_ARCH_AUDITSYSCALL
> + select HAVE_ARCH_GET_SECUREBOOT
> select HAVE_ARCH_JUMP_LABEL
> select HAVE_ARCH_JUMP_LABEL_RELATIVE
> select HAVE_ARCH_KASAN
> diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
> index 2d01a1713938..3c346b02ceb9 100644
> --- a/arch/s390/kernel/ipl.c
> +++ b/arch/s390/kernel/ipl.c
> @@ -2388,6 +2388,11 @@ void __no_stack_protector s390_reset_system(void)
> diag_amode31_ops.diag308_reset();
> }
>
> +bool arch_get_secureboot(void)
> +{
> + return ipl_secure_flag;
> +}
> +
> #ifdef CONFIG_KEXEC_FILE
>
> int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
> @@ -2505,11 +2510,6 @@ void *ipl_report_finish(struct ipl_report *report)
> return buf;
> }
>
> -bool arch_get_secureboot(void)
> -{
> - return ipl_secure_flag;
> -}
> -
> int ipl_report_free(struct ipl_report *report)
> {
> struct ipl_report_component *comp, *ncomp;
> diff --git a/include/linux/secure_boot.h b/include/linux/secure_boot.h
> index 3ded3f03655c..d17e92351567 100644
> --- a/include/linux/secure_boot.h
> +++ b/include/linux/secure_boot.h
> @@ -10,10 +10,14 @@
>
> #include <linux/types.h>
>
> +#ifdef CONFIG_HAVE_ARCH_GET_SECUREBOOT
> /*
> * Returns true if the platform secure boot is enabled.
> * Returns false if disabled or not supported.
> */
> bool arch_get_secureboot(void);
> +#else
> +static inline bool arch_get_secureboot(void) { return false; }
> +#endif
>
> #endif /* _LINUX_SECURE_BOOT_H */
> diff --git a/security/integrity/Makefile b/security/integrity/Makefile
> index 548665e2b702..45dfdedbdad4 100644
> --- a/security/integrity/Makefile
> +++ b/security/integrity/Makefile
> @@ -5,7 +5,7 @@
>
> obj-$(CONFIG_INTEGRITY) += integrity.o
>
> -integrity-y := iint.o secure_boot.o
> +integrity-y := iint.o
> integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
> integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
> integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
> diff --git a/security/integrity/secure_boot.c b/security/integrity/secure_boot.c
> deleted file mode 100644
> index fc2693c286f8..000000000000
> --- a/security/integrity/secure_boot.c
> +++ /dev/null
> @@ -1,16 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/*
> - * Copyright (C) 2026 Red Hat, Inc. All Rights Reserved.
> - *
> - * Author: Coiby Xu <coxu@redhat.com>
> - */
> -#include <linux/secure_boot.h>
> -
> -/*
> - * Default weak implementation.
> - * Architectures that support secure boot must override this.
> - */
> -__weak bool arch_get_secureboot(void)
> -{
> - return false;
> -}
^ permalink raw reply
* [PATCH] FIXUP: cachefiles: change cachefiles_bury_object to use start_renaming_dentry()
From: NeilBrown @ 2026-03-08 20:57 UTC (permalink / raw)
To: Christian Brauner
Cc: Alexander Viro, David Howells, Jan Kara, Chuck Lever, Jeff Layton,
Miklos Szeredi, Amir Goldstein, John Johansen, Paul Moore,
James Morris, Serge E. Hallyn, Stephen Smalley, Darrick J. Wong,
linux-kernel, netfs, linux-fsdevel, linux-nfs, linux-unionfs,
apparmor, linux-security-module, selinux
In-Reply-To: <20260306-stolz-verzichten-2ee626da4503@brauner>
From: NeilBrown <neil@brown.name>
[[This fixup for f242581e611e in vfs/vfs-7.1.directory provides a new
commit description has preserves the error returns and log message, and
importantly calls cachefiles_io_error() in exactly the same
circumstances as the original - thanks]]
Rather then using lock_rename() and lookup_one() etc we can use
the new start_renaming_dentry(). This is part of centralising dir
locking and lookup so that locking rules can be changed.
Some error conditions are checked in start_renaming_dentry() but need to
be re-checked when an error is reported to ensure correct handling.
The check that ->graveyard is still d_can_lookup() is dropped as this
was checked when ->graveyard was assigned, and it cannot be changed.
Signed-off-by: NeilBrown <neil@brown.name>
Link: https://patch.msgid.link/20260224222542.3458677-11-neilb@ownmail.net
---
fs/cachefiles/namei.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 3af42ec78411..c464c72a51cb 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -309,7 +309,26 @@ int cachefiles_bury_object(struct cachefiles_cache *cache,
rd.flags = 0;
ret = start_renaming_dentry(&rd, 0, rep, &QSTR(nbuffer));
if (ret) {
- cachefiles_io_error(cache, "Cannot lock/lookup in graveyard");
+ /* Some errors aren't fatal */
+ if (ret == -EXDEV)
+ /* double-lock failed */
+ return ret;
+ if (d_unhashed(rep) || rep->d_parent != dir || IS_DEADDIR(d_inode(rep))) {
+ /* the entry was probably culled when we dropped the parent dir
+ * lock */
+ _leave(" = 0 [culled?]");
+ return 0;
+ }
+ if (ret == -EINVAL || ret == -ENOTEMPTY) {
+ cachefiles_io_error(cache, "May not make directory loop");
+ return -EIO;
+ }
+ if (ret == -ENOMEM) {
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ cachefiles_io_error(cache, "Lookup error %d", ret);
return -EIO;
}
--
2.50.0.107.gf914562f5916.dirty
^ permalink raw reply related
* Re: [PATCH v2] docs: security: ipe: fix typos and grammar
From: Randy Dunlap @ 2026-03-08 19:41 UTC (permalink / raw)
To: Evan Ducas, wufan, corbet, skhan
Cc: bagasdotme, linux-security-module, linux-doc, linux-kernel
In-Reply-To: <20260308180734.5792-1-evan.j.ducas@gmail.com>
On 3/8/26 11:07 AM, Evan Ducas wrote:
> Fix several spelling and grammar mistakes in the IPE
> documentation.
>
> No functional change.
>
> Signed-off-by: Evan Ducas <evan.j.ducas@gmail.com>
Acked-by: Randy Dunlap <rdunlap@infradead.org>
Thanks.
> ---
> Documentation/security/ipe.rst | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/security/ipe.rst b/Documentation/security/ipe.rst
> index 4a7d953abcdc..5eb3e6265fbd 100644
> --- a/Documentation/security/ipe.rst
> +++ b/Documentation/security/ipe.rst
> @@ -18,7 +18,7 @@ strong integrity guarantees over both the executable code, and specific
> *data files* on the system, that were critical to its function. These
> specific data files would not be readable unless they passed integrity
> policy. A mandatory access control system would be present, and
> -as a result, xattrs would have to be protected. This lead to a selection
> +as a result, xattrs would have to be protected. This led to a selection
> of what would provide the integrity claims. At the time, there were two
> main mechanisms considered that could guarantee integrity for the system
> with these requirements:
> @@ -195,7 +195,7 @@ of the policy to apply the minute usermode starts. Generally, that storage
> can be handled in one of three ways:
>
> 1. The policy file(s) live on disk and the kernel loads the policy prior
> - to an code path that would result in an enforcement decision.
> + to a code path that would result in an enforcement decision.
> 2. The policy file(s) are passed by the bootloader to the kernel, who
> parses the policy.
> 3. There is a policy file that is compiled into the kernel that is
> @@ -235,8 +235,8 @@ Updatable, Rebootless Policy
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> As requirements change over time (vulnerabilities are found in previously
> -trusted applications, keys roll, etcetera). Updating a kernel to change the
> -meet those security goals is not always a suitable option, as updates are not
> +trusted applications, keys roll, etcetera), updating a kernel to meet
> +those security goals is not always a suitable option, as updates are not
> always risk-free, and blocking a security update leaves systems vulnerable.
> This means IPE requires a policy that can be completely updated (allowing
> revocations of existing policy) from a source external to the kernel (allowing
> @@ -370,7 +370,7 @@ Simplified Policy:
> Finally, IPE's policy is designed for sysadmins, not kernel developers. Instead
> of covering individual LSM hooks (or syscalls), IPE covers operations. This means
> instead of sysadmins needing to know that the syscalls ``mmap``, ``mprotect``,
> -``execve``, and ``uselib`` must have rules protecting them, they must simple know
> +``execve``, and ``uselib`` must have rules protecting them, they must simply know
> that they want to restrict code execution. This limits the amount of bypasses that
> could occur due to a lack of knowledge of the underlying system; whereas the
> maintainers of IPE, being kernel developers can make the correct choice to determine
--
~Randy
^ permalink raw reply
* [PATCH v2] docs: security: ipe: fix typos and grammar
From: Evan Ducas @ 2026-03-08 18:07 UTC (permalink / raw)
To: wufan, corbet, skhan
Cc: rdunlap, bagasdotme, linux-security-module, linux-doc,
linux-kernel, Evan Ducas
Fix several spelling and grammar mistakes in the IPE
documentation.
No functional change.
Signed-off-by: Evan Ducas <evan.j.ducas@gmail.com>
---
Documentation/security/ipe.rst | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/Documentation/security/ipe.rst b/Documentation/security/ipe.rst
index 4a7d953abcdc..5eb3e6265fbd 100644
--- a/Documentation/security/ipe.rst
+++ b/Documentation/security/ipe.rst
@@ -18,7 +18,7 @@ strong integrity guarantees over both the executable code, and specific
*data files* on the system, that were critical to its function. These
specific data files would not be readable unless they passed integrity
policy. A mandatory access control system would be present, and
-as a result, xattrs would have to be protected. This lead to a selection
+as a result, xattrs would have to be protected. This led to a selection
of what would provide the integrity claims. At the time, there were two
main mechanisms considered that could guarantee integrity for the system
with these requirements:
@@ -195,7 +195,7 @@ of the policy to apply the minute usermode starts. Generally, that storage
can be handled in one of three ways:
1. The policy file(s) live on disk and the kernel loads the policy prior
- to an code path that would result in an enforcement decision.
+ to a code path that would result in an enforcement decision.
2. The policy file(s) are passed by the bootloader to the kernel, who
parses the policy.
3. There is a policy file that is compiled into the kernel that is
@@ -235,8 +235,8 @@ Updatable, Rebootless Policy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As requirements change over time (vulnerabilities are found in previously
-trusted applications, keys roll, etcetera). Updating a kernel to change the
-meet those security goals is not always a suitable option, as updates are not
+trusted applications, keys roll, etcetera), updating a kernel to meet
+those security goals is not always a suitable option, as updates are not
always risk-free, and blocking a security update leaves systems vulnerable.
This means IPE requires a policy that can be completely updated (allowing
revocations of existing policy) from a source external to the kernel (allowing
@@ -370,7 +370,7 @@ Simplified Policy:
Finally, IPE's policy is designed for sysadmins, not kernel developers. Instead
of covering individual LSM hooks (or syscalls), IPE covers operations. This means
instead of sysadmins needing to know that the syscalls ``mmap``, ``mprotect``,
-``execve``, and ``uselib`` must have rules protecting them, they must simple know
+``execve``, and ``uselib`` must have rules protecting them, they must simply know
that they want to restrict code execution. This limits the amount of bypasses that
could occur due to a lack of knowledge of the underlying system; whereas the
maintainers of IPE, being kernel developers can make the correct choice to determine
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v5 2/9] landlock: Control pathname UNIX domain socket resolution by path
From: Mickaël Salaün @ 2026-03-08 11:50 UTC (permalink / raw)
To: Günther Noack
Cc: Günther Noack, John Johansen, Tingmao Wang, Justin Suess,
Jann Horn, linux-security-module, Samasth Norway Ananda,
Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
Demi Marie Obenour, Alyssa Ross, Tahera Fahimi
In-Reply-To: <20260307.aeth4weik2Ah@digikod.net>
On Sun, Mar 08, 2026 at 10:09:52AM +0100, Mickaël Salaün wrote:
> On Thu, Feb 19, 2026 at 02:59:38PM +0100, Günther Noack wrote:
> > On Thu, Feb 19, 2026 at 10:45:44AM +0100, Mickaël Salaün wrote:
> > > On Wed, Feb 18, 2026 at 10:37:16AM +0100, Mickaël Salaün wrote:
> > > > On Sun, Feb 15, 2026 at 11:51:50AM +0100, Günther Noack wrote:
> > > > > * Add a new access right LANDLOCK_ACCESS_FS_RESOLVE_UNIX, which
> > > > > controls the look up operations for named UNIX domain sockets. The
> > > > > resolution happens during connect() and sendmsg() (depending on
> > > > > socket type).
> > > > > * Hook into the path lookup in unix_find_bsd() in af_unix.c, using a
> > > > > LSM hook. Make policy decisions based on the new access rights
> > > > > * Increment the Landlock ABI version.
> > > > > * Minor test adaptions to keep the tests working.
> > > > >
> > > > > With this access right, access is granted if either of the following
> > > > > conditions is met:
> > > > >
> > > > > * The target socket's filesystem path was allow-listed using a
> > > > > LANDLOCK_RULE_PATH_BENEATH rule, *or*:
> > > > > * The target socket was created in the same Landlock domain in which
> > > > > LANDLOCK_ACCESS_FS_RESOLVE_UNIX was restricted.
> > > > >
> > > > > In case of a denial, connect() and sendmsg() return EACCES, which is
> > > > > the same error as it is returned if the user does not have the write
> > > > > bit in the traditional Unix file system permissions of that file.
> > > > >
> > > > > This feature was created with substantial discussion and input from
> > > > > Justin Suess, Tingmao Wang and Mickaël Salaün.
> > > > >
> > > > > Cc: Tingmao Wang <m@maowtm.org>
> > > > > Cc: Justin Suess <utilityemal77@gmail.com>
> > > > > Cc: Mickaël Salaün <mic@digikod.net>
> > > > > Suggested-by: Jann Horn <jannh@google.com>
> > > > > Link: https://github.com/landlock-lsm/linux/issues/36
> > > > > Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> > > > > ---
> > > > > include/uapi/linux/landlock.h | 10 ++
> > > > > security/landlock/access.h | 11 +-
> > > > > security/landlock/audit.c | 1 +
> > > > > security/landlock/fs.c | 102 ++++++++++++++++++-
> > > > > security/landlock/limits.h | 2 +-
> > > > > security/landlock/syscalls.c | 2 +-
> > > > > tools/testing/selftests/landlock/base_test.c | 2 +-
> > > > > tools/testing/selftests/landlock/fs_test.c | 5 +-
> > > > > 8 files changed, 128 insertions(+), 7 deletions(-)
> > >
> > > > > index 60ff217ab95b..8d0edf94037d 100644
> > > > > --- a/security/landlock/audit.c
> > > > > +++ b/security/landlock/audit.c
> > > > > @@ -37,6 +37,7 @@ static const char *const fs_access_strings[] = {
> > > > > [BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = "fs.refer",
> > > > > [BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate",
> > > > > [BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev",
> > > > > + [BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX)] = "fs.resolve_unix",
> > > > > };
> > > > >
> > > > > static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
> > > > > diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> > > > > index e764470f588c..76035c6f2bf1 100644
> > > > > --- a/security/landlock/fs.c
> > > > > +++ b/security/landlock/fs.c
> > > > > @@ -27,6 +27,7 @@
> > > > > #include <linux/lsm_hooks.h>
> > > > > #include <linux/mount.h>
> > > > > #include <linux/namei.h>
> > > > > +#include <linux/net.h>
> > > > > #include <linux/path.h>
> > > > > #include <linux/pid.h>
> > > > > #include <linux/rcupdate.h>
> > > > > @@ -314,7 +315,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
> > > > > LANDLOCK_ACCESS_FS_WRITE_FILE | \
> > > > > LANDLOCK_ACCESS_FS_READ_FILE | \
> > > > > LANDLOCK_ACCESS_FS_TRUNCATE | \
> > > > > - LANDLOCK_ACCESS_FS_IOCTL_DEV)
> > > > > + LANDLOCK_ACCESS_FS_IOCTL_DEV | \
> > > > > + LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
> > > > > /* clang-format on */
> > > > >
> > > > > /*
> > > > > @@ -1561,6 +1563,103 @@ static int hook_path_truncate(const struct path *const path)
> > > > > return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
> > > > > }
> > > > >
> > > > > +/**
> > > > > + * unmask_scoped_access - Remove access right bits in @masks in all layers
> > > > > + * where @client and @server have the same domain
> > > > > + *
> > > > > + * This does the same as domain_is_scoped(), but unmasks bits in @masks.
> > > > > + * It can not return early as domain_is_scoped() does.
> > >
> > > Why can't we use the same logic as for other scopes?
> >
> > The other scopes, for which this is implemented in domain_is_scoped(),
> > do not need to do this layer-by-layer.
> >
> > I have to admit, in my initial implementation, I was using
> > domain_is_scoped() directly, and the logic at the end of the hook was
> > roughly:
> >
> > --- BUGGY CODE START ---
> > // ...
> >
> > if (!domain_is_scoped(..., ..., LANDLOCK_ACCESS_FS_RESOLVE_UNIX))
> > return 0; /* permitted */
> >
> > return current_check_access_path(path, LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
> > }
> > --- BUGGY CODE END ---
> >
> > Unfortunately, that is a logic error though -- it implements the formula
> >
> > Access granted if:
> > (FOR-ALL l ∈ layers scoped-access-ok(l)) OR (FOR-ALL l ∈ layers path-access-ok(l)) (WRONG!)
> >
> > but the formula we want is:
> >
> > Access granted if:
> > FOR-ALL l ∈ layers (scoped-access-ok(l) OR path-access-ok(l)) (CORRECT!)
>
> It is worth it to add this explanation to the unmask_scoped_access()
> description, also pointing to the test that check this case.
>
> >
> > This makes a difference in the case where (pseudocode):
> >
> > 1. landlock_restrict_self(RESOLVE_UNIX) // d1
> > 2. create_unix_server("./sock")
> > 3. landlock_restrict_self(RESOLVE_UNIX, rule=Allow(".", RESOLVE_UNIX)) // d2
> > 4. connect_unix("./sock")
> >
> > ,------------------------------------------------d1--,
> > | |
> > | ./sock server |
> > | ^ |
> > | | |
> > | ,------------------------------------------d2--, |
> > | | | | |
> > | | client | |
> > | | | |
> > | '----------------------------------------------' |
> > | |
> > '----------------------------------------------------'
> >
> > (BTW, this scenario is covered in the selftests, that is why there is
> > a variant of these selftests where instead of applying "no domain", we
> > apply a domain with an exception rule like in step 3 in the pseudocode
> > above. Applying that domain should behave the same as applying no
> > domain at all.)
> >
> > Intuitively, it is clear that the access should be granted:
> >
> > - d1 does not restrict access to the server,
> > because the socket was created within d1 itself.
> > - d2 does not restrict access to the server,
> > because it has a rule to allow it
> >
> > But the "buggy code" logic above comes to a different conclusion:
> >
> > - the domain_is_scoped() check denies the access, because the server
> > is in a more privileged domain relative to the client domain.
> > - the current_check_access_path() check denies the access as well,
> > because the socket's path is not allow-listed in d1.
> >
> > In the 'intuitive' reasoning above, we are checking d1 and d2
> > independently of each other. While Landlock is not implemented like
> > that internally, we need to stay consistent with it so that domains
> > compose correctly. The way to do that is to track is access check
> > results on a per-layer basis again, and that is why
> > unmask_scoped_access() uses a layer mask for tracking. The original
> > domain_is_scoped() does not use a layer mask, but that also means that
> > it can return early in some scenarios -- if for any of the relevant
> > layer depths, the client and server domains are not the same, it exits
> > early with failure because it's overall not fulfillable any more. In
> > the RESOLVE_UNIX case though, we need to remember in which layers we
> > failed (both high an low ones), because these layers can still be
> > fulfilled with a PATH_BENEATH rule later.
> >
> > Summary:
> >
> > Option 1: We *can* unify this if you want. It just might come at a
> > small performance penalty for domain_is_scoped(), which now uses the
> > larger layer mask data structure and can't do the same early returns
> > any more as before.
> >
> > Option 2: Alternatively, if we move the two functions into the same
> > module, we can keep them separate but still test them against each
> > other to make sure they are in-line:
> >
> > This invocation should return true...
> >
> > domain_is_scoped(cli, srv, access)
> >
> > ...in the exactly the same situations where this invocation leaves any
> > bits set in layer_masks:
> >
> > landlock_init_layer_masks(dom, access, &layer_masks, LL_KEY_INODE);
> > unmask_scoped_access(cli, srv, &layer_masks, access);
> >
> > What do you prefer?
>
> I was thinking about factoring out domain_is_scoped() with
> unmask_scoped_access() but, after some tests, it is not worth it. Your
> approach is simple and good.
>
> >
> >
> > > > > + *
> > > > > + * @client: Client domain
> > > > > + * @server: Server domain
> > > > > + * @masks: Layer access masks to unmask
> > > > > + * @access: Access bit that controls scoping
> > > > > + */
> > > > > +static void unmask_scoped_access(const struct landlock_ruleset *const client,
> > > > > + const struct landlock_ruleset *const server,
> > > > > + struct layer_access_masks *const masks,
> > > > > + const access_mask_t access)
> > > >
> > > > This helper should be moved to task.c and factored out with
> > > > domain_is_scoped(). This should be a dedicated patch.
> > >
> > > Well, if domain_is_scoped() can be refactored and made generic, it would
> > > make more sense to move it to domain.c
> > >
> > > >
> > > > > +{
> > > > > + int client_layer, server_layer;
> > > > > + const struct landlock_hierarchy *client_walker, *server_walker;
> > > > > +
> > > > > + if (WARN_ON_ONCE(!client))
> > > > > + return; /* should not happen */
>
> Please no comment after ";"
>
> > > > > +
> > > > > + if (!server)
> > > > > + return; /* server has no Landlock domain; nothing to clear */
> > > > > +
> > > > > + client_layer = client->num_layers - 1;
> > > > > + client_walker = client->hierarchy;
> > > > > + server_layer = server->num_layers - 1;
> > > > > + server_walker = server->hierarchy;
> > > > > +
> > > > > + /*
> > > > > + * Clears the access bits at all layers where the client domain is the
> > > > > + * same as the server domain. We start the walk at min(client_layer,
> > > > > + * server_layer). The layer bits until there can not be cleared because
> > > > > + * either the client or the server domain is missing.
> > > > > + */
> > > > > + for (; client_layer > server_layer; client_layer--)
> > > > > + client_walker = client_walker->parent;
> > > > > +
> > > > > + for (; server_layer > client_layer; server_layer--)
> > > > > + server_walker = server_walker->parent;
> > > > > +
> > > > > + for (; client_layer >= 0; client_layer--) {
> > > > > + if (masks->access[client_layer] & access &&
> > > > > + client_walker == server_walker)
>
> I'd prefer to first check client_walker == server_walker and then the
> access. My main concern is that only one bit of access matching
> masks->access[client_layer] clear all the access request bits. In
> practice there is only one, for now, but this code should be more strict
> by following a defensive approach.
>
> > > > > + masks->access[client_layer] &= ~access;
Actually, why not removing the access argument and just reset
masks->access[client_layer]? The doc would need some updates.
> > > > > +
> > > > > + client_walker = client_walker->parent;
> > > > > + server_walker = server_walker->parent;
> > > > > + }
> > > > > +}
> >
^ permalink raw reply
* Re: [PATCH v5 2/9] landlock: Control pathname UNIX domain socket resolution by path
From: Mickaël Salaün @ 2026-03-08 9:18 UTC (permalink / raw)
To: Günther Noack, Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni,
Willem de Bruijn, Sebastian Andrzej Siewior, Jason Xing
Cc: John Johansen, Tingmao Wang, Justin Suess, Jann Horn,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Tahera Fahimi, netdev
In-Reply-To: <20260220.82a8adda6f95@gnoack.org>
On Fri, Feb 20, 2026 at 03:33:28PM +0100, Günther Noack wrote:
> +netdev, we could use some advice on the locking approach in af_unix (see below)
>
> On Wed, Feb 18, 2026 at 10:37:14AM +0100, Mickaël Salaün wrote:
> > On Sun, Feb 15, 2026 at 11:51:50AM +0100, Günther Noack wrote:
> > > diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
> > > index f88fa1f68b77..3a8fc3af0d64 100644
> > > --- a/include/uapi/linux/landlock.h
> > > +++ b/include/uapi/linux/landlock.h
> > > @@ -248,6 +248,15 @@ struct landlock_net_port_attr {
> > > *
> > > * This access right is available since the fifth version of the Landlock
> > > * ABI.
> > > + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX: Look up pathname UNIX domain sockets
> > > + * (:manpage:`unix(7)`). On UNIX domain sockets, this restricts both calls to
> > > + * :manpage:`connect(2)` as well as calls to :manpage:`sendmsg(2)` with an
> > > + * explicit recipient address.
> > > + *
> > > + * This access right only applies to connections to UNIX server sockets which
> > > + * were created outside of the newly created Landlock domain (e.g. from within
> > > + * a parent domain or from an unrestricted process). Newly created UNIX
> > > + * servers within the same Landlock domain continue to be accessible.
> >
> > It might help to add a reference to the explicit scope mechanism.
> >
> > Please squash patch 9/9 into this one and also add a reference here to
> > the rationale described in security/landlock.rst
>
> Sounds good, will do.
>
>
> > > +static void unmask_scoped_access(const struct landlock_ruleset *const client,
> > > + const struct landlock_ruleset *const server,
> > > + struct layer_access_masks *const masks,
> > > + const access_mask_t access)
> >
> > This helper should be moved to task.c and factored out with
> > domain_is_scoped(). This should be a dedicated patch.
>
> (already discussed in another follow-up mail)
>
>
> > > +static int hook_unix_find(const struct path *const path, struct sock *other,
> > > + int flags)
> > > +{
> > > + const struct landlock_ruleset *dom_other;
> > > + const struct landlock_cred_security *subject;
> > > + struct layer_access_masks layer_masks;
> > > + struct landlock_request request = {};
> > > + static const struct access_masks fs_resolve_unix = {
> > > + .fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> > > + };
> > > +
> > > + /* Lookup for the purpose of saving coredumps is OK. */
> > > + if (unlikely(flags & SOCK_COREDUMP))
> > > + return 0;
> > > +
> > > + /* Access to the same (or a lower) domain is always allowed. */
> > > + subject = landlock_get_applicable_subject(current_cred(),
> > > + fs_resolve_unix, NULL);
> > > +
> > > + if (!subject)
> > > + return 0;
> > > +
> > > + if (!landlock_init_layer_masks(subject->domain, fs_resolve_unix.fs,
> > > + &layer_masks, LANDLOCK_KEY_INODE))
> > > + return 0;
> > > +
> > > + /* Checks the layers in which we are connecting within the same domain. */
> > > + dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
> >
> > We need to call unix_state_lock(other) before reading it, and check for
> > SOCK_DEAD, and check sk_socket before dereferencing it. Indeed,
> > the socket can be make orphan (see unix_dgram_sendmsg and
> > unix_stream_connect). I *think* a socket cannot be "resurrected" or
> > recycled once dead, so we may assume there is no race condition wrt
> > dom_other, but please double check. This lockless call should be made
> > clear in the LSM hook. It's OK to not lock the socket before
> > security_unix_find() (1) because no LSM might implement and (2) they
> > might not need to lock the socket (e.g. if the caller is not sandboxed).
> >
> > The updated code should look something like this:
> >
> > unix_state_unlock(other);
unix_state_lock(other) of course...
> > if (unlikely(sock_flag(other, SOCK_DEAD) || !other->sk_socket)) {
> > unix_state_unlock(other);
> > return 0;
> > }
> >
> > dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
> > unix_state_unlock(other);
>
> Thank you for spotting the locking concern!
>
> @anyone from netdev, could you please advise on the correct locking
> approach here?
>
> * Do we need ot check SOCK_DEAD?
>
> You are saying that we need to do that, but it's not clear to me
> why.
>
> If you look at the places where unix_find_other() is called in
> af_unix.c, then you'll find that all of them check for SOCK_DEAD and
> then restart from unix_find_other() if they do actually discover
> that the socket is dead. I think that this is catching this race
> condition scenario:
>
> * a server socket exists and is alive
> * A client connects: af_unix.c's unix_stream_connect() calls
> unix_find_other() and finds the server socket...
> * (Concurrently): The server closes the socket and enters
> unix_release_sock(). This function:
> 1. disassociates the server sock from the named socket inode
> number in the hash table (=> future unix_find_other() calls
> will fail).
> 2. calls sock_orphan(), which sets SOCK_DEAD.
> * ...(client connection resuming): unix_stream_connect() continues,
> grabs the unix_state_lock(), which apparently protects everything
> here, checks that the socket is not dead - and discovers that it
> IS suddenly dead. This was not supposed to happen. The code
> recovers from that by retrying everything starting with the
> unix_find_other() call. From unix_release_sock(), we know that
> the inode is not associated with the sock any more -- so the
> unix_find_socket_by_inode() call should be failing on the next
> attempt.
>
> (This works with unix_dgram_connect() and unix_dgram_sendmsg() as
> well.)
>
> The comments next to the SOCK_DEAD checks are also suggesting this.
>
> * What lock to use
>
> I am having trouble reasoning about what lock is used for what in
> this code.
It's not clear to me neither, and it looks like it's not consistent
across protocols.
>
> Is it possible that the lock protecting ->sk_socket is the
> ->sk_callback_lock, not the unix_state_lock()? The only callers to
> sk_set_socket are either sock_orphan/sock_graft (both grabbing
> sk_callback_lock), or they are creating new struct sock objects that
> they own exclusively, and don't need locks yet.
>
> Admittedly, in af_unix.c, sock_orphan() and sock_graft() only get
> called in contexts where the unix_state_lock() is held, so it would
> probably work as well to lock that, but it is maybe a more
> fine-grained approach to use sk_callback_lock?
>
>
> So... how about a scheme where we only check for ->sk_socket not being
> NULL:
>
> read_lock_bh(&other->sk_callback_lock);
> struct sock *other_sk = other->sk_socket;
> if (!other_sk) {
> read_unlock_bh(&other->sk_callback_lock);
> return 0;
> }
> /* XXX double check whether we need a lock here too */
> struct file *file = other_sk->file;
> if (!other_file) {
> read_unlock_bh(&other->sk_callback_lock);
> return 0;
> }
> read_unlock_bh(&other->sk_callback_lock);
>
> If this fails, that would in my understanding also be because the
> socket has died after the path lookup. We'd then return 0 (success),
> because we know that the surrounding SOCK_DEAD logic will repeat
> everything starting from the path lookup operation (this time likely
> failing with ECONNREFUSED, but maybe also with a success, if another
> server process was quick enough).
>
> Does this sound reasonable?
Actually, since commit 983512f3a87f ("net: Drop the lock in
skb_may_tx_timestamp()"), we can just use RCU + READ_ONCE(sk_socket) +
READ_ONCE(file). The socket and file should only be freed after the RCU
grace periode. As a safeguard, this commit should be a Depends-on.
However, it is safer to return -ECONNREFULED when sk_socket or file are
NULL.
I would be good to hear from netdev folks though.
TIL, there is an LSM hook for sock_graft().
> –Günther
>
^ permalink raw reply
* Re: [PATCH v5 2/9] landlock: Control pathname UNIX domain socket resolution by path
From: Mickaël Salaün @ 2026-03-08 9:09 UTC (permalink / raw)
To: Günther Noack
Cc: John Johansen, Tingmao Wang, Justin Suess, Jann Horn,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Tahera Fahimi
In-Reply-To: <20260215105158.28132-3-gnoack3000@gmail.com>
On Sun, Feb 15, 2026 at 11:51:50AM +0100, Günther Noack wrote:
> * Add a new access right LANDLOCK_ACCESS_FS_RESOLVE_UNIX, which
> controls the look up operations for named UNIX domain sockets. The
> resolution happens during connect() and sendmsg() (depending on
> socket type).
> * Hook into the path lookup in unix_find_bsd() in af_unix.c, using a
> LSM hook. Make policy decisions based on the new access rights
> * Increment the Landlock ABI version.
> * Minor test adaptions to keep the tests working.
>
> With this access right, access is granted if either of the following
> conditions is met:
>
> * The target socket's filesystem path was allow-listed using a
> LANDLOCK_RULE_PATH_BENEATH rule, *or*:
> * The target socket was created in the same Landlock domain in which
> LANDLOCK_ACCESS_FS_RESOLVE_UNIX was restricted.
>
> In case of a denial, connect() and sendmsg() return EACCES, which is
> the same error as it is returned if the user does not have the write
> bit in the traditional Unix file system permissions of that file.
It is not the same error code as for scoped abstract unix socket
(EPERM), but it makes sense because the scope restrictions are closer to
ambient rights (i.e. similar to a network isolation), whereas here the
final denial comes from a missing FS rule (and all FS access checks may
return EACCES). It would be worth mentioning this difference in the
user documentation.
>
> This feature was created with substantial discussion and input from
> Justin Suess, Tingmao Wang and Mickaël Salaün.
>
> Cc: Tingmao Wang <m@maowtm.org>
> Cc: Justin Suess <utilityemal77@gmail.com>
> Cc: Mickaël Salaün <mic@digikod.net>
> Suggested-by: Jann Horn <jannh@google.com>
> Link: https://github.com/landlock-lsm/linux/issues/36
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
> include/uapi/linux/landlock.h | 10 ++
> security/landlock/access.h | 11 +-
> security/landlock/audit.c | 1 +
> security/landlock/fs.c | 102 ++++++++++++++++++-
> security/landlock/limits.h | 2 +-
> security/landlock/syscalls.c | 2 +-
> tools/testing/selftests/landlock/base_test.c | 2 +-
> tools/testing/selftests/landlock/fs_test.c | 5 +-
> 8 files changed, 128 insertions(+), 7 deletions(-)
> +static int hook_unix_find(const struct path *const path, struct sock *other,
> + int flags)
> +{
> + const struct landlock_ruleset *dom_other;
> + const struct landlock_cred_security *subject;
> + struct layer_access_masks layer_masks;
> + struct landlock_request request = {};
> + static const struct access_masks fs_resolve_unix = {
> + .fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + };
> +
> + /* Lookup for the purpose of saving coredumps is OK. */
> + if (unlikely(flags & SOCK_COREDUMP))
> + return 0;
> +
> + /* Access to the same (or a lower) domain is always allowed. */
> + subject = landlock_get_applicable_subject(current_cred(),
> + fs_resolve_unix, NULL);
> +
> + if (!subject)
> + return 0;
> +
> + if (!landlock_init_layer_masks(subject->domain, fs_resolve_unix.fs,
> + &layer_masks, LANDLOCK_KEY_INODE))
> + return 0;
> +
> + /* Checks the layers in which we are connecting within the same domain. */
> + dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
> + unmask_scoped_access(subject->domain, dom_other, &layer_masks,
> + fs_resolve_unix.fs);
> +
> + if (layer_access_masks_empty(&layer_masks))
I don't see the point of this helper and this call wrt the following
is_access_to_paths_allowed() call and the is_layer_masks_allowed()
check.
> + return 0;
> +
> + /* Checks the connections to allow-listed paths. */
> + if (is_access_to_paths_allowed(subject->domain, path,
> + fs_resolve_unix.fs, &layer_masks,
> + &request, NULL, 0, NULL, NULL, NULL))
> + return 0;
> +
> + landlock_log_denial(subject, &request);
> + return -EACCES;
> +}
^ permalink raw reply
* Re: [PATCH v5 2/9] landlock: Control pathname UNIX domain socket resolution by path
From: Mickaël Salaün @ 2026-03-08 9:09 UTC (permalink / raw)
To: Günther Noack
Cc: Günther Noack, John Johansen, Tingmao Wang, Justin Suess,
Jann Horn, linux-security-module, Samasth Norway Ananda,
Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
Demi Marie Obenour, Alyssa Ross, Tahera Fahimi
In-Reply-To: <aZcXSmhZRVcRCvum@google.com>
On Thu, Feb 19, 2026 at 02:59:38PM +0100, Günther Noack wrote:
> On Thu, Feb 19, 2026 at 10:45:44AM +0100, Mickaël Salaün wrote:
> > On Wed, Feb 18, 2026 at 10:37:16AM +0100, Mickaël Salaün wrote:
> > > On Sun, Feb 15, 2026 at 11:51:50AM +0100, Günther Noack wrote:
> > > > * Add a new access right LANDLOCK_ACCESS_FS_RESOLVE_UNIX, which
> > > > controls the look up operations for named UNIX domain sockets. The
> > > > resolution happens during connect() and sendmsg() (depending on
> > > > socket type).
> > > > * Hook into the path lookup in unix_find_bsd() in af_unix.c, using a
> > > > LSM hook. Make policy decisions based on the new access rights
> > > > * Increment the Landlock ABI version.
> > > > * Minor test adaptions to keep the tests working.
> > > >
> > > > With this access right, access is granted if either of the following
> > > > conditions is met:
> > > >
> > > > * The target socket's filesystem path was allow-listed using a
> > > > LANDLOCK_RULE_PATH_BENEATH rule, *or*:
> > > > * The target socket was created in the same Landlock domain in which
> > > > LANDLOCK_ACCESS_FS_RESOLVE_UNIX was restricted.
> > > >
> > > > In case of a denial, connect() and sendmsg() return EACCES, which is
> > > > the same error as it is returned if the user does not have the write
> > > > bit in the traditional Unix file system permissions of that file.
> > > >
> > > > This feature was created with substantial discussion and input from
> > > > Justin Suess, Tingmao Wang and Mickaël Salaün.
> > > >
> > > > Cc: Tingmao Wang <m@maowtm.org>
> > > > Cc: Justin Suess <utilityemal77@gmail.com>
> > > > Cc: Mickaël Salaün <mic@digikod.net>
> > > > Suggested-by: Jann Horn <jannh@google.com>
> > > > Link: https://github.com/landlock-lsm/linux/issues/36
> > > > Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> > > > ---
> > > > include/uapi/linux/landlock.h | 10 ++
> > > > security/landlock/access.h | 11 +-
> > > > security/landlock/audit.c | 1 +
> > > > security/landlock/fs.c | 102 ++++++++++++++++++-
> > > > security/landlock/limits.h | 2 +-
> > > > security/landlock/syscalls.c | 2 +-
> > > > tools/testing/selftests/landlock/base_test.c | 2 +-
> > > > tools/testing/selftests/landlock/fs_test.c | 5 +-
> > > > 8 files changed, 128 insertions(+), 7 deletions(-)
> >
> > > > index 60ff217ab95b..8d0edf94037d 100644
> > > > --- a/security/landlock/audit.c
> > > > +++ b/security/landlock/audit.c
> > > > @@ -37,6 +37,7 @@ static const char *const fs_access_strings[] = {
> > > > [BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = "fs.refer",
> > > > [BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate",
> > > > [BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev",
> > > > + [BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX)] = "fs.resolve_unix",
> > > > };
> > > >
> > > > static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
> > > > diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> > > > index e764470f588c..76035c6f2bf1 100644
> > > > --- a/security/landlock/fs.c
> > > > +++ b/security/landlock/fs.c
> > > > @@ -27,6 +27,7 @@
> > > > #include <linux/lsm_hooks.h>
> > > > #include <linux/mount.h>
> > > > #include <linux/namei.h>
> > > > +#include <linux/net.h>
> > > > #include <linux/path.h>
> > > > #include <linux/pid.h>
> > > > #include <linux/rcupdate.h>
> > > > @@ -314,7 +315,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
> > > > LANDLOCK_ACCESS_FS_WRITE_FILE | \
> > > > LANDLOCK_ACCESS_FS_READ_FILE | \
> > > > LANDLOCK_ACCESS_FS_TRUNCATE | \
> > > > - LANDLOCK_ACCESS_FS_IOCTL_DEV)
> > > > + LANDLOCK_ACCESS_FS_IOCTL_DEV | \
> > > > + LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
> > > > /* clang-format on */
> > > >
> > > > /*
> > > > @@ -1561,6 +1563,103 @@ static int hook_path_truncate(const struct path *const path)
> > > > return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
> > > > }
> > > >
> > > > +/**
> > > > + * unmask_scoped_access - Remove access right bits in @masks in all layers
> > > > + * where @client and @server have the same domain
> > > > + *
> > > > + * This does the same as domain_is_scoped(), but unmasks bits in @masks.
> > > > + * It can not return early as domain_is_scoped() does.
> >
> > Why can't we use the same logic as for other scopes?
>
> The other scopes, for which this is implemented in domain_is_scoped(),
> do not need to do this layer-by-layer.
>
> I have to admit, in my initial implementation, I was using
> domain_is_scoped() directly, and the logic at the end of the hook was
> roughly:
>
> --- BUGGY CODE START ---
> // ...
>
> if (!domain_is_scoped(..., ..., LANDLOCK_ACCESS_FS_RESOLVE_UNIX))
> return 0; /* permitted */
>
> return current_check_access_path(path, LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
> }
> --- BUGGY CODE END ---
>
> Unfortunately, that is a logic error though -- it implements the formula
>
> Access granted if:
> (FOR-ALL l ∈ layers scoped-access-ok(l)) OR (FOR-ALL l ∈ layers path-access-ok(l)) (WRONG!)
>
> but the formula we want is:
>
> Access granted if:
> FOR-ALL l ∈ layers (scoped-access-ok(l) OR path-access-ok(l)) (CORRECT!)
It is worth it to add this explanation to the unmask_scoped_access()
description, also pointing to the test that check this case.
>
> This makes a difference in the case where (pseudocode):
>
> 1. landlock_restrict_self(RESOLVE_UNIX) // d1
> 2. create_unix_server("./sock")
> 3. landlock_restrict_self(RESOLVE_UNIX, rule=Allow(".", RESOLVE_UNIX)) // d2
> 4. connect_unix("./sock")
>
> ,------------------------------------------------d1--,
> | |
> | ./sock server |
> | ^ |
> | | |
> | ,------------------------------------------d2--, |
> | | | | |
> | | client | |
> | | | |
> | '----------------------------------------------' |
> | |
> '----------------------------------------------------'
>
> (BTW, this scenario is covered in the selftests, that is why there is
> a variant of these selftests where instead of applying "no domain", we
> apply a domain with an exception rule like in step 3 in the pseudocode
> above. Applying that domain should behave the same as applying no
> domain at all.)
>
> Intuitively, it is clear that the access should be granted:
>
> - d1 does not restrict access to the server,
> because the socket was created within d1 itself.
> - d2 does not restrict access to the server,
> because it has a rule to allow it
>
> But the "buggy code" logic above comes to a different conclusion:
>
> - the domain_is_scoped() check denies the access, because the server
> is in a more privileged domain relative to the client domain.
> - the current_check_access_path() check denies the access as well,
> because the socket's path is not allow-listed in d1.
>
> In the 'intuitive' reasoning above, we are checking d1 and d2
> independently of each other. While Landlock is not implemented like
> that internally, we need to stay consistent with it so that domains
> compose correctly. The way to do that is to track is access check
> results on a per-layer basis again, and that is why
> unmask_scoped_access() uses a layer mask for tracking. The original
> domain_is_scoped() does not use a layer mask, but that also means that
> it can return early in some scenarios -- if for any of the relevant
> layer depths, the client and server domains are not the same, it exits
> early with failure because it's overall not fulfillable any more. In
> the RESOLVE_UNIX case though, we need to remember in which layers we
> failed (both high an low ones), because these layers can still be
> fulfilled with a PATH_BENEATH rule later.
>
> Summary:
>
> Option 1: We *can* unify this if you want. It just might come at a
> small performance penalty for domain_is_scoped(), which now uses the
> larger layer mask data structure and can't do the same early returns
> any more as before.
>
> Option 2: Alternatively, if we move the two functions into the same
> module, we can keep them separate but still test them against each
> other to make sure they are in-line:
>
> This invocation should return true...
>
> domain_is_scoped(cli, srv, access)
>
> ...in the exactly the same situations where this invocation leaves any
> bits set in layer_masks:
>
> landlock_init_layer_masks(dom, access, &layer_masks, LL_KEY_INODE);
> unmask_scoped_access(cli, srv, &layer_masks, access);
>
> What do you prefer?
I was thinking about factoring out domain_is_scoped() with
unmask_scoped_access() but, after some tests, it is not worth it. Your
approach is simple and good.
>
>
> > > > + *
> > > > + * @client: Client domain
> > > > + * @server: Server domain
> > > > + * @masks: Layer access masks to unmask
> > > > + * @access: Access bit that controls scoping
> > > > + */
> > > > +static void unmask_scoped_access(const struct landlock_ruleset *const client,
> > > > + const struct landlock_ruleset *const server,
> > > > + struct layer_access_masks *const masks,
> > > > + const access_mask_t access)
> > >
> > > This helper should be moved to task.c and factored out with
> > > domain_is_scoped(). This should be a dedicated patch.
> >
> > Well, if domain_is_scoped() can be refactored and made generic, it would
> > make more sense to move it to domain.c
> >
> > >
> > > > +{
> > > > + int client_layer, server_layer;
> > > > + const struct landlock_hierarchy *client_walker, *server_walker;
> > > > +
> > > > + if (WARN_ON_ONCE(!client))
> > > > + return; /* should not happen */
Please no comment after ";"
> > > > +
> > > > + if (!server)
> > > > + return; /* server has no Landlock domain; nothing to clear */
> > > > +
> > > > + client_layer = client->num_layers - 1;
> > > > + client_walker = client->hierarchy;
> > > > + server_layer = server->num_layers - 1;
> > > > + server_walker = server->hierarchy;
> > > > +
> > > > + /*
> > > > + * Clears the access bits at all layers where the client domain is the
> > > > + * same as the server domain. We start the walk at min(client_layer,
> > > > + * server_layer). The layer bits until there can not be cleared because
> > > > + * either the client or the server domain is missing.
> > > > + */
> > > > + for (; client_layer > server_layer; client_layer--)
> > > > + client_walker = client_walker->parent;
> > > > +
> > > > + for (; server_layer > client_layer; server_layer--)
> > > > + server_walker = server_walker->parent;
> > > > +
> > > > + for (; client_layer >= 0; client_layer--) {
> > > > + if (masks->access[client_layer] & access &&
> > > > + client_walker == server_walker)
I'd prefer to first check client_walker == server_walker and then the
access. My main concern is that only one bit of access matching
masks->access[client_layer] clear all the access request bits. In
practice there is only one, for now, but this code should be more strict
by following a defensive approach.
> > > > + masks->access[client_layer] &= ~access;
> > > > +
> > > > + client_walker = client_walker->parent;
> > > > + server_walker = server_walker->parent;
> > > > + }
> > > > +}
>
^ permalink raw reply
* Re: [PATCH] docs: security: ipe: fix typos and grammar
From: Bagas Sanjaya @ 2026-03-08 7:48 UTC (permalink / raw)
To: Evan Ducas, wufan, corbet, skhan
Cc: linux-security-module, linux-doc, linux-kernel
In-Reply-To: <20260308031633.28890-1-evan.j.ducas@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 721 bytes --]
On Sat, Mar 07, 2026 at 10:16:33PM -0500, Evan Ducas wrote:
> As requirements change over time (vulnerabilities are found in previously
> -trusted applications, keys roll, etcetera). Updating a kernel to change the
> +trusted applications, keys roll, etcetera). Updating a kernel to change to
> meet those security goals is not always a suitable option, as updates are not
> always risk-free, and blocking a security update leaves systems vulnerable.
> This means IPE requires a policy that can be completely updated (allowing
As requirements change over time ..., updating a kernel to meet ..., yet
blocking a security update ... .
Thanks.
--
An old man doll... just what I always wanted! - Clara
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH] docs: security: ipe: fix typos and grammar
From: Randy Dunlap @ 2026-03-08 6:17 UTC (permalink / raw)
To: Evan Ducas, wufan, corbet, skhan
Cc: linux-security-module, linux-doc, linux-kernel
In-Reply-To: <20260308031633.28890-1-evan.j.ducas@gmail.com>
Hi,
On 3/7/26 7:16 PM, Evan Ducas wrote:
> @@ -235,7 +235,7 @@ Updatable, Rebootless Policy
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> As requirements change over time (vulnerabilities are found in previously
> -trusted applications, keys roll, etcetera). Updating a kernel to change the
> +trusted applications, keys roll, etcetera). Updating a kernel to change to
What is the first sentence in the paragraph above?
Maybe s/. U/, u/ ?
> meet those security goals is not always a suitable option, as updates are not
> always risk-free, and blocking a security update leaves systems vulnerable.
> This means IPE requires a policy that can be completely updated (allowing
--
~Randy
^ permalink raw reply
* Re: [syzbot] [fuse?] general protection fault in task_work_cancel
From: syzbot @ 2026-03-08 3:46 UTC (permalink / raw)
To: gnoack, linux-fsdevel, linux-kernel, linux-security-module, mic,
miklos, penguin-kernel, syzkaller-bugs
In-Reply-To: <69abb4e3.050a0220.13f275.003d.GAE@google.com>
syzbot has found a reproducer for the following issue on:
HEAD commit: 4ae12d8bd9a8 Merge tag 'kbuild-fixes-7.0-2' of git://git.k..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=17dc475a580000
kernel config: https://syzkaller.appspot.com/x/.config?x=779072223d02a312
dashboard link: https://syzkaller.appspot.com/bug?extid=741e2278ef71fef03a10
compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=130b075a580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/010ac4052aed/disk-4ae12d8b.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/2aad8bef9031/vmlinux-4ae12d8b.xz
kernel image: https://storage.googleapis.com/syzbot-assets/fd350ec4896a/bzImage-4ae12d8b.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+741e2278ef71fef03a10@syzkaller.appspotmail.com
Oops: general protection fault, probably for non-canonical address 0xdffffc000000013c: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x00000000000009e0-0x00000000000009e7]
CPU: 1 UID: 0 PID: 13249 Comm: syz.1.1775 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
RIP: 0010:task_work_pending include/linux/task_work.h:26 [inline]
RIP: 0010:task_work_cancel_match kernel/task_work.c:124 [inline]
RIP: 0010:task_work_cancel+0x8a/0x220 kernel/task_work.c:187
Code: b8 f1 f1 f1 f1 f8 f3 f3 f3 4b 89 44 25 00 e8 ad b9 35 00 43 c6 44 25 04 00 49 89 de 48 81 c3 e0 09 00 00 49 89 df 49 c1 ef 03 <43> 80 3c 27 00 74 08 48 89 df e8 17 fe 9f 00 48 83 3b 00 75 51 e8
RSP: 0018:ffffc9000ddffb20 EFLAGS: 00010216
RAX: ffffffff818fdfc3 RBX: 00000000000009e0 RCX: ffff88805d5c3d00
RDX: 0000000000000000 RSI: ffff888032f5c540 RDI: 0000000000000000
RBP: ffffc9000ddffbd0 R08: ffffc9000ddffc97 R09: 1ffff92001bbff92
R10: dffffc0000000000 R11: fffff52001bbff93 R12: dffffc0000000000
R13: 1ffff92001bbff68 R14: 0000000000000000 R15: 000000000000013c
FS: 00007f9c8a1cb6c0(0000) GS:ffff888125561000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000200000010000 CR3: 0000000059bf0000 CR4: 0000000000350ef0
Call Trace:
<TASK>
cancel_tsync_works security/landlock/tsync.c:415 [inline]
landlock_restrict_sibling_threads+0xdc4/0x11f0 security/landlock/tsync.c:533
__do_sys_landlock_restrict_self security/landlock/syscalls.c:574 [inline]
__se_sys_landlock_restrict_self+0x540/0x810 security/landlock/syscalls.c:482
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f9c8939c799
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f9c8a1cb028 EFLAGS: 00000246 ORIG_RAX: 00000000000001be
RAX: ffffffffffffffda RBX: 00007f9c89616180 RCX: 00007f9c8939c799
RDX: 0000000000000000 RSI: 0000000000000008 RDI: 0000000000000003
RBP: 00007f9c89432bd9 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f9c89616218 R14: 00007f9c89616180 R15: 00007ffee5d65d48
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:task_work_pending include/linux/task_work.h:26 [inline]
RIP: 0010:task_work_cancel_match kernel/task_work.c:124 [inline]
RIP: 0010:task_work_cancel+0x8a/0x220 kernel/task_work.c:187
Code: b8 f1 f1 f1 f1 f8 f3 f3 f3 4b 89 44 25 00 e8 ad b9 35 00 43 c6 44 25 04 00 49 89 de 48 81 c3 e0 09 00 00 49 89 df 49 c1 ef 03 <43> 80 3c 27 00 74 08 48 89 df e8 17 fe 9f 00 48 83 3b 00 75 51 e8
RSP: 0018:ffffc9000ddffb20 EFLAGS: 00010216
RAX: ffffffff818fdfc3 RBX: 00000000000009e0 RCX: ffff88805d5c3d00
RDX: 0000000000000000 RSI: ffff888032f5c540 RDI: 0000000000000000
RBP: ffffc9000ddffbd0 R08: ffffc9000ddffc97 R09: 1ffff92001bbff92
R10: dffffc0000000000 R11: fffff52001bbff93 R12: dffffc0000000000
R13: 1ffff92001bbff68 R14: 0000000000000000 R15: 000000000000013c
FS: 00007f9c8a1cb6c0(0000) GS:ffff888125561000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f810d34da08 CR3: 0000000059bf0000 CR4: 0000000000350ef0
----------------
Code disassembly (best guess):
0: b8 f1 f1 f1 f1 mov $0xf1f1f1f1,%eax
5: f8 clc
6: f3 f3 f3 4b 89 44 25 repz repz xrelease mov %rax,0x0(%r13,%r12,1)
d: 00
e: e8 ad b9 35 00 call 0x35b9c0
13: 43 c6 44 25 04 00 movb $0x0,0x4(%r13,%r12,1)
19: 49 89 de mov %rbx,%r14
1c: 48 81 c3 e0 09 00 00 add $0x9e0,%rbx
23: 49 89 df mov %rbx,%r15
26: 49 c1 ef 03 shr $0x3,%r15
* 2a: 43 80 3c 27 00 cmpb $0x0,(%r15,%r12,1) <-- trapping instruction
2f: 74 08 je 0x39
31: 48 89 df mov %rbx,%rdi
34: e8 17 fe 9f 00 call 0x9ffe50
39: 48 83 3b 00 cmpq $0x0,(%rbx)
3d: 75 51 jne 0x90
3f: e8 .byte 0xe8
---
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
^ permalink raw reply
* [PATCH] docs: security: ipe: fix typos and grammar
From: Evan Ducas @ 2026-03-08 3:16 UTC (permalink / raw)
To: wufan, corbet, skhan
Cc: linux-security-module, linux-doc, linux-kernel, Evan Ducas
Fix several spelling and grammar mistakes in the IPE
documentation.
No functional change.
Signed-off-by: Evan Ducas <evan.j.ducas@gmail.com>
---
Documentation/security/ipe.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Documentation/security/ipe.rst b/Documentation/security/ipe.rst
index 4a7d953abcdc..d29824d7fd2d 100644
--- a/Documentation/security/ipe.rst
+++ b/Documentation/security/ipe.rst
@@ -18,7 +18,7 @@ strong integrity guarantees over both the executable code, and specific
*data files* on the system, that were critical to its function. These
specific data files would not be readable unless they passed integrity
policy. A mandatory access control system would be present, and
-as a result, xattrs would have to be protected. This lead to a selection
+as a result, xattrs would have to be protected. This led to a selection
of what would provide the integrity claims. At the time, there were two
main mechanisms considered that could guarantee integrity for the system
with these requirements:
@@ -195,7 +195,7 @@ of the policy to apply the minute usermode starts. Generally, that storage
can be handled in one of three ways:
1. The policy file(s) live on disk and the kernel loads the policy prior
- to an code path that would result in an enforcement decision.
+ to a code path that would result in an enforcement decision.
2. The policy file(s) are passed by the bootloader to the kernel, who
parses the policy.
3. There is a policy file that is compiled into the kernel that is
@@ -235,7 +235,7 @@ Updatable, Rebootless Policy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As requirements change over time (vulnerabilities are found in previously
-trusted applications, keys roll, etcetera). Updating a kernel to change the
+trusted applications, keys roll, etcetera). Updating a kernel to change to
meet those security goals is not always a suitable option, as updates are not
always risk-free, and blocking a security update leaves systems vulnerable.
This means IPE requires a policy that can be completely updated (allowing
@@ -370,7 +370,7 @@ Simplified Policy:
Finally, IPE's policy is designed for sysadmins, not kernel developers. Instead
of covering individual LSM hooks (or syscalls), IPE covers operations. This means
instead of sysadmins needing to know that the syscalls ``mmap``, ``mprotect``,
-``execve``, and ``uselib`` must have rules protecting them, they must simple know
+``execve``, and ``uselib`` must have rules protecting them, they must simply know
that they want to restrict code execution. This limits the amount of bypasses that
could occur due to a lack of knowledge of the underlying system; whereas the
maintainers of IPE, being kernel developers can make the correct choice to determine
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] landlock: add missing task != NULL check in cancel_tsync_works()
From: Mickaël Salaün @ 2026-03-07 9:01 UTC (permalink / raw)
To: Tetsuo Handa
Cc: linux-security-module, Günther Noack, syzkaller-bugs, syzbot
In-Reply-To: <a96efa12-003b-46ed-9444-40b69d84fa05@I-love.SAKURA.ne.jp>
Thanks. This issue was fixed in -next with
https://lore.kernel.org/all/20260217122341.2359582-1-mic@digikod.net/
I'll send a PR next week.
On Sat, Mar 07, 2026 at 02:21:32PM +0900, Tetsuo Handa wrote:
> syzbot is reporting NULL pointer dereference at cancel_tsync_works(), for
> tsync_works_release() checks for works->works[i]->task != NULL but
> cancel_tsync_works() does not.
>
> works->works[i]->task becomes NULL when tsync_works_provide() incremented
> works->size and then task_work_add() returned an error. Therefore,
> cancel_tsync_works() needs to check for works->works[i]->task != NULL.
>
> Reported-by: syzbot <syzbot+741e2278ef71fef03a10@syzkaller.appspotmail.com>
> Closes: https://syzkaller.appspot.com/bug?extid=741e2278ef71fef03a10
> Fixes: 42fc7e6543f6 ("landlock: Multithreading support for landlock_restrict_self()")
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
> security/landlock/tsync.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
> index de01aa899751..8925acbef8a5 100644
> --- a/security/landlock/tsync.c
> +++ b/security/landlock/tsync.c
> @@ -412,6 +412,8 @@ static void cancel_tsync_works(struct tsync_works *works,
> int i;
>
> for (i = 0; i < works->size; i++) {
> + if (!works->works[i]->task)
> + continue;
> if (!task_work_cancel(works->works[i]->task,
> &works->works[i]->work))
> continue;
> --
> 2.53.0
>
>
^ permalink raw reply
* [PATCH] landlock: add missing task != NULL check in cancel_tsync_works()
From: Tetsuo Handa @ 2026-03-07 5:21 UTC (permalink / raw)
To: linux-security-module, Günther Noack; +Cc: syzkaller-bugs, syzbot
In-Reply-To: <69abb4e3.050a0220.13f275.003d.GAE@google.com>
syzbot is reporting NULL pointer dereference at cancel_tsync_works(), for
tsync_works_release() checks for works->works[i]->task != NULL but
cancel_tsync_works() does not.
works->works[i]->task becomes NULL when tsync_works_provide() incremented
works->size and then task_work_add() returned an error. Therefore,
cancel_tsync_works() needs to check for works->works[i]->task != NULL.
Reported-by: syzbot <syzbot+741e2278ef71fef03a10@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=741e2278ef71fef03a10
Fixes: 42fc7e6543f6 ("landlock: Multithreading support for landlock_restrict_self()")
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
security/landlock/tsync.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
index de01aa899751..8925acbef8a5 100644
--- a/security/landlock/tsync.c
+++ b/security/landlock/tsync.c
@@ -412,6 +412,8 @@ static void cancel_tsync_works(struct tsync_works *works,
int i;
for (i = 0; i < works->size; i++) {
+ if (!works->works[i]->task)
+ continue;
if (!task_work_cancel(works->works[i]->task,
&works->works[i]->work))
continue;
--
2.53.0
^ permalink raw reply related
* Re: [PATCH] integrity: avoid using __weak functions
From: Arnd Bergmann @ 2026-03-06 23:28 UTC (permalink / raw)
To: Nathan Chancellor, Arnd Bergmann
Cc: Madhavan Srinivasan, Michael Ellerman, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Mimi Zohar, Roberto Sassu,
Dmitry Kasatkin, Paul Moore, James Morris, Serge E. Hallyn,
Jarkko Sakkinen, Ard Biesheuvel, Coiby Xu, Nicholas Piggin,
Christophe Leroy, Christian Borntraeger, Sven Schnelle,
Eric Snowberg, Nick Desaulniers, Bill Wendling, Justin Stitt,
Andrew Donnellan, linuxppc-dev, linux-kernel, linux-s390,
Linux-Arch, linux-integrity, linux-security-module, keyrings,
llvm
In-Reply-To: <20260306225648.GC2746259@ax162>
On Fri, Mar 6, 2026, at 23:56, Nathan Chancellor wrote:
> On Fri, Mar 06, 2026 at 04:03:24PM +0100, Arnd Bergmann wrote:
>
> Thanks, I noticed this as well. The version I came up with and have been
> locally testing is the following, which is a little bit more compact.
>
> arch/Kconfig | 3 +++
> arch/powerpc/Kconfig | 1 +
> arch/s390/Kconfig | 1 +
> arch/s390/kernel/ipl.c | 10 +++++-----
> include/linux/secure_boot.h | 4 ++++
> security/integrity/Makefile | 2 +-
> security/integrity/secure_boot.c | 16 ----------------
> 7 files changed, 15 insertions(+), 22 deletions(-)
>
Right, your version looks good to me as well.
Arnd
^ permalink raw reply
* Re: [PATCH] integrity: avoid using __weak functions
From: Nathan Chancellor @ 2026-03-06 22:56 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Madhavan Srinivasan, Michael Ellerman, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Arnd Bergmann, Mimi Zohar,
Roberto Sassu, Dmitry Kasatkin, Paul Moore, James Morris,
Serge E. Hallyn, Jarkko Sakkinen, Ard Biesheuvel, Coiby Xu,
Nicholas Piggin, Christophe Leroy (CS GROUP),
Christian Borntraeger, Sven Schnelle, Eric Snowberg,
Nick Desaulniers, Bill Wendling, Justin Stitt, Andrew Donnellan,
linuxppc-dev, linux-kernel, linux-s390, linux-arch,
linux-integrity, linux-security-module, keyrings, llvm
In-Reply-To: <20260306150421.270124-1-arnd@kernel.org>
On Fri, Mar 06, 2026 at 04:03:24PM +0100, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> The security/integrity/secure_boot.c file containing only a __weak function
> leads to a build failure with clang:
>
> Cannot find symbol for section 2: .text.
> security/integrity/secure_boot.o: failed
>
> Moving the function into another file that has at least one non-__weak
> symbol would solve this, but this is always fragile.
>
> Avoid __weak definitions entirely and instead move the stub helper into
> an asm-generic header that gets used by default on architectures that
> do not provide their own version. This is consistent with how a lot
> of other architecture specific functionality works, and is more reliable.
>
> Fixes: a0f87ede3bf4 ("integrity: Make arch_ima_get_secureboot integrity-wide")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> This is a larger change than I had hoped for.
>
> If you prefer a different way to address the build failure, please
> treat this as a Reported-by when you apply your own fix
> ---
> arch/powerpc/include/asm/secure_boot.h | 6 +++
> arch/powerpc/kernel/secure_boot.c | 1 -
> arch/s390/include/asm/secure_boot.h | 9 +++++
> include/asm-generic/Kbuild | 1 +
> include/asm-generic/secure_boot.h | 37 +++++++++++++++++++
> include/linux/secure_boot.h | 8 +---
> security/integrity/Makefile | 2 +-
> .../integrity/platform_certs/load_powerpc.c | 2 +-
> security/integrity/secure_boot.c | 16 --------
> 9 files changed, 56 insertions(+), 26 deletions(-)
> create mode 100644 arch/s390/include/asm/secure_boot.h
> create mode 100644 include/asm-generic/secure_boot.h
> delete mode 100644 security/integrity/secure_boot.c
Thanks, I noticed this as well. The version I came up with and have been
locally testing is the following, which is a little bit more compact.
arch/Kconfig | 3 +++
arch/powerpc/Kconfig | 1 +
arch/s390/Kconfig | 1 +
arch/s390/kernel/ipl.c | 10 +++++-----
include/linux/secure_boot.h | 4 ++++
security/integrity/Makefile | 2 +-
security/integrity/secure_boot.c | 16 ----------------
7 files changed, 15 insertions(+), 22 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 102ddbd4298e..a6d1c8cc1d64 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1841,4 +1841,7 @@ config ARCH_WANTS_PRE_LINK_VMLINUX
config ARCH_HAS_CPU_ATTACK_VECTORS
bool
+config HAVE_ARCH_GET_SECUREBOOT
+ def_bool EFI
+
endmenu
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index c28776660246..e76d6cf0c403 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1062,6 +1062,7 @@ config PPC_SECURE_BOOT
depends on IMA_ARCH_POLICY
imply IMA_SECURE_AND_OR_TRUSTED_BOOT
select PSERIES_PLPKS if PPC_PSERIES
+ select HAVE_ARCH_GET_SECUREBOOT
help
Systems with firmware secure boot enabled need to define security
policies to extend secure boot to the OS. This config allows a user
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 24695ea29d5b..76f191dd208b 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -181,6 +181,7 @@ config S390
select GENERIC_IOREMAP if PCI
select HAVE_ALIGNED_STRUCT_PAGE
select HAVE_ARCH_AUDITSYSCALL
+ select HAVE_ARCH_GET_SECUREBOOT
select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_JUMP_LABEL_RELATIVE
select HAVE_ARCH_KASAN
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 2d01a1713938..3c346b02ceb9 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -2388,6 +2388,11 @@ void __no_stack_protector s390_reset_system(void)
diag_amode31_ops.diag308_reset();
}
+bool arch_get_secureboot(void)
+{
+ return ipl_secure_flag;
+}
+
#ifdef CONFIG_KEXEC_FILE
int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
@@ -2505,11 +2510,6 @@ void *ipl_report_finish(struct ipl_report *report)
return buf;
}
-bool arch_get_secureboot(void)
-{
- return ipl_secure_flag;
-}
-
int ipl_report_free(struct ipl_report *report)
{
struct ipl_report_component *comp, *ncomp;
diff --git a/include/linux/secure_boot.h b/include/linux/secure_boot.h
index 3ded3f03655c..d17e92351567 100644
--- a/include/linux/secure_boot.h
+++ b/include/linux/secure_boot.h
@@ -10,10 +10,14 @@
#include <linux/types.h>
+#ifdef CONFIG_HAVE_ARCH_GET_SECUREBOOT
/*
* Returns true if the platform secure boot is enabled.
* Returns false if disabled or not supported.
*/
bool arch_get_secureboot(void);
+#else
+static inline bool arch_get_secureboot(void) { return false; }
+#endif
#endif /* _LINUX_SECURE_BOOT_H */
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 548665e2b702..45dfdedbdad4 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_INTEGRITY) += integrity.o
-integrity-y := iint.o secure_boot.o
+integrity-y := iint.o
integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
diff --git a/security/integrity/secure_boot.c b/security/integrity/secure_boot.c
deleted file mode 100644
index fc2693c286f8..000000000000
--- a/security/integrity/secure_boot.c
+++ /dev/null
@@ -1,16 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2026 Red Hat, Inc. All Rights Reserved.
- *
- * Author: Coiby Xu <coxu@redhat.com>
- */
-#include <linux/secure_boot.h>
-
-/*
- * Default weak implementation.
- * Architectures that support secure boot must override this.
- */
-__weak bool arch_get_secureboot(void)
-{
- return false;
-}
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox