* Re: [PATCH 04/11] treewide: Convert struct kernel_param_ops initializers to DEFINE_KERNEL_PARAM_OPS
From: Rafael J. Wysocki @ 2026-05-22 17:01 UTC (permalink / raw)
To: Kees Cook
Cc: Luis Chamberlain, Pengpeng Hou, Petr Pavlu, Richard Weinberger,
Anton Ivanov, Johannes Berg, Rafael J. Wysocki, Len Brown,
Corey Minyard, Gabriel Somlo, Michael S. Tsirkin, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, David Airlie,
Simona Vetter, Bart Van Assche, Jason Gunthorpe, Leon Romanovsky,
Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Bjorn Helgaas, Hannes Reinecke, James E.J. Bottomley,
Martin K. Petersen, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Greg Kroah-Hartman, Jiri Slaby, Alan Stern, Jason Wang, Xuan Zhuo,
Eugenio Pérez, Jason Baron, Jim Cromie, Tiwei Bie,
Benjamin Berg, Ilpo Järvinen, David E. Box,
Maciej W. Rozycki, Srinivas Pandruvada, Peter Zijlstra,
Heiko Carstens, Vasily Gorbik, Sean Christopherson, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Vinod Koul, Frank Li, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
Andrew Morton, John Johansen, Paul Moore, James Morris,
Serge E. Hallyn, Andy Shevchenko, Georgia Garcia, kvm, dmaengine,
linux-modules, kasan-dev, linux-mm, apparmor,
linux-security-module, linux-um, linux-acpi, openipmi-developer,
qemu-devel, intel-gfx, dri-devel, linux-rdma, linux-media,
linux-pci, linux-scsi, linux-pm, linuxppc-dev, linux-serial,
linux-usb, usb-storage, virtualization, linux-kernel, linux-arch,
netdev, linux-fsdevel, linux-hardening
In-Reply-To: <20260521133326.2465264-4-kees@kernel.org>
On Thu, May 21, 2026 at 3:33 PM Kees Cook <kees@kernel.org> wrote:
>
> Using Coccinelle, rewrite every struct kernel_param_ops initializer that
> sets .get into a DEFINE_KERNEL_PARAM_OPS-family macro invocation,
> for example:
>
> @@
> declarer name DEFINE_KERNEL_PARAM_OPS;
> identifier OPS;
> expression SET, GET;
> @@
> - const struct kernel_param_ops OPS = {
> - .set = SET,
> - .get = GET,
> - };
> + DEFINE_KERNEL_PARAM_OPS(OPS, SET, GET);
>
> Using the macro for initialization means future changes can manipulate
> the struct layout and callback prototypes without having to change every
> initializer.
>
> Signed-off-by: Kees Cook <kees@kernel.org>
For ACPI and hibernation:
Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
> ---
> mm/kfence/core.c | 7 +-
> arch/powerpc/kvm/book3s_hv.c | 5 +-
> arch/s390/kernel/perf_cpum_sf.c | 6 +-
> arch/um/drivers/vfio_kern.c | 6 +-
> arch/um/drivers/virtio_uml.c | 6 +-
> arch/x86/kernel/msr.c | 6 +-
> arch/x86/kvm/mmu/mmu.c | 12 +--
> arch/x86/kvm/svm/avic.c | 6 +-
> arch/x86/kvm/vmx/vmx.c | 6 +-
> arch/x86/platform/uv/uv_nmi.c | 12 +--
> block/disk-events.c | 6 +-
> drivers/acpi/sysfs.c | 25 +++----
> drivers/block/loop.c | 12 +--
> drivers/block/null_blk/main.c | 12 +--
> drivers/block/rnbd/rnbd-srv.c | 6 +-
> drivers/block/ublk_drv.c | 7 +-
> drivers/char/ipmi/ipmi_msghandler.c | 6 +-
> drivers/char/ipmi/ipmi_watchdog.c | 17 ++---
> drivers/crypto/hisilicon/hpre/hpre_main.c | 16 +---
> drivers/crypto/hisilicon/sec2/sec_main.c | 23 ++----
> drivers/crypto/hisilicon/zip/zip_crypto.c | 5 +-
> drivers/crypto/hisilicon/zip/zip_main.c | 21 ++----
> drivers/dma/dmatest.c | 20 ++---
> drivers/edac/i10nm_base.c | 6 +-
> drivers/firmware/efi/efi-pstore.c | 6 +-
> drivers/firmware/qcom/qcom_scm.c | 6 +-
> drivers/firmware/qemu_fw_cfg.c | 6 +-
> drivers/gpu/drm/drm_panic.c | 6 +-
> drivers/gpu/drm/i915/i915_mitigations.c | 5 +-
> drivers/gpu/drm/imagination/pvr_fw_trace.c | 6 +-
> drivers/hid/hid-cougar.c | 6 +-
> drivers/hid/hid-steam.c | 6 +-
> drivers/infiniband/hw/hfi1/driver.c | 5 +-
> drivers/infiniband/ulp/iser/iscsi_iser.c | 6 +-
> drivers/infiniband/ulp/isert/ib_isert.c | 6 +-
> drivers/infiniband/ulp/srp/ib_srp.c | 5 +-
> drivers/input/misc/ati_remote2.c | 13 ++--
> drivers/input/mouse/psmouse-base.c | 6 +-
> drivers/media/usb/uvc/uvc_driver.c | 6 +-
> drivers/misc/lis3lv02d/lis3lv02d.c | 5 +-
> drivers/net/wireless/ath/wil6210/main.c | 10 +--
> drivers/nvme/host/multipath.c | 12 +--
> drivers/nvme/host/pci.c | 18 ++---
> drivers/nvme/target/rdma.c | 5 +-
> drivers/nvme/target/tcp.c | 5 +-
> drivers/platform/x86/acerhdf.c | 5 +-
> drivers/power/supply/bq27xxx_battery.c | 6 +-
> drivers/power/supply/test_power.c | 75 ++++++++-----------
> drivers/scsi/sg.c | 6 +-
> drivers/target/target_core_user.c | 13 ++--
> .../processor_thermal_soc_slider.c | 12 +--
> drivers/thermal/intel/intel_powerclamp.c | 20 +----
> drivers/tty/hvc/hvc_iucv.c | 6 +-
> drivers/tty/sysrq.c | 6 +-
> drivers/ufs/core/ufs-fault-injection.c | 5 +-
> drivers/ufs/core/ufs-mcq.c | 18 ++---
> drivers/ufs/core/ufs-txeq.c | 5 +-
> drivers/ufs/core/ufshcd.c | 12 +--
> drivers/usb/core/quirks.c | 6 +-
> drivers/usb/gadget/legacy/serial.c | 5 +-
> drivers/usb/storage/usb.c | 5 +-
> drivers/vhost/scsi.c | 7 +-
> drivers/virt/nitro_enclaves/ne_misc_dev.c | 6 +-
> drivers/virtio/virtio_mmio.c | 6 +-
> fs/ceph/super.c | 10 +--
> fs/fuse/dir.c | 5 +-
> fs/nfs/namespace.c | 6 +-
> fs/nfs/super.c | 6 +-
> fs/ubifs/super.c | 6 +-
> kernel/locking/locktorture.c | 6 +-
> kernel/panic.c | 6 +-
> kernel/params.c | 44 +++--------
> kernel/power/hibernate.c | 6 +-
> kernel/rcu/tree.c | 18 ++---
> kernel/sched/ext.c | 11 +--
> kernel/workqueue.c | 12 +--
> lib/dynamic_debug.c | 6 +-
> lib/test_dynamic_debug.c | 6 +-
> mm/damon/lru_sort.c | 19 ++---
> mm/damon/reclaim.c | 19 ++---
> mm/damon/stat.c | 6 +-
> mm/memory_hotplug.c | 12 +--
> mm/page_reporting.c | 11 +--
> mm/shuffle.c | 6 +-
> mm/zswap.c | 14 ++--
> net/batman-adv/bat_algo.c | 6 +-
> net/ceph/ceph_common.c | 5 +-
> net/ipv4/tcp_dctcp.c | 6 +-
> net/sunrpc/auth.c | 6 +-
> net/sunrpc/xprtsock.c | 18 ++---
> samples/damon/mtier.c | 6 +-
> samples/damon/prcl.c | 6 +-
> samples/damon/wsse.c | 6 +-
> security/apparmor/lsm.c | 34 +++------
> sound/hda/controllers/intel.c | 5 +-
> sound/usb/card.c | 7 +-
> 96 files changed, 307 insertions(+), 660 deletions(-)
>
> diff --git a/mm/kfence/core.c b/mm/kfence/core.c
> index 655dc5ce3240..e14102c01520 100644
> --- a/mm/kfence/core.c
> +++ b/mm/kfence/core.c
> @@ -92,10 +92,9 @@ static int param_get_sample_interval(char *buffer, const struct kernel_param *kp
> return param_get_ulong(buffer, kp);
> }
>
> -static const struct kernel_param_ops sample_interval_param_ops = {
> - .set = param_set_sample_interval,
> - .get = param_get_sample_interval,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sample_interval_param_ops,
> + param_set_sample_interval,
> + param_get_sample_interval);
> module_param_cb(sample_interval, &sample_interval_param_ops, &kfence_sample_interval, 0600);
>
> /* Pool usage% threshold when currently covered allocations are skipped. */
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 61dbeea317f3..0c15f0426671 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -114,10 +114,7 @@ module_param(one_vm_per_core, bool, S_IRUGO | S_IWUSR);
> MODULE_PARM_DESC(one_vm_per_core, "Only run vCPUs from the same VM on a core (requires POWER8 or older)");
>
> #ifdef CONFIG_KVM_XICS
> -static const struct kernel_param_ops module_param_ops = {
> - .set = param_set_int,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(module_param_ops, param_set_int, param_get_int);
>
> module_param_cb(kvm_irq_bypass, &module_param_ops, &kvm_irq_bypass, 0644);
> MODULE_PARM_DESC(kvm_irq_bypass, "Bypass passthrough interrupt optimization");
> diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c
> index 7bfeb5208177..76119542562b 100644
> --- a/arch/s390/kernel/perf_cpum_sf.c
> +++ b/arch/s390/kernel/perf_cpum_sf.c
> @@ -2029,10 +2029,8 @@ static int param_set_sfb_size(const char *val, const struct kernel_param *kp)
> }
>
> #define param_check_sfb_size(name, p) __param_check(name, p, void)
> -static const struct kernel_param_ops param_ops_sfb_size = {
> - .set = param_set_sfb_size,
> - .get = param_get_sfb_size,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_sfb_size, param_set_sfb_size,
> + param_get_sfb_size);
>
> enum {
> RS_INIT_FAILURE_BSDES = 2, /* Bad basic sampling size */
> diff --git a/arch/um/drivers/vfio_kern.c b/arch/um/drivers/vfio_kern.c
> index e6dab473cde4..fb7988dc5482 100644
> --- a/arch/um/drivers/vfio_kern.c
> +++ b/arch/um/drivers/vfio_kern.c
> @@ -628,10 +628,8 @@ static int uml_vfio_cmdline_get(char *buffer, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops uml_vfio_cmdline_param_ops = {
> - .set = uml_vfio_cmdline_set,
> - .get = uml_vfio_cmdline_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(uml_vfio_cmdline_param_ops, uml_vfio_cmdline_set,
> + uml_vfio_cmdline_get);
>
> device_param_cb(device, ¨_vfio_cmdline_param_ops, NULL, 0400);
> __uml_help(uml_vfio_cmdline_param_ops,
> diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
> index 7425a8548141..f9ae745f4586 100644
> --- a/arch/um/drivers/virtio_uml.c
> +++ b/arch/um/drivers/virtio_uml.c
> @@ -1398,10 +1398,8 @@ static int vu_cmdline_get(char *buffer, const struct kernel_param *kp)
> return strlen(buffer) + 1;
> }
>
> -static const struct kernel_param_ops vu_cmdline_param_ops = {
> - .set = vu_cmdline_set,
> - .get = vu_cmdline_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vu_cmdline_param_ops, vu_cmdline_set,
> + vu_cmdline_get);
>
> device_param_cb(device, &vu_cmdline_param_ops, NULL, S_IRUSR);
> __uml_help(vu_cmdline_param_ops,
> diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
> index 4469c784eaa0..5f4e1814dc4d 100644
> --- a/arch/x86/kernel/msr.c
> +++ b/arch/x86/kernel/msr.c
> @@ -322,10 +322,8 @@ static int get_allow_writes(char *buf, const struct kernel_param *kp)
> return sprintf(buf, "%s\n", res);
> }
>
> -static const struct kernel_param_ops allow_writes_ops = {
> - .set = set_allow_writes,
> - .get = get_allow_writes
> -};
> +static DEFINE_KERNEL_PARAM_OPS(allow_writes_ops, set_allow_writes,
> + get_allow_writes);
>
> module_param_cb(allow_writes, &allow_writes_ops, NULL, 0600);
>
> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> index 24fbc9ea502a..996818ee9b09 100644
> --- a/arch/x86/kvm/mmu/mmu.c
> +++ b/arch/x86/kvm/mmu/mmu.c
> @@ -74,15 +74,11 @@ static int get_nx_huge_pages(char *buffer, const struct kernel_param *kp);
> static int set_nx_huge_pages(const char *val, const struct kernel_param *kp);
> static int set_nx_huge_pages_recovery_param(const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops nx_huge_pages_ops = {
> - .set = set_nx_huge_pages,
> - .get = get_nx_huge_pages,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(nx_huge_pages_ops, set_nx_huge_pages,
> + get_nx_huge_pages);
>
> -static const struct kernel_param_ops nx_huge_pages_recovery_param_ops = {
> - .set = set_nx_huge_pages_recovery_param,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(nx_huge_pages_recovery_param_ops,
> + set_nx_huge_pages_recovery_param, param_get_uint);
>
> module_param_cb(nx_huge_pages, &nx_huge_pages_ops, &nx_huge_pages, 0644);
> __MODULE_PARM_TYPE(nx_huge_pages, "bool");
> diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
> index adf211860949..7907f9addff9 100644
> --- a/arch/x86/kvm/svm/avic.c
> +++ b/arch/x86/kvm/svm/avic.c
> @@ -87,11 +87,7 @@ static int avic_param_get(char *buffer, const struct kernel_param *kp)
> return param_get_bool(buffer, kp);
> }
>
> -static const struct kernel_param_ops avic_ops = {
> - .flags = KERNEL_PARAM_OPS_FL_NOARG,
> - .set = avic_param_set,
> - .get = avic_param_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS_NOARG(avic_ops, avic_param_set, avic_param_get);
>
> /*
> * Enable / disable AVIC. In "auto" mode (default behavior), AVIC is enabled
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index a29896a9ef14..07f4c7209ac0 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -465,10 +465,8 @@ static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp)
> }
> #endif
>
> -static const struct kernel_param_ops vmentry_l1d_flush_ops = {
> - .set = vmentry_l1d_flush_set,
> - .get = vmentry_l1d_flush_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vmentry_l1d_flush_ops, vmentry_l1d_flush_set,
> + vmentry_l1d_flush_get);
> module_param_cb(vmentry_l1d_flush, &vmentry_l1d_flush_ops, NULL, 0644);
>
> static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx)
> diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c
> index 5c50e550ab63..a7ac80b5f8d9 100644
> --- a/arch/x86/platform/uv/uv_nmi.c
> +++ b/arch/x86/platform/uv/uv_nmi.c
> @@ -123,10 +123,8 @@ static int param_set_local64(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops param_ops_local64 = {
> - .get = param_get_local64,
> - .set = param_set_local64,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_local64, param_set_local64,
> + param_get_local64);
> #define param_check_local64(name, p) __param_check(name, p, local64_t)
>
> static local64_t uv_nmi_count;
> @@ -232,10 +230,8 @@ static int param_set_action(const char *val, const struct kernel_param *kp)
> return -EINVAL;
> }
>
> -static const struct kernel_param_ops param_ops_action = {
> - .get = param_get_action,
> - .set = param_set_action,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_action, param_set_action,
> + param_get_action);
> #define param_check_action(name, p) __param_check(name, p, enum action_t)
>
> module_param_named(action, uv_nmi_action, action, 0644);
> diff --git a/block/disk-events.c b/block/disk-events.c
> index 074731ecc3d2..f2d4b48294c6 100644
> --- a/block/disk-events.c
> +++ b/block/disk-events.c
> @@ -416,10 +416,8 @@ static int disk_events_set_dfl_poll_msecs(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops disk_events_dfl_poll_msecs_param_ops = {
> - .set = disk_events_set_dfl_poll_msecs,
> - .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(disk_events_dfl_poll_msecs_param_ops,
> + disk_events_set_dfl_poll_msecs, param_get_ulong);
>
> #undef MODULE_PARAM_PREFIX
> #define MODULE_PARAM_PREFIX "block."
> diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
> index a625de3c3c8b..3d32a5280432 100644
> --- a/drivers/acpi/sysfs.c
> +++ b/drivers/acpi/sysfs.c
> @@ -138,15 +138,11 @@ static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
> return result;
> }
>
> -static const struct kernel_param_ops param_ops_debug_layer = {
> - .set = param_set_uint,
> - .get = param_get_debug_layer,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_debug_layer, param_set_uint,
> + param_get_debug_layer);
>
> -static const struct kernel_param_ops param_ops_debug_level = {
> - .set = param_set_uint,
> - .get = param_get_debug_level,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_debug_level, param_set_uint,
> + param_get_debug_level);
>
> module_param_cb(debug_layer, ¶m_ops_debug_layer, &acpi_dbg_layer, 0644);
> module_param_cb(debug_level, ¶m_ops_debug_level, &acpi_dbg_level, 0644);
> @@ -201,15 +197,12 @@ static int param_get_trace_method_name(char *buffer, const struct kernel_param *
> return sysfs_emit(buffer, "%s\n", acpi_gbl_trace_method_name);
> }
>
> -static const struct kernel_param_ops param_ops_trace_method = {
> - .set = param_set_trace_method_name,
> - .get = param_get_trace_method_name,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_trace_method,
> + param_set_trace_method_name,
> + param_get_trace_method_name);
>
> -static const struct kernel_param_ops param_ops_trace_attrib = {
> - .set = param_set_uint,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_trace_attrib, param_set_uint,
> + param_get_uint);
>
> module_param_cb(trace_method_name, ¶m_ops_trace_method, &trace_method_name, 0644);
> module_param_cb(trace_debug_layer, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644);
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 0000913f7efc..147ad561e584 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -1806,10 +1806,8 @@ static int max_loop_param_set_int(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops max_loop_param_ops = {
> - .set = max_loop_param_set_int,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(max_loop_param_ops, max_loop_param_set_int,
> + param_get_int);
>
> module_param_cb(max_loop, &max_loop_param_ops, &max_loop, 0444);
> MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
> @@ -1836,10 +1834,8 @@ static int loop_set_hw_queue_depth(const char *s, const struct kernel_param *p)
> return 0;
> }
>
> -static const struct kernel_param_ops loop_hw_qdepth_param_ops = {
> - .set = loop_set_hw_queue_depth,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(loop_hw_qdepth_param_ops,
> + loop_set_hw_queue_depth, param_get_int);
>
> device_param_cb(hw_queue_depth, &loop_hw_qdepth_param_ops, &hw_queue_depth, 0444);
> MODULE_PARM_DESC(hw_queue_depth, "Queue depth for each hardware queue. Default: " __stringify(LOOP_DEFAULT_HW_Q_DEPTH));
> diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
> index f8c0fd57e041..332ad6ac838a 100644
> --- a/drivers/block/null_blk/main.c
> +++ b/drivers/block/null_blk/main.c
> @@ -149,10 +149,8 @@ static int null_set_queue_mode(const char *str, const struct kernel_param *kp)
> return null_param_store_val(str, &g_queue_mode, NULL_Q_BIO, NULL_Q_MQ);
> }
>
> -static const struct kernel_param_ops null_queue_mode_param_ops = {
> - .set = null_set_queue_mode,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(null_queue_mode_param_ops, null_set_queue_mode,
> + param_get_int);
>
> device_param_cb(queue_mode, &null_queue_mode_param_ops, &g_queue_mode, 0444);
> MODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,1=rq,2=multiqueue)");
> @@ -193,10 +191,8 @@ static int null_set_irqmode(const char *str, const struct kernel_param *kp)
> NULL_IRQ_TIMER);
> }
>
> -static const struct kernel_param_ops null_irqmode_param_ops = {
> - .set = null_set_irqmode,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(null_irqmode_param_ops, null_set_irqmode,
> + param_get_int);
>
> device_param_cb(irqmode, &null_irqmode_param_ops, &g_irqmode, 0444);
> MODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer");
> diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c
> index 10e8c438bb43..81961f7c883a 100644
> --- a/drivers/block/rnbd/rnbd-srv.c
> +++ b/drivers/block/rnbd/rnbd-srv.c
> @@ -49,10 +49,8 @@ static struct kparam_string dev_search_path_kparam_str = {
> .string = dev_search_path
> };
>
> -static const struct kernel_param_ops dev_search_path_ops = {
> - .set = dev_search_path_set,
> - .get = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(dev_search_path_ops, dev_search_path_set,
> + param_get_string);
>
> module_param_cb(dev_search_path, &dev_search_path_ops,
> &dev_search_path_kparam_str, 0444);
> diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> index 8e5f3738c203..f7bf7ea2d088 100644
> --- a/drivers/block/ublk_drv.c
> +++ b/drivers/block/ublk_drv.c
> @@ -5874,10 +5874,9 @@ static int ublk_get_max_unprivileged_ublks(char *buf,
> return sysfs_emit(buf, "%u\n", unprivileged_ublks_max);
> }
>
> -static const struct kernel_param_ops ublk_max_unprivileged_ublks_ops = {
> - .set = ublk_set_max_unprivileged_ublks,
> - .get = ublk_get_max_unprivileged_ublks,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ublk_max_unprivileged_ublks_ops,
> + ublk_set_max_unprivileged_ublks,
> + ublk_get_max_unprivileged_ublks);
>
> module_param_cb(ublks_max, &ublk_max_unprivileged_ublks_ops,
> &unprivileged_ublks_max, 0644);
> diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
> index 869ac87a4b6a..b5fed11707e8 100644
> --- a/drivers/char/ipmi/ipmi_msghandler.c
> +++ b/drivers/char/ipmi/ipmi_msghandler.c
> @@ -102,10 +102,8 @@ static int panic_op_read_handler(char *buffer, const struct kernel_param *kp)
> return sprintf(buffer, "%s\n", event_str);
> }
>
> -static const struct kernel_param_ops panic_op_ops = {
> - .set = panic_op_write_handler,
> - .get = panic_op_read_handler
> -};
> +static DEFINE_KERNEL_PARAM_OPS(panic_op_ops, panic_op_write_handler,
> + panic_op_read_handler);
> module_param_cb(panic_op, &panic_op_ops, NULL, 0600);
> MODULE_PARM_DESC(panic_op, "Sets if the IPMI driver will attempt to store panic information in the event log in the event of a panic. Set to 'none' for no, 'event' for a single event, or 'string' for a generic event and the panic string in IPMI OEM events.");
>
> diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
> index a013ddbf1466..91a99417d204 100644
> --- a/drivers/char/ipmi/ipmi_watchdog.c
> +++ b/drivers/char/ipmi/ipmi_watchdog.c
> @@ -193,10 +193,8 @@ static int set_param_timeout(const char *val, const struct kernel_param *kp)
> return rv;
> }
>
> -static const struct kernel_param_ops param_ops_timeout = {
> - .set = set_param_timeout,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_timeout, set_param_timeout,
> + param_get_int);
> #define param_check_timeout param_check_int
>
> typedef int (*action_fn)(const char *intval, char *outval);
> @@ -259,17 +257,12 @@ static int set_param_wdog_ifnum(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops param_ops_wdog_ifnum = {
> - .set = set_param_wdog_ifnum,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_wdog_ifnum, set_param_wdog_ifnum,
> + param_get_int);
>
> #define param_check_wdog_ifnum param_check_int
>
> -static const struct kernel_param_ops param_ops_str = {
> - .set = set_param_str,
> - .get = get_param_str,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_str, set_param_str, get_param_str);
>
> module_param(ifnum_to_use, wdog_ifnum, 0644);
> MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog "
> diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c
> index 357ab5e5887e..1104184c2f63 100644
> --- a/drivers/crypto/hisilicon/hpre/hpre_main.c
> +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c
> @@ -420,10 +420,8 @@ static int hpre_cluster_regs_show(struct seq_file *s, void *unused)
>
> DEFINE_SHOW_ATTRIBUTE(hpre_cluster_regs);
>
> -static const struct kernel_param_ops hpre_uacce_mode_ops = {
> - .set = uacce_mode_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(hpre_uacce_mode_ops, uacce_mode_set,
> + param_get_int);
>
> /*
> * uacce_mode = 0 means hpre only register to crypto,
> @@ -441,19 +439,13 @@ static int pf_q_num_set(const char *val, const struct kernel_param *kp)
> return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_HPRE_PF);
> }
>
> -static const struct kernel_param_ops hpre_pf_q_num_ops = {
> - .set = pf_q_num_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(hpre_pf_q_num_ops, pf_q_num_set, param_get_int);
>
> static u32 pf_q_num = HPRE_PF_DEF_Q_NUM;
> module_param_cb(pf_q_num, &hpre_pf_q_num_ops, &pf_q_num, 0444);
> MODULE_PARM_DESC(pf_q_num, "Number of queues in PF of CS(2-1024)");
>
> -static const struct kernel_param_ops vfs_num_ops = {
> - .set = vfs_num_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vfs_num_ops, vfs_num_set, param_get_int);
>
> static u32 vfs_num;
> module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444);
> diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c
> index 056bd8f4da5a..3d13f2faa3d0 100644
> --- a/drivers/crypto/hisilicon/sec2/sec_main.c
> +++ b/drivers/crypto/hisilicon/sec2/sec_main.c
> @@ -362,10 +362,8 @@ static int sec_pf_q_num_set(const char *val, const struct kernel_param *kp)
> return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_SEC_PF);
> }
>
> -static const struct kernel_param_ops sec_pf_q_num_ops = {
> - .set = sec_pf_q_num_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sec_pf_q_num_ops, sec_pf_q_num_set,
> + param_get_int);
>
> static u32 pf_q_num = SEC_PF_DEF_Q_NUM;
> module_param_cb(pf_q_num, &sec_pf_q_num_ops, &pf_q_num, 0444);
> @@ -391,18 +389,13 @@ static int sec_ctx_q_num_set(const char *val, const struct kernel_param *kp)
> return param_set_int(val, kp);
> }
>
> -static const struct kernel_param_ops sec_ctx_q_num_ops = {
> - .set = sec_ctx_q_num_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sec_ctx_q_num_ops, sec_ctx_q_num_set,
> + param_get_int);
> static u32 ctx_q_num = SEC_CTX_Q_NUM_DEF;
> module_param_cb(ctx_q_num, &sec_ctx_q_num_ops, &ctx_q_num, 0444);
> MODULE_PARM_DESC(ctx_q_num, "Queue num in ctx (2 default, 2, 4, ..., 32)");
>
> -static const struct kernel_param_ops vfs_num_ops = {
> - .set = vfs_num_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vfs_num_ops, vfs_num_set, param_get_int);
>
> static u32 vfs_num;
> module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444);
> @@ -454,10 +447,8 @@ u64 sec_get_alg_bitmap(struct hisi_qm *qm, u32 high, u32 low)
> return ((u64)cap_val_h << SEC_ALG_BITMAP_SHIFT) | (u64)cap_val_l;
> }
>
> -static const struct kernel_param_ops sec_uacce_mode_ops = {
> - .set = uacce_mode_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sec_uacce_mode_ops, uacce_mode_set,
> + param_get_int);
>
> /*
> * uacce_mode = 0 means sec only register to crypto,
> diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c
> index 70adde049b53..8f8d57420fb4 100644
> --- a/drivers/crypto/hisilicon/zip/zip_crypto.c
> +++ b/drivers/crypto/hisilicon/zip/zip_crypto.c
> @@ -108,10 +108,7 @@ static int sgl_sge_nr_set(const char *val, const struct kernel_param *kp)
> return param_set_ushort(val, kp);
> }
>
> -static const struct kernel_param_ops sgl_sge_nr_ops = {
> - .set = sgl_sge_nr_set,
> - .get = param_get_ushort,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sgl_sge_nr_ops, sgl_sge_nr_set, param_get_ushort);
>
> static u16 sgl_sge_nr = HZIP_SGL_SGE_NR;
> module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444);
> diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c
> index 44df9c859bd8..e07d0cf8eca8 100644
> --- a/drivers/crypto/hisilicon/zip/zip_main.c
> +++ b/drivers/crypto/hisilicon/zip/zip_main.c
> @@ -394,10 +394,7 @@ static int perf_mode_set(const char *val, const struct kernel_param *kp)
> return param_set_int(val, kp);
> }
>
> -static const struct kernel_param_ops zip_com_perf_ops = {
> - .set = perf_mode_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(zip_com_perf_ops, perf_mode_set, param_get_int);
>
> /*
> * perf_mode = 0 means enable high compression rate mode,
> @@ -408,10 +405,8 @@ static u32 perf_mode = HZIP_HIGH_COMP_RATE;
> module_param_cb(perf_mode, &zip_com_perf_ops, &perf_mode, 0444);
> MODULE_PARM_DESC(perf_mode, "ZIP high perf mode 0(default), 1(enable)");
>
> -static const struct kernel_param_ops zip_uacce_mode_ops = {
> - .set = uacce_mode_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(zip_uacce_mode_ops, uacce_mode_set,
> + param_get_int);
>
> /*
> * uacce_mode = 0 means zip only register to crypto,
> @@ -429,19 +424,13 @@ static int pf_q_num_set(const char *val, const struct kernel_param *kp)
> return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_ZIP_PF);
> }
>
> -static const struct kernel_param_ops pf_q_num_ops = {
> - .set = pf_q_num_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(pf_q_num_ops, pf_q_num_set, param_get_int);
>
> static u32 pf_q_num = HZIP_PF_DEF_Q_NUM;
> module_param_cb(pf_q_num, &pf_q_num_ops, &pf_q_num, 0444);
> MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 2-4096, v2 2-1024)");
>
> -static const struct kernel_param_ops vfs_num_ops = {
> - .set = vfs_num_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vfs_num_ops, vfs_num_set, param_get_int);
>
> static u32 vfs_num;
> module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444);
> diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
> index df38681a1ff4..a7bddadcc52d 100644
> --- a/drivers/dma/dmatest.c
> +++ b/drivers/dma/dmatest.c
> @@ -154,20 +154,15 @@ static struct dmatest_info {
>
> static int dmatest_run_set(const char *val, const struct kernel_param *kp);
> static int dmatest_run_get(char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops run_ops = {
> - .set = dmatest_run_set,
> - .get = dmatest_run_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(run_ops, dmatest_run_set, dmatest_run_get);
> static bool dmatest_run;
> module_param_cb(run, &run_ops, &dmatest_run, 0644);
> MODULE_PARM_DESC(run, "Run the test (default: false)");
>
> static int dmatest_chan_set(const char *val, const struct kernel_param *kp);
> static int dmatest_chan_get(char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops multi_chan_ops = {
> - .set = dmatest_chan_set,
> - .get = dmatest_chan_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(multi_chan_ops, dmatest_chan_set,
> + dmatest_chan_get);
>
> static char test_channel[20];
> static struct kparam_string newchan_kps = {
> @@ -178,9 +173,7 @@ module_param_cb(channel, &multi_chan_ops, &newchan_kps, 0644);
> MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
>
> static int dmatest_test_list_get(char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops test_list_ops = {
> - .get = dmatest_test_list_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(test_list_ops, NULL, dmatest_test_list_get);
> module_param_cb(test_list, &test_list_ops, NULL, 0444);
> MODULE_PARM_DESC(test_list, "Print current test list");
>
> @@ -292,10 +285,7 @@ static int dmatest_wait_get(char *val, const struct kernel_param *kp)
> return param_get_bool(val, kp);
> }
>
> -static const struct kernel_param_ops wait_ops = {
> - .get = dmatest_wait_get,
> - .set = param_set_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(wait_ops, param_set_bool, dmatest_wait_get);
> module_param_cb(wait, &wait_ops, &wait, 0444);
> MODULE_PARM_DESC(wait, "Wait for tests to complete (default: false)");
>
> diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
> index 63df35444214..ab05e58faaa8 100644
> --- a/drivers/edac/i10nm_base.c
> +++ b/drivers/edac/i10nm_base.c
> @@ -1284,10 +1284,8 @@ static int set_decoding_via_mca(const char *buf, const struct kernel_param *kp)
> return ret;
> }
>
> -static const struct kernel_param_ops decoding_via_mca_param_ops = {
> - .set = set_decoding_via_mca,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(decoding_via_mca_param_ops, set_decoding_via_mca,
> + param_get_int);
>
> module_param_cb(decoding_via_mca, &decoding_via_mca_param_ops, &decoding_via_mca, 0644);
> MODULE_PARM_DESC(decoding_via_mca, "decoding_via_mca: 0=off(default), 1=enable");
> diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
> index a253b6144945..fd0f3579fd54 100644
> --- a/drivers/firmware/efi/efi-pstore.c
> +++ b/drivers/firmware/efi/efi-pstore.c
> @@ -43,10 +43,8 @@ static int efi_pstore_disable_set(const char *val, const struct kernel_param *kp
> return 0;
> }
>
> -static const struct kernel_param_ops pstore_disable_ops = {
> - .set = efi_pstore_disable_set,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(pstore_disable_ops, efi_pstore_disable_set,
> + param_get_bool);
>
> module_param_cb(pstore_disable, &pstore_disable_ops, &pstore_disable, 0644);
> __MODULE_PARM_TYPE(pstore_disable, "bool");
> diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
> index 9b06a69d3a6d..ef57df53e087 100644
> --- a/drivers/firmware/qcom/qcom_scm.c
> +++ b/drivers/firmware/qcom/qcom_scm.c
> @@ -2725,10 +2725,8 @@ static int set_download_mode(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops download_mode_param_ops = {
> - .get = get_download_mode,
> - .set = set_download_mode,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(download_mode_param_ops, set_download_mode,
> + get_download_mode);
>
> module_param_cb(download_mode, &download_mode_param_ops, NULL, 0644);
> MODULE_PARM_DESC(download_mode, "download mode: off/0/N for no dump mode, full/on/1/Y for full dump mode, mini for minidump mode and full,mini for both full and minidump mode together are acceptable values");
> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
> index 87a5421bc7d5..c87a5449ba8c 100644
> --- a/drivers/firmware/qemu_fw_cfg.c
> +++ b/drivers/firmware/qemu_fw_cfg.c
> @@ -897,10 +897,8 @@ static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops fw_cfg_cmdline_param_ops = {
> - .set = fw_cfg_cmdline_set,
> - .get = fw_cfg_cmdline_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(fw_cfg_cmdline_param_ops, fw_cfg_cmdline_set,
> + fw_cfg_cmdline_get);
>
> device_param_cb(ioport, &fw_cfg_cmdline_param_ops, NULL, S_IRUSR);
> device_param_cb(mmio, &fw_cfg_cmdline_param_ops, NULL, S_IRUSR);
> diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
> index d6d3b8d85dea..c35d1adf2ce3 100644
> --- a/drivers/gpu/drm/drm_panic.c
> +++ b/drivers/gpu/drm/drm_panic.c
> @@ -847,10 +847,8 @@ static int drm_panic_type_get(char *buffer, const struct kernel_param *kp)
> drm_panic_type_map[drm_panic_type]);
> }
>
> -static const struct kernel_param_ops drm_panic_ops = {
> - .set = drm_panic_type_set,
> - .get = drm_panic_type_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(drm_panic_ops, drm_panic_type_set,
> + drm_panic_type_get);
>
> module_param_cb(panic_screen, &drm_panic_ops, NULL, 0644);
> MODULE_PARM_DESC(panic_screen,
> diff --git a/drivers/gpu/drm/i915/i915_mitigations.c b/drivers/gpu/drm/i915/i915_mitigations.c
> index def7302ef7fe..6061eae84e9c 100644
> --- a/drivers/gpu/drm/i915/i915_mitigations.c
> +++ b/drivers/gpu/drm/i915/i915_mitigations.c
> @@ -124,10 +124,7 @@ static int mitigations_get(char *buffer, const struct kernel_param *kp)
> return count;
> }
>
> -static const struct kernel_param_ops ops = {
> - .set = mitigations_set,
> - .get = mitigations_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ops, mitigations_set, mitigations_get);
>
> module_param_cb_unsafe(mitigations, &ops, NULL, 0600);
> MODULE_PARM_DESC(mitigations,
> diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c
> index 6193811ef7be..2df7274e21a8 100644
> --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c
> +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c
> @@ -71,10 +71,8 @@ pvr_fw_trace_init_mask_set(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -const struct kernel_param_ops pvr_fw_trace_init_mask_ops = {
> - .set = pvr_fw_trace_init_mask_set,
> - .get = param_get_hexint,
> -};
> +DEFINE_KERNEL_PARAM_OPS(pvr_fw_trace_init_mask_ops, pvr_fw_trace_init_mask_set,
> + param_get_hexint);
>
> param_check_hexint(init_fw_trace_mask, &pvr_fw_trace_init_mask);
> module_param_cb(init_fw_trace_mask, &pvr_fw_trace_init_mask_ops, &pvr_fw_trace_init_mask, 0600);
> diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c
> index ad027c45f162..271048bdf7fc 100644
> --- a/drivers/hid/hid-cougar.c
> +++ b/drivers/hid/hid-cougar.c
> @@ -314,10 +314,8 @@ static int cougar_param_set_g6_is_space(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops cougar_g6_is_space_ops = {
> - .set = cougar_param_set_g6_is_space,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(cougar_g6_is_space_ops,
> + cougar_param_set_g6_is_space, param_get_bool);
> module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
>
> static const struct hid_device_id cougar_id_table[] = {
> diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
> index 197126d6e081..962ed60492ea 100644
> --- a/drivers/hid/hid-steam.c
> +++ b/drivers/hid/hid-steam.c
> @@ -1840,10 +1840,8 @@ static int steam_param_set_lizard_mode(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops steam_lizard_mode_ops = {
> - .set = steam_param_set_lizard_mode,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(steam_lizard_mode_ops,
> + steam_param_set_lizard_mode, param_get_bool);
>
> module_param_cb(lizard_mode, &steam_lizard_mode_ops, &lizard_mode, 0644);
> MODULE_PARM_DESC(lizard_mode,
> diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c
> index c7259cc39013..5b9b0b38b419 100644
> --- a/drivers/infiniband/hw/hfi1/driver.c
> +++ b/drivers/infiniband/hw/hfi1/driver.c
> @@ -42,10 +42,7 @@ MODULE_PARM_DESC(cu, "Credit return units");
> unsigned long hfi1_cap_mask = HFI1_CAP_MASK_DEFAULT;
> static int hfi1_caps_set(const char *val, const struct kernel_param *kp);
> static int hfi1_caps_get(char *buffer, const struct kernel_param *kp);
> -static const struct kernel_param_ops cap_ops = {
> - .set = hfi1_caps_set,
> - .get = hfi1_caps_get
> -};
> +static DEFINE_KERNEL_PARAM_OPS(cap_ops, hfi1_caps_set, hfi1_caps_get);
> module_param_cb(cap_mask, &cap_ops, &hfi1_cap_mask, S_IWUSR | S_IRUGO);
> MODULE_PARM_DESC(cap_mask, "Bit mask of enabled/disabled HW features");
>
> diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
> index 7df441685780..758e527ca7c4 100644
> --- a/drivers/infiniband/ulp/iser/iscsi_iser.c
> +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
> @@ -90,10 +90,8 @@ module_param_named(debug_level, iser_debug_level, int, S_IRUGO | S_IWUSR);
> MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)");
>
> static int iscsi_iser_set(const char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops iscsi_iser_size_ops = {
> - .set = iscsi_iser_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(iscsi_iser_size_ops, iscsi_iser_set,
> + param_get_uint);
>
> static unsigned int iscsi_max_lun = 512;
> module_param_cb(max_lun, &iscsi_iser_size_ops, &iscsi_max_lun, S_IRUGO);
> diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
> index 348005e71891..bd91900a0ebf 100644
> --- a/drivers/infiniband/ulp/isert/ib_isert.c
> +++ b/drivers/infiniband/ulp/isert/ib_isert.c
> @@ -30,10 +30,8 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:0)");
>
> static int isert_sg_tablesize_set(const char *val,
> const struct kernel_param *kp);
> -static const struct kernel_param_ops sg_tablesize_ops = {
> - .set = isert_sg_tablesize_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sg_tablesize_ops, isert_sg_tablesize_set,
> + param_get_int);
>
> static int isert_sg_tablesize = ISCSI_ISER_MIN_SG_TABLESIZE;
> module_param_cb(sg_tablesize, &sg_tablesize_ops, &isert_sg_tablesize, 0644);
> diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
> index b58868e1cf11..a81515f52a4f 100644
> --- a/drivers/infiniband/ulp/srp/ib_srp.c
> +++ b/drivers/infiniband/ulp/srp/ib_srp.c
> @@ -195,10 +195,7 @@ static int srp_tmo_set(const char *val, const struct kernel_param *kp)
> return res;
> }
>
> -static const struct kernel_param_ops srp_tmo_ops = {
> - .get = srp_tmo_get,
> - .set = srp_tmo_set,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(srp_tmo_ops, srp_tmo_set, srp_tmo_get);
>
> static inline struct srp_target_port *host_to_target(struct Scsi_Host *host)
> {
> diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
> index 8db2dca84975..8b4ef7e163d3 100644
> --- a/drivers/input/misc/ati_remote2.c
> +++ b/drivers/input/misc/ati_remote2.c
> @@ -89,19 +89,16 @@ static int ati_remote2_get_mode_mask(char *buffer,
>
> static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
> #define param_check_channel_mask(name, p) __param_check(name, p, unsigned int)
> -static const struct kernel_param_ops param_ops_channel_mask = {
> - .set = ati_remote2_set_channel_mask,
> - .get = ati_remote2_get_channel_mask,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_channel_mask,
> + ati_remote2_set_channel_mask,
> + ati_remote2_get_channel_mask);
> module_param(channel_mask, channel_mask, 0644);
> MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
>
> static unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK;
> #define param_check_mode_mask(name, p) __param_check(name, p, unsigned int)
> -static const struct kernel_param_ops param_ops_mode_mask = {
> - .set = ati_remote2_set_mode_mask,
> - .get = ati_remote2_get_mode_mask,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_mode_mask, ati_remote2_set_mode_mask,
> + ati_remote2_get_mode_mask);
> module_param(mode_mask, mode_mask, 0644);
> MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
>
> diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
> index 6ab5f1d96eae..f9ebb1fd0b6f 100644
> --- a/drivers/input/mouse/psmouse-base.c
> +++ b/drivers/input/mouse/psmouse-base.c
> @@ -45,10 +45,8 @@ MODULE_LICENSE("GPL");
> static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
> static int psmouse_set_maxproto(const char *val, const struct kernel_param *);
> static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp);
> -static const struct kernel_param_ops param_ops_proto_abbrev = {
> - .set = psmouse_set_maxproto,
> - .get = psmouse_get_maxproto,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_proto_abbrev, psmouse_set_maxproto,
> + psmouse_get_maxproto);
> #define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
> module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
> MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index 31b4ac3b48c1..2338cab7fef9 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -2488,10 +2488,8 @@ static int param_set_nodrop(const char *val, const struct kernel_param *kp)
> return param_set_bool(val, kp);
> }
>
> -static const struct kernel_param_ops param_ops_nodrop = {
> - .set = param_set_nodrop,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_nodrop, param_set_nodrop,
> + param_get_uint);
>
> param_check_uint(nodrop, &uvc_no_drop_param);
> module_param_cb(nodrop, ¶m_ops_nodrop, &uvc_no_drop_param, 0644);
> diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
> index 21e8ad0a7444..6e40c14be51e 100644
> --- a/drivers/misc/lis3lv02d/lis3lv02d.c
> +++ b/drivers/misc/lis3lv02d/lis3lv02d.c
> @@ -103,10 +103,7 @@ static int param_set_axis(const char *val, const struct kernel_param *kp)
> return ret;
> }
>
> -static const struct kernel_param_ops param_ops_axis = {
> - .set = param_set_axis,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_axis, param_set_axis, param_get_int);
>
> #define param_check_axis(name, p) param_check_int(name, p)
>
> diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
> index d5aec72ecdce..e566d94d5f5c 100644
> --- a/drivers/net/wireless/ath/wil6210/main.c
> +++ b/drivers/net/wireless/ath/wil6210/main.c
> @@ -62,10 +62,7 @@ static int mtu_max_set(const char *val, const struct kernel_param *kp)
> return ret;
> }
>
> -static const struct kernel_param_ops mtu_max_ops = {
> - .set = mtu_max_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(mtu_max_ops, mtu_max_set, param_get_uint);
>
> module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444);
> MODULE_PARM_DESC(mtu_max, " Max MTU value.");
> @@ -91,10 +88,7 @@ static int ring_order_set(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops ring_order_ops = {
> - .set = ring_order_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ring_order_ops, ring_order_set, param_get_uint);
>
> module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, 0444);
> MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index 263161cb8ac0..f7362377e427 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -30,10 +30,8 @@ static int multipath_param_set(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops multipath_param_ops = {
> - .set = multipath_param_set,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(multipath_param_ops, multipath_param_set,
> + param_get_bool);
>
> module_param_cb(multipath, &multipath_param_ops, &multipath, 0444);
> MODULE_PARM_DESC(multipath,
> @@ -55,10 +53,8 @@ static int multipath_always_on_set(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops multipath_always_on_ops = {
> - .set = multipath_always_on_set,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(multipath_always_on_ops, multipath_always_on_set,
> + param_get_bool);
>
> module_param_cb(multipath_always_on, &multipath_always_on_ops,
> &multipath_always_on, 0444);
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 9fd04cd7c5cb..c77e9b848d03 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -100,10 +100,8 @@ MODULE_PARM_DESC(sgl_threshold,
> #define NVME_PCI_MIN_QUEUE_SIZE 2
> #define NVME_PCI_MAX_QUEUE_SIZE 4095
> static int io_queue_depth_set(const char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops io_queue_depth_ops = {
> - .set = io_queue_depth_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(io_queue_depth_ops, io_queue_depth_set,
> + param_get_uint);
>
> static unsigned int io_queue_depth = 1024;
> module_param_cb(io_queue_depth, &io_queue_depth_ops, &io_queue_depth, 0644);
> @@ -232,10 +230,8 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
> }
>
> static char quirks_param[128];
> -static const struct kernel_param_ops quirks_param_ops = {
> - .set = quirks_param_set,
> - .get = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(quirks_param_ops, quirks_param_set,
> + param_get_string);
>
> static struct kparam_string quirks_param_string = {
> .maxlen = sizeof(quirks_param),
> @@ -257,10 +253,8 @@ static int io_queue_count_set(const char *val, const struct kernel_param *kp)
> return param_set_uint(val, kp);
> }
>
> -static const struct kernel_param_ops io_queue_count_ops = {
> - .set = io_queue_count_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(io_queue_count_ops, io_queue_count_set,
> + param_get_uint);
>
> static unsigned int write_queues;
> module_param_cb(write_queues, &io_queue_count_ops, &write_queues, 0644);
> diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
> index e6e2c3f9afdf..dc544813300f 100644
> --- a/drivers/nvme/target/rdma.c
> +++ b/drivers/nvme/target/rdma.c
> @@ -147,10 +147,7 @@ module_param_named(use_srq, nvmet_rdma_use_srq, bool, 0444);
> MODULE_PARM_DESC(use_srq, "Use shared receive queue.");
>
> static int srq_size_set(const char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops srq_size_ops = {
> - .set = srq_size_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(srq_size_ops, srq_size_set, param_get_int);
>
> static int nvmet_rdma_srq_size = 1024;
> module_param_cb(srq_size, &srq_size_ops, &nvmet_rdma_srq_size, 0644);
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> index 164a564ba3b4..2f336cd7e559 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -46,10 +46,7 @@ static int set_params(const char *str, const struct kernel_param *kp)
> return param_store_val(str, kp->arg, 0, INT_MAX);
> }
>
> -static const struct kernel_param_ops set_param_ops = {
> - .set = set_params,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(set_param_ops, set_params, param_get_int);
>
> /* Define the socket priority to use for connections were it is desirable
> * that the NIC consider performing optimized packet processing or filtering.
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index 5ce5ad3efe69..bd59c3f3f2c5 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -762,10 +762,7 @@ static int interval_set_uint(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops interval_ops = {
> - .set = interval_set_uint,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(interval_ops, interval_set_uint, param_get_uint);
>
> module_param_cb(interval, &interval_ops, &interval, 0000);
> MODULE_PARM_DESC(interval, "Polling interval of temperature check");
> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
> index 45f0e39b8c2d..09829ee1a49d 100644
> --- a/drivers/power/supply/bq27xxx_battery.c
> +++ b/drivers/power/supply/bq27xxx_battery.c
> @@ -1133,10 +1133,8 @@ static int poll_interval_param_set(const char *val, const struct kernel_param *k
> return ret;
> }
>
> -static const struct kernel_param_ops param_ops_poll_interval = {
> - .get = param_get_uint,
> - .set = poll_interval_param_set,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_poll_interval, poll_interval_param_set,
> + param_get_uint);
>
> static unsigned int poll_interval = 360;
> module_param_cb(poll_interval, ¶m_ops_poll_interval, &poll_interval, 0644);
> diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c
> index 2c0e9ad820c0..0bf2bef3383a 100644
> --- a/drivers/power/supply/test_power.c
> +++ b/drivers/power/supply/test_power.c
> @@ -649,60 +649,47 @@ static int param_set_battery_extension(const char *key,
>
> #define param_get_battery_extension param_get_bool
>
> -static const struct kernel_param_ops param_ops_ac_online = {
> - .set = param_set_ac_online,
> - .get = param_get_ac_online,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_ac_online, param_set_ac_online,
> + param_get_ac_online);
>
> -static const struct kernel_param_ops param_ops_usb_online = {
> - .set = param_set_usb_online,
> - .get = param_get_usb_online,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_usb_online, param_set_usb_online,
> + param_get_usb_online);
>
> -static const struct kernel_param_ops param_ops_battery_status = {
> - .set = param_set_battery_status,
> - .get = param_get_battery_status,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_status,
> + param_set_battery_status,
> + param_get_battery_status);
>
> -static const struct kernel_param_ops param_ops_battery_present = {
> - .set = param_set_battery_present,
> - .get = param_get_battery_present,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_present,
> + param_set_battery_present,
> + param_get_battery_present);
>
> -static const struct kernel_param_ops param_ops_battery_technology = {
> - .set = param_set_battery_technology,
> - .get = param_get_battery_technology,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_technology,
> + param_set_battery_technology,
> + param_get_battery_technology);
>
> -static const struct kernel_param_ops param_ops_battery_health = {
> - .set = param_set_battery_health,
> - .get = param_get_battery_health,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_health,
> + param_set_battery_health,
> + param_get_battery_health);
>
> -static const struct kernel_param_ops param_ops_battery_capacity = {
> - .set = param_set_battery_capacity,
> - .get = param_get_battery_capacity,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_capacity,
> + param_set_battery_capacity,
> + param_get_battery_capacity);
>
> -static const struct kernel_param_ops param_ops_battery_voltage = {
> - .set = param_set_battery_voltage,
> - .get = param_get_battery_voltage,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_voltage,
> + param_set_battery_voltage,
> + param_get_battery_voltage);
>
> -static const struct kernel_param_ops param_ops_battery_charge_counter = {
> - .set = param_set_battery_charge_counter,
> - .get = param_get_battery_charge_counter,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_charge_counter,
> + param_set_battery_charge_counter,
> + param_get_battery_charge_counter);
>
> -static const struct kernel_param_ops param_ops_battery_current = {
> - .set = param_set_battery_current,
> - .get = param_get_battery_current,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_current,
> + param_set_battery_current,
> + param_get_battery_current);
>
> -static const struct kernel_param_ops param_ops_battery_extension = {
> - .set = param_set_battery_extension,
> - .get = param_get_battery_extension,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_extension,
> + param_set_battery_extension,
> + param_get_battery_extension);
>
> #define param_check_ac_online(name, p) __param_check(name, p, void);
> #define param_check_usb_online(name, p) __param_check(name, p, void);
> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
> index 2b4b2a1a8e44..c075b567f84e 100644
> --- a/drivers/scsi/sg.c
> +++ b/drivers/scsi/sg.c
> @@ -1644,10 +1644,8 @@ static int def_reserved_size_set(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops def_reserved_size_ops = {
> - .set = def_reserved_size_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(def_reserved_size_ops, def_reserved_size_set,
> + param_get_int);
>
> module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size,
> S_IRUGO | S_IWUSR);
> diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
> index edc2afd5f4ee..676a12b44e88 100644
> --- a/drivers/target/target_core_user.c
> +++ b/drivers/target/target_core_user.c
> @@ -255,10 +255,9 @@ static int tcmu_get_global_max_data_area(char *buffer,
> return sprintf(buffer, "%d\n", TCMU_PAGES_TO_MBS(tcmu_global_max_pages));
> }
>
> -static const struct kernel_param_ops tcmu_global_max_data_area_op = {
> - .set = tcmu_set_global_max_data_area,
> - .get = tcmu_get_global_max_data_area,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(tcmu_global_max_data_area_op,
> + tcmu_set_global_max_data_area,
> + tcmu_get_global_max_data_area);
>
> module_param_cb(global_max_data_area_mb, &tcmu_global_max_data_area_op, NULL,
> S_IWUSR | S_IRUGO);
> @@ -292,10 +291,8 @@ static int tcmu_set_block_netlink(const char *str,
> return 0;
> }
>
> -static const struct kernel_param_ops tcmu_block_netlink_op = {
> - .set = tcmu_set_block_netlink,
> - .get = tcmu_get_block_netlink,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(tcmu_block_netlink_op, tcmu_set_block_netlink,
> + tcmu_get_block_netlink);
>
> module_param_cb(block_netlink, &tcmu_block_netlink_op, NULL, S_IWUSR | S_IRUGO);
> MODULE_PARM_DESC(block_netlink, "Block new netlink commands.");
> diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> index 91f291627132..68275c3f2c9b 100644
> --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> @@ -83,10 +83,8 @@ static int slider_def_balance_get(char *buf, const struct kernel_param *kp)
> return sysfs_emit(buf, "%02x\n", slider_values[SOC_POWER_SLIDER_BALANCE]);
> }
>
> -static const struct kernel_param_ops slider_def_balance_ops = {
> - .set = slider_def_balance_set,
> - .get = slider_def_balance_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(slider_def_balance_ops, slider_def_balance_set,
> + slider_def_balance_get);
>
> module_param_cb(slider_balance, &slider_def_balance_ops, NULL, 0644);
> MODULE_PARM_DESC(slider_balance, "Set slider default value for balance");
> @@ -117,10 +115,8 @@ static int slider_def_offset_get(char *buf, const struct kernel_param *kp)
> return sysfs_emit(buf, "%02x\n", slider_offset);
> }
>
> -static const struct kernel_param_ops slider_offset_ops = {
> - .set = slider_def_offset_set,
> - .get = slider_def_offset_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(slider_offset_ops, slider_def_offset_set,
> + slider_def_offset_get);
>
> /*
> * To enhance power efficiency dynamically, the firmware can optionally
> diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c
> index ccf380da12f2..98fbc6892714 100644
> --- a/drivers/thermal/intel/intel_powerclamp.c
> +++ b/drivers/thermal/intel/intel_powerclamp.c
> @@ -112,10 +112,7 @@ static int duration_get(char *buf, const struct kernel_param *kp)
> return ret;
> }
>
> -static const struct kernel_param_ops duration_ops = {
> - .set = duration_set,
> - .get = duration_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(duration_ops, duration_set, duration_get);
>
> module_param_cb(duration, &duration_ops, NULL, 0644);
> MODULE_PARM_DESC(duration, "forced idle time for each attempt in msec.");
> @@ -203,10 +200,7 @@ static int cpumask_get(char *buf, const struct kernel_param *kp)
> return cpumap_print_to_pagebuf(false, buf, idle_injection_cpu_mask);
> }
>
> -static const struct kernel_param_ops cpumask_ops = {
> - .set = cpumask_set,
> - .get = cpumask_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(cpumask_ops, cpumask_set, cpumask_get);
>
> module_param_cb(cpumask, &cpumask_ops, NULL, 0644);
> MODULE_PARM_DESC(cpumask, "Mask of CPUs to use for idle injection.");
> @@ -252,10 +246,7 @@ static int max_idle_set(const char *arg, const struct kernel_param *kp)
> return ret;
> }
>
> -static const struct kernel_param_ops max_idle_ops = {
> - .set = max_idle_set,
> - .get = param_get_byte,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(max_idle_ops, max_idle_set, param_get_byte);
>
> module_param_cb(max_idle, &max_idle_ops, &max_idle, 0644);
> MODULE_PARM_DESC(max_idle, "maximum injected idle time to the total CPU time ratio in percent range:1-100");
> @@ -299,10 +290,7 @@ static int window_size_set(const char *arg, const struct kernel_param *kp)
> return ret;
> }
>
> -static const struct kernel_param_ops window_size_ops = {
> - .set = window_size_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(window_size_ops, window_size_set, param_get_int);
>
> module_param_cb(window_size, &window_size_ops, &window_size, 0644);
> MODULE_PARM_DESC(window_size, "sliding window in number of clamping cycles\n"
> diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
> index 37db8a3e5158..29612a4a32cb 100644
> --- a/drivers/tty/hvc/hvc_iucv.c
> +++ b/drivers/tty/hvc/hvc_iucv.c
> @@ -1290,10 +1290,8 @@ static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
>
> #define param_check_vmidfilter(name, p) __param_check(name, p, void)
>
> -static const struct kernel_param_ops param_ops_vmidfilter = {
> - .set = param_set_vmidfilter,
> - .get = param_get_vmidfilter,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_vmidfilter, param_set_vmidfilter,
> + param_get_vmidfilter);
>
> /**
> * hvc_iucv_init() - z/VM IUCV HVC device driver initialization
> diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
> index c2e4b31b699a..c6279c496279 100644
> --- a/drivers/tty/sysrq.c
> +++ b/drivers/tty/sysrq.c
> @@ -1074,10 +1074,8 @@ static int sysrq_reset_seq_param_set(const char *buffer,
> return 0;
> }
>
> -static const struct kernel_param_ops param_ops_sysrq_reset_seq = {
> - .get = param_get_ushort,
> - .set = sysrq_reset_seq_param_set,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_sysrq_reset_seq,
> + sysrq_reset_seq_param_set, param_get_ushort);
>
> #define param_check_sysrq_reset_seq(name, p) \
> __param_check(name, p, unsigned short)
> diff --git a/drivers/ufs/core/ufs-fault-injection.c b/drivers/ufs/core/ufs-fault-injection.c
> index 55db38e75cc4..7d2873da7dc5 100644
> --- a/drivers/ufs/core/ufs-fault-injection.c
> +++ b/drivers/ufs/core/ufs-fault-injection.c
> @@ -11,10 +11,7 @@
> static int ufs_fault_get(char *buffer, const struct kernel_param *kp);
> static int ufs_fault_set(const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops ufs_fault_ops = {
> - .get = ufs_fault_get,
> - .set = ufs_fault_set,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ufs_fault_ops, ufs_fault_set, ufs_fault_get);
>
> enum { FAULT_INJ_STR_SIZE = 80 };
>
> diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
> index c1b1d67a1ddc..83100aad2a97 100644
> --- a/drivers/ufs/core/ufs-mcq.c
> +++ b/drivers/ufs/core/ufs-mcq.c
> @@ -43,10 +43,8 @@ static int rw_queue_count_set(const char *val, const struct kernel_param *kp)
> num_possible_cpus());
> }
>
> -static const struct kernel_param_ops rw_queue_count_ops = {
> - .set = rw_queue_count_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(rw_queue_count_ops, rw_queue_count_set,
> + param_get_uint);
>
> static unsigned int rw_queues;
> module_param_cb(rw_queues, &rw_queue_count_ops, &rw_queues, 0644);
> @@ -59,10 +57,8 @@ static int read_queue_count_set(const char *val, const struct kernel_param *kp)
> num_possible_cpus());
> }
>
> -static const struct kernel_param_ops read_queue_count_ops = {
> - .set = read_queue_count_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(read_queue_count_ops, read_queue_count_set,
> + param_get_uint);
>
> static unsigned int read_queues;
> module_param_cb(read_queues, &read_queue_count_ops, &read_queues, 0644);
> @@ -75,10 +71,8 @@ static int poll_queue_count_set(const char *val, const struct kernel_param *kp)
> num_possible_cpus());
> }
>
> -static const struct kernel_param_ops poll_queue_count_ops = {
> - .set = poll_queue_count_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(poll_queue_count_ops, poll_queue_count_set,
> + param_get_uint);
>
> static unsigned int poll_queues = 1;
> module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644);
> diff --git a/drivers/ufs/core/ufs-txeq.c b/drivers/ufs/core/ufs-txeq.c
> index b2dc89124353..3bdd87b434ad 100644
> --- a/drivers/ufs/core/ufs-txeq.c
> +++ b/drivers/ufs/core/ufs-txeq.c
> @@ -23,10 +23,7 @@ static int txeq_gear_set(const char *val, const struct kernel_param *kp)
> return param_set_uint_minmax(val, kp, UFS_HS_G1, UFS_HS_GEAR_MAX);
> }
>
> -static const struct kernel_param_ops txeq_gear_ops = {
> - .set = txeq_gear_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(txeq_gear_ops, txeq_gear_set, param_get_uint);
>
> static unsigned int adaptive_txeq_gear = UFS_HS_G6;
> module_param_cb(adaptive_txeq_gear, &txeq_gear_ops, &adaptive_txeq_gear, 0644);
> diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
> index 4805e40ed4d7..4e930710d9a6 100644
> --- a/drivers/ufs/core/ufshcd.c
> +++ b/drivers/ufs/core/ufshcd.c
> @@ -128,10 +128,8 @@ static int uic_cmd_timeout_set(const char *val, const struct kernel_param *kp)
> UIC_CMD_TIMEOUT_MAX);
> }
>
> -static const struct kernel_param_ops uic_cmd_timeout_ops = {
> - .set = uic_cmd_timeout_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(uic_cmd_timeout_ops, uic_cmd_timeout_set,
> + param_get_uint);
>
> module_param_cb(uic_cmd_timeout, &uic_cmd_timeout_ops, &uic_cmd_timeout, 0644);
> MODULE_PARM_DESC(uic_cmd_timeout,
> @@ -145,10 +143,8 @@ static int dev_cmd_timeout_set(const char *val, const struct kernel_param *kp)
> QUERY_REQ_TIMEOUT_MAX);
> }
>
> -static const struct kernel_param_ops dev_cmd_timeout_ops = {
> - .set = dev_cmd_timeout_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(dev_cmd_timeout_ops, dev_cmd_timeout_set,
> + param_get_uint);
>
> module_param_cb(dev_cmd_timeout, &dev_cmd_timeout_ops, &dev_cmd_timeout, 0644);
> MODULE_PARM_DESC(dev_cmd_timeout,
> diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
> index 0ffdaefba508..d52ecc886925 100644
> --- a/drivers/usb/core/quirks.c
> +++ b/drivers/usb/core/quirks.c
> @@ -160,10 +160,8 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops quirks_param_ops = {
> - .set = quirks_param_set,
> - .get = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(quirks_param_ops, quirks_param_set,
> + param_get_string);
>
> static struct kparam_string quirks_param_string = {
> .maxlen = sizeof(quirks_param),
> diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c
> index 4974bee6049a..e34717e553da 100644
> --- a/drivers/usb/gadget/legacy/serial.c
> +++ b/drivers/usb/gadget/legacy/serial.c
> @@ -121,10 +121,7 @@ static int enable_set(const char *s, const struct kernel_param *kp)
> return ret;
> }
>
> -static const struct kernel_param_ops enable_ops = {
> - .set = enable_set,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enable_ops, enable_set, param_get_bool);
>
> module_param_cb(enable, &enable_ops, &enable, 0644);
>
> diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
> index fa83fe0defe2..71dd623b95c9 100644
> --- a/drivers/usb/storage/usb.c
> +++ b/drivers/usb/storage/usb.c
> @@ -158,10 +158,7 @@ static int delay_use_get(char *s, const struct kernel_param *kp)
> return format_delay_ms(delay_ms, 3, "ms", s, PAGE_SIZE);
> }
>
> -static const struct kernel_param_ops delay_use_ops = {
> - .set = delay_use_set,
> - .get = delay_use_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(delay_use_ops, delay_use_set, delay_use_get);
> module_param_cb(delay_use, &delay_use_ops, &delay_use, 0644);
> MODULE_PARM_DESC(delay_use, "time to delay before using a new device");
>
> diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
> index 9a1253b9d8c5..fd52f2213e27 100644
> --- a/drivers/vhost/scsi.c
> +++ b/drivers/vhost/scsi.c
> @@ -87,10 +87,9 @@ static int vhost_scsi_get_inline_sg_cnt(char *buf,
> return sprintf(buf, "%u\n", vhost_scsi_inline_sg_cnt);
> }
>
> -static const struct kernel_param_ops vhost_scsi_inline_sg_cnt_op = {
> - .get = vhost_scsi_get_inline_sg_cnt,
> - .set = vhost_scsi_set_inline_sg_cnt,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vhost_scsi_inline_sg_cnt_op,
> + vhost_scsi_set_inline_sg_cnt,
> + vhost_scsi_get_inline_sg_cnt);
>
> module_param_cb(inline_sg_cnt, &vhost_scsi_inline_sg_cnt_op, NULL, 0644);
> MODULE_PARM_DESC(inline_sg_cnt, "Set the number of scatterlist entries to pre-allocate. The default is 2048.");
> diff --git a/drivers/virt/nitro_enclaves/ne_misc_dev.c b/drivers/virt/nitro_enclaves/ne_misc_dev.c
> index c91300a73f50..218ddd93f960 100644
> --- a/drivers/virt/nitro_enclaves/ne_misc_dev.c
> +++ b/drivers/virt/nitro_enclaves/ne_misc_dev.c
> @@ -86,10 +86,8 @@ struct ne_devs ne_devs = {
> */
> static int ne_set_kernel_param(const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops ne_cpu_pool_ops = {
> - .get = param_get_string,
> - .set = ne_set_kernel_param,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ne_cpu_pool_ops, ne_set_kernel_param,
> + param_get_string);
>
> static char ne_cpus[NE_CPUS_SIZE];
> static struct kparam_string ne_cpus_arg = {
> diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
> index 595c2274fbb5..f6df9c76ee81 100644
> --- a/drivers/virtio/virtio_mmio.c
> +++ b/drivers/virtio/virtio_mmio.c
> @@ -748,10 +748,8 @@ static int vm_cmdline_get(char *buffer, const struct kernel_param *kp)
> return strlen(buffer) + 1;
> }
>
> -static const struct kernel_param_ops vm_cmdline_param_ops = {
> - .set = vm_cmdline_set,
> - .get = vm_cmdline_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vm_cmdline_param_ops, vm_cmdline_set,
> + vm_cmdline_get);
>
> device_param_cb(device, &vm_cmdline_param_ops, NULL, S_IRUSR);
>
> diff --git a/fs/ceph/super.c b/fs/ceph/super.c
> index c05fbd4237f8..dec8024b8ac7 100644
> --- a/fs/ceph/super.c
> +++ b/fs/ceph/super.c
> @@ -1684,10 +1684,8 @@ static int param_set_metrics(const char *val, const struct kernel_param *kp)
> return 0;
> }
>
> -static const struct kernel_param_ops param_ops_metrics = {
> - .set = param_set_metrics,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_metrics, param_set_metrics,
> + param_get_bool);
>
> bool disable_send_metrics = false;
> module_param_cb(disable_send_metrics, ¶m_ops_metrics, &disable_send_metrics, 0644);
> @@ -1695,9 +1693,7 @@ MODULE_PARM_DESC(disable_send_metrics, "Enable sending perf metrics to ceph clus
>
> /* for both v1 and v2 syntax */
> static bool mount_support = true;
> -static const struct kernel_param_ops param_ops_mount_syntax = {
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_mount_syntax, NULL, param_get_bool);
> module_param_cb(mount_syntax_v1, ¶m_ops_mount_syntax, &mount_support, 0444);
> module_param_cb(mount_syntax_v2, ¶m_ops_mount_syntax, &mount_support, 0444);
>
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index b658b6baf72f..cc955c9952d1 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -71,10 +71,7 @@ static int inval_wq_set(const char *val, const struct kernel_param *kp)
>
> return 0;
> }
> -static const struct kernel_param_ops inval_wq_ops = {
> - .set = inval_wq_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(inval_wq_ops, inval_wq_set, param_get_uint);
> module_param_cb(inval_wq, &inval_wq_ops, &inval_wq, 0644);
> __MODULE_PARM_TYPE(inval_wq, "uint");
> MODULE_PARM_DESC(inval_wq,
> diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
> index af9be0c5f516..f2fba60dc5ed 100644
> --- a/fs/nfs/namespace.c
> +++ b/fs/nfs/namespace.c
> @@ -372,10 +372,8 @@ static int param_get_nfs_timeout(char *buffer, const struct kernel_param *kp)
> return sysfs_emit(buffer, "%li\n", num);
> }
>
> -static const struct kernel_param_ops param_ops_nfs_timeout = {
> - .set = param_set_nfs_timeout,
> - .get = param_get_nfs_timeout,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_nfs_timeout, param_set_nfs_timeout,
> + param_get_nfs_timeout);
> #define param_check_nfs_timeout(name, p) __param_check(name, p, int)
>
> module_param(nfs_mountpoint_expiry_timeout, nfs_timeout, 0644);
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index 4cd420b14ce3..59d89a18aba6 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -1419,10 +1419,8 @@ static int param_set_portnr(const char *val, const struct kernel_param *kp)
> *((unsigned int *)kp->arg) = num;
> return 0;
> }
> -static const struct kernel_param_ops param_ops_portnr = {
> - .set = param_set_portnr,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_portnr, param_set_portnr,
> + param_get_uint);
> #define param_check_portnr(name, p) __param_check(name, p, unsigned int)
>
> module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644);
> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
> index 9a77d8b64ffa..e44f8e18f756 100644
> --- a/fs/ubifs/super.c
> +++ b/fs/ubifs/super.c
> @@ -36,10 +36,8 @@ static int ubifs_default_version_set(const char *val, const struct kernel_param
> return param_set_int(val, kp);
> }
>
> -static const struct kernel_param_ops ubifs_default_version_ops = {
> - .set = ubifs_default_version_set,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ubifs_default_version_ops,
> + ubifs_default_version_set, param_get_int);
>
> int ubifs_default_version = UBIFS_FORMAT_VERSION;
> module_param_cb(default_version, &ubifs_default_version_ops, &ubifs_default_version, 0600);
> diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
> index e618bcf75e2d..38ae3b596ef2 100644
> --- a/kernel/locking/locktorture.c
> +++ b/kernel/locking/locktorture.c
> @@ -98,10 +98,8 @@ static bool cpumask_nonempty(cpumask_var_t mask)
> return cpumask_available(mask) && !cpumask_empty(mask);
> }
>
> -static const struct kernel_param_ops lt_bind_ops = {
> - .set = param_set_cpumask,
> - .get = param_get_cpumask,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(lt_bind_ops, param_set_cpumask,
> + param_get_cpumask);
>
> module_param_cb(bind_readers, <_bind_ops, &bind_readers, 0444);
> module_param_cb(bind_writers, <_bind_ops, &bind_writers, 0444);
> diff --git a/kernel/panic.c b/kernel/panic.c
> index 42e5ebde4585..8698374b0d21 100644
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -1214,10 +1214,8 @@ static int panic_print_set(const char *val, const struct kernel_param *kp)
> return param_set_ulong(val, kp);
> }
>
> -static const struct kernel_param_ops panic_print_ops = {
> - .set = panic_print_set,
> - .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(panic_print_ops, panic_print_set,
> + param_get_ulong);
> __core_param_cb(panic_print, &panic_print_ops, &panic_print, 0644);
>
> static int __init oops_setup(char *s)
> diff --git a/kernel/params.c b/kernel/params.c
> index 2cbad1f4dd06..e19fff2926bc 100644
> --- a/kernel/params.c
> +++ b/kernel/params.c
> @@ -297,11 +297,8 @@ void param_free_charp(void *arg)
> }
> EXPORT_SYMBOL(param_free_charp);
>
> -const struct kernel_param_ops param_ops_charp = {
> - .set = param_set_charp,
> - .get = param_get_charp,
> - .free = param_free_charp,
> -};
> +DEFINE_KERNEL_PARAM_OPS_FREE(param_ops_charp, param_set_charp, param_get_charp,
> + param_free_charp);
> EXPORT_SYMBOL(param_ops_charp);
>
> /* Actually could be a bool or an int, for historical reasons. */
> @@ -322,11 +319,7 @@ int param_get_bool(char *buffer, const struct kernel_param *kp)
> }
> EXPORT_SYMBOL(param_get_bool);
>
> -const struct kernel_param_ops param_ops_bool = {
> - .flags = KERNEL_PARAM_OPS_FL_NOARG,
> - .set = param_set_bool,
> - .get = param_get_bool,
> -};
> +DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_bool, param_set_bool, param_get_bool);
> EXPORT_SYMBOL(param_ops_bool);
>
> int param_set_bool_enable_only(const char *val, const struct kernel_param *kp)
> @@ -353,11 +346,8 @@ int param_set_bool_enable_only(const char *val, const struct kernel_param *kp)
> }
> EXPORT_SYMBOL_GPL(param_set_bool_enable_only);
>
> -const struct kernel_param_ops param_ops_bool_enable_only = {
> - .flags = KERNEL_PARAM_OPS_FL_NOARG,
> - .set = param_set_bool_enable_only,
> - .get = param_get_bool,
> -};
> +DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_bool_enable_only,
> + param_set_bool_enable_only, param_get_bool);
> EXPORT_SYMBOL_GPL(param_ops_bool_enable_only);
>
> /* This one must be bool. */
> @@ -381,10 +371,7 @@ int param_get_invbool(char *buffer, const struct kernel_param *kp)
> }
> EXPORT_SYMBOL(param_get_invbool);
>
> -const struct kernel_param_ops param_ops_invbool = {
> - .set = param_set_invbool,
> - .get = param_get_invbool,
> -};
> +DEFINE_KERNEL_PARAM_OPS(param_ops_invbool, param_set_invbool, param_get_invbool);
> EXPORT_SYMBOL(param_ops_invbool);
>
> int param_set_bint(const char *val, const struct kernel_param *kp)
> @@ -403,11 +390,7 @@ int param_set_bint(const char *val, const struct kernel_param *kp)
> }
> EXPORT_SYMBOL(param_set_bint);
>
> -const struct kernel_param_ops param_ops_bint = {
> - .flags = KERNEL_PARAM_OPS_FL_NOARG,
> - .set = param_set_bint,
> - .get = param_get_int,
> -};
> +DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_bint, param_set_bint, param_get_int);
> EXPORT_SYMBOL(param_ops_bint);
>
> /* We break the rule and mangle the string. */
> @@ -515,11 +498,8 @@ static void param_array_free(void *arg)
> arr->ops->free(arr->elem + arr->elemsize * i);
> }
>
> -const struct kernel_param_ops param_array_ops = {
> - .set = param_array_set,
> - .get = param_array_get,
> - .free = param_array_free,
> -};
> +DEFINE_KERNEL_PARAM_OPS_FREE(param_array_ops, param_array_set, param_array_get,
> + param_array_free);
> EXPORT_SYMBOL(param_array_ops);
>
> int param_set_copystring(const char *val, const struct kernel_param *kp)
> @@ -544,10 +524,8 @@ int param_get_string(char *buffer, const struct kernel_param *kp)
> }
> EXPORT_SYMBOL(param_get_string);
>
> -const struct kernel_param_ops param_ops_string = {
> - .set = param_set_copystring,
> - .get = param_get_string,
> -};
> +DEFINE_KERNEL_PARAM_OPS(param_ops_string, param_set_copystring,
> + param_get_string);
> EXPORT_SYMBOL(param_ops_string);
>
> /* sysfs output in /sys/modules/XYZ/parameters/ */
> diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
> index af8d07bafe02..aba1e4489447 100644
> --- a/kernel/power/hibernate.c
> +++ b/kernel/power/hibernate.c
> @@ -1528,10 +1528,8 @@ static int hibernate_compressor_param_set(const char *compressor,
> return ret;
> }
>
> -static const struct kernel_param_ops hibernate_compressor_param_ops = {
> - .set = hibernate_compressor_param_set,
> - .get = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(hibernate_compressor_param_ops,
> + hibernate_compressor_param_set, param_get_string);
>
> static struct kparam_string hibernate_compressor_param_string = {
> .maxlen = sizeof(hibernate_compressor),
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index 55df6d37145e..e675d7f1b4ee 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -498,15 +498,11 @@ static int param_set_next_fqs_jiffies(const char *val, const struct kernel_param
> return ret;
> }
>
> -static const struct kernel_param_ops first_fqs_jiffies_ops = {
> - .set = param_set_first_fqs_jiffies,
> - .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(first_fqs_jiffies_ops,
> + param_set_first_fqs_jiffies, param_get_ulong);
>
> -static const struct kernel_param_ops next_fqs_jiffies_ops = {
> - .set = param_set_next_fqs_jiffies,
> - .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(next_fqs_jiffies_ops, param_set_next_fqs_jiffies,
> + param_get_ulong);
>
> module_param_cb(jiffies_till_first_fqs, &first_fqs_jiffies_ops, &jiffies_till_first_fqs, 0644);
> module_param_cb(jiffies_till_next_fqs, &next_fqs_jiffies_ops, &jiffies_till_next_fqs, 0644);
> @@ -3979,10 +3975,8 @@ static int param_get_do_rcu_barrier(char *buffer, const struct kernel_param *kp)
> return sprintf(buffer, "%d\n", atomic_read((atomic_t *)kp->arg));
> }
>
> -static const struct kernel_param_ops do_rcu_barrier_ops = {
> - .set = param_set_do_rcu_barrier,
> - .get = param_get_do_rcu_barrier,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(do_rcu_barrier_ops, param_set_do_rcu_barrier,
> + param_get_do_rcu_barrier);
> static atomic_t do_rcu_barrier;
> module_param_cb(do_rcu_barrier, &do_rcu_barrier_ops, &do_rcu_barrier, 0644);
>
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index 345aa11b84b2..fcf31e3e4965 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -166,20 +166,15 @@ static int set_slice_us(const char *val, const struct kernel_param *kp)
> return param_set_uint_minmax(val, kp, 100, 100 * USEC_PER_MSEC);
> }
>
> -static const struct kernel_param_ops slice_us_param_ops = {
> - .set = set_slice_us,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(slice_us_param_ops, set_slice_us, param_get_uint);
>
> static int set_bypass_lb_intv_us(const char *val, const struct kernel_param *kp)
> {
> return param_set_uint_minmax(val, kp, 0, 10 * USEC_PER_SEC);
> }
>
> -static const struct kernel_param_ops bypass_lb_intv_us_param_ops = {
> - .set = set_bypass_lb_intv_us,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(bypass_lb_intv_us_param_ops,
> + set_bypass_lb_intv_us, param_get_uint);
>
> #undef MODULE_PARAM_PREFIX
> #define MODULE_PARAM_PREFIX "sched_ext."
> diff --git a/kernel/workqueue.c b/kernel/workqueue.c
> index 5f747f241a5f..42562b811d94 100644
> --- a/kernel/workqueue.c
> +++ b/kernel/workqueue.c
> @@ -7162,10 +7162,8 @@ static int wq_affn_dfl_get(char *buffer, const struct kernel_param *kp)
> return scnprintf(buffer, PAGE_SIZE, "%s\n", wq_affn_names[wq_affn_dfl]);
> }
>
> -static const struct kernel_param_ops wq_affn_dfl_ops = {
> - .set = wq_affn_dfl_set,
> - .get = wq_affn_dfl_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(wq_affn_dfl_ops, wq_affn_dfl_set,
> + wq_affn_dfl_get);
>
> module_param_cb(default_affinity_scope, &wq_affn_dfl_ops, NULL, 0644);
>
> @@ -7861,10 +7859,8 @@ static int wq_watchdog_param_set_thresh(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops wq_watchdog_thresh_ops = {
> - .set = wq_watchdog_param_set_thresh,
> - .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(wq_watchdog_thresh_ops,
> + wq_watchdog_param_set_thresh, param_get_ulong);
>
> module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh,
> 0644);
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 18a71a9108d3..cf0405ba0dbd 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -807,10 +807,8 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
> }
> EXPORT_SYMBOL(param_get_dyndbg_classes);
>
> -const struct kernel_param_ops param_ops_dyndbg_classes = {
> - .set = param_set_dyndbg_classes,
> - .get = param_get_dyndbg_classes,
> -};
> +DEFINE_KERNEL_PARAM_OPS(param_ops_dyndbg_classes, param_set_dyndbg_classes,
> + param_get_dyndbg_classes);
> EXPORT_SYMBOL(param_ops_dyndbg_classes);
>
> #define PREFIX_SIZE 128
> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> index 77c2a669b6af..30880b6c726a 100644
> --- a/lib/test_dynamic_debug.c
> +++ b/lib/test_dynamic_debug.c
> @@ -23,10 +23,8 @@ static int param_get_do_prints(char *buffer, const struct kernel_param *kp)
> do_prints();
> return scnprintf(buffer, PAGE_SIZE, "did do_prints\n");
> }
> -static const struct kernel_param_ops param_ops_do_prints = {
> - .set = param_set_do_prints,
> - .get = param_get_do_prints,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_do_prints, param_set_do_prints,
> + param_get_do_prints);
> module_param_cb(do_prints, ¶m_ops_do_prints, NULL, 0600);
>
> /*
> diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
> index 8494040b1ee4..5feb93c5262e 100644
> --- a/mm/damon/lru_sort.c
> +++ b/mm/damon/lru_sort.c
> @@ -405,10 +405,8 @@ static int damon_lru_sort_addr_unit_store(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops addr_unit_param_ops = {
> - .set = damon_lru_sort_addr_unit_store,
> - .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(addr_unit_param_ops,
> + damon_lru_sort_addr_unit_store, param_get_ulong);
>
> module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
> MODULE_PARM_DESC(addr_unit,
> @@ -446,10 +444,8 @@ static int damon_lru_sort_enabled_load(char *buffer,
> return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N');
> }
>
> -static const struct kernel_param_ops enabled_param_ops = {
> - .set = damon_lru_sort_enabled_store,
> - .get = damon_lru_sort_enabled_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_lru_sort_enabled_store,
> + damon_lru_sort_enabled_load);
>
> module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
> MODULE_PARM_DESC(enabled,
> @@ -478,10 +474,9 @@ static int damon_lru_sort_kdamond_pid_load(char *buffer,
> return sprintf(buffer, "%d\n", kdamond_pid);
> }
>
> -static const struct kernel_param_ops kdamond_pid_param_ops = {
> - .set = damon_lru_sort_kdamond_pid_store,
> - .get = damon_lru_sort_kdamond_pid_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(kdamond_pid_param_ops,
> + damon_lru_sort_kdamond_pid_store,
> + damon_lru_sort_kdamond_pid_load);
>
> /*
> * PID of the DAMON thread
> diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
> index fe7fce26cf6c..27e772b095fa 100644
> --- a/mm/damon/reclaim.c
> +++ b/mm/damon/reclaim.c
> @@ -307,10 +307,8 @@ static int damon_reclaim_addr_unit_store(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops addr_unit_param_ops = {
> - .set = damon_reclaim_addr_unit_store,
> - .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(addr_unit_param_ops,
> + damon_reclaim_addr_unit_store, param_get_ulong);
>
> module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
> MODULE_PARM_DESC(addr_unit,
> @@ -348,10 +346,8 @@ static int damon_reclaim_enabled_load(char *buffer,
> return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
> }
>
> -static const struct kernel_param_ops enabled_param_ops = {
> - .set = damon_reclaim_enabled_store,
> - .get = damon_reclaim_enabled_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_reclaim_enabled_store,
> + damon_reclaim_enabled_load);
>
> module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
> MODULE_PARM_DESC(enabled,
> @@ -380,10 +376,9 @@ static int damon_reclaim_kdamond_pid_load(char *buffer,
> return sprintf(buffer, "%d\n", kdamond_pid);
> }
>
> -static const struct kernel_param_ops kdamond_pid_param_ops = {
> - .set = damon_reclaim_kdamond_pid_store,
> - .get = damon_reclaim_kdamond_pid_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(kdamond_pid_param_ops,
> + damon_reclaim_kdamond_pid_store,
> + damon_reclaim_kdamond_pid_load);
>
> /*
> * PID of the DAMON thread
> diff --git a/mm/damon/stat.c b/mm/damon/stat.c
> index 3951b762cbdd..6eb548793802 100644
> --- a/mm/damon/stat.c
> +++ b/mm/damon/stat.c
> @@ -22,10 +22,8 @@ static int damon_stat_enabled_store(
> static int damon_stat_enabled_load(char *buffer,
> const struct kernel_param *kp);
>
> -static const struct kernel_param_ops enabled_param_ops = {
> - .set = damon_stat_enabled_store,
> - .get = damon_stat_enabled_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_stat_enabled_store,
> + damon_stat_enabled_load);
>
> static bool enabled __read_mostly = IS_ENABLED(
> CONFIG_DAMON_STAT_ENABLED_DEFAULT);
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index 2a943ec57c85..42e0cf313281 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -109,10 +109,8 @@ static int get_memmap_mode(char *buffer, const struct kernel_param *kp)
> return sprintf(buffer, "%c\n", mode ? 'Y' : 'N');
> }
>
> -static const struct kernel_param_ops memmap_mode_ops = {
> - .set = set_memmap_mode,
> - .get = get_memmap_mode,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(memmap_mode_ops, set_memmap_mode,
> + get_memmap_mode);
> module_param_cb(memmap_on_memory, &memmap_mode_ops, &memmap_mode, 0444);
> MODULE_PARM_DESC(memmap_on_memory, "Enable memmap on memory for memory hotplug\n"
> "With value \"force\" it could result in memory wastage due "
> @@ -163,10 +161,8 @@ static int get_online_policy(char *buffer, const struct kernel_param *kp)
> * (auto_movable_ratio, auto_movable_numa_aware) allows for it
> */
> static int online_policy __read_mostly = ONLINE_POLICY_CONTIG_ZONES;
> -static const struct kernel_param_ops online_policy_ops = {
> - .set = set_online_policy,
> - .get = get_online_policy,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(online_policy_ops, set_online_policy,
> + get_online_policy);
> module_param_cb(online_policy, &online_policy_ops, &online_policy, 0644);
> MODULE_PARM_DESC(online_policy,
> "Set the online policy (\"contig-zones\", \"auto-movable\") "
> diff --git a/mm/page_reporting.c b/mm/page_reporting.c
> index 7418f2e500bb..61351e12b4d9 100644
> --- a/mm/page_reporting.c
> +++ b/mm/page_reporting.c
> @@ -23,15 +23,8 @@ static int page_order_update_notify(const char *val, const struct kernel_param *
> return param_set_uint_minmax(val, kp, 0, MAX_PAGE_ORDER);
> }
>
> -static const struct kernel_param_ops page_reporting_param_ops = {
> - .set = &page_order_update_notify,
> - /*
> - * For the get op, use param_get_int instead of param_get_uint.
> - * This is to make sure that when unset the initialized value of
> - * -1 is shown correctly
> - */
> - .get = ¶m_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(page_reporting_param_ops,
> + &page_order_update_notify, ¶m_get_int);
>
> module_param_cb(page_reporting_order, &page_reporting_param_ops,
> &page_reporting_order, 0644);
> diff --git a/mm/shuffle.c b/mm/shuffle.c
> index fb1393b8b3a9..114fe7467516 100644
> --- a/mm/shuffle.c
> +++ b/mm/shuffle.c
> @@ -23,10 +23,8 @@ static __meminit int shuffle_param_set(const char *val,
> return 0;
> }
>
> -static const struct kernel_param_ops shuffle_param_ops = {
> - .set = shuffle_param_set,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(shuffle_param_ops, shuffle_param_set,
> + param_get_bool);
> module_param_cb(shuffle, &shuffle_param_ops, &shuffle_param, 0400);
>
> /*
> diff --git a/mm/zswap.c b/mm/zswap.c
> index 4b5149173b0e..ed3aa07c2f1d 100644
> --- a/mm/zswap.c
> +++ b/mm/zswap.c
> @@ -90,21 +90,17 @@ static DEFINE_STATIC_KEY_MAYBE(CONFIG_ZSWAP_DEFAULT_ON, zswap_ever_enabled);
> static bool zswap_enabled = IS_ENABLED(CONFIG_ZSWAP_DEFAULT_ON);
> static int zswap_enabled_param_set(const char *,
> const struct kernel_param *);
> -static const struct kernel_param_ops zswap_enabled_param_ops = {
> - .set = zswap_enabled_param_set,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(zswap_enabled_param_ops, zswap_enabled_param_set,
> + param_get_bool);
> module_param_cb(enabled, &zswap_enabled_param_ops, &zswap_enabled, 0644);
>
> /* Crypto compressor to use */
> static char *zswap_compressor = CONFIG_ZSWAP_COMPRESSOR_DEFAULT;
> static int zswap_compressor_param_set(const char *,
> const struct kernel_param *);
> -static const struct kernel_param_ops zswap_compressor_param_ops = {
> - .set = zswap_compressor_param_set,
> - .get = param_get_charp,
> - .free = param_free_charp,
> -};
> +static DEFINE_KERNEL_PARAM_OPS_FREE(zswap_compressor_param_ops,
> + zswap_compressor_param_set, param_get_charp,
> + param_free_charp);
> module_param_cb(compressor, &zswap_compressor_param_ops,
> &zswap_compressor, 0644);
>
> diff --git a/net/batman-adv/bat_algo.c b/net/batman-adv/bat_algo.c
> index 49e5861b58ec..54d66a948298 100644
> --- a/net/batman-adv/bat_algo.c
> +++ b/net/batman-adv/bat_algo.c
> @@ -134,10 +134,8 @@ static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
> return param_set_copystring(algo_name, kp);
> }
>
> -static const struct kernel_param_ops batadv_param_ops_ra = {
> - .set = batadv_param_set_ra,
> - .get = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(batadv_param_ops_ra, batadv_param_set_ra,
> + param_get_string);
>
> static struct kparam_string batadv_param_string_ra = {
> .maxlen = sizeof(batadv_routing_algo),
> diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
> index 952121849180..633202a99e4a 100644
> --- a/net/ceph/ceph_common.c
> +++ b/net/ceph/ceph_common.c
> @@ -52,9 +52,8 @@ static int param_get_supported_features(char *buffer,
> {
> return sprintf(buffer, "0x%llx", CEPH_FEATURES_SUPPORTED_DEFAULT);
> }
> -static const struct kernel_param_ops param_ops_supported_features = {
> - .get = param_get_supported_features,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_supported_features, NULL,
> + param_get_supported_features);
> module_param_cb(supported_features, ¶m_ops_supported_features, NULL,
> 0444);
>
> diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c
> index 274e628e7cf8..2c9c3d0f3c3d 100644
> --- a/net/ipv4/tcp_dctcp.c
> +++ b/net/ipv4/tcp_dctcp.c
> @@ -64,10 +64,8 @@ static int dctcp_shift_g_set(const char *val, const struct kernel_param *kp)
> return param_set_uint_minmax(val, kp, 0, 10);
> }
>
> -static const struct kernel_param_ops dctcp_shift_g_ops = {
> - .set = dctcp_shift_g_set,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(dctcp_shift_g_ops, dctcp_shift_g_set,
> + param_get_uint);
>
> module_param_cb(dctcp_shift_g, &dctcp_shift_g_ops, &dctcp_shift_g, 0644);
> MODULE_PARM_DESC(dctcp_shift_g, "parameter g for updating dctcp_alpha");
> diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
> index 68c0595ea2fd..64a3e894fd4c 100644
> --- a/net/sunrpc/auth.c
> +++ b/net/sunrpc/auth.c
> @@ -83,10 +83,8 @@ static int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp)
>
> #define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);
>
> -static const struct kernel_param_ops param_ops_hashtbl_sz = {
> - .set = param_set_hashtbl_sz,
> - .get = param_get_hashtbl_sz,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_hashtbl_sz, param_set_hashtbl_sz,
> + param_get_hashtbl_sz);
>
> module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644);
> MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
> diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
> index 2e1fe6013361..e8d087798994 100644
> --- a/net/sunrpc/xprtsock.c
> +++ b/net/sunrpc/xprtsock.c
> @@ -3710,10 +3710,8 @@ static int param_set_portnr(const char *val, const struct kernel_param *kp)
> RPC_MAX_RESVPORT);
> }
>
> -static const struct kernel_param_ops param_ops_portnr = {
> - .set = param_set_portnr,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_portnr, param_set_portnr,
> + param_get_uint);
>
> #define param_check_portnr(name, p) \
> __param_check(name, p, unsigned int);
> @@ -3729,10 +3727,8 @@ static int param_set_slot_table_size(const char *val,
> RPC_MAX_SLOT_TABLE);
> }
>
> -static const struct kernel_param_ops param_ops_slot_table_size = {
> - .set = param_set_slot_table_size,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_slot_table_size,
> + param_set_slot_table_size, param_get_uint);
>
> #define param_check_slot_table_size(name, p) \
> __param_check(name, p, unsigned int);
> @@ -3745,10 +3741,8 @@ static int param_set_max_slot_table_size(const char *val,
> RPC_MAX_SLOT_TABLE_LIMIT);
> }
>
> -static const struct kernel_param_ops param_ops_max_slot_table_size = {
> - .set = param_set_max_slot_table_size,
> - .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_max_slot_table_size,
> + param_set_max_slot_table_size, param_get_uint);
>
> #define param_check_max_slot_table_size(name, p) \
> __param_check(name, p, unsigned int);
> diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c
> index 775838a23d93..c8018a7ea891 100644
> --- a/samples/damon/mtier.c
> +++ b/samples/damon/mtier.c
> @@ -38,10 +38,8 @@ module_param(node0_mem_free_bp, ulong, 0600);
> static int damon_sample_mtier_enable_store(
> const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops enabled_param_ops = {
> - .set = damon_sample_mtier_enable_store,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops,
> + damon_sample_mtier_enable_store, param_get_bool);
>
> static bool enabled __read_mostly;
> module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
> diff --git a/samples/damon/prcl.c b/samples/damon/prcl.c
> index b7c50f2656ce..7cab9bd0f7bd 100644
> --- a/samples/damon/prcl.c
> +++ b/samples/damon/prcl.c
> @@ -22,10 +22,8 @@ module_param(target_pid, int, 0600);
> static int damon_sample_prcl_enable_store(
> const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops enabled_param_ops = {
> - .set = damon_sample_prcl_enable_store,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops,
> + damon_sample_prcl_enable_store, param_get_bool);
>
> static bool enabled __read_mostly;
> module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
> diff --git a/samples/damon/wsse.c b/samples/damon/wsse.c
> index 799ad4443943..56634853bd0b 100644
> --- a/samples/damon/wsse.c
> +++ b/samples/damon/wsse.c
> @@ -23,10 +23,8 @@ module_param(target_pid, int, 0600);
> static int damon_sample_wsse_enable_store(
> const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops enabled_param_ops = {
> - .set = damon_sample_wsse_enable_store,
> - .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops,
> + damon_sample_wsse_enable_store, param_get_bool);
>
> static bool enabled __read_mostly;
> module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index 3491e9f60194..8a253c743363 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -1767,38 +1767,30 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
> static int param_set_aabool(const char *val, const struct kernel_param *kp);
> static int param_get_aabool(char *buffer, const struct kernel_param *kp);
> #define param_check_aabool param_check_bool
> -static const struct kernel_param_ops param_ops_aabool = {
> - .flags = KERNEL_PARAM_OPS_FL_NOARG,
> - .set = param_set_aabool,
> - .get = param_get_aabool
> -};
> +static DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_aabool, param_set_aabool,
> + param_get_aabool);
>
> static int param_set_aauint(const char *val, const struct kernel_param *kp);
> static int param_get_aauint(char *buffer, const struct kernel_param *kp);
> #define param_check_aauint param_check_uint
> -static const struct kernel_param_ops param_ops_aauint = {
> - .set = param_set_aauint,
> - .get = param_get_aauint
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_aauint, param_set_aauint,
> + param_get_aauint);
>
> static int param_set_aacompressionlevel(const char *val,
> const struct kernel_param *kp);
> static int param_get_aacompressionlevel(char *buffer,
> const struct kernel_param *kp);
> #define param_check_aacompressionlevel param_check_int
> -static const struct kernel_param_ops param_ops_aacompressionlevel = {
> - .set = param_set_aacompressionlevel,
> - .get = param_get_aacompressionlevel
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_aacompressionlevel,
> + param_set_aacompressionlevel,
> + param_get_aacompressionlevel);
>
> static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
> static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
> #define param_check_aalockpolicy param_check_bool
> -static const struct kernel_param_ops param_ops_aalockpolicy = {
> - .flags = KERNEL_PARAM_OPS_FL_NOARG,
> - .set = param_set_aalockpolicy,
> - .get = param_get_aalockpolicy
> -};
> +static DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_aalockpolicy,
> + param_set_aalockpolicy,
> + param_get_aalockpolicy);
>
> static int param_set_debug(const char *val, const struct kernel_param *kp);
> static int param_get_debug(char *buffer, const struct kernel_param *kp);
> @@ -1879,10 +1871,8 @@ module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
> static int param_get_aaintbool(char *buffer, const struct kernel_param *kp);
> static int param_set_aaintbool(const char *val, const struct kernel_param *kp);
> #define param_check_aaintbool param_check_int
> -static const struct kernel_param_ops param_ops_aaintbool = {
> - .set = param_set_aaintbool,
> - .get = param_get_aaintbool
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_aaintbool, param_set_aaintbool,
> + param_get_aaintbool);
> /* Boot time disable flag */
> static int apparmor_enabled __ro_after_init = 1;
> module_param_named(enabled, apparmor_enabled, aaintbool, 0444);
> diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
> index c87d75dbd8aa..02bd61e67902 100644
> --- a/sound/hda/controllers/intel.c
> +++ b/sound/hda/controllers/intel.c
> @@ -164,10 +164,7 @@ MODULE_PARM_DESC(ctl_dev_id, "Use control device identifier (based on codec addr
>
> #ifdef CONFIG_PM
> static int param_set_xint(const char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops param_ops_xint = {
> - .set = param_set_xint,
> - .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_xint, param_set_xint, param_get_int);
> #define param_check_xint param_check_int
>
> static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
> diff --git a/sound/usb/card.c b/sound/usb/card.c
> index f42d72cd0378..34cbb9d72315 100644
> --- a/sound/usb/card.c
> +++ b/sound/usb/card.c
> @@ -118,11 +118,8 @@ static int param_set_quirkp(const char *val,
> return param_set_charp(val, kp);
> }
>
> -static const struct kernel_param_ops param_ops_quirkp = {
> - .set = param_set_quirkp,
> - .get = param_get_charp,
> - .free = param_free_charp,
> -};
> +static DEFINE_KERNEL_PARAM_OPS_FREE(param_ops_quirkp, param_set_quirkp,
> + param_get_charp, param_free_charp);
>
> #define param_check_quirkp param_check_charp
>
> --
> 2.34.1
>
^ permalink raw reply
* Re: [RFC PATCH v4 01/19] landlock: Support socket access-control
From: Günther Noack @ 2026-05-22 15:42 UTC (permalink / raw)
To: Mickaël Salaün
Cc: Mikhail Ivanov, gnoack, willemdebruijn.kernel, matthieu,
linux-security-module, netdev, netfilter-devel, yusongping,
artem.kuzin, konstantin.meskhidze
In-Reply-To: <20260508.aeJoht7aepho@digikod.net>
On Fri, May 08, 2026 at 03:29:21PM +0200, Mickaël Salaün wrote:
> On Sat, Apr 18, 2026 at 02:29:04PM +0300, Mikhail Ivanov wrote:
> > On 11/22/2025 2:13 PM, Mikhail Ivanov wrote:
> > > On 11/22/2025 1:49 PM, Günther Noack wrote:
> > > > On Tue, Nov 18, 2025 at 09:46:21PM +0800, Mikhail Ivanov wrote:
> > > > > +/**
> > > > > + * struct landlock_socket_attr - Socket protocol definition
> > > > > + *
> > > > > + * Argument of sys_landlock_add_rule().
> > > > > + */
> > > > > +struct landlock_socket_attr {
> > > > > + /**
> > > > > + * @allowed_access: Bitmask of allowed access for a socket protocol
> > > > > + * (cf. `Socket flags`_).
> > > > > + */
> > > > > + __u64 allowed_access;
> > > > > + /**
> > > > > + * @family: Protocol family used for communication
> > > > > + * (cf. include/linux/socket.h).
> > > > > + */
> > > > > + __s32 family;
> > > > > + /**
> > > > > + * @type: Socket type (cf. include/linux/net.h)
> > > > > + */
> > > > > + __s32 type;
> > > > > + /**
> > > > > + * @protocol: Communication protocol specific to protocol
> > > > > family set in
> > > > > + * @family field.
> > > >
> > > > This is specific to both the @family and the @type, not just the @family.
> > > >
> > > > > From socket(2):
> > > >
> > > > Normally only a single protocol exists to support a particular
> > > > socket type within a given protocol family.
> > > >
> > > > For instance, in your commit message above the protocol in the example
> > > > is IPPROTO_TCP, which would imply the type SOCK_STREAM, but not work
> > > > with SOCK_DGRAM.
> > >
> > > You're right.
> > >
> >
> > I revised the socket(2) semantics and this part is about that kernel
> > maps (family, type, 0) to the default protocol of given family and type.
> > Eg. (AF_INET, SOCK_STREAM, 0) is mapped to (AF_INET, SOCK_STREAM,
> > IPPROTO_TCP). I would like to clarify that such mapping is taking place
> > in landlock_socket_attr.protocol field doc.
> >
> > There should be list of protocols defined per protocol family. From
> > socket(2):
> > The domain argument specifies a communication domain.
> > ...
> > The protocol number to use is specific to the “communication
> > domain” in which communication is to take place.
> >
> > Such mapping allows to define strange socket rules if setting @type=-1.
> > For example:
> > struct landlock_socket_attr attr = {
> > .family = AF_INET,
> > .type = -1,
> > .protocol = 0,
> > };
>
> Looking again at this API, I think we should not have a special handling
> of the "-1" values but instead change the struct landlock_socket_attr to
> start with a "wildcards" field to properly identify which socket
> property should be "any" value (according to a dedicated flag):
>
> struct landlock_socket_attr {
> __u64 allowed_perm; /* see the ns/cap patch series */
> __u32 wildcards; /* LANDLOCK_SOCKET_ANY_PROTOCOL */
> __u32 family;
> __u32 type;
> __u32 protocol;
> };
>
> In fact, I though a lot about the two potential wildcards (type and
> family we previously discussed), and my conclusion is that we should
> only handle "any protocol" (instead of any type too). This makes the
> UAPI simpler and less dangerous, especially wrt families that have very
> specific and sometime privileged types (e.g. SOCK_RAW).
I'm on board with that, API-wise. This seems reasonable.
> Another
> important point is that it would allow to do only one rbtree lookup
> (tweaking a bit the rbtree walk) instead of four lookup like with the
> current implementation. The idea is to generate an rbtree key with:
>
> family | type | !any-protocol-boolean | protocol
>
> This key format allows a one-descent walk lookup. We'll have to replace
> the use of landlock_find_rule() with a custom walk that first look for
> the any-protocol-boolean (which should probably be represented by 0 for
> "any protocol" and by 1 for "specific protocol"), and if no "any
> protocol" key is found, to continue the walk to match the full protocol
> value.
Seems reasonable as well.
> > This definition corresponds to (AF_INET, SOCK_STREAM, 0->IPPROTO_TCP)
> > and to (AF_INET, SOCK_DGRAM, 0->IPPROTO_UDP).
> >
> > I don't see this as a bad thing as far as there is proper documentation
> > for landlock_socket_attr.
>
> Thinking more about the asymmetry between UAPI and kernel state, I think
> the best approach is to canonicalize the rules' values to make them
> match the kernel equivalent. This behavior would be much less
> surprising to users (this is mostly an UX improvement, but also a way to
> deduplicate some rules). Indeed, users would be able to use the default
> value (e.g. protocol 0 for INET/STREAM) *and* the canonicalized value
> (e.g. protocol IPPROTO_TCP). Here is a patch to implement this approach
> and (most importantly) with the related kernel tests to make sure the
> canonicalizations are correct:
Impressive reverse engineering of that mapping. o_O
The approach makes sense to me in general, but I left some more
specific comments below.
> [PATCH] landlock: Canonicalize socket rules and add drift detection
>
> The kernel socket stack performs family-specific rewrites between the
> (family, type, protocol) triple passed to socket(2) and the resulting
> socket object. Rewrites currently mirrored:
>
> - __sock_create rewrites AF_INET + SOCK_PACKET to AF_PACKET for pre-2.2
> compatibility.
> - unix_create rewrites AF_UNIX + SOCK_RAW to AF_UNIX + SOCK_DGRAM as a
> BSD leftover, and ignores the user protocol (sk_protocol stays 0 for
> every AF_UNIX socket).
> - inet_create and inet6_create resolve protocol=0 to a type-specific
> default (IPPROTO_TCP for SOCK_STREAM, IPPROTO_UDP for SOCK_DGRAM,
> IPPROTO_SCTP for SOCK_SEQPACKET) via the inetsw walk.
> - ax25_create rewrites protocol=0 and protocol=PF_AX25 to AX25_P_TEXT
> for SOCK_DGRAM and SOCK_SEQPACKET.
> - pn_socket_create rewrites protocol=0 to PN_PROTO_PHONET (SOCK_DGRAM)
> or PN_PROTO_PIPE (SOCK_SEQPACKET).
> - vsock_create accepts protocol=0 or PF_VSOCK and stores sk_protocol=0
> for both, so PF_VSOCK aliases protocol=0.
> - Several families (AF_PACKET, AF_KEY, AF_APPLETALK, AF_ATMPVC,
> AF_ATMSVC, AF_LLC, AF_CAN raw/bcm, AF_RXRPC, AF_IEEE802154,
> AF_QIPCRTR) accept the user protocol but never write sk_protocol, so
> the kernel stores 0 regardless of input.
> - AF_CAN + SOCK_DGRAM is asymmetric: bcm and raw leave sk_protocol=0,
> but j1939_sk_init writes sk_protocol = CAN_J1939.
Relevant remark on the side:
With the socket options SO_DOMAIN, SO_TYPE and SO_PROTOCOL, the
canonicalized sockets have become exposed to userspace. So these are
not purely kernel-private mappings, but this canonicalization is
exposed to userspace (which should presumably make the mappings
stable).
I hope that the assumption is correct that the mappings for the
existing (f, t, p) combinations *are* stable? If these mappings were
permitted to change for existing (f, t, p) combinations, I suspect it
might be possible to construct a scenario where a landlocked program
that used to work stops working after a kernel update. That would be
a worse backwards compatibility issue than when getsockopt() returns a
new value for one of SO_{DOMAIN,TYPE,PROTOCOL}.
> Without Landlock-side canonicalization, a rule inserted with the user-
> facing form (e.g., AF_INET + SOCK_STREAM + 0) silently misses sockets
> the user wants to match: a socket created with protocol=0 reaches
> sk_protocol=IPPROTO_TCP, so a rule keyed on 0 does not apply. Each
> socket call form would require the user to write a separate rule.
>
> Store rules in the canonical form at insertion. The new
> landlock_canon_map[AF_MAX][SOCK_MAX] table with flag-driven entries
> (_LANDLOCK_CANON_REWRITE_FAMILY, _LANDLOCK_CANON_REWRITE_TYPE,
> _LANDLOCK_CANON_PROTOCOL_ZERO, _LANDLOCK_CANON_PROTOCOL_FAMILY_ID,
> _LANDLOCK_CANON_PROTOCOL_ALWAYS, _LANDLOCK_CANON_PROTOCOL_PRESERVE)
> encodes the rewrites. landlock_canonicalize_socket_key applies them
> idempotently; wildcards (TYPE_ALL, PROTOCOL_ALL) are preserved so
> wildcard rules remain first-class. Per-protocol overrides (the
> preserve_protocol field) handle asymmetries like AF_CAN + SOCK_DGRAM
> where one sub-protocol writes sk_protocol differently from the others.
> Lookup remains O(1): the override is part of the same cell the array
> index returns.
>
> Keep enforcement at security_socket_create (pre-create) so Landlock
> denies unauthorized triples before the kernel loads any family-specific
> module or allocates a socket. This preserves the EACCES error path for
> triples the kernel itself would reject (AF_UNSPEC, invalid family and
> type pairs) rather than leaking EAFNOSUPPORT, ESOCKTNOSUPPORT, or
> EPROTONOSUPPORT as a sandbox bypass signal. The pre-create hook
> canonicalizes the caller input through the same map before the rule
> lookup so that a rule keyed on the user form matches at the hook.
>
> Add security_socket_post_create purely for runtime drift detection. At
> post_create the family .create() has completed, so sk_family,
> sock->type, and sk_protocol are authoritative. Per-field WARN_ONCE
> fires when landlock_canonicalize_socket_key disagrees with these values,
> identifying which axis (family, type, or protocol) drifted and the
> user-supplied triple. This hook only runs for tasks sandboxed by a
> domain that handles LANDLOCK_ACCESS_SOCKET_CREATE, so non-sandboxed
> tasks pay no overhead.
Shouldn't this only be enabled under a suitable debug build config?
This is all supposed to be captured by the KUnit test already, right?
Or do you expect that there are differences that the KUnit test
doesn't cover?
>
> Four layers guard against landlock_canon_map drift:
>
> - static_assert(AF_MAX == N) and static_assert(SOCK_MAX == N) anchor the
> dimensions at the current kernel ABI; a new AF_* or SOCK_* value
> breaks the build and forces a map audit.
> - A new KUnit suite (landlock_socket) iterates every (family, type,
> protocol) triple over a probe range that covers all family IDs
> (0..NPROTO) plus IPPROTO_SCTP, 255, and 0xFFFF. For triples the
> kernel accepts, sock_create_kern is the oracle; canonicalization is
> validated against the resulting sk_family, sock->type, and
> sk_protocol. Families known to be unsupported by the default
> configuration are marked, and -EAFNOSUPPORT on those families is
> ignored so additional sub-protocol configs can extend coverage without
> per-arch .kunitconfig fragmentation. A separate map-entry test covers
> cells unreachable through sock_create_kern (currently AF_VSOCK +
> SOCK_DGRAM, which requires CONFIG_VIRTIO_VSOCKETS). A
> wildcard-preservation test pins the TYPE_ALL and PROTOCOL_ALL
> invariants.
> - The per-field runtime WARN_ONCE described above.
> - security/landlock/.kunitconfig enumerates the CONFIG entries required
> to exercise every audited family so a family disabled by kernel config
> causes a build-visible coverage loss rather than a silent KUnit skip.
>
> The four-way wildcard grid lookup in hook_socket_create gates every
> pack_socket_key call on a successful return. This incidentally fixes a
> latent bug in the original hook where the first pack failure was
> detected with == -EACCES (the helper only ever returns 0 or -EINVAL), so
> an out-of-range triple fed three subsequent check_socket_access calls
> with an uninitialized key.
>
> The tcp_protocol.variant2 selftest previously asserted that a rule for
> IPPROTO_TCP did NOT match socket(AF_INET, SOCK_STREAM, 0). Under
> canonicalization both forms alias by design, so the test is renamed to
> alias_equivalence and its body is updated to assert the aliasing (both
> call forms match irrespective of which form the rule was inserted with).
> Unrelated families remain restricted.
>
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> ---
> security/landlock/.kunitconfig | 40 +
> security/landlock/socket.c | 871 +++++++++++++++++-
> .../testing/selftests/landlock/socket_test.c | 38 +-
> 3 files changed, 910 insertions(+), 39 deletions(-)
>
> diff --git a/security/landlock/.kunitconfig b/security/landlock/.kunitconfig
> index f9423f01ac5b..5aafd56e8ebd 100644
> --- a/security/landlock/.kunitconfig
> +++ b/security/landlock/.kunitconfig
> @@ -1,6 +1,46 @@
> +CONFIG_AF_RXRPC=y
> +CONFIG_ATALK=y
> +CONFIG_ATM=y
> CONFIG_AUDIT=y
> +CONFIG_AX25=y
> +CONFIG_BT=y
> +CONFIG_CAIF=y
> +CONFIG_CAN=y
> +CONFIG_CAN_BCM=y
> +CONFIG_CRYPTO=y
> +CONFIG_CRYPTO_USER_API_AEAD=y
> +CONFIG_HAMRADIO=y
> +CONFIG_IEEE802154=y
> +CONFIG_IEEE802154_SOCKET=y
> +CONFIG_INET=y
> +CONFIG_INFINIBAND=y
> +CONFIG_IP_SCTP=y
> +CONFIG_IPV6=y
> +CONFIG_ISDN=y
> CONFIG_KUNIT=y
> +CONFIG_LLC=y
> +CONFIG_LLC2=y
> +CONFIG_MCTP=y
> +CONFIG_MISDN=y
> +CONFIG_MPTCP=y
> +CONFIG_MPTCP_IPV6=y
> CONFIG_NET=y
> +CONFIG_NET_KEY=y
> +CONFIG_NETDEVICES=y
> +CONFIG_NETROM=y
> +CONFIG_NFC=y
> +CONFIG_PACKET=y
> +CONFIG_PHONET=y
> +CONFIG_PPP=y
> +CONFIG_PPPOE=y
> +CONFIG_QRTR=y
> +CONFIG_RDS=y
> +CONFIG_ROSE=y
> CONFIG_SECURITY=y
> CONFIG_SECURITY_LANDLOCK=y
> CONFIG_SECURITY_LANDLOCK_KUNIT_TEST=y
> +CONFIG_SMC=y
> +CONFIG_TIPC=y
> +CONFIG_UNIX=y
> +CONFIG_VSOCKETS=y
> +CONFIG_X25=y
Are there possible kernel configurations where the mapping changes in
incompatible ways?
Specifically, are there kernel configurations where there is a family,
type and protocol such that:
(a) the call to socket(f, t, p) yields a valid socket FD
(b) and the socket's mapping is still different to what Landlock says
It seems that for the CONFIG_* options which are enabling address
families, this should stay compatible because without these, step (a)
presumably yields an error. Are there other CONFIG_* options which
are not about address families where this is not the case?
> diff --git a/security/landlock/socket.c b/security/landlock/socket.c
> index 6afd5a0ac6d7..ef48949fa7d3 100644
> --- a/security/landlock/socket.c
> +++ b/security/landlock/socket.c
> @@ -5,20 +5,385 @@
> * Copyright © 2025 Huawei Tech. Co., Ltd.
> */
>
> +#include <linux/in.h>
> #include <linux/net.h>
> #include <linux/socket.h>
> #include <linux/stddef.h>
> #include <net/ipv6.h>
> +#include <net/sock.h>
>
> #include "audit.h"
> +#include "cred.h"
> #include "limits.h"
> #include "ruleset.h"
> #include "socket.h"
> -#include "cred.h"
>
> #define TYPE_ALL (-1)
> #define PROTOCOL_ALL (-1)
>
> +/*
> + * Compensation for kernel-internal socket rewrites.
> + *
> + * The kernel maps the user-visible (family, type, protocol) triple into
> + * (sk->sk_family, sock->type, sk->sk_protocol) following per-family rules.
> + * Landlock mirrors those rules at rule insertion and at hook time so that rules
> + * inserted with a user-facing form match the canonical triple seen after
> + * socket(2) completes. The known patterns are:
> + *
> + * - __sock_create rewrites AF_INET + SOCK_PACKET to AF_PACKET for
> + * pre-2.2 compatibility (net/socket.c).
> + * - unix_create rewrites AF_UNIX + SOCK_RAW to AF_UNIX + SOCK_DGRAM and
> + * ignores the user protocol (sk_protocol stays 0).
> + * - inet_create and inet6_create resolve protocol=0 to a type-specific
> + * default (IPPROTO_TCP for SOCK_STREAM, IPPROTO_UDP for SOCK_DGRAM,
> + * IPPROTO_SCTP for SOCK_SEQPACKET) via the inetsw walk.
> + * - ax25_create rewrites protocol=0 or PF_AX25 to AX25_P_TEXT for
> + * SOCK_DGRAM and SOCK_SEQPACKET.
> + * - pn_socket_create rewrites protocol=0 to PN_PROTO_PHONET for
> + * SOCK_DGRAM and PN_PROTO_PIPE for SOCK_SEQPACKET.
> + * - vsock_create accepts either 0 or PF_VSOCK and stores sk_protocol=0
> + * for both; Landlock canonicalizes the rule to protocol=0.
> + *
> + * Enforcement happens at security_socket_create (pre-create) so Landlock denies
> + * unauthorized triples before any family-specific module is loaded or socket
> + * allocated, preserving the EACCES error path for triples the kernel itself
> + * would reject.
> + *
> + * Drift between landlock_canon_map and kernel behavior is detected in four
> + * layers: static_asserts on AF_MAX and SOCK_MAX (new AF or SOCK values break
> + * the build), the exhaustive KUnit suite in this file using sock_create_kern as
> + * the oracle, a runtime WARN_ON_ONCE in the post_create hook, and an explicit
> + * CONFIG list in .kunitconfig so a missing family fails the build instead of
> + * silently skipping.
> + */
> +
> +#define _LANDLOCK_CANON_REWRITE_FAMILY BIT(0)
> +#define _LANDLOCK_CANON_REWRITE_TYPE BIT(1)
> +#define _LANDLOCK_CANON_PROTOCOL_ZERO BIT(2)
> +#define _LANDLOCK_CANON_PROTOCOL_FAMILY_ID BIT(3)
> +#define _LANDLOCK_CANON_PROTOCOL_ALWAYS BIT(4)
> +#define _LANDLOCK_CANON_PROTOCOL_PRESERVE BIT(5)
Naming nits:
* _LANDLOCK_CANON_PROTOCOL_ALWAYS could maybe be
_LANDLOCK_CANON_REWRITE_PROTOCOL, for symmetry with *REWRITE_FAMILY
and *REWRITE_TYPE.
* similarly, _LANDLOCK_CANON_PROTOCOL_ZERO =>
_LANDLOCK_CANON_REWRITE_PROTOCOL_IF_ZERO?
At the higher abstraction level in this implementation:
These enum values, the struct landlock_canon_entry and its
interpretation in landlock_canonicalize_socket_key() feels a bit heavy
handed for the mapping, and when reading it, I had to jump between the
table, the struct, the enums and the canonicalization function.
I assume that you have attempted to express that table as a big switch
statement with normal `if` conditions where these preconditions are
expressed more directly? Was that code worse?
> +
> +/*
> + * All fields fit in u8 today: ops uses 6 bits; SOCK_MAX-1 and AF_MAX-1 are both
> + * small; the largest canonicalization target is AX25_P_TEXT (0xF0), well within
> + * u8. -Woverflow catches a too-wide initializer at build time if a future
> + * entry exceeds the field width.
> + */
> +struct landlock_canon_entry {
> + u8 ops;
> + u8 new_type;
> + u8 new_family;
> + u8 new_protocol;
> + /*
> + * When PROTOCOL_PRESERVE is set and the user protocol matches this
> + * value, the protocol field is left unchanged regardless of the other
> + * PROTOCOL_* flags. Captures sub-protocols whose .create() writes
> + * sk_protocol explicitly (e.g. CAN_J1939) when other sub-protocols of
> + * the same (family, type) do not. Lookup stays O(1) because the
> + * override is part of the same cell.
> + */
> + u8 preserve_protocol;
> +};
> +
> +/*
> + * Shared initializer for Case 4 families (AF_UNIX, AF_PACKET, AF_VSOCK, AF_KEY,
> + * ...) whose .create() ignores the user protocol and leaves sk_protocol at 0.
> + * The canonical form is any type, protocol=0.
> + */
> +#define _LANDLOCK_CANON_ALWAYS_ZERO \
> + { \
> + .ops = _LANDLOCK_CANON_PROTOCOL_ALWAYS, .new_protocol = 0, \
> + }
> +
> +/*
> + * A change to AF_MAX or SOCK_MAX implies a new protocol family or socket type
> + * reached upstream. The assertion fires a build error that forces an audit:
> + * does the new family or type introduce a kernel-internal rewrite that Landlock
> + * must mirror? If not, bump the expected value below.
> + */
> +static_assert(AF_MAX == 46,
> + "AF_MAX changed; audit landlock_canon_map for new families.");
> +static_assert(SOCK_MAX == 11,
> + "SOCK_MAX changed; audit landlock_canon_map for new types.");
> +
> +static const struct landlock_canon_entry
> + landlock_canon_map[AF_MAX][SOCK_MAX] = {
> + /*
> + * unix_create rewrites SOCK_RAW to SOCK_DGRAM and ignores the
> + * user protocol; normalize every AF_UNIX socket to protocol=0.
> + */
> + [AF_UNIX] = {
> + [SOCK_STREAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_SEQPACKET] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_RAW] = {
> + .ops = _LANDLOCK_CANON_REWRITE_TYPE |
> + _LANDLOCK_CANON_PROTOCOL_ALWAYS,
> + .new_type = SOCK_DGRAM,
> + .new_protocol = 0,
> + },
> + },
> + [AF_INET] = {
> + [SOCK_STREAM] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO,
> + .new_protocol = IPPROTO_TCP,
> + },
> + [SOCK_DGRAM] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO,
> + .new_protocol = IPPROTO_UDP,
> + },
> + [SOCK_SEQPACKET] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO,
> + .new_protocol = IPPROTO_SCTP,
> + },
> + /*
> + * __sock_create rewrites AF_INET + SOCK_PACKET to
> + * AF_PACKET; packet_create then stores sk_protocol=0
> + * regardless of the user protocol (see AF_PACKET rows
> + * below), so the canonical triple is (AF_PACKET,
> + * SOCK_PACKET, 0).
> + */
> + [SOCK_PACKET] = {
> + .ops = _LANDLOCK_CANON_REWRITE_FAMILY |
> + _LANDLOCK_CANON_PROTOCOL_ALWAYS,
> + .new_family = AF_PACKET,
> + .new_protocol = 0,
> + },
> + },
> + /*
> + * packet_create stores the user-provided protocol in po->num
> + * (for filtering) but never writes sk_protocol, so sk_protocol
> + * stays at 0 for every AF_PACKET socket. Canonicalize rules to
> + * protocol=0 to match.
> + */
> + [AF_PACKET] = {
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_RAW] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_PACKET] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + /*
> + * AX.25 rewrites protocol=0 AND PF_AX25 to AX25_P_TEXT (0xF0)
> + * for SOCK_DGRAM and SOCK_SEQPACKET; see ax25_create in
> + * net/ax25/af_ax25.c. SOCK_RAW preserves user input.
> + */
> + [AF_AX25] = {
> + [SOCK_DGRAM] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO |
> + _LANDLOCK_CANON_PROTOCOL_FAMILY_ID,
> + .new_protocol = 0xF0, /* AX25_P_TEXT */
> + },
> + [SOCK_SEQPACKET] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO |
> + _LANDLOCK_CANON_PROTOCOL_FAMILY_ID,
> + .new_protocol = 0xF0, /* AX25_P_TEXT */
> + },
> + },
> + [AF_INET6] = {
> + [SOCK_STREAM] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO,
> + .new_protocol = IPPROTO_TCP,
> + },
> + [SOCK_DGRAM] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO,
> + .new_protocol = IPPROTO_UDP,
> + },
> + [SOCK_SEQPACKET] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO,
> + .new_protocol = IPPROTO_SCTP,
> + },
> + },
> + /*
> + * Phonet rewrites protocol=0 to PN_PROTO_PHONET for SOCK_DGRAM
> + * and PN_PROTO_PIPE for SOCK_SEQPACKET; see pn_socket_create in
> + * net/phonet/af_phonet.c.
> + */
> + [AF_PHONET] = {
> + [SOCK_DGRAM] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO,
> + .new_protocol = 1, /* PN_PROTO_PHONET */
> + },
> + [SOCK_SEQPACKET] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ZERO,
> + .new_protocol = 2, /* PN_PROTO_PIPE */
> + },
> + },
> + /*
> + * atalk_create accepts SOCK_DGRAM and SOCK_RAW but never writes
> + * sk_protocol.
> + */
> + [AF_APPLETALK] = {
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_RAW] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + /*
> + * ATM PVC and SVC go through vcc_create, which rejects
> + * SOCK_STREAM and accepts every other type in the
> + * 0..SOCK_PACKET range without writing sk_protocol.
> + */
> + [AF_ATMPVC] = {
> + [0] = _LANDLOCK_CANON_ALWAYS_ZERO, /* reserved hole */
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_RAW] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_RDM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_SEQPACKET] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_DCCP] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [7] = _LANDLOCK_CANON_ALWAYS_ZERO, /* reserved hole */
> + [8] = _LANDLOCK_CANON_ALWAYS_ZERO, /* reserved hole */
> + [9] = _LANDLOCK_CANON_ALWAYS_ZERO, /* reserved hole */
> + [SOCK_PACKET] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + [AF_ATMSVC] = {
> + [0] = _LANDLOCK_CANON_ALWAYS_ZERO, /* reserved hole */
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_RAW] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_RDM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_SEQPACKET] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_DCCP] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [7] = _LANDLOCK_CANON_ALWAYS_ZERO, /* reserved hole */
> + [8] = _LANDLOCK_CANON_ALWAYS_ZERO, /* reserved hole */
> + [9] = _LANDLOCK_CANON_ALWAYS_ZERO, /* reserved hole */
> + [SOCK_PACKET] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + /*
> + * LLC, CAN, RxRPC, IEEE 802.15.4, and QRTR all rely on
> + * sock_init_data to zero sk_protocol and never override it, so
> + * any reachable triple is canonicalized to protocol=0.
> + */
> + [AF_LLC] = {
> + [SOCK_STREAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + /*
> + * AF_CAN dispatches by protocol: can_raw and can_bcm leave
> + * sk_protocol=0, but j1939_sk_init writes sk_protocol =
> + * CAN_J1939. Use PROTOCOL_PRESERVE on SOCK_DGRAM so the J1939
> + * value survives the canonicalization while all other
> + * sub-protocols get normalized to 0. SOCK_SEQPACKET has no
> + * registered CAN sub-protocol so no entry is needed (the cell
> + * is unreachable at the kernel).
> + */
> + [AF_CAN] = {
> + [SOCK_DGRAM] = {
> + .ops = _LANDLOCK_CANON_PROTOCOL_ALWAYS |
> + _LANDLOCK_CANON_PROTOCOL_PRESERVE,
> + .new_protocol = 0,
> + .preserve_protocol =
> + 7 /* CAN_J1939 */,
> + },
> + [SOCK_RAW] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + [AF_RXRPC] = {
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + [AF_IEEE802154] = {
> + [SOCK_RAW] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + [AF_QIPCRTR] = {
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + /*
> + * pfkey_create accepts only PF_KEY_V2 for SOCK_RAW but never
> + * writes sk_protocol, so the kernel stores sk_protocol=0.
> + */
> + [AF_KEY] = {
> + [SOCK_RAW] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + /*
> + * vsock accepts protocol=0 or PF_VSOCK and leaves sk_protocol
> + * at 0 in either case, for every transport (loopback, VMCI,
> + * virtio, hyperv) because vsock_create never writes
> + * sk_protocol. Canonicalize every AF_VSOCK rule to protocol=0
> + * so both call forms match the same rule.
> + *
> + * The vsock loopback transport (the only one enabled by the
> + * default .kunitconfig) does not advertise DGRAM capability, so
> + * the SOCK_DGRAM cell is not reachable through sock_create_kern
> + * at KUnit time; DGRAM reachability requires
> + * CONFIG_VIRTIO_VSOCKETS=y. The canonicalization is
> + * nonetheless correct; a dedicated map-entry test case
> + * validates it independently of any kernel configuration.
> + */
> + [AF_VSOCK] = {
> + [SOCK_STREAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_DGRAM] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + [SOCK_SEQPACKET] = _LANDLOCK_CANON_ALWAYS_ZERO,
> + },
> + };
Some impressive code archeology here! :)
> +
> +/*
> + * landlock_canonicalize_socket_key - Apply kernel-equivalent rewrites
> + *
> + * @family: in/out protocol family.
> + * @type: in/out socket type.
> + * @protocol: in/out protocol.
> + *
> + * Transforms a (@family, @type, @protocol) triple into the form the kernel
> + * stores after the family .create() completes. Wildcards (TYPE_ALL,
> + * PROTOCOL_ALL) are preserved unchanged since they do not pin a specific
> + * triple. Out-of-range values are left for the caller (pack_socket_key) to
> + * reject.
> + */
> +static void landlock_canonicalize_socket_key(s32 *family, s32 *type,
> + s32 *protocol)
> +{
> + const struct landlock_canon_entry *entry;
> + s32 input_family;
> +
> + /*
> + * Type is the map second index, so it must be concrete. Family is the
> + * map first index; checked below via bounds.
> + */
> + if (*type == TYPE_ALL)
> + return;
> +
> + if (*family < 0 || *family >= AF_MAX || *type < 0 || *type >= SOCK_MAX)
> + return;
> +
> + entry = &landlock_canon_map[*family][*type];
> + input_family = *family;
> +
> + /*
> + * Family and type rewrites apply regardless of protocol value; a
> + * PROTOCOL_ALL rule still benefits from an alias family or type
> + * rewrite.
> + */
If I understand correctly, this remark is crucial for the correctness;
if the API allows PROTOCOL_ALL, then the rewrite results must be
independent of the protocol, so that we can still rewrite the family
and type correctly in these cases.
But if I understand correctly, if the API allows TYPE_ALL, a rule with
TYPE_ALL can *not* be canonicalized correctly in all cases, and that
would be another reason why the "type" wildcard is problematic?
It's an obscure example, but a rule could then allow (AF_INET,
TYPE_ALL, PROTOCOL_ALL). When a process now invokes socket(AF_INET,
SOCK_PACKET, 0), that invocation *looks like it should match the
rule*, but the existing socket(2) logic rewrites that socket to a
(AF_PACKET, SOCK_PACKET, 0), which does not match the rule.
Generalized to the KUnit test, I think a very general test that would
catch this would need to look a bit like the
test_family_canonicalization test, but it would also have to try the
canonicalization with the permitted wildcard combinations and see that
the resulting rule still *matches* the socket that was created.
> + if (entry->ops & _LANDLOCK_CANON_REWRITE_FAMILY)
> + *family = entry->new_family;
> + if (entry->ops & _LANDLOCK_CANON_REWRITE_TYPE)
> + *type = entry->new_type;
> +
> + /*
> + * Protocol rewrites are skipped for wildcard protocols so that a
> + * PROTOCOL_ALL rule stays wildcard even for families the kernel
> + * canonicalizes.
> + */
> + if (*protocol == PROTOCOL_ALL)
> + return;
> +
> + /*
> + * Per-protocol preservation: when the map declares that one specific
> + * user protocol survives unchanged in sk_protocol (e.g., AF_CAN +
> + * SOCK_DGRAM + CAN_J1939: j1939_sk_init writes sk_protocol = CAN_J1939,
> + * while raw_init and bcm_init leave sk_protocol = 0), skip all protocol
> + * rewrites when the user input matches that value. Keeps the runtime
> + * drift WARN silent for the exception while PROTOCOL_ALWAYS still
> + * normalizes the rest of the cell to new_protocol.
> + */
> + if ((entry->ops & _LANDLOCK_CANON_PROTOCOL_PRESERVE) &&
> + *protocol == entry->preserve_protocol)
> + return;
> +
> + if (entry->ops & _LANDLOCK_CANON_PROTOCOL_ALWAYS)
> + *protocol = entry->new_protocol;
> + else if (((entry->ops & _LANDLOCK_CANON_PROTOCOL_ZERO) &&
> + *protocol == 0) ||
> + ((entry->ops & _LANDLOCK_CANON_PROTOCOL_FAMILY_ID) &&
> + *protocol == input_family))
> + *protocol = entry->new_protocol;
> +}
> +
> static int pack_socket_key(const s32 family, const s32 type, const s32 protocol,
> uintptr_t *val)
> {
> @@ -78,12 +443,12 @@ int landlock_append_socket_rule(struct landlock_ruleset *const ruleset,
> {
> int err;
> uintptr_t key;
> +
> /*
> - * (AF_INET, SOCK_PACKET) is an alias for (AF_PACKET, SOCK_PACKET)
> - * (cf. __sock_create).
> + * Apply the kernel rewrites so that this rule matches the triple seen
> + * at hook time. See landlock_canon_map.
> */
> - if (family == AF_INET && type == SOCK_PACKET)
> - family = AF_PACKET;
> + landlock_canonicalize_socket_key(&family, &type, &protocol);
>
> err = pack_socket_key(family, type, protocol, &key);
> if (err)
> @@ -123,6 +488,12 @@ static int check_socket_access(const struct landlock_ruleset *dom,
> return -EACCES;
> }
>
> +/*
> + * Enforcement happens at security_socket_create (pre-create) so Landlock denies
> + * unauthorized triples before the kernel loads any family-specific module or
> + * allocates a socket. This preserves the EACCES error path even for triples
> + * the kernel itself would reject (AF_UNSPEC, invalid family and type pairs).
> + */
> static int hook_socket_create(int family, int type, int protocol, int kern)
> {
> layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_SOCKET] = {};
> @@ -133,45 +504,52 @@ static int hook_socket_create(int family, int type, int protocol, int kern)
> const struct landlock_cred_security *const subject =
> landlock_get_applicable_subject(current_cred(), masks, NULL);
> uintptr_t key;
> + s32 canon_family = family, canon_type = type, canon_protocol = protocol;
> struct lsm_socket_audit audit_socket = {
> .family = family,
> .type = type,
> .protocol = protocol,
> };
>
> - if (!subject)
> - return 0;
> - /* Checks only user space sockets. */
> + /* Kernel-internal sockets bypass (accept, sock_create_lite, ...). */
> if (kern)
> return 0;
> + if (!subject)
> + return 0;
> +
> + /* Canonicalize the user-facing triple to match the rule storage. */
> + landlock_canonicalize_socket_key(&canon_family, &canon_type,
> + &canon_protocol);
>
> handled_access = landlock_init_layer_masks(
> subject->domain, LANDLOCK_ACCESS_SOCKET_CREATE, &layer_masks,
> LANDLOCK_KEY_SOCKET);
> +
> /*
> - * Error could happen due to parameters are outside of the allowed range,
> - * so this combination couldn't be added in ruleset previously.
> - * Therefore, it's not permitted.
> + * Four-way wildcard grid lookup. Each pack_socket_key call is gated on
> + * its return value so a rejected triple does not feed an uninitialized
> + * key into check_socket_access.
> */
> - if (pack_socket_key(family, type, protocol, &key) == -EACCES)
> - return -EACCES;
> - if (check_socket_access(subject->domain, key, &layer_masks,
> + if (pack_socket_key(canon_family, canon_type, canon_protocol, &key) ==
> + 0 &&
> + check_socket_access(subject->domain, key, &layer_masks,
> handled_access) == 0)
> return 0;
>
> - /* Ranges were already checked. */
> - (void)pack_socket_key(family, TYPE_ALL, protocol, &key);
> - if (check_socket_access(subject->domain, key, &layer_masks,
> + if (pack_socket_key(canon_family, TYPE_ALL, canon_protocol, &key) ==
> + 0 &&
> + check_socket_access(subject->domain, key, &layer_masks,
> handled_access) == 0)
> return 0;
>
> - (void)pack_socket_key(family, type, PROTOCOL_ALL, &key);
> - if (check_socket_access(subject->domain, key, &layer_masks,
> + if (pack_socket_key(canon_family, canon_type, PROTOCOL_ALL, &key) ==
> + 0 &&
> + check_socket_access(subject->domain, key, &layer_masks,
> handled_access) == 0)
> return 0;
>
> - (void)pack_socket_key(family, TYPE_ALL, PROTOCOL_ALL, &key);
> - if (check_socket_access(subject->domain, key, &layer_masks,
> + if (pack_socket_key(canon_family, TYPE_ALL, PROTOCOL_ALL, &key) == 0 &&
> + check_socket_access(subject->domain, key, &layer_masks,
> handled_access) == 0)
> return 0;
>
> @@ -187,8 +565,64 @@ static int hook_socket_create(int family, int type, int protocol, int kern)
> return -EACCES;
> }
>
> +/*
> + * Runtime drift detection: at post_create the family .create() has completed,
> + * so sk_family, sock->type and sk_protocol are authoritative. Compare them
> + * against what landlock_canonicalize_socket_key produces from the user input; a
> + * mismatch means a kernel canonicalization is not mirrored in
> + * landlock_canon_map. Enforcement already happened at socket_create, so this
> + * hook always returns 0.
> + *
> + * This hook only runs for tasks sandboxed by a Landlock domain that handles
> + * LANDLOCK_ACCESS_SOCKET_CREATE, so non-sandboxed tasks pay no overhead.
> + * Sandboxed tasks still cover enough of the reachable (family, type, protocol)
> + * space over the lifetime of a typical workload to surface drift in the field.
> + */
> +static int hook_socket_post_create(struct socket *sock, int family, int type,
> + int protocol, int kern)
> +{
> + const struct access_masks masks = {
> + .socket = LANDLOCK_ACCESS_SOCKET_CREATE,
> + };
> + s32 canon_family = family, canon_type = type, canon_protocol = protocol;
> +
> + if (kern)
> + return 0;
> + if (!landlock_get_applicable_subject(current_cred(), masks, NULL))
> + return 0;
> +
> + /*
> + * Kernel-resolved values are authoritative; no fallback to the user
> + * protocol argument. Families that ignore the user protocol (e.g.,
> + * AF_UNIX, AF_VSOCK) are represented in landlock_canon_map with
> + * PROTOCOL_ALWAYS so the canonicalization below yields the same value
> + * for both rule insertion and this comparison.
> + *
> + * Drift is reported per field so a reviewer knows which axis disagrees
> + * with the kernel without having to diff three values. WARN_ONCE
> + * rather than WARN_ON_ONCE keeps the stack trace but swallows
> + * subsequent identical drifts in the same boot.
> + */
> + landlock_canonicalize_socket_key(&canon_family, &canon_type,
> + &canon_protocol);
> + WARN_ONCE(
> + canon_family != sock->sk->sk_family,
> + "Landlock canon family drift: canon=%d kernel=%d (user family=%d type=%d protocol=%d)\n",
> + canon_family, sock->sk->sk_family, family, type, protocol);
> + WARN_ONCE(
> + canon_type != sock->type,
> + "Landlock canon type drift: canon=%d kernel=%d (user family=%d type=%d protocol=%d)\n",
> + canon_type, sock->type, family, type, protocol);
> + WARN_ONCE(
> + canon_protocol != sock->sk->sk_protocol,
> + "Landlock canon protocol drift: canon=%d kernel=%d (user family=%d type=%d protocol=%d)\n",
> + canon_protocol, sock->sk->sk_protocol, family, type, protocol);
> + return 0;
> +}
> +
> static struct security_hook_list landlock_hooks[] __ro_after_init = {
> LSM_HOOK_INIT(socket_create, hook_socket_create),
> + LSM_HOOK_INIT(socket_post_create, hook_socket_post_create),
> };
>
> __init void landlock_add_socket_hooks(void)
> @@ -196,3 +630,398 @@ __init void landlock_add_socket_hooks(void)
> security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
> &landlock_lsmid);
> }
> +
> +#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
> +
> +#include <kunit/test.h>
> +#include <net/net_namespace.h>
> +
> +/*
> + * Per-family parameterized coverage test. One subtest per AF_*; each subtest
> + * iterates every (type, protocol) probe through sock_create_kern and checks
> + * either that landlock_canonicalize_socket_key matches the kernel-resolved
> + * triple (for reachable families) or that the call fails with the expected
> + * errno (for unsupported families). No subtest is skipped: every family
> + * produces PASS or FAIL, so an unsupported entry that quietly becomes stale is
> + * caught immediately.
> + *
> + * Every unsupported family entry expects sock_create_kern to fail with
> + * -EAFNOSUPPORT because no handler is registered for that family in the KUnit
> + * build environment (either the family was never implemented, was removed from
> + * Linux, is a reserved pseudo family, or requires an arch or CONFIG not
> + * satisfied by .kunitconfig). The family name in the TAP subtest header,
> + * combined with this errno, identifies the case unambiguously.
> + */
> +struct landlock_canon_family_case {
> + int af;
> + const char *name;
> + /*
> + * True means the family must be supported in the KUnit environment and
> + * canonicalization is exercised against the kernel. False means every
> + * probe must fail with -EAFNOSUPPORT.
> + */
> + bool supported;
> +};
> +
> +#define _LANDLOCK_AF_SUPPORTED(f) \
> + { \
> + .af = (f), .name = #f, .supported = true, \
> + }
> +
> +#define _LANDLOCK_AF_UNSUPPORTED(f) \
> + { \
> + .af = (f), .name = #f, .supported = false, \
> + }
> +
> +static const struct landlock_canon_family_case landlock_canon_families[] = {
> + /* kernel rejects socket(AF_UNSPEC) */
> + _LANDLOCK_AF_UNSUPPORTED(AF_UNSPEC),
> + _LANDLOCK_AF_SUPPORTED(AF_UNIX),
> + _LANDLOCK_AF_SUPPORTED(AF_INET),
> + _LANDLOCK_AF_SUPPORTED(AF_AX25),
> + /* AF_IPX removed from Linux */
> + _LANDLOCK_AF_UNSUPPORTED(AF_IPX),
> + _LANDLOCK_AF_SUPPORTED(AF_APPLETALK),
> + _LANDLOCK_AF_SUPPORTED(AF_NETROM),
> + /* AF_BRIDGE cannot be used to create sockets */
> + _LANDLOCK_AF_UNSUPPORTED(AF_BRIDGE),
> + _LANDLOCK_AF_SUPPORTED(AF_ATMPVC),
> + _LANDLOCK_AF_SUPPORTED(AF_X25),
> + _LANDLOCK_AF_SUPPORTED(AF_INET6),
> + _LANDLOCK_AF_SUPPORTED(AF_ROSE),
> + /* AF_DECnet removed from Linux */
> + _LANDLOCK_AF_UNSUPPORTED(AF_DECnet),
> + /* AF_NETBEUI not implemented */
> + _LANDLOCK_AF_UNSUPPORTED(AF_NETBEUI),
> + /* AF_SECURITY is a pseudo family */
> + _LANDLOCK_AF_UNSUPPORTED(AF_SECURITY),
> + _LANDLOCK_AF_SUPPORTED(AF_KEY),
> + _LANDLOCK_AF_SUPPORTED(AF_NETLINK),
> + _LANDLOCK_AF_SUPPORTED(AF_PACKET),
> + /* AF_ASH not implemented */
> + _LANDLOCK_AF_UNSUPPORTED(AF_ASH),
> + /* AF_ECONET removed from Linux */
> + _LANDLOCK_AF_UNSUPPORTED(AF_ECONET),
> + _LANDLOCK_AF_SUPPORTED(AF_ATMSVC),
> + _LANDLOCK_AF_SUPPORTED(AF_RDS),
> + /* AF_SNA not implemented */
> + _LANDLOCK_AF_UNSUPPORTED(AF_SNA),
> + /* AF_IRDA removed from Linux */
> + _LANDLOCK_AF_UNSUPPORTED(AF_IRDA),
> + _LANDLOCK_AF_SUPPORTED(AF_PPPOX),
> + /* AF_WANPIPE not implemented */
> + _LANDLOCK_AF_UNSUPPORTED(AF_WANPIPE),
> + _LANDLOCK_AF_SUPPORTED(AF_LLC),
> + /* AF_IB reserved by infiniband */
> + _LANDLOCK_AF_UNSUPPORTED(AF_IB),
> + /* AF_MPLS cannot be used to create sockets */
> + _LANDLOCK_AF_UNSUPPORTED(AF_MPLS),
> + _LANDLOCK_AF_SUPPORTED(AF_CAN),
> + _LANDLOCK_AF_SUPPORTED(AF_TIPC),
> + _LANDLOCK_AF_SUPPORTED(AF_BLUETOOTH),
> + /* AF_IUCV only on s390 */
> + _LANDLOCK_AF_UNSUPPORTED(AF_IUCV),
> + _LANDLOCK_AF_SUPPORTED(AF_RXRPC),
> + _LANDLOCK_AF_SUPPORTED(AF_ISDN),
> + _LANDLOCK_AF_SUPPORTED(AF_PHONET),
> + _LANDLOCK_AF_SUPPORTED(AF_IEEE802154),
> + _LANDLOCK_AF_SUPPORTED(AF_CAIF),
> + _LANDLOCK_AF_SUPPORTED(AF_ALG),
> + _LANDLOCK_AF_SUPPORTED(AF_NFC),
> + _LANDLOCK_AF_SUPPORTED(AF_VSOCK),
> + /* AF_KCM requires a kcm multiplexer setup */
> + _LANDLOCK_AF_UNSUPPORTED(AF_KCM),
> + _LANDLOCK_AF_SUPPORTED(AF_QIPCRTR),
> + _LANDLOCK_AF_SUPPORTED(AF_SMC),
> + /* AF_XDP requires a netdev with XDP support */
> + _LANDLOCK_AF_UNSUPPORTED(AF_XDP),
> + _LANDLOCK_AF_SUPPORTED(AF_MCTP),
> +};
> +
> +static_assert(ARRAY_SIZE(landlock_canon_families) == AF_MAX,
> + "landlock_canon_families size must track AF_MAX.");
> +
> +static void
> +landlock_canon_family_to_desc(const struct landlock_canon_family_case *c,
> + char *desc)
> +{
> + strscpy(desc, c->name, KUNIT_PARAM_DESC_SIZE);
> +}
> +
> +KUNIT_ARRAY_PARAM(landlock_canon_family, landlock_canon_families,
> + landlock_canon_family_to_desc);
> +
> +/*
> + * Edge protocol sentinels beyond the 0..NPROTO range exercised by the main
> + * sweep. IPPROTO_SCTP is the only value in landlock_canon_map above NPROTO
> + * today; 255 = IPPROTO_RAW covers the top of the IP protocol byte; 0xFFFF = u16
> + * upper bound covers the ethertype-wide range accepted by AF_PACKET and
> + * saturates pack_socket_key's u16 field.
> + */
> +static const int landlock_edge_protocols[] = {
> + IPPROTO_SCTP,
> + 255 /* IPPROTO_RAW */,
> + 0xFFFF /* u16 max */,
> +};
> +
> +/*
> + * Return the protocol value for probe index @p: indices 0..NPROTO cover every
> + * family-ID range (and NPROTO itself, one past the last valid PF_*, exercises
> + * an out-of-range probe); subsequent indices draw from landlock_edge_protocols.
> + * Returns -1 when the iteration is exhausted.
> + */
> +static int landlock_probe_protocol(size_t p)
> +{
> + if (p <= NPROTO)
> + return (int)p;
> + if (p - (NPROTO + 1) < ARRAY_SIZE(landlock_edge_protocols))
> + return landlock_edge_protocols[p - (NPROTO + 1)];
> + return -1;
> +}
> +
> +static void test_family_canonicalization(struct kunit *const test)
> +{
> + const struct landlock_canon_family_case *const c = test->param_value;
> + unsigned int tested = 0, canonicalized = 0, confirmed_unsupported = 0;
> + int type;
> + size_t probe;
> +
> + for (type = 0; type < SOCK_MAX; type++) {
> + for (probe = 0;; probe++) {
> + const int protocol = landlock_probe_protocol(probe);
> + struct socket *sock = NULL;
> + int ret, kernel_family, kernel_type, kernel_protocol;
> + s32 landlock_family, landlock_type, landlock_protocol;
> +
> + if (protocol < 0)
> + break;
> +
> + ret = sock_create_kern(&init_net, c->af, type, protocol,
> + &sock);
> +
> + if (ret == 0) {
> + /*
> + * Reached the kernel: fully verify Landlock
> + * canonicalization against the resolved
> + * sk_family / sock->type / sk_protocol triple.
> + * This path runs whether or not the family is
> + * listed as unsupported: if an extra CONFIG_*
> + * turns an unsupported family entry reachable,
> + * the test picks it up naturally.
> + */
> + kernel_family = sock->sk->sk_family;
> + kernel_type = sock->type;
> + kernel_protocol = sock->sk->sk_protocol;
> + sock_release(sock);
> +
> + landlock_family = c->af;
> + landlock_type = type;
> + landlock_protocol = protocol;
> + landlock_canonicalize_socket_key(
> + &landlock_family, &landlock_type,
> + &landlock_protocol);
> +
> + /* Drift axis identified by the failing macro
> + * line; KUNIT_EXPECT_EQ_MSG already prints
> + * expected vs actual values. The format
> + * "(F,T,P)" carries the user input that
> + * triggered the mismatch.
> + */
> + KUNIT_EXPECT_EQ_MSG(test, landlock_family,
> + kernel_family,
> + "family (%d,%d,%d)", c->af,
> + type, protocol);
> + KUNIT_EXPECT_EQ_MSG(test, landlock_type,
> + kernel_type,
> + "type (%d,%d,%d)", c->af,
> + type, protocol);
> + KUNIT_EXPECT_EQ_MSG(test, landlock_protocol,
> + kernel_protocol,
> + "protocol (%d,%d,%d)",
> + c->af, type, protocol);
> +
> + tested++;
> + if (landlock_family != c->af ||
> + landlock_type != type ||
> + landlock_protocol != protocol)
> + canonicalized++;
> + } else if (ret == -EAFNOSUPPORT && !c->supported) {
> + /*
> + * Ignore this specific combination when the
> + * kernel says the family is not registered AND
> + * the family is on the unsupported list.
> + * Rationale: the unsupported flag declares "we
> + * expect no kernel handler for this family in
> + * the KUnit build". If extra CONFIG_* entries
> + * are added later (e.g. via --kconfig_add or a
> + * per-arch config layer), an unsupported family
> + * entry may start returning ret == 0 for some
> + * probes; those fall into the branch above and
> + * are fully tested. No per-arch .kunitconfig
> + * fragmentation is required.
> + *
> + * Other negative errno values (e.g.,
> + * -EPROTONOSUPPORT, -ESOCKTNOSUPPORT,
> + * -EPROTOTYPE) indicate that this specific
> + * (type, protocol) triple is not supported by
> + * an otherwise-loaded family; silently skip the
> + * probe in that case too.
> + */
> + confirmed_unsupported++;
> + }
> + /*
> + * All other non-zero returns are silently skipped: the
> + * kernel rejected the specific triple; nothing to
> + * canonicalize.
> + */
> + }
> + }
> +
> + if (!c->supported) {
> + kunit_info(test,
> + "%u probes confirmed %s unsupported (errno %d)",
> + confirmed_unsupported, c->name, -EAFNOSUPPORT);
> + return;
> + }
> + if (tested == 0) {
> + /*
> + * Resolve by either (a) adding a sub-protocol CONFIG to
> + * .kunitconfig so sock_create_kern can reach the family, or (b)
> + * flipping the family entry's .supported field to false to
> + * declare it expected-unreachable.
> + */
> + KUNIT_FAIL(test, "%s: no reachable triple", c->name);
> + return;
> + }
> + kunit_info(test, "%u reachable triples (%u canonicalized)", tested,
> + canonicalized);
> +}
> +
> +/*
> + * Wildcards bypass canonicalization: the input triple is returned unchanged for
> + * TYPE_ALL, and protocol rewrites are skipped for PROTOCOL_ALL while family and
> + * type rewrites still apply.
> + */
> +static void test_canonicalization_preserves_wildcards(struct kunit *const test)
> +{
> + s32 family, type, protocol;
> +
> + /* Type wildcard: no map lookup. */
> + family = AF_INET;
> + type = TYPE_ALL;
> + protocol = 0;
> + landlock_canonicalize_socket_key(&family, &type, &protocol);
> + KUNIT_EXPECT_EQ(test, family, AF_INET);
> + KUNIT_EXPECT_EQ(test, type, TYPE_ALL);
> + KUNIT_EXPECT_EQ(test, protocol, 0);
This is btw the same example as the one I mentioned above; When you
call socket(AF_INET, SOCK_PACKET, 0), the resulting socket turns into
a (AF_PACKET, SOCK_PACKET, 0) and it does not match the canonicalized
(AF_INET, TYPE_ALL, 0) rule any more.
> +
> + /* Protocol wildcard with REWRITE_FAMILY row: family still rewrites. */
> + family = AF_INET;
> + type = SOCK_PACKET;
> + protocol = PROTOCOL_ALL;
> + landlock_canonicalize_socket_key(&family, &type, &protocol);
> + KUNIT_EXPECT_EQ(test, family, AF_PACKET);
> + KUNIT_EXPECT_EQ(test, type, SOCK_PACKET);
> + KUNIT_EXPECT_EQ(test, protocol, PROTOCOL_ALL);
> +
> + /* Protocol wildcard with PROTOCOL_ZERO row: protocol stays wildcard. */
> + family = AF_INET;
> + type = SOCK_STREAM;
> + protocol = PROTOCOL_ALL;
> + landlock_canonicalize_socket_key(&family, &type, &protocol);
> + KUNIT_EXPECT_EQ(test, family, AF_INET);
> + KUNIT_EXPECT_EQ(test, type, SOCK_STREAM);
> + KUNIT_EXPECT_EQ(test, protocol, PROTOCOL_ALL);
> +
> + /*
> + * Protocol wildcard with PROTOCOL_ALWAYS row: protocol stays wildcard
> + * even though the entry would unconditionally rewrite concrete protocol
> + * values.
> + */
> + family = AF_UNIX;
> + type = SOCK_STREAM;
> + protocol = PROTOCOL_ALL;
> + landlock_canonicalize_socket_key(&family, &type, &protocol);
> + KUNIT_EXPECT_EQ(test, family, AF_UNIX);
> + KUNIT_EXPECT_EQ(test, type, SOCK_STREAM);
> + KUNIT_EXPECT_EQ(test, protocol, PROTOCOL_ALL);
> +
> + /*
> + * REWRITE_TYPE with PROTOCOL_ALL still folds the type while leaving the
> + * protocol wildcard intact.
> + */
> + family = AF_UNIX;
> + type = SOCK_RAW;
> + protocol = PROTOCOL_ALL;
> + landlock_canonicalize_socket_key(&family, &type, &protocol);
> + KUNIT_EXPECT_EQ(test, family, AF_UNIX);
> + KUNIT_EXPECT_EQ(test, type, SOCK_DGRAM);
> + KUNIT_EXPECT_EQ(test, protocol, PROTOCOL_ALL);
> +}
> +
> +/*
> + * Each map entry produces the expected rewrite for a concrete triple.
> + * Parameterized for per-entry pass/fail visibility; semantic descriptors name
> + * what each entry is supposed to do.
> + */
> +struct landlock_canon_map_case {
> + const char *name;
> + s32 in_family, in_type, in_protocol;
> + s32 out_family, out_type, out_protocol;
> +};
> +
> +/*
> + * test_family_canonicalization covers every (family, type, protocol) cell that
> + * sock_create_kern can reach. The cases listed here are the kernel-unreachable
> + * cells whose canonicalization still matters in production and therefore needs
> + * config-independent validation.
> + *
> + * AF_VSOCK SOCK_DGRAM is the only such cell today: its reachability requires
> + * CONFIG_VIRTIO_VSOCKETS=y, which the default .kunitconfig does not enable.
> + * The two entries below cover both user call forms (protocol=0 and
> + * protocol=PF_VSOCK) that vsock_create accepts and canonicalize to 0.
> + */
> +static const struct landlock_canon_map_case landlock_canon_map_cases[] = {
> + { "vsock_dgram_zero_stays_zero", AF_VSOCK, SOCK_DGRAM, 0, AF_VSOCK,
> + SOCK_DGRAM, 0 },
> + { "vsock_dgram_family_id_forced_to_zero", AF_VSOCK, SOCK_DGRAM,
> + AF_VSOCK, AF_VSOCK, SOCK_DGRAM, 0 },
> +};
> +
> +static void landlock_canon_map_to_desc(const struct landlock_canon_map_case *c,
> + char *desc)
> +{
> + strscpy(desc, c->name, KUNIT_PARAM_DESC_SIZE);
> +}
> +
> +KUNIT_ARRAY_PARAM(landlock_canon_map, landlock_canon_map_cases,
> + landlock_canon_map_to_desc);
> +
> +static void test_canonicalization_map_entry(struct kunit *const test)
> +{
> + const struct landlock_canon_map_case *const c = test->param_value;
> + s32 family = c->in_family, type = c->in_type, protocol = c->in_protocol;
> +
> + landlock_canonicalize_socket_key(&family, &type, &protocol);
> + KUNIT_EXPECT_EQ(test, family, c->out_family);
> + KUNIT_EXPECT_EQ(test, type, c->out_type);
> + KUNIT_EXPECT_EQ(test, protocol, c->out_protocol);
> +}
> +
> +static struct kunit_case test_cases[] = {
> + KUNIT_CASE_PARAM(test_family_canonicalization,
> + landlock_canon_family_gen_params),
> + KUNIT_CASE(test_canonicalization_preserves_wildcards),
> + KUNIT_CASE_PARAM(test_canonicalization_map_entry,
> + landlock_canon_map_gen_params),
> + {}
> +};
> +
> +static struct kunit_suite test_suite = {
> + .name = "landlock_socket",
> + .test_cases = test_cases,
> +};
> +
> +kunit_test_suite(test_suite);
> +
> +#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
> diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c
> index a091b8a883c8..5c0959f50ba2 100644
> --- a/tools/testing/selftests/landlock/socket_test.c
> +++ b/tools/testing/selftests/landlock/socket_test.c
> @@ -7,15 +7,15 @@
>
> #define _GNU_SOURCE
>
> +#include <arpa/inet.h>
> +#include <linux/can.h>
> +#include <linux/kcm.h>
> #include <linux/landlock.h>
> -#include <sys/prctl.h>
> #include <linux/pfkeyv2.h>
> -#include <linux/kcm.h>
> -#include <linux/can.h>
> -#include <sys/socket.h>
> -#include <stdint.h>
> #include <linux/sctp.h>
> -#include <arpa/inet.h>
> +#include <stdint.h>
> +#include <sys/prctl.h>
> +#include <sys/socket.h>
>
> #include "audit.h"
> #include "common.h"
> @@ -829,11 +829,12 @@ FIXTURE_VARIANT_ADD(tcp_protocol, variant2) {
> };
>
> /*
> - * Landlock doesn't perform protocol mappings handled by network stack on
> - * protocol family level. Test verifies that if only one definition is
> - * allowed another becomes restricted.
> + * Landlock canonicalizes AF_INET, SOCK_STREAM, protocol=0 to IPPROTO_TCP at
> + * rule insertion so that a rule inserted with either the default-protocol form
> + * or the explicit IPPROTO_TCP form matches both call syntaxes. Test verifies
> + * this aliasing. Unrelated families (AF_PACKET here) remain restricted.
> */
> -TEST_F(tcp_protocol, alias_restriction)
> +TEST_F(tcp_protocol, alias_equivalence)
> {
> const struct landlock_ruleset_attr ruleset_attr = {
> .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE,
> @@ -861,14 +862,15 @@ TEST_F(tcp_protocol, alias_restriction)
> enforce_ruleset(_metadata, ruleset_fd);
> ASSERT_EQ(0, close(ruleset_fd));
>
> - if (protocol == 0) {
> - EXPECT_EQ(0, test_socket(AF_INET, SOCK_STREAM, 0));
> - EXPECT_EQ(EACCES,
> - test_socket(AF_PACKET, SOCK_STREAM, IPPROTO_TCP));
> - } else if (protocol == IPPROTO_TCP) {
> - EXPECT_EQ(EACCES, test_socket(AF_INET, SOCK_STREAM, 0));
> - EXPECT_EQ(0, test_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
> - }
> + /*
> + * Irrespective of which call form was used to insert the rule, both
> + * call forms of socket(2) match.
> + */
> + EXPECT_EQ(0, test_socket(AF_INET, SOCK_STREAM, 0));
> + EXPECT_EQ(0, test_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
> +
> + /* Other families remain restricted. */
> + EXPECT_EQ(EACCES, test_socket(AF_PACKET, SOCK_STREAM, IPPROTO_TCP));
> }
>
> static int test_socketpair(int family, int type, int protocol)
> --
> 2.53.0
>
–Günther
^ permalink raw reply
* Re: [PATCH v3] keys/trusted_keys: move TPM-specific fields into trusted_tpm_options
From: Jarkko Sakkinen @ 2026-05-22 12:41 UTC (permalink / raw)
To: Srish Srinivasan
Cc: linux-integrity, keyrings, James.Bottomley, stefanb, zohar, nayna,
rnsastry, linux-kernel, linux-security-module
In-Reply-To: <20260522081637.189546-1-ssrish@linux.ibm.com>
On Fri, May 22, 2026 at 01:46:37PM +0530, Srish Srinivasan wrote:
> The trusted_key_options struct contains TPM-specific fields (keyhandle,
> keyauth, blobauth_len, blobauth, pcrinfo_len, pcrinfo, pcrlock, hash,
> policydigest_len, policydigest, and policyhandle). This leads to the
> accumulation of backend-specific fields in the generic options structure.
>
> Define a trusted_tpm_options structure and move the TPM-specific fields
> there. Store a pointer to trusted_tpm_options in trusted_key_options's
> private.
>
> No functional change intended.
>
> Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> ---
I'm supporting this change yes but before spreading tpm_buf all over the
place I'd like to get this merged:
https://lore.kernel.org/linux-integrity/20260522013555.1063716-1-jarkko@kernel.org/T/#u
It'd need tested-by's most importantly. There's another patch shoe-horning
buffers a bit upgrading tpm_buf so I thought now would be good tiem to
get this finally applied.
Possible merge conflicts for +1 change of this should be fairly trivial.
BR, Jarkko
> This patch depends on 9ec4175a30eb ("KEYS: trusted: Debugging as a
> feature"), which is in linux-tpmdd/master but not yet in mainline.
>
> Please apply on top of linux-tpmdd/master.
>
> base-commit: 67657fb65aa9f2d7dd46235246b1677792bd103e
>
> Changelog:
> v3:
> - Exclude the preparatory clean up patch as the problem has been addressed
> in commit 9ec4175a30eb ("KEYS: trusted: Debugging as a feature")
>
> v2:
> - Exclude the bug-fix patch as it has already been applied to 6.19-rc7
> - Rename instances of trusted_tpm_options from tpm_opts to private
> - Use pr_debug and KERN_DEBUG for logging debug messages (preparatory clean
> up patch)
> - Address other minor comments from Jarkko
>
> include/keys/trusted-type.h | 11 ---
> include/keys/trusted_tpm.h | 14 ++++
> security/keys/trusted-keys/trusted_tpm1.c | 95 ++++++++++++++---------
> security/keys/trusted-keys/trusted_tpm2.c | 51 ++++++------
> 4 files changed, 102 insertions(+), 69 deletions(-)
>
> diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
> index 9f9940482da4..3db61b57cf73 100644
> --- a/include/keys/trusted-type.h
> +++ b/include/keys/trusted-type.h
> @@ -39,17 +39,6 @@ struct trusted_key_payload {
>
> struct trusted_key_options {
> uint16_t keytype;
> - uint32_t keyhandle;
> - unsigned char keyauth[TPM_DIGEST_SIZE];
> - uint32_t blobauth_len;
> - unsigned char blobauth[TPM_DIGEST_SIZE];
> - uint32_t pcrinfo_len;
> - unsigned char pcrinfo[MAX_PCRINFO_SIZE];
> - int pcrlock;
> - uint32_t hash;
> - uint32_t policydigest_len;
> - unsigned char policydigest[MAX_DIGEST_SIZE];
> - uint32_t policyhandle;
> void *private;
> };
>
> diff --git a/include/keys/trusted_tpm.h b/include/keys/trusted_tpm.h
> index 0fadc6a4f166..355ebd36cbfd 100644
> --- a/include/keys/trusted_tpm.h
> +++ b/include/keys/trusted_tpm.h
> @@ -7,6 +7,20 @@
>
> extern struct trusted_key_ops trusted_key_tpm_ops;
>
> +struct trusted_tpm_options {
> + uint32_t keyhandle;
> + unsigned char keyauth[TPM_DIGEST_SIZE];
> + uint32_t blobauth_len;
> + unsigned char blobauth[TPM_DIGEST_SIZE];
> + uint32_t pcrinfo_len;
> + unsigned char pcrinfo[MAX_PCRINFO_SIZE];
> + int pcrlock;
> + uint32_t hash;
> + uint32_t policydigest_len;
> + unsigned char policydigest[MAX_DIGEST_SIZE];
> + uint32_t policyhandle;
> +};
> +
> int tpm2_seal_trusted(struct tpm_chip *chip,
> struct trusted_key_payload *payload,
> struct trusted_key_options *options);
> diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
> index 13513819991e..21360a41d290 100644
> --- a/security/keys/trusted-keys/trusted_tpm1.c
> +++ b/security/keys/trusted-keys/trusted_tpm1.c
> @@ -49,15 +49,17 @@ enum {
> #ifdef CONFIG_TRUSTED_KEYS_DEBUG
> static inline void dump_options(struct trusted_key_options *o)
> {
> + struct trusted_tpm_options *private = o->private;
> +
> if (!trusted_debug)
> return;
>
> pr_debug("sealing key type %d\n", o->keytype);
> - pr_debug("sealing key handle %0X\n", o->keyhandle);
> - pr_debug("pcrlock %d\n", o->pcrlock);
> - pr_debug("pcrinfo %d\n", o->pcrinfo_len);
> + pr_debug("sealing key handle %0X\n", private->keyhandle);
> + pr_debug("pcrlock %d\n", private->pcrlock);
> + pr_debug("pcrinfo %d\n", private->pcrinfo_len);
> print_hex_dump_debug("pcrinfo ", DUMP_PREFIX_NONE,
> - 16, 1, o->pcrinfo, o->pcrinfo_len, 0);
> + 16, 1, private->pcrinfo, private->pcrinfo_len, 0);
> }
>
> static inline void dump_sess(struct osapsess *s)
> @@ -631,6 +633,7 @@ static int tpm_unseal(struct tpm_buf *tb,
> static int key_seal(struct trusted_key_payload *p,
> struct trusted_key_options *o)
> {
> + struct trusted_tpm_options *private = o->private;
> struct tpm_buf tb;
> int ret;
>
> @@ -641,9 +644,10 @@ static int key_seal(struct trusted_key_payload *p,
> /* include migratable flag at end of sealed key */
> p->key[p->key_len] = p->migratable;
>
> - ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
> + ret = tpm_seal(&tb, o->keytype, private->keyhandle, private->keyauth,
> p->key, p->key_len + 1, p->blob, &p->blob_len,
> - o->blobauth, o->pcrinfo, o->pcrinfo_len);
> + private->blobauth, private->pcrinfo,
> + private->pcrinfo_len);
> if (ret < 0)
> pr_info("srkseal failed (%d)\n", ret);
>
> @@ -657,6 +661,7 @@ static int key_seal(struct trusted_key_payload *p,
> static int key_unseal(struct trusted_key_payload *p,
> struct trusted_key_options *o)
> {
> + struct trusted_tpm_options *private = o->private;
> struct tpm_buf tb;
> int ret;
>
> @@ -664,8 +669,8 @@ static int key_unseal(struct trusted_key_payload *p,
> if (ret)
> return ret;
>
> - ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
> - o->blobauth, p->key, &p->key_len);
> + ret = tpm_unseal(&tb, private->keyhandle, private->keyauth, p->blob,
> + p->blob_len, private->blobauth, p->key, &p->key_len);
> if (ret < 0)
> pr_info("srkunseal failed (%d)\n", ret);
> else
> @@ -702,6 +707,7 @@ static const match_table_t key_tokens = {
> static int getoptions(char *c, struct trusted_key_payload *pay,
> struct trusted_key_options *opt)
> {
> + struct trusted_tpm_options *private = opt->private;
> substring_t args[MAX_OPT_ARGS];
> char *p = c;
> int token;
> @@ -717,7 +723,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
> if (tpm2 < 0)
> return tpm2;
>
> - opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
> + private->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
>
> if (!c)
> return 0;
> @@ -731,11 +737,11 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
>
> switch (token) {
> case Opt_pcrinfo:
> - opt->pcrinfo_len = strlen(args[0].from) / 2;
> - if (opt->pcrinfo_len > MAX_PCRINFO_SIZE)
> + private->pcrinfo_len = strlen(args[0].from) / 2;
> + if (private->pcrinfo_len > MAX_PCRINFO_SIZE)
> return -EINVAL;
> - res = hex2bin(opt->pcrinfo, args[0].from,
> - opt->pcrinfo_len);
> + res = hex2bin(private->pcrinfo, args[0].from,
> + private->pcrinfo_len);
> if (res < 0)
> return -EINVAL;
> break;
> @@ -744,12 +750,12 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
> if (res < 0)
> return -EINVAL;
> opt->keytype = SEAL_keytype;
> - opt->keyhandle = handle;
> + private->keyhandle = handle;
> break;
> case Opt_keyauth:
> if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
> return -EINVAL;
> - res = hex2bin(opt->keyauth, args[0].from,
> + res = hex2bin(private->keyauth, args[0].from,
> SHA1_DIGEST_SIZE);
> if (res < 0)
> return -EINVAL;
> @@ -760,21 +766,23 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
> * hex strings. TPM 2.0 authorizations are simple
> * passwords (although it can take a hash as well)
> */
> - opt->blobauth_len = strlen(args[0].from);
> + private->blobauth_len = strlen(args[0].from);
>
> - if (opt->blobauth_len == 2 * TPM_DIGEST_SIZE) {
> - res = hex2bin(opt->blobauth, args[0].from,
> + if (private->blobauth_len == 2 * TPM_DIGEST_SIZE) {
> + res = hex2bin(private->blobauth, args[0].from,
> TPM_DIGEST_SIZE);
> if (res < 0)
> return -EINVAL;
>
> - opt->blobauth_len = TPM_DIGEST_SIZE;
> + private->blobauth_len = TPM_DIGEST_SIZE;
> break;
> }
>
> - if (tpm2 && opt->blobauth_len <= sizeof(opt->blobauth)) {
> - memcpy(opt->blobauth, args[0].from,
> - opt->blobauth_len);
> + if (tpm2 &&
> + private->blobauth_len <=
> + sizeof(private->blobauth)) {
> + memcpy(private->blobauth, args[0].from,
> + private->blobauth_len);
> break;
> }
>
> @@ -792,14 +800,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
> res = kstrtoul(args[0].from, 10, &lock);
> if (res < 0)
> return -EINVAL;
> - opt->pcrlock = lock;
> + private->pcrlock = lock;
> break;
> case Opt_hash:
> if (test_bit(Opt_policydigest, &token_mask))
> return -EINVAL;
> for (i = 0; i < HASH_ALGO__LAST; i++) {
> if (!strcmp(args[0].from, hash_algo_name[i])) {
> - opt->hash = i;
> + private->hash = i;
> break;
> }
> }
> @@ -811,14 +819,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
> }
> break;
> case Opt_policydigest:
> - digest_len = hash_digest_size[opt->hash];
> + digest_len = hash_digest_size[private->hash];
> if (!tpm2 || strlen(args[0].from) != (2 * digest_len))
> return -EINVAL;
> - res = hex2bin(opt->policydigest, args[0].from,
> + res = hex2bin(private->policydigest, args[0].from,
> digest_len);
> if (res < 0)
> return -EINVAL;
> - opt->policydigest_len = digest_len;
> + private->policydigest_len = digest_len;
> break;
> case Opt_policyhandle:
> if (!tpm2)
> @@ -826,7 +834,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
> res = kstrtoul(args[0].from, 16, &handle);
> if (res < 0)
> return -EINVAL;
> - opt->policyhandle = handle;
> + private->policyhandle = handle;
> break;
> default:
> return -EINVAL;
> @@ -837,6 +845,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
>
> static struct trusted_key_options *trusted_options_alloc(void)
> {
> + struct trusted_tpm_options *private;
> struct trusted_key_options *options;
> int tpm2;
>
> @@ -849,14 +858,23 @@ static struct trusted_key_options *trusted_options_alloc(void)
> /* set any non-zero defaults */
> options->keytype = SRK_keytype;
>
> - if (!tpm2)
> - options->keyhandle = SRKHANDLE;
> + private = kzalloc_obj(*private);
> + if (!private) {
> + kfree_sensitive(options);
> + options = NULL;
> + } else {
> + if (!tpm2)
> + private->keyhandle = SRKHANDLE;
> +
> + options->private = private;
> + }
> }
> return options;
> }
>
> static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
> {
> + struct trusted_tpm_options *private = NULL;
> struct trusted_key_options *options = NULL;
> int ret = 0;
> int tpm2;
> @@ -874,7 +892,8 @@ static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
> goto out;
> dump_options(options);
>
> - if (!options->keyhandle && !tpm2) {
> + private = options->private;
> + if (!private->keyhandle && !tpm2) {
> ret = -EINVAL;
> goto out;
> }
> @@ -888,20 +907,22 @@ static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
> goto out;
> }
>
> - if (options->pcrlock) {
> - ret = pcrlock(options->pcrlock);
> + if (private->pcrlock) {
> + ret = pcrlock(private->pcrlock);
> if (ret < 0) {
> pr_info("pcrlock failed (%d)\n", ret);
> goto out;
> }
> }
> out:
> + kfree_sensitive(options->private);
> kfree_sensitive(options);
> return ret;
> }
>
> static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
> {
> + struct trusted_tpm_options *private = NULL;
> struct trusted_key_options *options = NULL;
> int ret = 0;
> int tpm2;
> @@ -919,7 +940,8 @@ static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
> goto out;
> dump_options(options);
>
> - if (!options->keyhandle && !tpm2) {
> + private = options->private;
> + if (!private->keyhandle && !tpm2) {
> ret = -EINVAL;
> goto out;
> }
> @@ -931,14 +953,15 @@ static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
> if (ret < 0)
> pr_info("key_unseal failed (%d)\n", ret);
>
> - if (options->pcrlock) {
> - ret = pcrlock(options->pcrlock);
> + if (private->pcrlock) {
> + ret = pcrlock(private->pcrlock);
> if (ret < 0) {
> pr_info("pcrlock failed (%d)\n", ret);
> goto out;
> }
> }
> out:
> + kfree_sensitive(options->private);
> kfree_sensitive(options);
> return ret;
> }
> diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> index 6340823f8b53..94e01249b921 100644
> --- a/security/keys/trusted-keys/trusted_tpm2.c
> +++ b/security/keys/trusted-keys/trusted_tpm2.c
> @@ -24,6 +24,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
> struct trusted_key_options *options,
> u8 *src, u32 len)
> {
> + struct trusted_tpm_options *private = options->private;
> const int SCRATCH_SIZE = PAGE_SIZE;
> u8 *scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL);
> u8 *work = scratch, *work1;
> @@ -46,7 +47,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
> work = asn1_encode_oid(work, end_work, tpm2key_oid,
> asn1_oid_len(tpm2key_oid));
>
> - if (options->blobauth_len == 0) {
> + if (private->blobauth_len == 0) {
> unsigned char bool[3], *w = bool;
> /* tag 0 is emptyAuth */
> w = asn1_encode_boolean(w, w + sizeof(bool), true);
> @@ -69,7 +70,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
> goto err;
> }
>
> - work = asn1_encode_integer(work, end_work, options->keyhandle);
> + work = asn1_encode_integer(work, end_work, private->keyhandle);
> work = asn1_encode_octet_string(work, end_work, pub, pub_len);
> work = asn1_encode_octet_string(work, end_work, priv, priv_len);
>
> @@ -102,6 +103,7 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
> struct trusted_key_options *options,
> u8 **buf)
> {
> + struct trusted_tpm_options *private = options->private;
> int ret;
> struct tpm2_key_context ctx;
> u8 *blob;
> @@ -121,7 +123,7 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
> return -ENOMEM;
>
> *buf = blob;
> - options->keyhandle = ctx.parent;
> + private->keyhandle = ctx.parent;
>
> memcpy(blob, ctx.priv, ctx.priv_len);
> blob += ctx.priv_len;
> @@ -233,6 +235,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> struct trusted_key_payload *payload,
> struct trusted_key_options *options)
> {
> + struct trusted_tpm_options *private = options->private;
> off_t offset = TPM_HEADER_SIZE;
> struct tpm_buf buf, sized;
> int blob_len = 0;
> @@ -240,11 +243,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> u32 flags;
> int rc;
>
> - hash = tpm2_find_hash_alg(options->hash);
> + hash = tpm2_find_hash_alg(private->hash);
> if (hash < 0)
> return hash;
>
> - if (!options->keyhandle)
> + if (!private->keyhandle)
> return -EINVAL;
>
> rc = tpm_try_get_ops(chip);
> @@ -268,18 +271,19 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> goto out_put;
> }
>
> - rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
> + rc = tpm_buf_append_name(chip, &buf, private->keyhandle, NULL);
> if (rc)
> goto out;
>
> tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
> - options->keyauth, TPM_DIGEST_SIZE);
> + private->keyauth, TPM_DIGEST_SIZE);
>
> /* sensitive */
> - tpm_buf_append_u16(&sized, options->blobauth_len);
> + tpm_buf_append_u16(&sized, private->blobauth_len);
>
> - if (options->blobauth_len)
> - tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
> + if (private->blobauth_len)
> + tpm_buf_append(&sized, private->blobauth,
> + private->blobauth_len);
>
> tpm_buf_append_u16(&sized, payload->key_len);
> tpm_buf_append(&sized, payload->key, payload->key_len);
> @@ -292,14 +296,15 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
>
> /* key properties */
> flags = 0;
> - flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
> + flags |= private->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
> flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
> tpm_buf_append_u32(&sized, flags);
>
> /* policy */
> - tpm_buf_append_u16(&sized, options->policydigest_len);
> - if (options->policydigest_len)
> - tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
> + tpm_buf_append_u16(&sized, private->policydigest_len);
> + if (private->policydigest_len)
> + tpm_buf_append(&sized, private->policydigest,
> + private->policydigest_len);
>
> /* public parameters */
> tpm_buf_append_u16(&sized, TPM_ALG_NULL);
> @@ -373,6 +378,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> u32 *blob_handle)
> {
> u8 *blob_ref __free(kfree) = NULL;
> + struct trusted_tpm_options *private = options->private;
> struct tpm_buf buf;
> unsigned int private_len;
> unsigned int public_len;
> @@ -392,7 +398,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> }
>
> /* new format carries keyhandle but old format doesn't */
> - if (!options->keyhandle)
> + if (!private->keyhandle)
> return -EINVAL;
>
> /* must be big enough for at least the two be16 size counts */
> @@ -433,11 +439,11 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> return rc;
> }
>
> - rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
> + rc = tpm_buf_append_name(chip, &buf, private->keyhandle, NULL);
> if (rc)
> goto out;
>
> - tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
> + tpm_buf_append_hmac_session(chip, &buf, 0, private->keyauth,
> TPM_DIGEST_SIZE);
>
> tpm_buf_append(&buf, blob, blob_len);
> @@ -481,6 +487,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> struct trusted_key_options *options,
> u32 blob_handle)
> {
> + struct trusted_tpm_options *private = options->private;
> struct tpm_header *head;
> struct tpm_buf buf;
> u16 data_len;
> @@ -502,10 +509,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> if (rc)
> goto out;
>
> - if (!options->policyhandle) {
> + if (!private->policyhandle) {
> tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
> - options->blobauth,
> - options->blobauth_len);
> + private->blobauth,
> + private->blobauth_len);
> } else {
> /*
> * FIXME: The policy session was generated outside the
> @@ -518,9 +525,9 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> * could repeat our actions with the exfiltrated
> * password.
> */
> - tpm2_buf_append_auth(&buf, options->policyhandle,
> + tpm2_buf_append_auth(&buf, private->policyhandle,
> NULL /* nonce */, 0, 0,
> - options->blobauth, options->blobauth_len);
> + private->blobauth, private->blobauth_len);
> if (tpm2_chip_auth(chip)) {
> tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT, NULL, 0);
> } else {
>
> --
> 2.51.0
>
^ permalink raw reply
* Re: [PATCH v4 1/7] lsm: Add granular mount hooks to replace security_sb_mount
From: Christian Brauner @ 2026-05-22 9:15 UTC (permalink / raw)
To: Song Liu
Cc: linux-security-module, linux-fsdevel, selinux, apparmor, paul,
jmorris, serge, viro, brauner, jack, john.johansen,
stephen.smalley.work, omosnace, mic, gnoack, takedakn,
penguin-kernel, herton, kernel-team
In-Reply-To: <20260515200158.4081915-2-song@kernel.org>
On Fri, 15 May 2026 13:01:52 -0700, Song Liu <song@kernel.org> wrote:
> [...]
>
> Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
> Tested-by: Stephen Smalley <stephen.smalley.work@gmail.com> # for selinux only
> Signed-off-by: Song Liu <song@kernel.org>
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Please cleanly separate the preparatory work for introducing the new
hooks from any changes to fs/namespace.c
Once you have all of the new machinery in place, switch fs/namespace.c
over to the new hooks.
This will make it way easier to review and easier to distribute the
--
Christian Brauner <brauner@kernel.org>
^ permalink raw reply
* [PATCH v3] keys/trusted_keys: move TPM-specific fields into trusted_tpm_options
From: Srish Srinivasan @ 2026-05-22 8:16 UTC (permalink / raw)
To: linux-integrity, keyrings
Cc: James.Bottomley, stefanb, jarkko, zohar, nayna, rnsastry,
linux-kernel, linux-security-module, ssrish
The trusted_key_options struct contains TPM-specific fields (keyhandle,
keyauth, blobauth_len, blobauth, pcrinfo_len, pcrinfo, pcrlock, hash,
policydigest_len, policydigest, and policyhandle). This leads to the
accumulation of backend-specific fields in the generic options structure.
Define a trusted_tpm_options structure and move the TPM-specific fields
there. Store a pointer to trusted_tpm_options in trusted_key_options's
private.
No functional change intended.
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
This patch depends on 9ec4175a30eb ("KEYS: trusted: Debugging as a
feature"), which is in linux-tpmdd/master but not yet in mainline.
Please apply on top of linux-tpmdd/master.
base-commit: 67657fb65aa9f2d7dd46235246b1677792bd103e
Changelog:
v3:
- Exclude the preparatory clean up patch as the problem has been addressed
in commit 9ec4175a30eb ("KEYS: trusted: Debugging as a feature")
v2:
- Exclude the bug-fix patch as it has already been applied to 6.19-rc7
- Rename instances of trusted_tpm_options from tpm_opts to private
- Use pr_debug and KERN_DEBUG for logging debug messages (preparatory clean
up patch)
- Address other minor comments from Jarkko
include/keys/trusted-type.h | 11 ---
include/keys/trusted_tpm.h | 14 ++++
security/keys/trusted-keys/trusted_tpm1.c | 95 ++++++++++++++---------
security/keys/trusted-keys/trusted_tpm2.c | 51 ++++++------
4 files changed, 102 insertions(+), 69 deletions(-)
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index 9f9940482da4..3db61b57cf73 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -39,17 +39,6 @@ struct trusted_key_payload {
struct trusted_key_options {
uint16_t keytype;
- uint32_t keyhandle;
- unsigned char keyauth[TPM_DIGEST_SIZE];
- uint32_t blobauth_len;
- unsigned char blobauth[TPM_DIGEST_SIZE];
- uint32_t pcrinfo_len;
- unsigned char pcrinfo[MAX_PCRINFO_SIZE];
- int pcrlock;
- uint32_t hash;
- uint32_t policydigest_len;
- unsigned char policydigest[MAX_DIGEST_SIZE];
- uint32_t policyhandle;
void *private;
};
diff --git a/include/keys/trusted_tpm.h b/include/keys/trusted_tpm.h
index 0fadc6a4f166..355ebd36cbfd 100644
--- a/include/keys/trusted_tpm.h
+++ b/include/keys/trusted_tpm.h
@@ -7,6 +7,20 @@
extern struct trusted_key_ops trusted_key_tpm_ops;
+struct trusted_tpm_options {
+ uint32_t keyhandle;
+ unsigned char keyauth[TPM_DIGEST_SIZE];
+ uint32_t blobauth_len;
+ unsigned char blobauth[TPM_DIGEST_SIZE];
+ uint32_t pcrinfo_len;
+ unsigned char pcrinfo[MAX_PCRINFO_SIZE];
+ int pcrlock;
+ uint32_t hash;
+ uint32_t policydigest_len;
+ unsigned char policydigest[MAX_DIGEST_SIZE];
+ uint32_t policyhandle;
+};
+
int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index 13513819991e..21360a41d290 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -49,15 +49,17 @@ enum {
#ifdef CONFIG_TRUSTED_KEYS_DEBUG
static inline void dump_options(struct trusted_key_options *o)
{
+ struct trusted_tpm_options *private = o->private;
+
if (!trusted_debug)
return;
pr_debug("sealing key type %d\n", o->keytype);
- pr_debug("sealing key handle %0X\n", o->keyhandle);
- pr_debug("pcrlock %d\n", o->pcrlock);
- pr_debug("pcrinfo %d\n", o->pcrinfo_len);
+ pr_debug("sealing key handle %0X\n", private->keyhandle);
+ pr_debug("pcrlock %d\n", private->pcrlock);
+ pr_debug("pcrinfo %d\n", private->pcrinfo_len);
print_hex_dump_debug("pcrinfo ", DUMP_PREFIX_NONE,
- 16, 1, o->pcrinfo, o->pcrinfo_len, 0);
+ 16, 1, private->pcrinfo, private->pcrinfo_len, 0);
}
static inline void dump_sess(struct osapsess *s)
@@ -631,6 +633,7 @@ static int tpm_unseal(struct tpm_buf *tb,
static int key_seal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
+ struct trusted_tpm_options *private = o->private;
struct tpm_buf tb;
int ret;
@@ -641,9 +644,10 @@ static int key_seal(struct trusted_key_payload *p,
/* include migratable flag at end of sealed key */
p->key[p->key_len] = p->migratable;
- ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
+ ret = tpm_seal(&tb, o->keytype, private->keyhandle, private->keyauth,
p->key, p->key_len + 1, p->blob, &p->blob_len,
- o->blobauth, o->pcrinfo, o->pcrinfo_len);
+ private->blobauth, private->pcrinfo,
+ private->pcrinfo_len);
if (ret < 0)
pr_info("srkseal failed (%d)\n", ret);
@@ -657,6 +661,7 @@ static int key_seal(struct trusted_key_payload *p,
static int key_unseal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
+ struct trusted_tpm_options *private = o->private;
struct tpm_buf tb;
int ret;
@@ -664,8 +669,8 @@ static int key_unseal(struct trusted_key_payload *p,
if (ret)
return ret;
- ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
- o->blobauth, p->key, &p->key_len);
+ ret = tpm_unseal(&tb, private->keyhandle, private->keyauth, p->blob,
+ p->blob_len, private->blobauth, p->key, &p->key_len);
if (ret < 0)
pr_info("srkunseal failed (%d)\n", ret);
else
@@ -702,6 +707,7 @@ static const match_table_t key_tokens = {
static int getoptions(char *c, struct trusted_key_payload *pay,
struct trusted_key_options *opt)
{
+ struct trusted_tpm_options *private = opt->private;
substring_t args[MAX_OPT_ARGS];
char *p = c;
int token;
@@ -717,7 +723,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
if (tpm2 < 0)
return tpm2;
- opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
+ private->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
if (!c)
return 0;
@@ -731,11 +737,11 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
switch (token) {
case Opt_pcrinfo:
- opt->pcrinfo_len = strlen(args[0].from) / 2;
- if (opt->pcrinfo_len > MAX_PCRINFO_SIZE)
+ private->pcrinfo_len = strlen(args[0].from) / 2;
+ if (private->pcrinfo_len > MAX_PCRINFO_SIZE)
return -EINVAL;
- res = hex2bin(opt->pcrinfo, args[0].from,
- opt->pcrinfo_len);
+ res = hex2bin(private->pcrinfo, args[0].from,
+ private->pcrinfo_len);
if (res < 0)
return -EINVAL;
break;
@@ -744,12 +750,12 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
if (res < 0)
return -EINVAL;
opt->keytype = SEAL_keytype;
- opt->keyhandle = handle;
+ private->keyhandle = handle;
break;
case Opt_keyauth:
if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
return -EINVAL;
- res = hex2bin(opt->keyauth, args[0].from,
+ res = hex2bin(private->keyauth, args[0].from,
SHA1_DIGEST_SIZE);
if (res < 0)
return -EINVAL;
@@ -760,21 +766,23 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
* hex strings. TPM 2.0 authorizations are simple
* passwords (although it can take a hash as well)
*/
- opt->blobauth_len = strlen(args[0].from);
+ private->blobauth_len = strlen(args[0].from);
- if (opt->blobauth_len == 2 * TPM_DIGEST_SIZE) {
- res = hex2bin(opt->blobauth, args[0].from,
+ if (private->blobauth_len == 2 * TPM_DIGEST_SIZE) {
+ res = hex2bin(private->blobauth, args[0].from,
TPM_DIGEST_SIZE);
if (res < 0)
return -EINVAL;
- opt->blobauth_len = TPM_DIGEST_SIZE;
+ private->blobauth_len = TPM_DIGEST_SIZE;
break;
}
- if (tpm2 && opt->blobauth_len <= sizeof(opt->blobauth)) {
- memcpy(opt->blobauth, args[0].from,
- opt->blobauth_len);
+ if (tpm2 &&
+ private->blobauth_len <=
+ sizeof(private->blobauth)) {
+ memcpy(private->blobauth, args[0].from,
+ private->blobauth_len);
break;
}
@@ -792,14 +800,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
res = kstrtoul(args[0].from, 10, &lock);
if (res < 0)
return -EINVAL;
- opt->pcrlock = lock;
+ private->pcrlock = lock;
break;
case Opt_hash:
if (test_bit(Opt_policydigest, &token_mask))
return -EINVAL;
for (i = 0; i < HASH_ALGO__LAST; i++) {
if (!strcmp(args[0].from, hash_algo_name[i])) {
- opt->hash = i;
+ private->hash = i;
break;
}
}
@@ -811,14 +819,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
}
break;
case Opt_policydigest:
- digest_len = hash_digest_size[opt->hash];
+ digest_len = hash_digest_size[private->hash];
if (!tpm2 || strlen(args[0].from) != (2 * digest_len))
return -EINVAL;
- res = hex2bin(opt->policydigest, args[0].from,
+ res = hex2bin(private->policydigest, args[0].from,
digest_len);
if (res < 0)
return -EINVAL;
- opt->policydigest_len = digest_len;
+ private->policydigest_len = digest_len;
break;
case Opt_policyhandle:
if (!tpm2)
@@ -826,7 +834,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
res = kstrtoul(args[0].from, 16, &handle);
if (res < 0)
return -EINVAL;
- opt->policyhandle = handle;
+ private->policyhandle = handle;
break;
default:
return -EINVAL;
@@ -837,6 +845,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
static struct trusted_key_options *trusted_options_alloc(void)
{
+ struct trusted_tpm_options *private;
struct trusted_key_options *options;
int tpm2;
@@ -849,14 +858,23 @@ static struct trusted_key_options *trusted_options_alloc(void)
/* set any non-zero defaults */
options->keytype = SRK_keytype;
- if (!tpm2)
- options->keyhandle = SRKHANDLE;
+ private = kzalloc_obj(*private);
+ if (!private) {
+ kfree_sensitive(options);
+ options = NULL;
+ } else {
+ if (!tpm2)
+ private->keyhandle = SRKHANDLE;
+
+ options->private = private;
+ }
}
return options;
}
static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
{
+ struct trusted_tpm_options *private = NULL;
struct trusted_key_options *options = NULL;
int ret = 0;
int tpm2;
@@ -874,7 +892,8 @@ static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
goto out;
dump_options(options);
- if (!options->keyhandle && !tpm2) {
+ private = options->private;
+ if (!private->keyhandle && !tpm2) {
ret = -EINVAL;
goto out;
}
@@ -888,20 +907,22 @@ static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
goto out;
}
- if (options->pcrlock) {
- ret = pcrlock(options->pcrlock);
+ if (private->pcrlock) {
+ ret = pcrlock(private->pcrlock);
if (ret < 0) {
pr_info("pcrlock failed (%d)\n", ret);
goto out;
}
}
out:
+ kfree_sensitive(options->private);
kfree_sensitive(options);
return ret;
}
static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
{
+ struct trusted_tpm_options *private = NULL;
struct trusted_key_options *options = NULL;
int ret = 0;
int tpm2;
@@ -919,7 +940,8 @@ static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
goto out;
dump_options(options);
- if (!options->keyhandle && !tpm2) {
+ private = options->private;
+ if (!private->keyhandle && !tpm2) {
ret = -EINVAL;
goto out;
}
@@ -931,14 +953,15 @@ static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
if (ret < 0)
pr_info("key_unseal failed (%d)\n", ret);
- if (options->pcrlock) {
- ret = pcrlock(options->pcrlock);
+ if (private->pcrlock) {
+ ret = pcrlock(private->pcrlock);
if (ret < 0) {
pr_info("pcrlock failed (%d)\n", ret);
goto out;
}
}
out:
+ kfree_sensitive(options->private);
kfree_sensitive(options);
return ret;
}
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 6340823f8b53..94e01249b921 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -24,6 +24,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
struct trusted_key_options *options,
u8 *src, u32 len)
{
+ struct trusted_tpm_options *private = options->private;
const int SCRATCH_SIZE = PAGE_SIZE;
u8 *scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL);
u8 *work = scratch, *work1;
@@ -46,7 +47,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
work = asn1_encode_oid(work, end_work, tpm2key_oid,
asn1_oid_len(tpm2key_oid));
- if (options->blobauth_len == 0) {
+ if (private->blobauth_len == 0) {
unsigned char bool[3], *w = bool;
/* tag 0 is emptyAuth */
w = asn1_encode_boolean(w, w + sizeof(bool), true);
@@ -69,7 +70,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
goto err;
}
- work = asn1_encode_integer(work, end_work, options->keyhandle);
+ work = asn1_encode_integer(work, end_work, private->keyhandle);
work = asn1_encode_octet_string(work, end_work, pub, pub_len);
work = asn1_encode_octet_string(work, end_work, priv, priv_len);
@@ -102,6 +103,7 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
struct trusted_key_options *options,
u8 **buf)
{
+ struct trusted_tpm_options *private = options->private;
int ret;
struct tpm2_key_context ctx;
u8 *blob;
@@ -121,7 +123,7 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
return -ENOMEM;
*buf = blob;
- options->keyhandle = ctx.parent;
+ private->keyhandle = ctx.parent;
memcpy(blob, ctx.priv, ctx.priv_len);
blob += ctx.priv_len;
@@ -233,6 +235,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
+ struct trusted_tpm_options *private = options->private;
off_t offset = TPM_HEADER_SIZE;
struct tpm_buf buf, sized;
int blob_len = 0;
@@ -240,11 +243,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
u32 flags;
int rc;
- hash = tpm2_find_hash_alg(options->hash);
+ hash = tpm2_find_hash_alg(private->hash);
if (hash < 0)
return hash;
- if (!options->keyhandle)
+ if (!private->keyhandle)
return -EINVAL;
rc = tpm_try_get_ops(chip);
@@ -268,18 +271,19 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
goto out_put;
}
- rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
+ rc = tpm_buf_append_name(chip, &buf, private->keyhandle, NULL);
if (rc)
goto out;
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
- options->keyauth, TPM_DIGEST_SIZE);
+ private->keyauth, TPM_DIGEST_SIZE);
/* sensitive */
- tpm_buf_append_u16(&sized, options->blobauth_len);
+ tpm_buf_append_u16(&sized, private->blobauth_len);
- if (options->blobauth_len)
- tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
+ if (private->blobauth_len)
+ tpm_buf_append(&sized, private->blobauth,
+ private->blobauth_len);
tpm_buf_append_u16(&sized, payload->key_len);
tpm_buf_append(&sized, payload->key, payload->key_len);
@@ -292,14 +296,15 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
/* key properties */
flags = 0;
- flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
+ flags |= private->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
tpm_buf_append_u32(&sized, flags);
/* policy */
- tpm_buf_append_u16(&sized, options->policydigest_len);
- if (options->policydigest_len)
- tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
+ tpm_buf_append_u16(&sized, private->policydigest_len);
+ if (private->policydigest_len)
+ tpm_buf_append(&sized, private->policydigest,
+ private->policydigest_len);
/* public parameters */
tpm_buf_append_u16(&sized, TPM_ALG_NULL);
@@ -373,6 +378,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
u32 *blob_handle)
{
u8 *blob_ref __free(kfree) = NULL;
+ struct trusted_tpm_options *private = options->private;
struct tpm_buf buf;
unsigned int private_len;
unsigned int public_len;
@@ -392,7 +398,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
}
/* new format carries keyhandle but old format doesn't */
- if (!options->keyhandle)
+ if (!private->keyhandle)
return -EINVAL;
/* must be big enough for at least the two be16 size counts */
@@ -433,11 +439,11 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
return rc;
}
- rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
+ rc = tpm_buf_append_name(chip, &buf, private->keyhandle, NULL);
if (rc)
goto out;
- tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
+ tpm_buf_append_hmac_session(chip, &buf, 0, private->keyauth,
TPM_DIGEST_SIZE);
tpm_buf_append(&buf, blob, blob_len);
@@ -481,6 +487,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 blob_handle)
{
+ struct trusted_tpm_options *private = options->private;
struct tpm_header *head;
struct tpm_buf buf;
u16 data_len;
@@ -502,10 +509,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
if (rc)
goto out;
- if (!options->policyhandle) {
+ if (!private->policyhandle) {
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
- options->blobauth,
- options->blobauth_len);
+ private->blobauth,
+ private->blobauth_len);
} else {
/*
* FIXME: The policy session was generated outside the
@@ -518,9 +525,9 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
* could repeat our actions with the exfiltrated
* password.
*/
- tpm2_buf_append_auth(&buf, options->policyhandle,
+ tpm2_buf_append_auth(&buf, private->policyhandle,
NULL /* nonce */, 0, 0,
- options->blobauth, options->blobauth_len);
+ private->blobauth, private->blobauth_len);
if (tpm2_chip_auth(chip)) {
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT, NULL, 0);
} else {
--
2.51.0
^ permalink raw reply related
* [ANN] Linux Security Summit Europe 2026 CfP
From: Reshetova, Elena @ 2026-05-22 5:56 UTC (permalink / raw)
To: linux-security-module@vger.kernel.org
Cc: Linux Security Summit Program Committee, Friend,
linux-integrity@vger.kernel.org, lwn@lwn.net,
linux-crypto@vger.kernel.org, keyrings@vger.kernel.org,
linux-coco@lists.linux.dev, kernel-hardening@lists.openwall.com
====================================================================
ANNOUNCEMENT AND CALL FOR PARTICIPATION
LINUX SECURITY SUMMIT EUROPE 2026
Thursday, 8 October
Prague, Czechia
====================================================================
DESCRIPTION
Linux Security Summit Europe (LSS-EU) 2026 is a technical forum for
collaboration between Linux developers, researchers, and end-users.
Its primary aim is to foster community efforts in deeply analyzing and
solving Linux operating system security challenges, including those in the
Linux kernel.
This year LSS-EU is a single day event happening right after Linux Plumbers 2026
https://lpc.events/
Proposals to LSS-EU should be submitted via:
https://events.linuxfoundation.org/linux-security-summit-europe/program/cfp/
SUGGESTED TOPICS
* Access Control
* Case Studies
* Cryptography and Key Management
* Emerging Technologies, Threats & Techniques
* Hardware Security
* IoT and Embedded Security
* Integrity Policy and Enforcement
* Open Source Supply Chain for the Linux OS
* Security Tools
* Security UX
* Linux OS Hardening
* Virtualization and Containers
DATES TO REMEMBER:
* CFP Close: Sunday, 28 June at 11:59 PM CEST (UTC +2) / 2:59 PM PDT (UTC -7)
* CFP Notifications: Tuesday, 14 July
* Schedule Announced: Wednesday, 15 July
* Event Date: Thursday, 8 October
WHO SHOULD ATTEND
We're seeking a diverse range of attendees and welcome participation by
people involved in Linux security development, operations, and research.
LSS is a unique global event that provides the opportunity to present and
discuss your work or research with key Linux security community members and
maintainers. It's also useful for those who wish to keep up with the latest
in Linux security development and to provide input to the development
process.
MASTODON
For event updates and announcements, follow:
https://social.kernel.org/LinuxSecSummit
#linuxsecuritysummit
PROGRAM COMMITTEE
The program committee for LSS 2026 is:
* James Morris, Microsoft
* Serge Hallyn, Geico
* Paul Moore, Microsoft
* Stephen Smalley, NSA
* Elena Reshetova, Intel
* John Johansen, Canonical
* Kees Cook, Google
* Casey Schaufler
* Mimi Zohar, IBM
* David A. Wheeler, Linux Foundation
The program committee may be contacted as a group via email:
lss-pc () lists.linuxfoundation.org
^ permalink raw reply
* [net-next] netlabel: validate unlabeled mask attribute length
From: Chenguang Zhao @ 2026-05-22 5:45 UTC (permalink / raw)
To: Paul Moore, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman
Cc: Chenguang Zhao, netdev, linux-security-module
netlbl_unlabel_addrinfo_get() checked the address length
but allowed shorter mask attributes to pass through to
fixed-size address reads.
Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
---
netlbl_unlabel_addrinfo_get() only rejected a mask
length mismatch when the address attribute length
was also invalid. A crafted Generic Netlink request
could therefore provide a valid IPv4/IPv6 address
attribute with a shorter mask attribute.
NLA_BINARY policy lengths are maximum lengths,
not exact lengths, so the short mask can pass
policy validation. The mask is later read as
a full struct in_addr or struct in6_addr.
Require both address and mask attributes to
have the exact expected size.
---
net/netlabel/netlabel_unlabeled.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index ca7a9e2a3de7..c1b7e0061886 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -762,8 +762,9 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info,
if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] &&
info->attrs[NLBL_UNLABEL_A_IPV4MASK]) {
addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
- if (addr_len != sizeof(struct in_addr) &&
- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]))
+ if (addr_len != sizeof(struct in_addr) ||
+ nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]) !=
+ sizeof(struct in_addr))
return -EINVAL;
*len = addr_len;
*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
@@ -771,8 +772,9 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info,
return 0;
} else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) {
addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
- if (addr_len != sizeof(struct in6_addr) &&
- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]))
+ if (addr_len != sizeof(struct in6_addr) ||
+ nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]) !=
+ sizeof(struct in6_addr))
return -EINVAL;
*len = addr_len;
*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
--
2.25.1
^ permalink raw reply related
* Re: [net-next] netlabel: fix IPv6 unlabeled address add error handling
From: Paul Moore @ 2026-05-22 3:50 UTC (permalink / raw)
To: Chenguang Zhao
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, netdev, linux-security-module
In-Reply-To: <20260522022910.398416-1-zhaochenguang@kylinos.cn>
On Thu, May 21, 2026 at 10:30 PM Chenguang Zhao
<zhaochenguang@kylinos.cn> wrote:
>
> netlbl_unlhsh_add_addr6() always returned zero after
> netlbl_af6list_add(), masking failures such as duplicate
> IPv6 static label entries.
>
> Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
> ---
> net/netlabel/netlabel_unlabeled.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Nice catch, thanks!
Acked-by: Paul Moore <paul@paul-moore.com>
--
paul-moore.com
^ permalink raw reply
* [PATCH bpf-next 13/13] selftests/bpf: add IPE BPF policy integration tests
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
Smoke test for the IPE BPF signing properties and ops added in the
preceding patches. The test primes the kernel config with IPE
knobs, writes a boot policy, and boots vmtest.sh to verify that
signed lskels load, unsigned loads are denied, and the policy
audit lines match.
Manual only for now, not wired into the selftests Makefile.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
.../selftests/bpf/test_signed_bpf_ipe.sh | 156 ++++++++++++++++++
tools/testing/selftests/bpf/vmtest.sh | 4 +-
2 files changed, 158 insertions(+), 2 deletions(-)
create mode 100755 tools/testing/selftests/bpf/test_signed_bpf_ipe.sh
diff --git a/tools/testing/selftests/bpf/test_signed_bpf_ipe.sh b/tools/testing/selftests/bpf/test_signed_bpf_ipe.sh
new file mode 100755
index 000000000000..aaa259ddb917
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_signed_bpf_ipe.sh
@@ -0,0 +1,156 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# IPE BPF policy integration tests.
+
+if [ "${1:-}" = "--in-vm" ]; then
+ set -u
+ fail=0
+ record() {
+ id=$1; verdict=$2; shift 2
+ printf '%s %s %s\n' "$verdict" "$id" "$*"
+ [ "$verdict" = FAIL ] && fail=$((fail + 1))
+ return 0
+ }
+
+ mountpoint -q /sys/kernel/security 2>/dev/null \
+ || mount -t securityfs none /sys/kernel/security 2>/dev/null || true
+ if [ -d /sys/kernel/security/ipe ]; then
+ record T0 PASS "securityfs/ipe present"
+ elif grep -qw ipe /sys/kernel/security/lsm 2>/dev/null; then
+ record T0 PASS "ipe in /sys/kernel/security/lsm"
+ elif [ -r /sys/module/ipe/parameters/enforce ]; then
+ record T0 PASS "ipe module parameters present"
+ else
+ record T0 FAIL "no sign that IPE LSM is loaded"
+ fi
+
+ if ./test_progs -t atomics 2>&1 | grep -qE '^#[0-9]+[[:space:]]+atomics:OK$'; then
+ record T1 PASS "atomics signed lskel loaded"
+ else
+ record T1 FAIL "atomics signed lskel did not load"
+ fi
+
+ if dmesg | grep -q 'ipe_op=BPF_PROG_LOAD ipe_hook=BPF_PROG_LOAD'; then
+ record T2 PASS "ipe_op=BPF_PROG_LOAD audit line found"
+ else
+ record T2 FAIL "no ipe_op=BPF_PROG_LOAD audit lines in dmesg"
+ fi
+
+ if dmesg | grep 'ipe_op=BPF_PROG_LOAD' \
+ | grep -q 'bpf_signature=UNSIGNED action=DENY'; then
+ record T3 PASS "deny-UNSIGNED rule matched"
+ else
+ record T3 FAIL "deny-UNSIGNED rule never matched"
+ fi
+
+ mountpoint -q /sys/kernel/security 2>/dev/null \
+ || mount -t securityfs none /sys/kernel/security 2>/dev/null || true
+ content=
+ for d in /sys/kernel/security/ipe/policies/*/; do
+ [ -d "$d" ] || continue
+ if [ -r "$d/policy" ]; then
+ content=$(cat "$d/policy" 2>/dev/null || true)
+ break
+ fi
+ done
+ if [ -z "$content" ]; then
+ record T5 SKIP "could not read /sys/kernel/security/ipe/policies/*/policy"
+ elif echo "$content" | grep -q '^op=BPF_PROG_LOAD_POST_INTEGRITY'; then
+ record T5 PASS "post-integrity rule present in active policy"
+ else
+ record T5 FAIL "active policy does not contain a BPF_PROG_LOAD_POST_INTEGRITY rule"
+ fi
+
+ ENFORCE=/sys/kernel/security/ipe/enforce
+ mountpoint -q /sys/kernel/security 2>/dev/null \
+ || mount -t securityfs none /sys/kernel/security 2>/dev/null || true
+
+ if [ ! -w "$ENFORCE" ]; then
+ record T4 SKIP "$ENFORCE not writable"
+ elif ! echo 1 > "$ENFORCE" 2>/dev/null; then
+ record T4 SKIP "could not toggle IPE to enforce=1"
+ else
+ out=$(./test_progs -t bind_perm 2>&1 || true)
+ if echo "$out" | grep -q -- '-EACCES\|errno 13'; then
+ record T4 PASS "unsigned load denied with -EACCES under enforce=1"
+ else
+ record T4 FAIL "no -EACCES seen from unsigned load under enforce=1"
+ echo "$out" | tail -10 | sed 's/^/ T4: /'
+ fi
+ echo 0 > "$ENFORCE" 2>/dev/null || true
+ fi
+
+ if [ "$fail" -eq 0 ]; then
+ echo ALL_TESTS_PASSED
+ else
+ echo FAIL_COUNT "$fail"
+ fi
+ exit 0
+fi
+
+set -euo pipefail
+
+SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+KERNEL_DIR=$(cd "$SCRIPT_DIR/../../../.." && pwd)
+VMTEST="$SCRIPT_DIR/vmtest.sh"
+
+POLICY_PATH=${IPE_TEST_POLICY:-/tmp/ipe_bpf_test_policy}
+
+red() { printf '\033[31m%s\033[0m\n' "$*"; }
+green() { printf '\033[32m%s\033[0m\n' "$*"; }
+bold() { printf '\033[1m%s\033[0m\n' "$*"; }
+
+bold "=== IPE BPF policy integration tests ==="
+
+tmpfile=$(mktemp -p "$(dirname "$POLICY_PATH")" \
+ ".$(basename "$POLICY_PATH").XXXXXX")
+cat > "$tmpfile" <<EOF
+policy_name="ipe_bpf_test" policy_version=0.0.1
+op=BPF_PROG_LOAD bpf_signature=OK action=ALLOW
+op=BPF_PROG_LOAD bpf_signature=UNSIGNED action=DENY
+op=BPF_PROG_LOAD_POST_INTEGRITY action=ALLOW
+DEFAULT op=BPF_PROG_LOAD action=ALLOW
+DEFAULT op=BPF_PROG_LOAD_POST_INTEGRITY action=ALLOW
+DEFAULT action=ALLOW
+EOF
+mv "$tmpfile" "$POLICY_PATH"
+echo "policy written to $POLICY_PATH"
+
+export OUTPUT_DIR=${OUTPUT_DIR:-$HOME/.bpf_selftests_ipe}
+CFG="$OUTPUT_DIR/latest.config"
+mkdir -p "$OUTPUT_DIR"
+if [ ! -f "$CFG" ]; then
+ PLATFORM=$(uname -m)
+ for src in "$KERNEL_DIR/tools/testing/selftests/bpf/config" \
+ "$KERNEL_DIR/tools/testing/selftests/bpf/config.vm" \
+ "$KERNEL_DIR/tools/testing/selftests/bpf/config.$PLATFORM"; do
+ [ -f "$src" ] && cat "$src" >> "$CFG"
+ done
+fi
+"$KERNEL_DIR/scripts/config" --file "$CFG" \
+ --enable SECURITY_IPE \
+ --enable IPE_PROP_BPF_SIGNATURE \
+ --set-str IPE_BOOT_POLICY "$POLICY_PATH"
+lsm=$("$KERNEL_DIR/scripts/config" --file "$CFG" --state LSM 2>/dev/null)
+if [ -z "$lsm" ] || [ "$lsm" = "undef" ]; then
+ "$KERNEL_DIR/scripts/config" --file "$CFG" --set-str LSM "bpf,ipe"
+elif ! echo ",${lsm}," | grep -q ',ipe,'; then
+ "$KERNEL_DIR/scripts/config" --file "$CFG" --set-str LSM "${lsm},ipe"
+fi
+touch "$CFG"
+
+RUN_OUT=$(mktemp -t ipe_test_run.XXXXXX)
+trap 'rm -f "$RUN_OUT"' EXIT
+export VMTEST_EXTRA_CMDLINE="ipe.enforce=0 ipe.success_audit=1"
+"$VMTEST" -- ./test_signed_bpf_ipe.sh --in-vm 2>&1 | tee "$RUN_OUT"
+
+if grep -q 'ALL_TESTS_PASSED' "$RUN_OUT"; then
+ green "=== all IPE policy integration tests PASSED ==="
+ grep -E '^(PASS|FAIL|SKIP) T[0-9]+' "$RUN_OUT" || true
+ exit 0
+else
+ red "=== IPE policy integration tests FAILED ==="
+ grep -E '^(PASS|FAIL|SKIP) T[0-9]+' "$RUN_OUT" || true
+ exit 1
+fi
diff --git a/tools/testing/selftests/bpf/vmtest.sh b/tools/testing/selftests/bpf/vmtest.sh
index 2f869daf8a06..b30e2b359413 100755
--- a/tools/testing/selftests/bpf/vmtest.sh
+++ b/tools/testing/selftests/bpf/vmtest.sh
@@ -61,7 +61,7 @@ DEFAULT_COMMAND="./test_progs"
MOUNT_DIR="mnt"
LOCAL_ROOTFS_IMAGE=""
ROOTFS_IMAGE="root.img"
-OUTPUT_DIR="$HOME/.bpf_selftests"
+OUTPUT_DIR="${OUTPUT_DIR:-$HOME/.bpf_selftests}"
KCONFIG_REL_PATHS=("tools/testing/selftests/bpf/config"
"tools/testing/selftests/bpf/config.vm"
"tools/testing/selftests/bpf/config.${PLATFORM}")
@@ -294,7 +294,7 @@ EOF
-m 4G \
-drive file="${rootfs_img}",format=raw,index=1,media=disk,if=virtio,cache=none \
-kernel "${kernel_bzimage}" \
- -append "root=/dev/vda rw console=${QEMU_CONSOLE}"
+ -append "root=/dev/vda rw console=${QEMU_CONSOLE} ${VMTEST_EXTRA_CMDLINE:-}"
}
copy_logs()
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 12/13] ipe: gate post-integrity BPF program loads
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
Register on security_bpf_prog_load_post_integrity and expose a new
IPE op BPF_PROG_LOAD_POST_INTEGRITY. Kept distinct from
BPF_PROG_LOAD so policies need not reason about the same rule
firing at two timings with different verdict states.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
security/ipe/audit.c | 2 ++
security/ipe/hooks.c | 6 ++++++
security/ipe/hooks.h | 2 ++
security/ipe/ipe.c | 1 +
security/ipe/policy.h | 1 +
security/ipe/policy_parser.c | 1 +
6 files changed, 13 insertions(+)
diff --git a/security/ipe/audit.c b/security/ipe/audit.c
index fec98c396d49..bcb3e6c0a310 100644
--- a/security/ipe/audit.c
+++ b/security/ipe/audit.c
@@ -42,6 +42,7 @@ static const char *const audit_op_names[__IPE_OP_MAX + 1] = {
"POLICY",
"X509_CERT",
"BPF_PROG_LOAD",
+ "BPF_PROG_LOAD_POST_INTEGRITY",
"UNKNOWN",
};
@@ -53,6 +54,7 @@ static const char *const audit_hook_names[__IPE_HOOK_MAX] = {
"KERNEL_READ",
"KERNEL_LOAD",
"BPF_PROG_LOAD",
+ "BPF_PROG_LOAD_POST_INTEGRITY",
};
static const char *const audit_prop_names[__IPE_PROP_MAX] = {
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index bdc1b634bb08..3f6e260a8787 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -335,6 +335,12 @@ int ipe_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
return ipe_evaluate_event(&ctx);
}
+/**
+ * ipe_bpf_prog_load_post_integrity() - IPE hook for post-integrity verdict.
+ * @prog: The loader BPF program.
+ *
+ * Return: %0 on success, %-EACCES if denied by policy.
+ */
int ipe_bpf_prog_load_post_integrity(struct bpf_prog *prog)
{
struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
diff --git a/security/ipe/hooks.h b/security/ipe/hooks.h
index abdedd436aa8..bd24067705ea 100644
--- a/security/ipe/hooks.h
+++ b/security/ipe/hooks.h
@@ -20,6 +20,7 @@ enum ipe_hook_type {
IPE_HOOK_KERNEL_READ,
IPE_HOOK_KERNEL_LOAD,
IPE_HOOK_BPF_PROG_LOAD,
+ IPE_HOOK_BPF_PROG_LOAD_POST_INTEGRITY,
__IPE_HOOK_MAX
};
@@ -57,6 +58,7 @@ int ipe_inode_setintegrity(const struct inode *inode, enum lsm_integrity_type ty
#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
int ipe_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
struct bpf_token *token, bool kernel);
+int ipe_bpf_prog_load_post_integrity(struct bpf_prog *prog);
#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
#endif /* _IPE_HOOKS_H */
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 17ace9236253..d5e6f339639a 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -62,6 +62,7 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = {
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
LSM_HOOK_INIT(bpf_prog_load, ipe_bpf_prog_load),
+ LSM_HOOK_INIT(bpf_prog_load_post_integrity, ipe_bpf_prog_load_post_integrity),
#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
};
diff --git a/security/ipe/policy.h b/security/ipe/policy.h
index eb066750a48b..84b3e69e618d 100644
--- a/security/ipe/policy.h
+++ b/security/ipe/policy.h
@@ -18,6 +18,7 @@ enum ipe_op_type {
IPE_OP_POLICY,
IPE_OP_X509,
IPE_OP_BPF_PROG_LOAD,
+ IPE_OP_BPF_PROG_LOAD_POST_INTEGRITY,
__IPE_OP_MAX,
};
diff --git a/security/ipe/policy_parser.c b/security/ipe/policy_parser.c
index c1e374d2ec34..350cc93a1af1 100644
--- a/security/ipe/policy_parser.c
+++ b/security/ipe/policy_parser.c
@@ -238,6 +238,7 @@ static const match_table_t operation_tokens = {
{IPE_OP_POLICY, "op=POLICY"},
{IPE_OP_X509, "op=X509_CERT"},
{IPE_OP_BPF_PROG_LOAD, "op=BPF_PROG_LOAD"},
+ {IPE_OP_BPF_PROG_LOAD_POST_INTEGRITY, "op=BPF_PROG_LOAD_POST_INTEGRITY"},
{IPE_OP_INVALID, NULL}
};
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 11/13] ipe: add BPF program signature properties
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
Wire IPE to the BPF signing verdict stored in prog->aux->sig before
security_bpf_prog_load fires. Add three properties on a new IPE op
BPF_PROG_LOAD:
bpf_signature= UNSIGNED | OK | METADATA_VERIFIED
bpf_keyring= BUILTIN | SECONDARY | PLATFORM | USER
bpf_kernel= TRUE | FALSE
Example policy:
op=BPF_PROG_LOAD bpf_signature=UNSIGNED action=DENY
op=BPF_PROG_LOAD bpf_signature=OK action=ALLOW
Gated by CONFIG_IPE_PROP_BPF_SIGNATURE (depends on BPF_SYSCALL).
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
security/ipe/Kconfig | 14 +++++++++
security/ipe/audit.c | 11 +++++++
security/ipe/eval.c | 57 ++++++++++++++++++++++++++++++++++++
security/ipe/eval.h | 5 ++++
security/ipe/hooks.c | 36 +++++++++++++++++++++++
security/ipe/hooks.h | 7 +++++
security/ipe/ipe.c | 3 ++
security/ipe/policy.h | 10 +++++++
security/ipe/policy_parser.c | 19 ++++++++++++
9 files changed, 162 insertions(+)
diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig
index a110a6cd848b..204517c60a34 100644
--- a/security/ipe/Kconfig
+++ b/security/ipe/Kconfig
@@ -13,6 +13,7 @@ menuconfig SECURITY_IPE
select IPE_PROP_DM_VERITY_SIGNATURE if DM_VERITY && DM_VERITY_VERIFY_ROOTHASH_SIG
select IPE_PROP_FS_VERITY if FS_VERITY
select IPE_PROP_FS_VERITY_BUILTIN_SIG if FS_VERITY && FS_VERITY_BUILTIN_SIGNATURES
+ select IPE_PROP_BPF_SIGNATURE if BPF_SYSCALL
help
This option enables the Integrity Policy Enforcement LSM
allowing users to define a policy to enforce a trust-based access
@@ -95,6 +96,19 @@ config IPE_PROP_FS_VERITY_BUILTIN_SIG
if unsure, answer Y.
+config IPE_PROP_BPF_SIGNATURE
+ bool "Enable support for BPF program signature verdicts"
+ depends on BPF_SYSCALL
+ help
+ This option enables the 'bpf_signature', 'bpf_keyring' and
+ 'bpf_kernel' properties within IPE policies. The properties
+ These allow
+ policy rules to gate BPF program loads based on the loader's
+ signature verdict, the keyring used for verification, and
+ whether the load originated in kernel mode.
+
+ if unsure, answer Y.
+
endmenu
config SECURITY_IPE_KUNIT_TEST
diff --git a/security/ipe/audit.c b/security/ipe/audit.c
index 93fb59fbddd6..fec98c396d49 100644
--- a/security/ipe/audit.c
+++ b/security/ipe/audit.c
@@ -41,6 +41,7 @@ static const char *const audit_op_names[__IPE_OP_MAX + 1] = {
"KEXEC_INITRAMFS",
"POLICY",
"X509_CERT",
+ "BPF_PROG_LOAD",
"UNKNOWN",
};
@@ -51,6 +52,7 @@ static const char *const audit_hook_names[__IPE_HOOK_MAX] = {
"MPROTECT",
"KERNEL_READ",
"KERNEL_LOAD",
+ "BPF_PROG_LOAD",
};
static const char *const audit_prop_names[__IPE_PROP_MAX] = {
@@ -62,6 +64,15 @@ static const char *const audit_prop_names[__IPE_PROP_MAX] = {
"fsverity_digest=",
"fsverity_signature=FALSE",
"fsverity_signature=TRUE",
+ "bpf_signature=UNSIGNED",
+ "bpf_signature=OK",
+ "bpf_signature=METADATA_VERIFIED",
+ "bpf_keyring=BUILTIN",
+ "bpf_keyring=SECONDARY",
+ "bpf_keyring=PLATFORM",
+ "bpf_keyring=USER",
+ "bpf_kernel=FALSE",
+ "bpf_kernel=TRUE",
};
/**
diff --git a/security/ipe/eval.c b/security/ipe/eval.c
index 21439c5be336..e4b4e3723fc8 100644
--- a/security/ipe/eval.c
+++ b/security/ipe/eval.c
@@ -11,6 +11,7 @@
#include <linux/rcupdate.h>
#include <linux/moduleparam.h>
#include <linux/fsverity.h>
+#include <linux/bpf.h>
#include "ipe.h"
#include "eval.h"
@@ -265,6 +266,44 @@ static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx)
}
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
+static bool evaluate_bpf_verdict(const struct ipe_eval_ctx *const ctx,
+ enum bpf_sig_verdict expected)
+{
+ return ctx->bpf_verdict == expected;
+}
+
+static bool evaluate_bpf_keyring(const struct ipe_eval_ctx *const ctx,
+ enum bpf_sig_keyring expected)
+{
+ return ctx->bpf_keyring == expected;
+}
+
+static bool evaluate_bpf_kernel(const struct ipe_eval_ctx *const ctx,
+ bool expected)
+{
+ return ctx->bpf_kernel == expected;
+}
+#else
+static bool evaluate_bpf_verdict(const struct ipe_eval_ctx *const ctx,
+ enum bpf_sig_verdict expected)
+{
+ return false;
+}
+
+static bool evaluate_bpf_keyring(const struct ipe_eval_ctx *const ctx,
+ enum bpf_sig_keyring expected)
+{
+ return false;
+}
+
+static bool evaluate_bpf_kernel(const struct ipe_eval_ctx *const ctx,
+ bool expected)
+{
+ return false;
+}
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
+
/**
* evaluate_property() - Analyze @ctx against a rule property.
* @ctx: Supplies a pointer to the context to be evaluated.
@@ -297,6 +336,24 @@ static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
return evaluate_fsv_sig_false(ctx);
case IPE_PROP_FSV_SIG_TRUE:
return evaluate_fsv_sig_true(ctx);
+ case IPE_PROP_BPF_SIG_UNSIGNED:
+ return evaluate_bpf_verdict(ctx, BPF_SIG_UNSIGNED);
+ case IPE_PROP_BPF_SIG_OK:
+ return evaluate_bpf_verdict(ctx, BPF_SIG_OK);
+ case IPE_PROP_BPF_SIG_METADATA_VERIFIED:
+ return evaluate_bpf_verdict(ctx, BPF_SIG_METADATA_VERIFIED);
+ case IPE_PROP_BPF_KEYRING_BUILTIN:
+ return evaluate_bpf_keyring(ctx, BPF_SIG_KEYRING_BUILTIN);
+ case IPE_PROP_BPF_KEYRING_SECONDARY:
+ return evaluate_bpf_keyring(ctx, BPF_SIG_KEYRING_SECONDARY);
+ case IPE_PROP_BPF_KEYRING_PLATFORM:
+ return evaluate_bpf_keyring(ctx, BPF_SIG_KEYRING_PLATFORM);
+ case IPE_PROP_BPF_KEYRING_USER:
+ return evaluate_bpf_keyring(ctx, BPF_SIG_KEYRING_USER);
+ case IPE_PROP_BPF_KERNEL_FALSE:
+ return evaluate_bpf_kernel(ctx, false);
+ case IPE_PROP_BPF_KERNEL_TRUE:
+ return evaluate_bpf_kernel(ctx, true);
default:
return false;
}
diff --git a/security/ipe/eval.h b/security/ipe/eval.h
index fef65a36468c..2ddf89695818 100644
--- a/security/ipe/eval.h
+++ b/security/ipe/eval.h
@@ -52,6 +52,11 @@ struct ipe_eval_ctx {
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
const struct ipe_inode *ipe_inode;
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
+ u8 bpf_verdict; /* enum bpf_sig_verdict */
+ u8 bpf_keyring; /* enum bpf_sig_keyring */
+ bool bpf_kernel;
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
};
enum ipe_match {
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index 0ae54a880405..bdc1b634bb08 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -312,6 +312,42 @@ int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type typ
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
+/**
+ * ipe_bpf_prog_load() - IPE hook for BPF program load.
+ * @prog: The BPF program being loaded.
+ * @attr: BPF syscall attributes.
+ * @token: BPF token.
+ * @kernel: Whether the load originated in kernel mode.
+ *
+ * Return: %0 on success, %-EACCES if denied by policy.
+ */
+int ipe_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
+ struct bpf_token *token, bool kernel)
+{
+ struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
+
+ ipe_build_eval_ctx(&ctx, NULL, IPE_OP_BPF_PROG_LOAD,
+ IPE_HOOK_BPF_PROG_LOAD);
+ ctx.bpf_verdict = prog->aux->sig.verdict;
+ ctx.bpf_keyring = prog->aux->sig.keyring;
+ ctx.bpf_kernel = kernel;
+ return ipe_evaluate_event(&ctx);
+}
+
+int ipe_bpf_prog_load_post_integrity(struct bpf_prog *prog)
+{
+ struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
+
+ ipe_build_eval_ctx(&ctx, NULL, IPE_OP_BPF_PROG_LOAD_POST_INTEGRITY,
+ IPE_HOOK_BPF_PROG_LOAD_POST_INTEGRITY);
+ ctx.bpf_verdict = BPF_SIG_METADATA_VERIFIED;
+ ctx.bpf_keyring = prog->aux->sig.keyring;
+ ctx.bpf_kernel = prog->aux->is_kernel;
+ return ipe_evaluate_event(&ctx);
+}
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
/**
* ipe_inode_setintegrity() - save integrity data from a inode to IPE's LSM blob.
diff --git a/security/ipe/hooks.h b/security/ipe/hooks.h
index 07db37332740..abdedd436aa8 100644
--- a/security/ipe/hooks.h
+++ b/security/ipe/hooks.h
@@ -10,6 +10,7 @@
#include <linux/security.h>
#include <linux/blk_types.h>
#include <linux/fsverity.h>
+#include <linux/bpf.h>
enum ipe_hook_type {
IPE_HOOK_BPRM_CHECK = 0,
@@ -18,6 +19,7 @@ enum ipe_hook_type {
IPE_HOOK_MPROTECT,
IPE_HOOK_KERNEL_READ,
IPE_HOOK_KERNEL_LOAD,
+ IPE_HOOK_BPF_PROG_LOAD,
__IPE_HOOK_MAX
};
@@ -52,4 +54,9 @@ int ipe_inode_setintegrity(const struct inode *inode, enum lsm_integrity_type ty
const void *value, size_t size);
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
+int ipe_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
+ struct bpf_token *token, bool kernel);
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
+
#endif /* _IPE_HOOKS_H */
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 495bb765de1b..17ace9236253 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -60,6 +60,9 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = {
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
LSM_HOOK_INIT(inode_setintegrity, ipe_inode_setintegrity),
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
+ LSM_HOOK_INIT(bpf_prog_load, ipe_bpf_prog_load),
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
};
/**
diff --git a/security/ipe/policy.h b/security/ipe/policy.h
index 5bfbdbddeef8..eb066750a48b 100644
--- a/security/ipe/policy.h
+++ b/security/ipe/policy.h
@@ -17,6 +17,7 @@ enum ipe_op_type {
IPE_OP_KEXEC_INITRAMFS,
IPE_OP_POLICY,
IPE_OP_X509,
+ IPE_OP_BPF_PROG_LOAD,
__IPE_OP_MAX,
};
@@ -39,6 +40,15 @@ enum ipe_prop_type {
IPE_PROP_FSV_DIGEST,
IPE_PROP_FSV_SIG_FALSE,
IPE_PROP_FSV_SIG_TRUE,
+ IPE_PROP_BPF_SIG_UNSIGNED,
+ IPE_PROP_BPF_SIG_OK,
+ IPE_PROP_BPF_SIG_METADATA_VERIFIED,
+ IPE_PROP_BPF_KEYRING_BUILTIN,
+ IPE_PROP_BPF_KEYRING_SECONDARY,
+ IPE_PROP_BPF_KEYRING_PLATFORM,
+ IPE_PROP_BPF_KEYRING_USER,
+ IPE_PROP_BPF_KERNEL_FALSE,
+ IPE_PROP_BPF_KERNEL_TRUE,
__IPE_PROP_MAX
};
diff --git a/security/ipe/policy_parser.c b/security/ipe/policy_parser.c
index 6fa5bebf8471..c1e374d2ec34 100644
--- a/security/ipe/policy_parser.c
+++ b/security/ipe/policy_parser.c
@@ -237,6 +237,7 @@ static const match_table_t operation_tokens = {
{IPE_OP_KEXEC_INITRAMFS, "op=KEXEC_INITRAMFS"},
{IPE_OP_POLICY, "op=POLICY"},
{IPE_OP_X509, "op=X509_CERT"},
+ {IPE_OP_BPF_PROG_LOAD, "op=BPF_PROG_LOAD"},
{IPE_OP_INVALID, NULL}
};
@@ -281,6 +282,15 @@ static const match_table_t property_tokens = {
{IPE_PROP_FSV_DIGEST, "fsverity_digest=%s"},
{IPE_PROP_FSV_SIG_FALSE, "fsverity_signature=FALSE"},
{IPE_PROP_FSV_SIG_TRUE, "fsverity_signature=TRUE"},
+ {IPE_PROP_BPF_SIG_UNSIGNED, "bpf_signature=UNSIGNED"},
+ {IPE_PROP_BPF_SIG_OK, "bpf_signature=OK"},
+ {IPE_PROP_BPF_SIG_METADATA_VERIFIED, "bpf_signature=METADATA_VERIFIED"},
+ {IPE_PROP_BPF_KEYRING_BUILTIN, "bpf_keyring=BUILTIN"},
+ {IPE_PROP_BPF_KEYRING_SECONDARY, "bpf_keyring=SECONDARY"},
+ {IPE_PROP_BPF_KEYRING_PLATFORM, "bpf_keyring=PLATFORM"},
+ {IPE_PROP_BPF_KEYRING_USER, "bpf_keyring=USER"},
+ {IPE_PROP_BPF_KERNEL_FALSE, "bpf_kernel=FALSE"},
+ {IPE_PROP_BPF_KERNEL_TRUE, "bpf_kernel=TRUE"},
{IPE_PROP_INVALID, NULL}
};
@@ -331,6 +341,15 @@ static int parse_property(char *t, struct ipe_rule *r)
case IPE_PROP_DMV_SIG_TRUE:
case IPE_PROP_FSV_SIG_FALSE:
case IPE_PROP_FSV_SIG_TRUE:
+ case IPE_PROP_BPF_SIG_UNSIGNED:
+ case IPE_PROP_BPF_SIG_OK:
+ case IPE_PROP_BPF_SIG_METADATA_VERIFIED:
+ case IPE_PROP_BPF_KEYRING_BUILTIN:
+ case IPE_PROP_BPF_KEYRING_SECONDARY:
+ case IPE_PROP_BPF_KEYRING_PLATFORM:
+ case IPE_PROP_BPF_KEYRING_USER:
+ case IPE_PROP_BPF_KERNEL_FALSE:
+ case IPE_PROP_BPF_KERNEL_TRUE:
p->type = token;
break;
default:
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 10/13] bpf: invoke security_bpf_prog_load_post_integrity from the metadata kfunc
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
Call security_bpf_prog_load_post_integrity from
bpf_loader_verify_metadata just before promoting
prog->aux->sig.verdict from BPF_SIG_OK to BPF_SIG_METADATA_VERIFIED.
This lets policy LSMs deny the metadata-verified transition.
A non-zero return aborts the kfunc and leaves the verdict at
BPF_SIG_OK; observers that key off METADATA_VERIFIED never see a
verdict the LSM denied.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
kernel/bpf/helpers.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 9afa71fbcac3..52e71fb6e200 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -4300,6 +4300,14 @@ __bpf_kfunc int bpf_loader_verify_metadata(struct bpf_map *map,
if (memcmp(sha, hash, SHA256_DIGEST_SIZE))
return -EBADMSG;
+ /* Metadata integrity is decided by the checks above; the LSM hook
+ * is an observer of that verdict and may apply policy (e.g. deny),
+ * but cannot vouch for integrity it did not verify itself.
+ */
+ err = security_bpf_prog_load_post_integrity(aux__ign->prog);
+ if (err)
+ return err;
+
aux__ign->sig.verdict = BPF_SIG_METADATA_VERIFIED;
return 0;
}
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 09/13] lsm: add bpf_prog_load_post_integrity hook
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
Add a companion to security_bpf_prog_load. The existing hook fires
at PROG_LOAD entry where the verdict is at most BPF_SIG_OK; the new
hook fires from bpf_loader_verify_metadata after the in-kernel
metadata check, just before sig.verdict is promoted to
BPF_SIG_METADATA_VERIFIED. Policy LSMs that want to gate on
metadata verification (not just signature presence) register here.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
include/linux/lsm_hook_defs.h | 1 +
include/linux/security.h | 6 ++++++
security/security.c | 17 +++++++++++++++++
3 files changed, 24 insertions(+)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2b8dfb35caed..c0e7899756d4 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -446,6 +446,7 @@ LSM_HOOK(int, 0, bpf_map_create, struct bpf_map *map, union bpf_attr *attr,
LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map)
LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr,
struct bpf_token *token, bool kernel)
+LSM_HOOK(int, 0, bpf_prog_load_post_integrity, struct bpf_prog *prog)
LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog)
LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr,
const struct path *path)
diff --git a/include/linux/security.h b/include/linux/security.h
index 41d7367cf403..3a8f2c50f7be 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -2305,6 +2305,7 @@ extern int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
extern void security_bpf_map_free(struct bpf_map *map);
extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
struct bpf_token *token, bool kernel);
+extern int security_bpf_prog_load_post_integrity(struct bpf_prog *prog);
extern void security_bpf_prog_free(struct bpf_prog *prog);
extern int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
const struct path *path);
@@ -2343,6 +2344,11 @@ static inline int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *
return 0;
}
+static inline int security_bpf_prog_load_post_integrity(struct bpf_prog *prog)
+{
+ return 0;
+}
+
static inline void security_bpf_prog_free(struct bpf_prog *prog)
{ }
diff --git a/security/security.c b/security/security.c
index 4e999f023651..05153e8496c9 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5383,6 +5383,23 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
return rc;
}
+/**
+ * security_bpf_prog_load_post_integrity() - Notify LSMs that a signed loader
+ * has just verified its metadata map.
+ * @prog: the loader BPF program whose metadata check passed.
+ *
+ * Invoked by bpf_loader_verify_metadata() after the kernel-side hash check
+ * succeeds, before prog->aux->sig_verdict is promoted to
+ * BPF_SIG_METADATA_VERIFIED. A non-zero return aborts the kfunc and leaves
+ * the verdict at BPF_SIG_OK.
+ *
+ * Return: 0 on success, negative errno to deny.
+ */
+int security_bpf_prog_load_post_integrity(struct bpf_prog *prog)
+{
+ return call_int_hook(bpf_prog_load_post_integrity, prog);
+}
+
/**
* security_bpf_token_create() - Check if creating of BPF token is allowed
* @token: BPF token object
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 08/13] bpftool gen: embed loader prog BTF in the lskel header
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
Extend the signed lskel codegen to include the loader prog BTF in
the generated header and the PKCS#7 signature scope. The loader
needs this BTF at load time so the kernel can resolve kfunc calls
by name.
Lskels generated without -S are unchanged; the new codegen is gated
on opts.btf_sz.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
tools/bpf/bpftool/gen.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 2f9e10752e28..95dba5c53ef4 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -793,6 +793,8 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
if (sign_progs) {
sopts.insns = opts.insns;
sopts.insns_sz = opts.insns_sz;
+ sopts.btf = opts.btf;
+ sopts.btf_sz = opts.btf_sz;
sopts.excl_prog_hash = prog_sha;
sopts.excl_prog_hash_sz = sizeof(prog_sha);
sopts.signature = sig_buf;
@@ -822,6 +824,17 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
\n\
\";\n");
+ if (opts.btf_sz) {
+ codegen("\
+ \n\
+ static const char opts_btf[] __attribute__((__aligned__(8))) = \"\\\n\
+ ");
+ print_hex(opts.btf, opts.btf_sz);
+ codegen("\
+ \n\
+ \";\n");
+ }
+
codegen("\
\n\
opts.signature = (void *)opts_sig; \n\
@@ -830,6 +843,14 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
opts.excl_prog_hash_sz = sizeof(opts_excl_hash) - 1; \n\
opts.keyring_id = skel->keyring_id; \n\
");
+
+ if (opts.btf_sz) {
+ codegen("\
+ \n\
+ opts.btf = (void *)opts_btf; \n\
+ opts.btf_sz = sizeof(opts_btf) - 1; \n\
+ ");
+ }
}
codegen("\
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 07/13] libbpf: generate prog BTF for loader programs
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
For signed loaders, build a minimal prog BTF containing one FUNC entry
for bpf_loader_verify_metadata with a FUNC_PROTO of primitives (int,
void *) so the bytes are reproducible across build hosts.
In emit_verify_metadata, spill four signed ld_imm64 immediates into
a 32-byte stack buffer and invoke the kfunc once with (map, &buf, 32),
replacing ~24 inline dword comparisons. Expose the serialized BTF on
gen_loader_opts from bpf_gen__finish so bpftool gen can embed it in
the lskel.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
tools/lib/bpf/bpf_gen_internal.h | 2 +
tools/lib/bpf/gen_loader.c | 127 ++++++++++++++++++++++++-------
tools/lib/bpf/libbpf.h | 4 +-
3 files changed, 105 insertions(+), 28 deletions(-)
diff --git a/tools/lib/bpf/bpf_gen_internal.h b/tools/lib/bpf/bpf_gen_internal.h
index 49af4260b8e6..e4aed9e99b56 100644
--- a/tools/lib/bpf/bpf_gen_internal.h
+++ b/tools/lib/bpf/bpf_gen_internal.h
@@ -52,6 +52,8 @@ struct bpf_gen {
int fd_array;
int nr_fd_array;
int hash_insn_offset[SHA256_DWORD_SIZE];
+ struct btf *loader_btf;
+ int loader_btf_func_id;
};
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps);
diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c
index fee35c26deb8..48ac25c058e3 100644
--- a/tools/lib/bpf/gen_loader.c
+++ b/tools/lib/bpf/gen_loader.c
@@ -35,6 +35,7 @@ struct loader_stack {
__u32 btf_fd;
__u32 inner_map_fd;
__u32 prog_fd[MAX_USED_PROGS];
+ __u64 metadata_hash[SHA256_DWORD_SIZE];
};
#define stack_off(field) \
@@ -109,7 +110,7 @@ static void emit2(struct bpf_gen *gen, struct bpf_insn insn1, struct bpf_insn in
static int add_data(struct bpf_gen *gen, const void *data, __u32 size);
static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off);
-static void emit_signature_match(struct bpf_gen *gen);
+static void emit_verify_metadata(struct bpf_gen *gen);
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps)
{
@@ -152,8 +153,68 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps
/* R7 contains the error code from sys_bpf. Copy it into R0 and exit. */
emit(gen, BPF_MOV64_REG(BPF_REG_0, BPF_REG_7));
emit(gen, BPF_EXIT_INSN());
- if (OPTS_GET(gen->opts, gen_hash, false))
- emit_signature_match(gen);
+ if (OPTS_GET(gen->opts, gen_hash, false)) {
+ int int_id, u32_id, ptr_id, proto_id, err;
+
+ /* Prog BTF built from primitives so the bytes are reproducible
+ * across build hosts.
+ */
+ gen->loader_btf = btf__new_empty();
+ if (libbpf_get_error(gen->loader_btf)) {
+ gen->error = -ENOMEM;
+ gen->loader_btf = NULL;
+ return;
+ }
+ if (gen->swapped_endian) {
+ enum btf_endianness target =
+ btf__endianness(gen->loader_btf) == BTF_LITTLE_ENDIAN
+ ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN;
+
+ err = btf__set_endianness(gen->loader_btf, target);
+ if (err) {
+ gen->error = err;
+ return;
+ }
+ }
+ int_id = btf__add_int(gen->loader_btf, "int", 4, BTF_INT_SIGNED);
+ if (int_id < 0) {
+ gen->error = int_id;
+ return;
+ }
+ u32_id = btf__add_int(gen->loader_btf, "u32", 4, 0);
+ if (u32_id < 0) {
+ gen->error = u32_id;
+ return;
+ }
+ ptr_id = btf__add_ptr(gen->loader_btf, 0);
+ if (ptr_id < 0) {
+ gen->error = ptr_id;
+ return;
+ }
+ proto_id = btf__add_func_proto(gen->loader_btf, int_id);
+ if (proto_id < 0) {
+ gen->error = proto_id;
+ return;
+ }
+ err = btf__add_func_param(gen->loader_btf, "map", ptr_id);
+ if (!err)
+ err = btf__add_func_param(gen->loader_btf, "hash", ptr_id);
+ if (!err)
+ err = btf__add_func_param(gen->loader_btf, "hash__sz", u32_id);
+ if (err) {
+ gen->error = err;
+ return;
+ }
+ gen->loader_btf_func_id = btf__add_func(gen->loader_btf,
+ "bpf_loader_verify_metadata",
+ BTF_FUNC_GLOBAL, proto_id);
+ if (gen->loader_btf_func_id < 0) {
+ gen->error = gen->loader_btf_func_id;
+ gen->loader_btf_func_id = 0;
+ return;
+ }
+ emit_verify_metadata(gen);
+ }
}
static int add_data(struct bpf_gen *gen, const void *data, __u32 size)
@@ -398,7 +459,7 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
blob_fd_array_off(gen, i));
emit(gen, BPF_MOV64_IMM(BPF_REG_0, 0));
emit(gen, BPF_EXIT_INSN());
- if (OPTS_GET(gen->opts, gen_hash, false))
+ if (!gen->error && OPTS_GET(gen->opts, gen_hash, false))
compute_sha_update_offsets(gen);
pr_debug("gen: finish %s\n", errstr(gen->error));
@@ -410,6 +471,19 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
opts->data = gen->data_start;
opts->data_sz = gen->data_cur - gen->data_start;
+ if (gen->loader_btf) {
+ __u32 btf_sz = 0;
+ const void *btf_data;
+
+ btf_data = btf__raw_data(gen->loader_btf, &btf_sz);
+ if (!btf_data) {
+ gen->error = -ENOMEM;
+ return gen->error;
+ }
+ OPTS_SET(opts, btf, btf_data);
+ OPTS_SET(opts, btf_sz, btf_sz);
+ }
+
/* use target endianness for embedded loader */
if (gen->swapped_endian) {
struct bpf_insn *insn = (struct bpf_insn *)opts->insns;
@@ -426,6 +500,7 @@ void bpf_gen__free(struct bpf_gen *gen)
{
if (!gen)
return;
+ btf__free(gen->loader_btf);
free(gen->data_start);
free(gen->insn_start);
free(gen);
@@ -580,39 +655,37 @@ void bpf_gen__map_create(struct bpf_gen *gen,
emit_sys_close_stack(gen, stack_off(inner_map_fd));
}
-static void emit_signature_match(struct bpf_gen *gen)
+static void emit_verify_metadata(struct bpf_gen *gen)
{
__s64 off;
int i;
+ /* arg1: metadata struct bpf_map */
+ emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
+ 0, 0, 0, 0));
+
+ /* arg2: hash buffer on our BPF stack, populated from ld_imm64
+ * immediates patched in by compute_sha_update_offsets() before signing.
+ */
+ emit(gen, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
+ emit(gen, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, stack_off(metadata_hash)));
for (i = 0; i < SHA256_DWORD_SIZE; i++) {
- emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
- 0, 0, 0, 0));
- emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, i * sizeof(__u64)));
gen->hash_insn_offset[i] = gen->insn_cur - gen->insn_start;
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_3, 0, 0, 0, 0, 0));
-
- off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 2;
- if (is_simm16(off)) {
- emit(gen, BPF_MOV64_IMM(BPF_REG_7, -EINVAL));
- emit(gen, BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, off));
- } else {
- gen->error = -ERANGE;
- }
+ emit(gen, BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3,
+ i * sizeof(__u64)));
}
- /* Reject if the metadata map is not exclusive. Without exclusivity
- * the cached map->sha[] verified above can be stale: another BPF
- * program with map access could have mutated the contents between
- * BPF_OBJ_GET_INFO_BY_FD and loader execution.
- */
- emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
- 0, 0, 0, 0));
- emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, SHA256_DWORD_SIZE * sizeof(__u64)));
- off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 2;
+ /* arg3: hash length */
+ emit(gen, BPF_MOV64_IMM(BPF_REG_3, SHA256_DWORD_SIZE * sizeof(__u64)));
+
+ emit(gen, BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0,
+ BPF_PSEUDO_KFUNC_CALL_PROG_BTF, 0,
+ gen->loader_btf_func_id));
+ emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
+ off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 1;
if (is_simm16(off)) {
- emit(gen, BPF_MOV64_IMM(BPF_REG_7, -EINVAL));
- emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, off));
+ emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, off));
} else {
gen->error = -ERANGE;
}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index bba4e8464396..25906fb695f9 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -1899,9 +1899,11 @@ struct gen_loader_opts {
__u32 data_sz;
__u32 insns_sz;
bool gen_hash;
+ const void *btf;
+ __u32 btf_sz;
};
-#define gen_loader_opts__last_field gen_hash
+#define gen_loader_opts__last_field btf_sz
LIBBPF_API int bpf_object__gen_loader(struct bpf_object *obj,
struct gen_loader_opts *opts);
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 06/13] bpf: resolve loader-style kfunc CALLs against prog BTF
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
gen_loader-emitted signed loaders cannot bake vmlinux BTF ids into
kfunc CALL imm at sign time. Add a new pseudo
BPF_PSEUDO_KFUNC_CALL_PROG_BTF that gen_loader emits in src_reg, with
imm holding the FUNC type id in the loader's own prog BTF.
In add_subprog_and_kfunc, look the FUNC up by name in vmlinux BTF,
patch imm with the resolved id, and rewrite src_reg back to
BPF_PSEUDO_KFUNC_CALL so downstream passes see a normal kfunc CALL.
Leave standard src_reg calls unchanged.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
include/linux/bpf_verifier.h | 6 ++++
include/uapi/linux/bpf.h | 5 ++++
kernel/bpf/verifier.c | 54 ++++++++++++++++++++++++++++++++--
tools/include/uapi/linux/bpf.h | 5 ++++
4 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 185b2aa43a42..396b85830996 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -959,6 +959,12 @@ static inline bool bpf_pseudo_kfunc_call(const struct bpf_insn *insn)
insn->src_reg == BPF_PSEUDO_KFUNC_CALL;
}
+static inline bool bpf_pseudo_kfunc_call_prog_btf(const struct bpf_insn *insn)
+{
+ return insn->code == (BPF_JMP | BPF_CALL) &&
+ insn->src_reg == BPF_PSEUDO_KFUNC_CALL_PROG_BTF;
+}
+
__printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log,
const char *fmt, va_list args);
__printf(2, 3) void bpf_verifier_log_write(struct bpf_verifier_env *env,
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 552bc5d9afbd..06056e714e8e 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1382,6 +1382,11 @@ enum {
* bpf_call->imm == btf_id of a BTF_KIND_FUNC in the running kernel
*/
#define BPF_PSEUDO_KFUNC_CALL 2
+/* when bpf_call->src_reg == BPF_PSEUDO_KFUNC_CALL_PROG_BTF,
+ * bpf_call->imm == btf_id of a BTF_KIND_FUNC in the program's
+ * prog BTF. The verifier resolves it to a vmlinux btf_id by name.
+ */
+#define BPF_PSEUDO_KFUNC_CALL_PROG_BTF 3
enum bpf_addr_space_cast {
BPF_ADDR_SPACE_CAST = 1,
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index f0e45cfa5b34..1b5d06b9d74a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3088,6 +3088,47 @@ bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog)
return !!prog->aux->kfunc_tab;
}
+/*
+ * Resolve a gen_loader-emitted kfunc CALL by FUNC name in vmlinux BTF,
+ * then rewrite src_reg back to BPF_PSEUDO_KFUNC_CALL. Caller must have
+ * already filtered for BPF_PSEUDO_KFUNC_CALL_PROG_BTF.
+ */
+static int resolve_loader_kfunc(struct bpf_verifier_env *env,
+ struct bpf_insn *insn, int insn_idx)
+{
+ struct btf *prog_btf = env->prog->aux->btf;
+ const struct btf_type *t;
+ const char *name;
+ s32 vmlinux_id;
+
+ if (!prog_btf || !btf_vmlinux || insn->off) {
+ verbose(env, "kfunc call insn %d: PROG_BTF resolution requires prog BTF and insn->off == 0\n",
+ insn_idx);
+ return -EINVAL;
+ }
+ t = btf_type_by_id(prog_btf, insn->imm);
+ if (!t || !btf_type_is_func(t)) {
+ verbose(env, "kfunc call insn %d: imm %d is not a FUNC in prog BTF\n",
+ insn_idx, insn->imm);
+ return -EINVAL;
+ }
+ name = btf_name_by_offset(prog_btf, t->name_off);
+ if (!name || !name[0]) {
+ verbose(env, "kfunc call insn %d: prog-BTF FUNC has no name\n",
+ insn_idx);
+ return -EINVAL;
+ }
+ vmlinux_id = btf_find_by_name_kind(btf_vmlinux, name, BTF_KIND_FUNC);
+ if (vmlinux_id < 0) {
+ verbose(env, "kfunc call insn %d: %s not found in vmlinux BTF\n",
+ insn_idx, name);
+ return vmlinux_id;
+ }
+ insn->imm = vmlinux_id;
+ insn->src_reg = BPF_PSEUDO_KFUNC_CALL;
+ return 0;
+}
+
static int add_subprog_and_kfunc(struct bpf_verifier_env *env)
{
struct bpf_subprog_info *subprog = env->subprog_info;
@@ -3101,7 +3142,8 @@ static int add_subprog_and_kfunc(struct bpf_verifier_env *env)
for (i = 0; i < insn_cnt; i++, insn++) {
if (!bpf_pseudo_func(insn) && !bpf_pseudo_call(insn) &&
- !bpf_pseudo_kfunc_call(insn))
+ !bpf_pseudo_kfunc_call(insn) &&
+ !bpf_pseudo_kfunc_call_prog_btf(insn))
continue;
if (!env->bpf_capable) {
@@ -3109,10 +3151,16 @@ static int add_subprog_and_kfunc(struct bpf_verifier_env *env)
return -EPERM;
}
- if (bpf_pseudo_func(insn) || bpf_pseudo_call(insn))
+ if (bpf_pseudo_func(insn) || bpf_pseudo_call(insn)) {
ret = add_subprog(env, i + insn->imm + 1);
- else
+ } else {
+ if (bpf_pseudo_kfunc_call_prog_btf(insn)) {
+ ret = resolve_loader_kfunc(env, insn, i);
+ if (ret < 0)
+ return ret;
+ }
ret = bpf_add_kfunc_call(env, insn->imm, insn->off);
+ }
if (ret < 0)
return ret;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 677be9a47347..d4f7f3e0aaa3 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1382,6 +1382,11 @@ enum {
* bpf_call->imm == btf_id of a BTF_KIND_FUNC in the running kernel
*/
#define BPF_PSEUDO_KFUNC_CALL 2
+/* when bpf_call->src_reg == BPF_PSEUDO_KFUNC_CALL_PROG_BTF,
+ * bpf_call->imm == btf_id of a BTF_KIND_FUNC in the program's
+ * prog BTF. The verifier resolves it to a vmlinux btf_id by name.
+ */
+#define BPF_PSEUDO_KFUNC_CALL_PROG_BTF 3
enum bpf_addr_space_cast {
BPF_ADDR_SPACE_CAST = 1,
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 05/13] bpf: compute prog->digest at BPF_PROG_LOAD entry
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
add_subprog_and_kfunc relocates kfunc CALLs by patching insn->imm
and src_reg, and bpf_prog_calc_tag has no rule to mask kfunc CALL
fields. The tag has to be computed over the unmodified user-supplied
insns to match the excl_prog_hash userspace signed, so move the call
to bpf_prog_load right after signature verification.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
kernel/bpf/syscall.c | 7 +++++++
kernel/bpf/verifier.c | 4 ----
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6d1db5eaad3c..39ebd825c136 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3086,6 +3086,13 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
}
prog->aux->is_kernel = uattr.is_kernel;
+ /* Hash insns now, before any verifier-side rewrite, so prog->digest
+ * matches the excl_prog_hash userspace computed.
+ */
+ err = bpf_prog_calc_tag(prog);
+ if (err)
+ goto free_prog;
+
prog->orig_prog = NULL;
prog->jited = 0;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7fb88e1cd7c4..f0e45cfa5b34 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18434,10 +18434,6 @@ static int check_and_resolve_insns(struct bpf_verifier_env *env)
int insn_cnt = env->prog->len;
int i, err;
- err = bpf_prog_calc_tag(env->prog);
- if (err)
- return err;
-
for (i = 0; i < insn_cnt; i++, insn++) {
if (insn->dst_reg >= MAX_BPF_REG) {
verbose(env, "R%d is invalid\n", insn->dst_reg);
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 04/13] bpf: add bpf_loader_verify_metadata kfunc
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
A signed loader reaches sig.verdict = BPF_SIG_OK after PKCS#7
verification, but the metadata map content the loader writes has not
been checked against its expected SHA256. The map carries that SHA256
in the signed instruction stream, spilled to the loader's stack at
runtime as four ld_imm64 immediates.
Assert the map is exclusive, compare its frozen content hash against
the spilled SHA256, and promote sig.verdict to
BPF_SIG_METADATA_VERIFIED. The verifier injects the calling
prog->aux as an implicit argument via KF_IMPLICIT_ARGS so the kfunc
can read the prog digest and signature verdict directly.
Drop skel_obj_get_info_by_fd from bpf_load_and_run since the kfunc
computes the map hash itself via map_get_hash; the prior
BPF_OBJ_GET_INFO_BY_FD call to populate map->sha is not
needed.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
kernel/bpf/helpers.c | 57 +++++++++++++++++++++++++++++++++++
tools/bpf/bpftool/sign.c | 17 ++++++++++-
tools/lib/bpf/skel_internal.h | 25 ---------------
3 files changed, 73 insertions(+), 26 deletions(-)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index b5314c9fed3c..9afa71fbcac3 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -4257,6 +4257,53 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_p,
return -EOPNOTSUPP;
#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
}
+
+/**
+ * bpf_loader_verify_metadata - perform the signed loader's metadata-map check
+ * in a single kernel-side step.
+ *
+ * Asserts the metadata map is exclusive, compares its frozen content hash
+ * against the expected SHA256 carried in the loader's signed instruction
+ * stream, and promotes sig.verdict from BPF_SIG_OK to
+ * BPF_SIG_METADATA_VERIFIED.
+ *
+ * @map: metadata map bound to this loader via excl_prog_hash at sign time
+ * @hash: pointer to the expected SHA256, spilled to the loader's BPF stack
+ * from signed ld_imm64 immediates
+ * @hash__sz: byte length of @hash (must equal SHA256_DIGEST_SIZE)
+ * @aux__ign: verifier-supplied prog aux; BPF programs do not set it
+ *
+ * Return: 0 on success, -EPERM if not called from a signed loader,
+ * -EINVAL if the map is not exclusive or the hash buffer is the wrong size,
+ * -EBADMSG if the hash does not match.
+ */
+__bpf_kfunc int bpf_loader_verify_metadata(struct bpf_map *map,
+ const u64 *hash, u32 hash__sz,
+ struct bpf_prog_aux *aux__ign)
+{
+ u8 sha[SHA256_DIGEST_SIZE];
+ int err;
+
+ if (!aux__ign || aux__ign->sig.verdict != BPF_SIG_OK)
+ return -EPERM;
+ if (!map->excl_prog_sha || hash__sz != SHA256_DIGEST_SIZE)
+ return -EINVAL;
+ if (memcmp(map->excl_prog_sha, aux__ign->prog->digest, SHA256_DIGEST_SIZE))
+ return -EPERM;
+ if (!READ_ONCE(map->frozen))
+ return -EPERM;
+ if (!map->ops->map_get_hash)
+ return -EINVAL;
+ err = map->ops->map_get_hash(map, SHA256_DIGEST_SIZE, sha);
+ if (err)
+ return err;
+ if (memcmp(sha, hash, SHA256_DIGEST_SIZE))
+ return -EBADMSG;
+
+ aux__ign->sig.verdict = BPF_SIG_METADATA_VERIFIED;
+ return 0;
+}
+
#endif /* CONFIG_KEYS */
typedef int (*bpf_task_work_callback_t)(struct bpf_map *map, void *key, void *value);
@@ -4764,6 +4811,15 @@ static const struct btf_kfunc_id_set generic_kfunc_set = {
.set = &generic_btf_ids,
};
+BTF_KFUNCS_START(syscall_btf_ids)
+BTF_ID_FLAGS(func, bpf_loader_verify_metadata, KF_SLEEPABLE | KF_IMPLICIT_ARGS)
+BTF_KFUNCS_END(syscall_btf_ids)
+
+static const struct btf_kfunc_id_set syscall_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &syscall_btf_ids,
+};
+
BTF_ID_LIST(generic_dtor_ids)
BTF_ID(struct, task_struct)
@@ -4893,6 +4949,7 @@ static int __init kfunc_init(void)
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &generic_kfunc_set);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &generic_kfunc_set);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SKB, &generic_kfunc_set);
+ ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &syscall_kfunc_set);
ret = ret ?: register_btf_id_dtor_kfuncs(generic_dtors,
ARRAY_SIZE(generic_dtors),
THIS_MODULE);
diff --git a/tools/bpf/bpftool/sign.c b/tools/bpf/bpftool/sign.c
index f9b742f4bb10..13f256546cf0 100644
--- a/tools/bpf/bpftool/sign.c
+++ b/tools/bpf/bpftool/sign.c
@@ -134,10 +134,24 @@ int bpftool_prog_sign(struct bpf_load_and_run_opts *opts)
EVP_PKEY *private_key = NULL;
CMS_ContentInfo *cms = NULL;
long actual_sig_len = 0;
+ void *signed_buf = NULL;
+ size_t signed_sz;
X509 *x509 = NULL;
int err = 0;
- bd_in = BIO_new_mem_buf(opts->insns, opts->insns_sz);
+ signed_sz = opts->insns_sz + opts->btf_sz;
+ if (opts->btf_sz) {
+ signed_buf = malloc(signed_sz);
+ if (!signed_buf) {
+ err = -ENOMEM;
+ goto cleanup;
+ }
+ memcpy(signed_buf, opts->insns, opts->insns_sz);
+ memcpy(signed_buf + opts->insns_sz, opts->btf, opts->btf_sz);
+ bd_in = BIO_new_mem_buf(signed_buf, signed_sz);
+ } else {
+ bd_in = BIO_new_mem_buf(opts->insns, opts->insns_sz);
+ }
if (!bd_in) {
err = -ENOMEM;
goto cleanup;
@@ -212,6 +226,7 @@ int bpftool_prog_sign(struct bpf_load_and_run_opts *opts)
X509_free(x509);
EVP_PKEY_free(private_key);
BIO_free(bd_in);
+ free(signed_buf);
DISPLAY_OSSL_ERR(err < 0);
return err;
}
diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
index 0b6b1ecedd45..d194f4e23d12 100644
--- a/tools/lib/bpf/skel_internal.h
+++ b/tools/lib/bpf/skel_internal.h
@@ -335,25 +335,6 @@ static inline int skel_link_create(int prog_fd, int target_fd,
return skel_sys_bpf(BPF_LINK_CREATE, &attr, attr_sz);
}
-static inline int skel_obj_get_info_by_fd(int fd)
-{
- const size_t attr_sz = offsetofend(union bpf_attr, info);
- __u8 sha[SHA256_DIGEST_LENGTH];
- struct bpf_map_info info;
- __u32 info_len = sizeof(info);
- union bpf_attr attr;
-
- memset(&info, 0, sizeof(info));
- info.hash = (long) &sha;
- info.hash_size = SHA256_DIGEST_LENGTH;
-
- memset(&attr, 0, attr_sz);
- attr.info.bpf_fd = fd;
- attr.info.info = (long) &info;
- attr.info.info_len = info_len;
- return skel_sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, attr_sz);
-}
-
static inline int skel_map_freeze(int fd)
{
const size_t attr_sz = offsetofend(union bpf_attr, map_fd);
@@ -400,12 +381,6 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
set_err;
goto out;
}
- err = skel_obj_get_info_by_fd(map_fd);
- if (err < 0) {
- opts->errstr = "failed to fetch obj info";
- set_err;
- goto out;
- }
#endif
#ifndef __KERNEL__
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 03/13] bpf, libbpf: load prog BTF in the skel_internal loader
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
bpf_load_and_run loads only the loader insns and the metadata map.
To match the kernel's extended signature scope (insns || btf), the
loader needs to BPF_BTF_LOAD the prog BTF before BPF_PROG_LOAD so
attr->prog_btf_fd can be filled in.
Add btf and btf_sz to bpf_load_and_run_opts; when set, do the
BPF_BTF_LOAD before BPF_PROG_LOAD and pass the resulting fd as
attr->prog_btf_fd.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
tools/lib/bpf/skel_internal.h | 44 ++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
index 6a8f5c7a02eb..0b6b1ecedd45 100644
--- a/tools/lib/bpf/skel_internal.h
+++ b/tools/lib/bpf/skel_internal.h
@@ -11,6 +11,8 @@
#include <linux/bpf.h>
#else
#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <linux/keyctl.h>
@@ -66,8 +68,10 @@ struct bpf_load_and_run_opts {
struct bpf_loader_ctx *ctx;
const void *data;
const void *insns;
+ const void *btf;
__u32 data_sz;
__u32 insns_sz;
+ __u32 btf_sz;
const char *errstr;
void *signature;
__u32 signature_sz;
@@ -88,6 +92,22 @@ static inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
#endif
}
+#ifndef __KERNEL__
+static inline int skel_sys_btf_load(union bpf_attr *attr, unsigned int size)
+{
+ int fd;
+
+ fd = skel_sys_bpf(BPF_BTF_LOAD, attr, size);
+ if (fd >= 0 && fd < 3) {
+ int new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+
+ close(fd);
+ fd = new_fd;
+ }
+ return fd;
+}
+#endif
+
#ifdef __KERNEL__
static inline int close(int fd)
{
@@ -353,8 +373,9 @@ static inline int skel_map_freeze(int fd)
static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
{
const size_t prog_load_attr_sz = offsetofend(union bpf_attr, keyring_id);
+ const size_t btf_load_attr_sz = offsetofend(union bpf_attr, btf_token_fd);
const size_t test_run_attr_sz = offsetofend(union bpf_attr, test);
- int map_fd = -1, prog_fd = -1, key = 0, err;
+ int map_fd = -1, prog_fd = -1, btf_fd = -1, key = 0, err;
union bpf_attr attr;
err = map_fd = skel_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4, opts->data_sz, 1,
@@ -387,11 +408,30 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
}
#endif
+#ifndef __KERNEL__
+ if (opts->btf && opts->btf_sz) {
+ memset(&attr, 0, btf_load_attr_sz);
+ attr.btf = (long) opts->btf;
+ attr.btf_size = opts->btf_sz;
+ attr.btf_log_level = opts->ctx->log_level;
+ attr.btf_log_size = opts->ctx->log_size;
+ attr.btf_log_buf = opts->ctx->log_buf;
+ err = btf_fd = skel_sys_btf_load(&attr, btf_load_attr_sz);
+ if (btf_fd < 0) {
+ opts->errstr = "failed to load loader BTF";
+ set_err;
+ goto out;
+ }
+ }
+#endif
+
memset(&attr, 0, prog_load_attr_sz);
attr.prog_type = BPF_PROG_TYPE_SYSCALL;
attr.insns = (long) opts->insns;
attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
attr.license = (long) "Dual BSD/GPL";
+ if (btf_fd >= 0)
+ attr.prog_btf_fd = btf_fd;
#ifndef __KERNEL__
attr.signature = (long) opts->signature;
attr.signature_size = opts->signature_sz;
@@ -437,6 +477,8 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
close(map_fd);
if (prog_fd >= 0)
close(prog_fd);
+ if (btf_fd >= 0)
+ close(btf_fd);
return err;
}
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 02/13] bpf: include prog BTF in the signed loader signature scope
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
bpf_prog_verify_signature hashes only prog->insnsi, so FUNC names
in prog BTF are not covered by the signature. Since we need to
support kfuncs for loader programs with prog BTF information, the
signature needs to cover BTF so that it can be trusted.
When attr->prog_btf_fd is set, build the verify dynptr over
insns || raw_btf so the signature covers both. Fall back to insns-only
otherwise so existing signed lskels keep loading. Hoist the
prog_btf_fd resolution into bpf_prog_load so the BTF is available
before signature verification.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
include/linux/btf.h | 1 +
kernel/bpf/btf.c | 8 +++++++
kernel/bpf/check_btf.c | 18 +++-------------
kernel/bpf/syscall.c | 49 +++++++++++++++++++++++++++++++++++++-----
4 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/include/linux/btf.h b/include/linux/btf.h
index 48108471c5b1..ab1fe7c8df20 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -216,6 +216,7 @@ int btf_type_snprintf_show(const struct btf *btf, u32 type_id, void *obj,
int btf_get_fd_by_id(u32 id);
u32 btf_obj_id(const struct btf *btf);
bool btf_is_kernel(const struct btf *btf);
+const void *btf_get_raw_data(const struct btf *btf, u32 *data_size);
bool btf_is_module(const struct btf *btf);
bool btf_is_vmlinux(const struct btf *btf);
struct module *btf_try_get_module(const struct btf *btf);
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index a62d78581207..6f1d9b3ba6a3 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8322,11 +8322,19 @@ u32 btf_obj_id(const struct btf *btf)
return READ_ONCE(btf->id);
}
+const void *btf_get_raw_data(const struct btf *btf, u32 *data_size)
+{
+ if (data_size)
+ *data_size = btf->data_size;
+ return btf->data;
+}
+
bool btf_is_kernel(const struct btf *btf)
{
return btf->kernel_btf;
}
+
bool btf_is_module(const struct btf *btf)
{
return btf->kernel_btf && strcmp(btf->name, "vmlinux") != 0;
diff --git a/kernel/bpf/check_btf.c b/kernel/bpf/check_btf.c
index 93bebe6fe12e..c52cc859abac 100644
--- a/kernel/bpf/check_btf.c
+++ b/kernel/bpf/check_btf.c
@@ -411,28 +411,16 @@ int bpf_check_btf_info_early(struct bpf_verifier_env *env,
const union bpf_attr *attr,
bpfptr_t uattr)
{
- struct btf *btf;
- int err;
-
if (!attr->func_info_cnt && !attr->line_info_cnt) {
if (check_abnormal_return(env))
return -EINVAL;
return 0;
}
- btf = btf_get_by_fd(attr->prog_btf_fd);
- if (IS_ERR(btf))
- return PTR_ERR(btf);
- if (btf_is_kernel(btf)) {
- btf_put(btf);
- return -EACCES;
- }
- env->prog->aux->btf = btf;
+ if (env->prog->aux->btf)
+ return check_btf_func_early(env, attr, uattr);
- err = check_btf_func_early(env, attr, uattr);
- if (err)
- return err;
- return 0;
+ return -EINVAL;
}
int bpf_check_btf_info(struct bpf_verifier_env *env,
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 51fe8d77bb39..6d1db5eaad3c 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2816,9 +2816,11 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr
bool is_kernel)
{
bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
- struct bpf_dynptr_kern sig_ptr, insns_ptr;
+ struct bpf_dynptr_kern sig_ptr, data_ptr;
struct bpf_key *key = NULL;
- void *sig;
+ u32 insns_sz, btf_sz = 0;
+ const void *btf_data = NULL;
+ void *sig, *data = NULL;
int err = 0;
/*
@@ -2842,14 +2844,34 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr
return PTR_ERR(sig);
}
+ insns_sz = prog->len * sizeof(struct bpf_insn);
+
+ if (prog->aux->btf)
+ btf_data = btf_get_raw_data(prog->aux->btf, &btf_sz);
+
+ if (bpf_dynptr_check_size(insns_sz + btf_sz)) {
+ err = -E2BIG;
+ goto out;
+ }
+ data = kvmalloc(insns_sz + btf_sz, GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto out;
+ }
+ memcpy(data, prog->insnsi, insns_sz);
+ if (btf_sz)
+ memcpy(data + insns_sz, btf_data, btf_sz);
+
+ bpf_dynptr_init(&data_ptr, data, BPF_DYNPTR_TYPE_LOCAL, 0,
+ insns_sz + btf_sz);
bpf_dynptr_init(&sig_ptr, sig, BPF_DYNPTR_TYPE_LOCAL, 0,
attr->signature_size);
- bpf_dynptr_init(&insns_ptr, prog->insnsi, BPF_DYNPTR_TYPE_LOCAL, 0,
- prog->len * sizeof(struct bpf_insn));
- err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
+ err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&data_ptr,
(struct bpf_dynptr *)&sig_ptr, key);
+out:
+ kvfree(data);
bpf_key_put(key);
kvfree(sig);
return err;
@@ -3037,6 +3059,21 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
/* eBPF programs must be GPL compatible to use GPL-ed functions */
prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
+ if (attr->prog_btf_fd) {
+ struct btf *btf = btf_get_by_fd(attr->prog_btf_fd);
+
+ if (IS_ERR(btf)) {
+ err = PTR_ERR(btf);
+ goto free_prog;
+ }
+ if (btf_is_kernel(btf)) {
+ btf_put(btf);
+ err = -EACCES;
+ goto free_prog;
+ }
+ prog->aux->btf = btf;
+ }
+
if (attr->signature) {
err = bpf_prog_verify_signature(prog, attr, uattr.is_kernel);
if (err)
@@ -3148,6 +3185,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
free_uid(prog->aux->user);
if (prog->aux->attach_btf)
btf_put(prog->aux->attach_btf);
+ if (prog->aux->btf)
+ btf_put(prog->aux->btf);
bpf_prog_free(prog);
put_token:
bpf_token_put(token);
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 01/13] bpf: expose signature verdict to LSMs via bpf_prog_aux
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: ast, daniel, memxor, James.Bottomley, paul, KP Singh
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>
BPF_PROG_LOAD verifies the loader signature but does not record the
outcome on the prog. LSMs and audit can read attr->signature and
attr->keyring_id to infer "was this signed, against which keyring",
but there is no canonical state for "loader signature + map content
verified". Only the in-kernel kfunc can confirm the latter.
Add prog->aux->sig (verdict + keyring) and prog->aux->is_kernel,
populated by bpf_prog_load before the LSM hook. Failed verifications
reject the load before the hook runs, so it observes only UNSIGNED
or OK. The bpf_loader_verify_metadata kfunc promotes to
METADATA_VERIFIED later.
Signed-off-by: KP Singh <kpsingh@kernel.org>
---
include/linux/bpf.h | 19 +++++++++++++++++++
kernel/bpf/syscall.c | 20 ++++++++++++++++++++
2 files changed, 39 insertions(+)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 11bec73db199..14f65259f414 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1656,6 +1656,20 @@ struct bpf_stream_stage {
int len;
};
+enum bpf_sig_verdict {
+ BPF_SIG_UNSIGNED = 0,
+ BPF_SIG_OK, /* loader signature verified */
+ BPF_SIG_METADATA_VERIFIED, /* loader signature + map content verified */
+};
+
+enum bpf_sig_keyring {
+ BPF_SIG_KEYRING_NONE = 0,
+ BPF_SIG_KEYRING_BUILTIN,
+ BPF_SIG_KEYRING_SECONDARY,
+ BPF_SIG_KEYRING_PLATFORM,
+ BPF_SIG_KEYRING_USER,
+};
+
struct bpf_prog_aux {
atomic64_t refcnt;
u32 used_map_cnt;
@@ -1698,6 +1712,11 @@ struct bpf_prog_aux {
bool changes_pkt_data;
bool might_sleep;
bool kprobe_write_ctx;
+ struct {
+ u8 verdict;
+ u8 keyring;
+ } sig;
+ bool is_kernel;
u64 prog_array_member_cnt; /* counts how many times as member of prog_array */
struct mutex ext_mutex; /* mutex for is_extended and prog_array_member_cnt */
struct bpf_arena *arena;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 630d530782fe..51fe8d77bb39 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2798,6 +2798,20 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
}
}
+static enum bpf_sig_keyring bpf_classify_keyring(s32 keyring_id)
+{
+ switch (keyring_id) {
+ case 0:
+ return BPF_SIG_KEYRING_BUILTIN;
+ case (s32)(unsigned long)VERIFY_USE_SECONDARY_KEYRING:
+ return BPF_SIG_KEYRING_SECONDARY;
+ case (s32)(unsigned long)VERIFY_USE_PLATFORM_KEYRING:
+ return BPF_SIG_KEYRING_PLATFORM;
+ default:
+ return BPF_SIG_KEYRING_USER;
+ }
+}
+
static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr,
bool is_kernel)
{
@@ -3027,7 +3041,13 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
err = bpf_prog_verify_signature(prog, attr, uattr.is_kernel);
if (err)
goto free_prog;
+ prog->aux->sig.verdict = BPF_SIG_OK;
+ prog->aux->sig.keyring = bpf_classify_keyring(attr->keyring_id);
+ } else {
+ prog->aux->sig.verdict = BPF_SIG_UNSIGNED;
+ prog->aux->sig.keyring = BPF_SIG_KEYRING_NONE;
}
+ prog->aux->is_kernel = uattr.is_kernel;
prog->orig_prog = NULL;
prog->jited = 0;
--
2.53.0
^ permalink raw reply related
* [PATCH bpf-next 00/13] Signed BPF + IPE Policies
From: KP Singh @ 2026-05-22 2:32 UTC (permalink / raw)
To: linux-security-module, bpf; +Cc: ast, daniel, memxor, James.Bottomley, paul
This series continues the "Signed BPF programs" work and adds
the missing pieces needed for an LSM to do policy enforcement
and addresses the concerns raised by the developers of Hornet.
One signing scheme, please.
BPF does not need a second signing scheme. It needs a policy
framework that consumes the verdict the existing signing pipeline
produces. Two parallel signing stacks is harmful UX for Cilium,
bpftrace, systemd, distros, and everyone shipping signed lskels.
Hornet has been NACK'd repeatedly by the BPF maintainers [1][2]
on layering and TOCTOU grounds.
What this series adds
- prog->aux->sig (verdict + keyring) and prog->aux->is_kernel,
populated by the syscall path before security_bpf_prog_load
fires.
- bpf_loader_verify_metadata kfunc -- the metadata check is now
kernel C code, not BPF bytecode. The verifier injects the
calling prog->aux as an implicit argument via KF_IMPLICIT_ARGS.
- Loader-side prog BTF with BPF_PSEUDO_KFUNC_CALL_PROG_BTF so
the kfunc CALL is reproducible across build hosts and resolved
at load time.
- security_bpf_prog_load_post_integrity LSM hook, fired by the
kfunc on a successful metadata check.
- IPE properties (bpf_signature, bpf_keyring, bpf_kernel) and
two ops (BPF_PROG_LOAD, BPF_PROG_LOAD_POST_INTEGRITY).
This series address concerns raised by the Hornet developers:
* The metadata hash check should be in kernel C, not BPF
bytecode -- Blaise Boscaccy [3]:
The bpf_loader_verify_metadata kfunc moves the hash check from
inline BPF instructions into kernel C code.
* LSMs cannot observe the verification result at hook time --
Paul Moore [4]:
prog->aux->sig.verdict and sig.keyring are populated before any
LSM hook runs. Furthermore, security_bpf_prog_load_post_integrity
hook fires after the in-kernel hash check for consumers that want
to observe or gate the post-integrity transition.
[1] Alexei Starovoitov, NACK on Hornet (TOCTOU + layering),
https://lore.kernel.org/all/CAADnVQJ1CRvTXBU771KaYzrx-vRaWF+k164DcFOqOsCxmuL+ig@mail.gmail.com/
[2] Daniel Borkmann, NACK on Hornet v3,
https://lore.kernel.org/all/798dba24-b5a7-4584-a1f6-793883fe9b5e@iogearbox.net/
[3] Blaise Boscaccy, Hornet v6 (C-side hash verification rationale),
https://lore.kernel.org/all/20260429191431.2345448-1-bboscaccy@linux.microsoft.com/
[4] Paul Moore, push for post-verifier observability,
https://lore.kernel.org/all/CACYkzJ4+=3owK+ELD9Nw7Rrm-UajxXEw8kVtOTJJ+SNAXpsOpw@mail.gmail.com/
KP Singh (13):
bpf: expose signature verdict to LSMs via bpf_prog_aux
bpf: include prog BTF in the signed loader signature scope
bpf, libbpf: load prog BTF in the skel_internal loader
bpf: add bpf_loader_verify_metadata kfunc
bpf: compute prog->digest at BPF_PROG_LOAD entry
bpf: resolve loader-style kfunc CALLs against prog BTF
libbpf: generate prog BTF for loader programs
bpftool gen: embed loader prog BTF in the lskel header
lsm: add bpf_prog_load_post_integrity hook
bpf: invoke security_bpf_prog_load_post_integrity from the metadata
kfunc
ipe: add BPF program signature properties
ipe: gate post-integrity BPF program loads
selftests/bpf: add IPE BPF policy integration tests
include/linux/bpf.h | 19 +++
include/linux/bpf_verifier.h | 6 +
include/linux/btf.h | 1 +
include/linux/lsm_hook_defs.h | 1 +
include/linux/security.h | 6 +
include/uapi/linux/bpf.h | 5 +
kernel/bpf/btf.c | 8 +
kernel/bpf/check_btf.c | 18 +-
kernel/bpf/helpers.c | 65 ++++++++
kernel/bpf/syscall.c | 76 ++++++++-
kernel/bpf/verifier.c | 58 ++++++-
security/ipe/Kconfig | 14 ++
security/ipe/audit.c | 13 ++
security/ipe/eval.c | 57 +++++++
security/ipe/eval.h | 5 +
security/ipe/hooks.c | 42 +++++
security/ipe/hooks.h | 9 +
security/ipe/ipe.c | 4 +
security/ipe/policy.h | 11 ++
security/ipe/policy_parser.c | 20 +++
security/security.c | 17 ++
tools/bpf/bpftool/gen.c | 21 +++
tools/bpf/bpftool/sign.c | 17 +-
tools/include/uapi/linux/bpf.h | 5 +
tools/lib/bpf/bpf_gen_internal.h | 2 +
tools/lib/bpf/gen_loader.c | 127 +++++++++++---
tools/lib/bpf/libbpf.h | 4 +-
tools/lib/bpf/skel_internal.h | 67 +++++---
.../selftests/bpf/test_signed_bpf_ipe.sh | 156 ++++++++++++++++++
tools/testing/selftests/bpf/vmtest.sh | 4 +-
30 files changed, 775 insertions(+), 83 deletions(-)
create mode 100755 tools/testing/selftests/bpf/test_signed_bpf_ipe.sh
--
2.53.0
^ permalink raw reply
* [net-next] netlabel: fix IPv6 unlabeled address add error handling
From: Chenguang Zhao @ 2026-05-22 2:29 UTC (permalink / raw)
To: Paul Moore, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman
Cc: Chenguang Zhao, netdev, linux-security-module
netlbl_unlhsh_add_addr6() always returned zero after
netlbl_af6list_add(), masking failures such as duplicate
IPv6 static label entries.
Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
---
net/netlabel/netlabel_unlabeled.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index ca7a9e2a3de7..0ab825d7f637 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -295,7 +295,7 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
if (ret_val != 0)
kfree(entry);
- return 0;
+ return ret_val;
}
#endif /* IPv6 */
--
2.25.1
^ permalink raw reply related
* [PATCH] tpm-buf: memory-safe allocations
From: Jarkko Sakkinen @ 2026-05-22 1:35 UTC (permalink / raw)
To: linux-integrity
Cc: Jarkko Sakkinen, Arun Menon, Daniel P. Smith, Alec Brown,
Ross Philipson, Stefan Berger, Peter Huewe, Jarkko Sakkinen,
Jason Gunthorpe, James Bottomley, Mimi Zohar, David Howells,
Paul Moore, James Morris, Serge E. Hallyn, linux-kernel, keyrings,
linux-security-module
From: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
Decouple kzalloc from buffer creation, so that a managed allocation can be
used:
struct tpm_buf *buf __free(kfree) buf = kzalloc(TPM_BUFSIZE,
GFP_KERNEL);
if (!buf)
return -ENOMEM;
tpm_buf_init(buf, TPM_BUFSIZE);
Alternatively, stack allocations are also possible:
u8 buf_data[512];
struct tpm_buf *buf = (struct tpm_buf *)buf_data;
tpm_buf_init(buf, sizeof(buf_data));
This is achieved by embedding buffer's header inside the allocated blob,
instead of having an outer wrapper.
Cc: Arun Menon <armenon@redhat.com>
Cc: Daniel P. Smith <dpsmith@apertussolutions.com>
Cc: Alec Brown <alec.r.brown@oracle.com>
Cc: Ross Philipson <ross.philipson@gmail.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
---
Rebased the managed allocations patch, which has been probably like a
year in circulation.
drivers/char/tpm/tpm-buf.c | 122 ++++++----
drivers/char/tpm/tpm-sysfs.c | 17 +-
drivers/char/tpm/tpm.h | 1 -
drivers/char/tpm/tpm1-cmd.c | 150 ++++++------
drivers/char/tpm/tpm2-cmd.c | 277 +++++++++++-----------
drivers/char/tpm/tpm2-sessions.c | 149 ++++++------
drivers/char/tpm/tpm2-space.c | 44 ++--
drivers/char/tpm/tpm_vtpm_proxy.c | 30 +--
include/linux/tpm.h | 18 +-
security/keys/trusted-keys/trusted_tpm1.c | 44 ++--
security/keys/trusted-keys/trusted_tpm2.c | 165 ++++++-------
11 files changed, 505 insertions(+), 512 deletions(-)
diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
index dc882fc9fa9e..b16d824ef0af 100644
--- a/drivers/char/tpm/tpm-buf.c
+++ b/drivers/char/tpm/tpm-buf.c
@@ -7,82 +7,110 @@
#include <linux/module.h>
#include <linux/tpm.h>
-/**
- * tpm_buf_init() - Allocate and initialize a TPM command
- * @buf: A &tpm_buf
- * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
- * @ordinal: A command ordinal
- *
- * Return: 0 or -ENOMEM
- */
-int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
+static void __tpm_buf_size_invariant(struct tpm_buf *buf, u16 buf_size)
{
- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
- if (!buf->data)
- return -ENOMEM;
-
- tpm_buf_reset(buf, tag, ordinal);
- return 0;
+ u32 buf_size_2 = (u32)buf->capacity + (u32)sizeof(*buf);
+
+ if (!buf->capacity) {
+ if (buf_size > TPM_BUFSIZE) {
+ WARN(1, "%s: size overflow: %u\n", __func__, buf_size);
+ buf->flags |= TPM_BUF_OVERFLOW;
+ }
+ } else {
+ if (buf_size != buf_size_2) {
+ WARN(1, "%s: size mismatch: %u != %u\n", __func__,
+ buf_size, buf_size_2);
+ buf->flags |= TPM_BUF_OVERFLOW;
+ }
+ }
}
-EXPORT_SYMBOL_GPL(tpm_buf_init);
-/**
- * tpm_buf_reset() - Initialize a TPM command
- * @buf: A &tpm_buf
- * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
- * @ordinal: A command ordinal
- */
-void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
+static void __tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag,
+ u32 ordinal)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
+ __tpm_buf_size_invariant(buf, buf_size);
+
+ if (buf->flags & TPM_BUF_OVERFLOW)
+ return;
+
WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
tag != TPM2_ST_SESSIONS && tag != 0);
buf->flags = 0;
buf->length = sizeof(*head);
+ buf->capacity = buf_size - sizeof(*buf);
+ buf->handles = 0;
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
+}
+
+static void __tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
+{
+ __tpm_buf_size_invariant(buf, buf_size);
+
+ if (buf->flags & TPM_BUF_OVERFLOW)
+ return;
+
+ buf->flags = TPM_BUF_TPM2B;
+ buf->length = 2;
+ buf->capacity = buf_size - sizeof(*buf);
buf->handles = 0;
+ buf->data[0] = 0;
+ buf->data[1] = 0;
}
-EXPORT_SYMBOL_GPL(tpm_buf_reset);
/**
- * tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
- * @buf: A @tpm_buf
- *
- * Return: 0 or -ENOMEM
+ * tpm_buf_init() - Initialize a TPM command
+ * @buf: A &tpm_buf
+ * @buf_size: Size of the buffer.
*/
-int tpm_buf_init_sized(struct tpm_buf *buf)
+void tpm_buf_init(struct tpm_buf *buf, u16 buf_size)
{
- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
- if (!buf->data)
- return -ENOMEM;
+ memset(buf, 0, buf_size);
+ __tpm_buf_reset(buf, buf_size, TPM_TAG_RQU_COMMAND, 0);
+}
+EXPORT_SYMBOL_GPL(tpm_buf_init);
- tpm_buf_reset_sized(buf);
- return 0;
+/**
+ * tpm_buf_init_sized() - Initialize a sized buffer
+ * @buf: A &tpm_buf
+ * @buf_size: Size of the buffer.
+ */
+void tpm_buf_init_sized(struct tpm_buf *buf, u16 buf_size)
+{
+ memset(buf, 0, buf_size);
+ __tpm_buf_reset_sized(buf, buf_size);
}
EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
/**
- * tpm_buf_reset_sized() - Initialize a sized buffer
+ * tpm_buf_reset() - Re-initialize a TPM command
* @buf: A &tpm_buf
+ * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
+ * @ordinal: A command ordinal
*/
-void tpm_buf_reset_sized(struct tpm_buf *buf)
+void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
- buf->flags = TPM_BUF_TPM2B;
- buf->length = 2;
- buf->data[0] = 0;
- buf->data[1] = 0;
+ u16 buf_size = buf->capacity + sizeof(*buf);
+
+ __tpm_buf_reset(buf, buf_size, tag, ordinal);
}
-EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
+EXPORT_SYMBOL_GPL(tpm_buf_reset);
-void tpm_buf_destroy(struct tpm_buf *buf)
+/**
+ * tpm_buf_reset_sized() - Re-initialize a sized buffer
+ * @buf: A &tpm_buf
+ */
+void tpm_buf_reset_sized(struct tpm_buf *buf)
{
- free_page((unsigned long)buf->data);
+ u16 buf_size = buf->capacity + sizeof(*buf);
+
+ __tpm_buf_reset_sized(buf, buf_size);
}
-EXPORT_SYMBOL_GPL(tpm_buf_destroy);
+EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
/**
* tpm_buf_length() - Return the number of bytes consumed by the data
@@ -90,7 +118,7 @@ EXPORT_SYMBOL_GPL(tpm_buf_destroy);
*
* Return: The number of bytes consumed by the buffer
*/
-u32 tpm_buf_length(struct tpm_buf *buf)
+u16 tpm_buf_length(struct tpm_buf *buf)
{
return buf->length;
}
@@ -104,11 +132,13 @@ EXPORT_SYMBOL_GPL(tpm_buf_length);
*/
void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
{
+ u32 total_length = (u32)buf->length + (u32)new_length;
+
/* Return silently if overflow has already happened. */
if (buf->flags & TPM_BUF_OVERFLOW)
return;
- if ((buf->length + new_length) > PAGE_SIZE) {
+ if (total_length > (u32)buf->capacity) {
WARN(1, "tpm_buf: write overflow\n");
buf->flags |= TPM_BUF_OVERFLOW;
return;
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 94231f052ea7..1de03cf340b3 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -32,28 +32,31 @@ struct tpm_readpubek_out {
static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct tpm_buf tpm_buf;
struct tpm_readpubek_out *out;
int i;
char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev);
char anti_replay[20];
+ struct tpm_buf *tpm_buf __free(kfree) = NULL;
memset(&anti_replay, 0, sizeof(anti_replay));
if (tpm_try_get_ops(chip))
return 0;
- if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
+ tpm_buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!tpm_buf)
goto out_ops;
- tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
+ tpm_buf_init(tpm_buf, TPM_BUFSIZE);
+ tpm_buf_reset(tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
+ tpm_buf_append(tpm_buf, anti_replay, sizeof(anti_replay));
- if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
+ if (tpm_transmit_cmd(chip, tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
"attempting to read the PUBEK"))
- goto out_buf;
+ goto out_ops;
- out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
+ out = (struct tpm_readpubek_out *)&tpm_buf->data[10];
str +=
sprintf(str,
"Algorithm: %4ph\n"
@@ -71,8 +74,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
for (i = 0; i < 256; i += 16)
str += sprintf(str, "%16ph\n", &out->modulus[i]);
-out_buf:
- tpm_buf_destroy(&tpm_buf);
out_ops:
tpm_put_ops(chip);
return str - buf;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 87d68ddf270a..03f5346343ab 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -33,7 +33,6 @@
#endif
#define TPM_MINOR 224 /* officially assigned */
-#define TPM_BUFSIZE 4096
#define TPM_NUM_DEVICES 65536
#define TPM_RETRY 50
diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
index b49a790f1bd5..6facc3de2c46 100644
--- a/drivers/char/tpm/tpm1-cmd.c
+++ b/drivers/char/tpm/tpm1-cmd.c
@@ -323,20 +323,18 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
*/
static int tpm1_startup(struct tpm_chip *chip)
{
- struct tpm_buf buf;
- int rc;
+ struct tpm_buf *buf __free(kfree) = NULL;
dev_info(&chip->dev, "starting up the TPM manually\n");
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
- if (rc < 0)
- return rc;
-
- tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
- tpm_buf_destroy(&buf);
- return rc;
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
+ tpm_buf_append_u16(buf, TPM_ST_CLEAR);
+ return tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
}
int tpm1_get_timeouts(struct tpm_chip *chip)
@@ -463,50 +461,47 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
const char *log_msg)
{
- struct tpm_buf buf;
- int rc;
-
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
- if (rc)
- return rc;
-
- tpm_buf_append_u32(&buf, pcr_idx);
- tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
-
- rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
- tpm_buf_destroy(&buf);
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
+ tpm_buf_append_u32(buf, pcr_idx);
+ tpm_buf_append(buf, hash, TPM_DIGEST_SIZE);
+ return tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE, log_msg);
}
#define TPM_ORD_GET_CAP 101
ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
if (subcap_id == TPM_CAP_VERSION_1_1 ||
subcap_id == TPM_CAP_VERSION_1_2) {
- tpm_buf_append_u32(&buf, subcap_id);
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, subcap_id);
+ tpm_buf_append_u32(buf, 0);
} else {
if (subcap_id == TPM_CAP_FLAG_PERM ||
subcap_id == TPM_CAP_FLAG_VOL)
- tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
+ tpm_buf_append_u32(buf, TPM_CAP_FLAG);
else
- tpm_buf_append_u32(&buf, TPM_CAP_PROP);
+ tpm_buf_append_u32(buf, TPM_CAP_PROP);
- tpm_buf_append_u32(&buf, 4);
- tpm_buf_append_u32(&buf, subcap_id);
+ tpm_buf_append_u32(buf, 4);
+ tpm_buf_append_u32(buf, subcap_id);
}
- rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
+ rc = tpm_transmit_cmd(chip, buf, min_cap_length, desc);
if (!rc)
- *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
- tpm_buf_destroy(&buf);
+ *cap = *(cap_t *)&buf->data[TPM_HEADER_SIZE + 4];
return rc;
}
EXPORT_SYMBOL_GPL(tpm1_getcap);
@@ -530,21 +525,24 @@ struct tpm1_get_random_out {
int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm1_get_random_out *out;
+ struct tpm_buf *buf __free(kfree) = NULL;
u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
- struct tpm_buf buf;
u32 total = 0;
int retries = 5;
u32 recd;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
- if (rc)
- return rc;
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
do {
- tpm_buf_append_u32(&buf, num_bytes);
+ tpm_buf_append_u32(buf, num_bytes);
- rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
+ rc = tpm_transmit_cmd(chip, buf, sizeof(out->rng_data_len),
"attempting get random");
if (rc) {
if (rc > 0)
@@ -552,7 +550,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
goto out;
}
- out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
+ out = (struct tpm1_get_random_out *)&buf->data[TPM_HEADER_SIZE];
recd = be32_to_cpu(out->rng_data_len);
if (recd > num_bytes) {
@@ -560,8 +558,8 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
goto out;
}
- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE +
- sizeof(out->rng_data_len) + recd) {
+ if (tpm_buf_length(buf) < TPM_HEADER_SIZE +
+ sizeof(out->rng_data_len) + recd) {
rc = -EFAULT;
goto out;
}
@@ -571,41 +569,36 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
total += recd;
num_bytes -= recd;
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
} while (retries-- && total < max);
rc = total ? (int)total : -EIO;
out:
- tpm_buf_destroy(&buf);
return rc;
}
#define TPM_ORD_PCRREAD 21
int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, pcr_idx);
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
+ tpm_buf_append_u32(buf, pcr_idx);
- rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
+ rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE,
"attempting to read a pcr value");
if (rc)
- goto out;
-
- if (tpm_buf_length(&buf) < TPM_DIGEST_SIZE) {
- rc = -EFAULT;
- goto out;
- }
+ return rc;
- memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
+ if (tpm_buf_length(buf) < TPM_DIGEST_SIZE)
+ return -EFAULT;
-out:
- tpm_buf_destroy(&buf);
+ memcpy(res_buf, &buf->data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
return rc;
}
@@ -619,16 +612,13 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
*/
static int tpm1_continue_selftest(struct tpm_chip *chip)
{
- struct tpm_buf buf;
- int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
- if (rc)
- return rc;
-
- rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
- tpm_buf_destroy(&buf);
- return rc;
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
+ return tpm_transmit_cmd(chip, buf, 0, "continue selftest");
}
/**
@@ -742,22 +732,24 @@ int tpm1_auto_startup(struct tpm_chip *chip)
int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
{
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
- struct tpm_buf buf;
unsigned int try;
+ struct tpm_buf *buf __free(kfree) = NULL;
int rc;
-
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr)
rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
"extending dummy pcr before suspend");
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
- if (rc)
- return rc;
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
/*
* If the TPM indicates that it is too busy to respond to
* this command then retry before giving up. It can take
@@ -772,7 +764,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
break;
tpm_msleep(TPM_TIMEOUT_RETRY);
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
}
if (rc)
@@ -782,8 +774,6 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
dev_warn(&chip->dev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
- tpm_buf_destroy(&buf);
-
return rc;
}
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 52ee350da867..f619ce390f6d 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -119,12 +119,13 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
{
int i;
int rc;
- struct tpm_buf buf;
struct tpm2_pcr_read_out *out;
u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
u16 digest_size;
u16 expected_digest_size = 0;
+ struct tpm_buf *buf __free(kfree) = NULL;
+
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
@@ -139,36 +140,35 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
expected_digest_size = chip->allocated_banks[i].digest_size;
}
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
- if (rc)
- return rc;
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
- tpm_buf_append_u32(&buf, 1);
- tpm_buf_append_u16(&buf, digest->alg_id);
- tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
- tpm_buf_append(&buf, (const unsigned char *)pcr_select,
+ tpm_buf_append_u32(buf, 1);
+ tpm_buf_append_u16(buf, digest->alg_id);
+ tpm_buf_append_u8(buf, TPM2_PCR_SELECT_MIN);
+ tpm_buf_append(buf, (const unsigned char *)pcr_select,
sizeof(pcr_select));
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to read a pcr value");
if (rc)
- goto out;
+ return rc;
- out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
+ out = (struct tpm2_pcr_read_out *)&buf->data[TPM_HEADER_SIZE];
digest_size = be16_to_cpu(out->digest_size);
if (digest_size > sizeof(digest->digest) ||
- (!digest_size_ptr && digest_size != expected_digest_size)) {
- rc = -EINVAL;
- goto out;
- }
+ (!digest_size_ptr && digest_size != expected_digest_size))
+ return -EINVAL;
if (digest_size_ptr)
*digest_size_ptr = digest_size;
memcpy(digest->digest, out->digest, digest_size);
-out:
- tpm_buf_destroy(&buf);
return rc;
}
@@ -184,56 +184,54 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests)
{
- struct tpm_buf buf;
int rc;
int i;
+ struct tpm_buf *buf __free(kfree) = NULL;
+
if (!disable_pcr_integrity) {
rc = tpm2_start_auth_session(chip);
if (rc)
return rc;
}
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
- if (rc) {
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
if (!disable_pcr_integrity)
tpm2_end_auth_session(chip);
- return rc;
+ return -ENOMEM;
}
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
+
if (!disable_pcr_integrity) {
- rc = tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
- if (rc) {
- tpm_buf_destroy(&buf);
+ rc = tpm_buf_append_name(chip, buf, pcr_idx, NULL);
+ if (rc)
return rc;
- }
- tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
+ tpm_buf_append_hmac_session(chip, buf, 0, NULL, 0);
} else {
- tpm_buf_append_handle(chip, &buf, pcr_idx);
- tpm_buf_append_auth(chip, &buf, NULL, 0);
+ tpm_buf_append_handle(chip, buf, pcr_idx);
+ tpm_buf_append_auth(chip, buf, NULL, 0);
}
- tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
+ tpm_buf_append_u32(buf, chip->nr_allocated_banks);
for (i = 0; i < chip->nr_allocated_banks; i++) {
- tpm_buf_append_u16(&buf, digests[i].alg_id);
- tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
+ tpm_buf_append_u16(buf, digests[i].alg_id);
+ tpm_buf_append(buf, (const unsigned char *)&digests[i].digest,
chip->allocated_banks[i].digest_size);
}
if (!disable_pcr_integrity) {
- rc = tpm_buf_fill_hmac_session(chip, &buf);
- if (rc) {
- tpm_buf_destroy(&buf);
+ rc = tpm_buf_fill_hmac_session(chip, buf);
+ if (rc)
return rc;
- }
}
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting extend a PCR value");
if (!disable_pcr_integrity)
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
-
- tpm_buf_destroy(&buf);
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
return rc;
}
@@ -258,7 +256,6 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm2_get_random_out *out;
struct tpm_header *head;
- struct tpm_buf buf;
u32 recd;
u32 num_bytes = max;
int err;
@@ -267,6 +264,8 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
u8 *dest_ptr = dest;
off_t offset;
+ struct tpm_buf *buf __free(kfree) = NULL;
+
if (!num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
@@ -274,50 +273,52 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
if (err)
return err;
- err = tpm_buf_init(&buf, 0, 0);
- if (err) {
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
tpm2_end_auth_session(chip);
- return err;
+ return -ENOMEM;
}
+ tpm_buf_init(buf, TPM_BUFSIZE);
+
do {
- tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
+ tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
if (tpm2_chip_auth(chip)) {
- tpm_buf_append_hmac_session(chip, &buf,
+ tpm_buf_append_hmac_session(chip, buf,
TPM2_SA_ENCRYPT |
TPM2_SA_CONTINUE_SESSION,
NULL, 0);
} else {
- offset = buf.handles * 4 + TPM_HEADER_SIZE;
- head = (struct tpm_header *)buf.data;
- if (tpm_buf_length(&buf) == offset)
+ offset = buf->handles * 4 + TPM_HEADER_SIZE;
+ head = (struct tpm_header *)buf->data;
+ if (tpm_buf_length(buf) == offset)
head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
}
- tpm_buf_append_u16(&buf, num_bytes);
- err = tpm_buf_fill_hmac_session(chip, &buf);
+ tpm_buf_append_u16(buf, num_bytes);
+ err = tpm_buf_fill_hmac_session(chip, buf);
if (err)
goto out;
- err = tpm_transmit_cmd(chip, &buf,
+ err = tpm_transmit_cmd(chip, buf,
offsetof(struct tpm2_get_random_out,
buffer),
"attempting get random");
- err = tpm_buf_check_hmac_response(chip, &buf, err);
+ err = tpm_buf_check_hmac_response(chip, buf, err);
if (err) {
if (err > 0)
err = -EIO;
goto out;
}
- head = (struct tpm_header *)buf.data;
+ head = (struct tpm_header *)buf->data;
offset = TPM_HEADER_SIZE;
/* Skip the parameter size field: */
if (be16_to_cpu(head->tag) == TPM2_ST_SESSIONS)
offset += 4;
- out = (struct tpm2_get_random_out *)&buf.data[offset];
+ out = (struct tpm2_get_random_out *)&buf->data[offset];
recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
- if (tpm_buf_length(&buf) <
+ if (tpm_buf_length(buf) <
TPM_HEADER_SIZE +
offsetof(struct tpm2_get_random_out, buffer) +
recd) {
@@ -331,11 +332,8 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
num_bytes -= recd;
} while (retries-- && total < max);
- tpm_buf_destroy(&buf);
-
return total ? total : -EIO;
out:
- tpm_buf_destroy(&buf);
tpm2_end_auth_session(chip);
return err;
}
@@ -347,20 +345,18 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
*/
void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
{
- struct tpm_buf buf;
- int rc;
-
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
- if (rc) {
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
handle);
return;
}
- tpm_buf_append_u32(&buf, handle);
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
+ tpm_buf_append_u32(buf, handle);
- tpm_transmit_cmd(chip, &buf, 0, "flushing context");
- tpm_buf_destroy(&buf);
+ tpm_transmit_cmd(chip, buf, 0, "flushing context");
}
EXPORT_SYMBOL_GPL(tpm2_flush_context);
@@ -387,19 +383,21 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
const char *desc)
{
struct tpm2_get_cap_out *out;
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
- tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
- tpm_buf_append_u32(&buf, property_id);
- tpm_buf_append_u32(&buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
+ tpm_buf_append_u32(buf, property_id);
+ tpm_buf_append_u32(buf, 1);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
if (!rc) {
out = (struct tpm2_get_cap_out *)
- &buf.data[TPM_HEADER_SIZE];
+ &buf->data[TPM_HEADER_SIZE];
/*
* To prevent failing boot up of some systems, Infineon TPM2.0
* returns SUCCESS on TPM2_Startup in field upgrade mode. Also
@@ -411,7 +409,6 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
else
rc = -ENODATA;
}
- tpm_buf_destroy(&buf);
return rc;
}
EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
@@ -428,15 +425,14 @@ EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
*/
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{
- struct tpm_buf buf;
- int rc;
-
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
- if (rc)
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
return;
- tpm_buf_append_u16(&buf, shutdown_type);
- tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
- tpm_buf_destroy(&buf);
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
+ tpm_buf_append_u16(buf, shutdown_type);
+ tpm_transmit_cmd(chip, buf, 0, "stopping the TPM");
}
/**
@@ -454,20 +450,21 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
*/
static int tpm2_do_selftest(struct tpm_chip *chip)
{
- struct tpm_buf buf;
int full;
int rc;
for (full = 0; full < 2; full++) {
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = NULL;
- tpm_buf_append_u8(&buf, full);
- rc = tpm_transmit_cmd(chip, &buf, 0,
- "attempting the self test");
- tpm_buf_destroy(&buf);
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
+ tpm_buf_append_u8(buf, full);
+ rc = tpm_transmit_cmd(chip, buf, 0,
+ "attempting the self test");
if (rc == TPM2_RC_TESTING)
rc = TPM2_RC_SUCCESS;
if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS)
@@ -492,23 +489,24 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
int tpm2_probe(struct tpm_chip *chip)
{
struct tpm_header *out;
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
- tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
- tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
- tpm_buf_append_u32(&buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
+ tpm_buf_append_u32(buf, TPM_PT_TOTAL_COMMANDS);
+ tpm_buf_append_u32(buf, 1);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
/* We ignore TPM return codes on purpose. */
if (rc >= 0) {
- out = (struct tpm_header *)buf.data;
+ out = (struct tpm_header *)buf->data;
if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
chip->flags |= TPM_CHIP_FLAG_TPM2;
}
- tpm_buf_destroy(&buf);
return 0;
}
EXPORT_SYMBOL_GPL(tpm2_probe);
@@ -548,7 +546,6 @@ struct tpm2_pcr_selection {
ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
{
struct tpm2_pcr_selection pcr_selection;
- struct tpm_buf buf;
void *marker;
void *end;
void *pcr_select_offset;
@@ -560,20 +557,22 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
int rc;
int i = 0;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
- tpm_buf_append_u32(&buf, 0);
- tpm_buf_append_u32(&buf, 1);
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_PCRS);
+ tpm_buf_append_u32(buf, 0);
+ tpm_buf_append_u32(buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
+ rc = tpm_transmit_cmd(chip, buf, 9, "get tpm pcr allocation");
if (rc)
goto out;
nr_possible_banks = be32_to_cpup(
- (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
+ (__be32 *)&buf->data[TPM_HEADER_SIZE + 5]);
if (nr_possible_banks > TPM2_MAX_PCR_BANKS) {
pr_err("tpm: out of bank capacity: %u > %u\n",
nr_possible_banks, TPM2_MAX_PCR_BANKS);
@@ -581,10 +580,10 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
goto out;
}
- marker = &buf.data[TPM_HEADER_SIZE + 9];
+ marker = &buf->data[TPM_HEADER_SIZE + 9];
- rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
- end = &buf.data[rsp_len];
+ rsp_len = be32_to_cpup((__be32 *)&buf->data[2]);
+ end = &buf->data[rsp_len];
for (i = 0; i < nr_possible_banks; i++) {
pcr_select_offset = marker +
@@ -617,20 +616,19 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
chip->nr_allocated_banks = nr_alloc_banks;
out:
- tpm_buf_destroy(&buf);
-
return rc;
}
int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
{
- struct tpm_buf buf;
u32 nr_commands;
__be32 *attrs;
u32 cc;
int i;
int rc;
+ struct tpm_buf *buf __free(kfree) = NULL;
+
rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
if (rc)
goto out;
@@ -647,30 +645,31 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
goto out;
}
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
goto out;
+ }
- tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
- tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
- tpm_buf_append_u32(&buf, nr_commands);
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_COMMANDS);
+ tpm_buf_append_u32(buf, TPM2_CC_FIRST);
+ tpm_buf_append_u32(buf, nr_commands);
- rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
- if (rc) {
- tpm_buf_destroy(&buf);
+ rc = tpm_transmit_cmd(chip, buf, 9 + 4 * nr_commands, NULL);
+ if (rc)
goto out;
- }
if (nr_commands !=
- be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
+ be32_to_cpup((__be32 *)&buf->data[TPM_HEADER_SIZE + 5])) {
rc = -EFAULT;
- tpm_buf_destroy(&buf);
goto out;
}
chip->nr_commands = nr_commands;
- attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
+ attrs = (__be32 *)&buf->data[TPM_HEADER_SIZE + 9];
for (i = 0; i < nr_commands; i++, attrs++) {
chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
cc = chip->cc_attrs_tbl[i] & 0xFFFF;
@@ -682,8 +681,6 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
}
}
- tpm_buf_destroy(&buf);
-
out:
if (rc > 0)
rc = -ENODEV;
@@ -704,20 +701,18 @@ EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl);
static int tpm2_startup(struct tpm_chip *chip)
{
- struct tpm_buf buf;
- int rc;
+ struct tpm_buf *buf __free(kfree) = NULL;
dev_info(&chip->dev, "starting up the TPM manually\n");
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
- if (rc < 0)
- return rc;
-
- tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
- tpm_buf_destroy(&buf);
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- return rc;
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
+ tpm_buf_append_u16(buf, TPM2_SU_CLEAR);
+ return tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
}
/**
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 795cd99dc6fe..b6a93db5a5ee 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -167,8 +167,8 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
{
u32 mso = tpm2_handle_mso(handle);
off_t offset = TPM_HEADER_SIZE;
+ struct tpm_buf *buf __free(kfree) = NULL;
int rc, name_size_alg;
- struct tpm_buf buf;
if (mso != TPM2_MSO_PERSISTENT && mso != TPM2_MSO_VOLATILE &&
mso != TPM2_MSO_NVRAM) {
@@ -176,50 +176,40 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
return sizeof(u32);
}
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
- if (rc)
- return rc;
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, handle);
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
+ tpm_buf_append_u32(buf, handle);
- rc = tpm_transmit_cmd(chip, &buf, 0, "TPM2_ReadPublic");
- if (rc) {
- tpm_buf_destroy(&buf);
+ rc = tpm_transmit_cmd(chip, buf, 0, "TPM2_ReadPublic");
+ if (rc)
return tpm_ret_to_err(rc);
- }
/* Skip TPMT_PUBLIC: */
- offset += tpm_buf_read_u16(&buf, &offset);
+ offset += tpm_buf_read_u16(buf, &offset);
/*
* Ensure space for the length field of TPM2B_NAME and hashAlg field of
* TPMT_HA (the extra four bytes).
*/
- if (offset + 4 > tpm_buf_length(&buf)) {
- tpm_buf_destroy(&buf);
+ if (offset + 4 > tpm_buf_length(buf))
return -EIO;
- }
-
- rc = tpm_buf_read_u16(&buf, &offset);
- name_size_alg = name_size(&buf.data[offset]);
- if (name_size_alg < 0) {
- tpm_buf_destroy(&buf);
+ rc = tpm_buf_read_u16(buf, &offset);
+ name_size_alg = name_size(&buf->data[offset]);
+ if (name_size_alg < 0)
return name_size_alg;
- }
- if (rc != name_size_alg) {
- tpm_buf_destroy(&buf);
+ if (rc != name_size_alg)
return -EIO;
- }
- if (offset + rc > tpm_buf_length(&buf)) {
- tpm_buf_destroy(&buf);
+ if (offset + rc > tpm_buf_length(buf))
return -EIO;
- }
- memcpy(name, &buf.data[offset], rc);
- tpm_buf_destroy(&buf);
+ memcpy(name, &buf->data[offset], rc);
return name_size_alg;
}
#endif /* CONFIG_TCG_TPM2_HMAC */
@@ -987,8 +977,8 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
*/
int tpm2_start_auth_session(struct tpm_chip *chip)
{
+ struct tpm_buf *buf __free(kfree) = NULL;
struct tpm2_auth *auth;
- struct tpm_buf buf;
u32 null_key;
int rc;
@@ -1007,41 +997,43 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
auth->session = TPM_HEADER_SIZE;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
- if (rc)
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
goto out;
+ }
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
/* salt key handle */
- tpm_buf_append_u32(&buf, null_key);
+ tpm_buf_append_u32(buf, null_key);
/* bind key handle */
- tpm_buf_append_u32(&buf, TPM2_RH_NULL);
+ tpm_buf_append_u32(buf, TPM2_RH_NULL);
/* nonce caller */
get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
- tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
- tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
+ tpm_buf_append_u16(buf, sizeof(auth->our_nonce));
+ tpm_buf_append(buf, auth->our_nonce, sizeof(auth->our_nonce));
/* append encrypted salt and squirrel away unencrypted in auth */
- tpm_buf_append_salt(&buf, chip, auth);
+ tpm_buf_append_salt(buf, chip, auth);
/* session type (HMAC, audit or policy) */
- tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
+ tpm_buf_append_u8(buf, TPM2_SE_HMAC);
/* symmetric encryption parameters */
/* symmetric algorithm */
- tpm_buf_append_u16(&buf, TPM_ALG_AES);
+ tpm_buf_append_u16(buf, TPM_ALG_AES);
/* bits for symmetric algorithm */
- tpm_buf_append_u16(&buf, AES_KEY_BITS);
+ tpm_buf_append_u16(buf, AES_KEY_BITS);
/* symmetric algorithm mode (must be CFB) */
- tpm_buf_append_u16(&buf, TPM_ALG_CFB);
+ tpm_buf_append_u16(buf, TPM_ALG_CFB);
/* hash algorithm for session */
- tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
+ tpm_buf_append_u16(buf, TPM_ALG_SHA256);
- rc = tpm_ret_to_err(tpm_transmit_cmd(chip, &buf, 0, "StartAuthSession"));
+ rc = tpm_ret_to_err(tpm_transmit_cmd(chip, buf, 0, "StartAuthSession"));
tpm2_flush_context(chip, null_key);
if (rc == TPM2_RC_SUCCESS)
- rc = tpm2_parse_start_auth_session(auth, &buf);
-
- tpm_buf_destroy(&buf);
+ rc = tpm2_parse_start_auth_session(auth, buf);
if (rc == TPM2_RC_SUCCESS) {
chip->auth = auth;
@@ -1262,19 +1254,21 @@ static int tpm2_parse_create_primary(struct tpm_chip *chip, struct tpm_buf *buf,
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
u32 *handle, u8 *name)
{
+ struct tpm_buf *template __free(kfree) = NULL;
+ struct tpm_buf *buf __free(kfree) = NULL;
int rc;
- struct tpm_buf buf;
- struct tpm_buf template;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
- if (rc)
- return rc;
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_buf_init_sized(&template);
- if (rc) {
- tpm_buf_destroy(&buf);
- return rc;
- }
+ template = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!template)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
+ tpm_buf_init_sized(template, TPM_BUFSIZE);
/*
* create the template. Note: in order for userspace to
@@ -1286,75 +1280,72 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
*/
/* key type */
- tpm_buf_append_u16(&template, TPM_ALG_ECC);
+ tpm_buf_append_u16(template, TPM_ALG_ECC);
/* name algorithm */
- tpm_buf_append_u16(&template, TPM_ALG_SHA256);
+ tpm_buf_append_u16(template, TPM_ALG_SHA256);
/* object properties */
- tpm_buf_append_u32(&template, TPM2_OA_NULL_KEY);
+ tpm_buf_append_u32(template, TPM2_OA_NULL_KEY);
/* sauth policy (empty) */
- tpm_buf_append_u16(&template, 0);
+ tpm_buf_append_u16(template, 0);
/* BEGIN parameters: key specific; for ECC*/
/* symmetric algorithm */
- tpm_buf_append_u16(&template, TPM_ALG_AES);
+ tpm_buf_append_u16(template, TPM_ALG_AES);
/* bits for symmetric algorithm */
- tpm_buf_append_u16(&template, AES_KEY_BITS);
+ tpm_buf_append_u16(template, AES_KEY_BITS);
/* algorithm mode (must be CFB) */
- tpm_buf_append_u16(&template, TPM_ALG_CFB);
+ tpm_buf_append_u16(template, TPM_ALG_CFB);
/* scheme (NULL means any scheme) */
- tpm_buf_append_u16(&template, TPM_ALG_NULL);
+ tpm_buf_append_u16(template, TPM_ALG_NULL);
/* ECC Curve ID */
- tpm_buf_append_u16(&template, TPM2_ECC_NIST_P256);
+ tpm_buf_append_u16(template, TPM2_ECC_NIST_P256);
/* KDF Scheme */
- tpm_buf_append_u16(&template, TPM_ALG_NULL);
+ tpm_buf_append_u16(template, TPM_ALG_NULL);
/* unique: key specific; for ECC it is two zero size points */
- tpm_buf_append_u16(&template, 0);
- tpm_buf_append_u16(&template, 0);
+ tpm_buf_append_u16(template, 0);
+ tpm_buf_append_u16(template, 0);
/* END parameters */
/* primary handle */
- tpm_buf_append_u32(&buf, hierarchy);
- tpm_buf_append_empty_auth(&buf, TPM2_RS_PW);
+ tpm_buf_append_u32(buf, hierarchy);
+ tpm_buf_append_empty_auth(buf, TPM2_RS_PW);
/* sensitive create size is 4 for two empty buffers */
- tpm_buf_append_u16(&buf, 4);
+ tpm_buf_append_u16(buf, 4);
/* sensitive create auth data (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* sensitive create sensitive data (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* the public template */
- tpm_buf_append(&buf, template.data, template.length);
- tpm_buf_destroy(&template);
+ tpm_buf_append(buf, template->data, template->length);
/* outside info (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* creation PCR (none) */
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, 0);
- rc = tpm_transmit_cmd(chip, &buf, 0,
+ rc = tpm_transmit_cmd(chip, buf, 0,
"attempting to create NULL primary");
if (rc == TPM2_RC_SUCCESS)
- rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy,
+ rc = tpm2_parse_create_primary(chip, buf, handle, hierarchy,
name);
- tpm_buf_destroy(&buf);
-
return rc;
}
diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
index 60354cd53b5c..cbf86ff5931f 100644
--- a/drivers/char/tpm/tpm2-space.c
+++ b/drivers/char/tpm/tpm2-space.c
@@ -71,24 +71,25 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
unsigned int *offset, u32 *handle)
{
- struct tpm_buf tbuf;
struct tpm2_context *ctx;
unsigned int body_size;
int rc;
- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
- if (rc)
- return rc;
+ struct tpm_buf *tbuf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
+
+ tpm_buf_init(tbuf, TPM_BUFSIZE);
+ tpm_buf_reset(tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
ctx = (struct tpm2_context *)&buf[*offset];
body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
- tpm_buf_append(&tbuf, &buf[*offset], body_size);
+ tpm_buf_append(tbuf, &buf[*offset], body_size);
- rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
+ rc = tpm_transmit_cmd(chip, tbuf, 4, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
rc == TPM2_RC_REFERENCE_H0) {
@@ -103,64 +104,55 @@ int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
* flushed outside the space
*/
*handle = 0;
- tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
- tpm_buf_destroy(&tbuf);
return -EINVAL;
} else if (rc > 0) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
}
- *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
+ *handle = be32_to_cpup((__be32 *)&tbuf->data[TPM_HEADER_SIZE]);
*offset += body_size;
-
- tpm_buf_destroy(&tbuf);
return 0;
}
int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
unsigned int buf_size, unsigned int *offset)
{
- struct tpm_buf tbuf;
unsigned int body_size;
int rc;
- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
- if (rc)
- return rc;
+ struct tpm_buf *tbuf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
- tpm_buf_append_u32(&tbuf, handle);
+ tpm_buf_init(tbuf, TPM_BUFSIZE);
+ tpm_buf_reset(tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
+ tpm_buf_append_u32(tbuf, handle);
- rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
+ rc = tpm_transmit_cmd(chip, tbuf, 0, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
- tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (rc) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
}
- body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
+ body_size = tpm_buf_length(tbuf) - TPM_HEADER_SIZE;
if ((*offset + body_size) > buf_size) {
dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
- tpm_buf_destroy(&tbuf);
return -ENOMEM;
}
- memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
+ memcpy(&buf[*offset], &tbuf->data[TPM_HEADER_SIZE], body_size);
*offset += body_size;
- tpm_buf_destroy(&tbuf);
return 0;
}
diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c
index 7bb0f4d4a2ed..b81fd2a537df 100644
--- a/drivers/char/tpm/tpm_vtpm_proxy.c
+++ b/drivers/char/tpm/tpm_vtpm_proxy.c
@@ -395,40 +395,36 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
{
- struct tpm_buf buf;
int rc;
const struct tpm_header *header;
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
+ struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_init(buf, TPM_BUFSIZE);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
- TPM2_CC_SET_LOCALITY);
+ tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_SET_LOCALITY);
else
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
- TPM_ORD_SET_LOCALITY);
- if (rc)
- return rc;
- tpm_buf_append_u8(&buf, locality);
+ tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SET_LOCALITY);
+
+ tpm_buf_append_u8(buf, locality);
proxy_dev->state |= STATE_DRIVER_COMMAND;
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to set locality");
proxy_dev->state &= ~STATE_DRIVER_COMMAND;
- if (rc < 0) {
- locality = rc;
- goto out;
- }
+ if (rc < 0)
+ return rc;
- header = (const struct tpm_header *)buf.data;
+ header = (const struct tpm_header *)buf->data;
rc = be32_to_cpu(header->return_code);
if (rc)
locality = -1;
-out:
- tpm_buf_destroy(&buf);
-
return locality;
}
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 202da079d500..14d75c1482d6 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -26,6 +26,7 @@
#include <crypto/aes.h>
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
+#define TPM_BUFSIZE 4096
#define TPM2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
#define TPM2_MAX_PCR_BANKS 8
@@ -378,13 +379,15 @@ enum tpm_buf_flags {
};
/*
- * A string buffer type for constructing TPM commands.
+ * A buffer for constructing and parsing TPM commands, responses and sized
+ * (TPM2B) buffers.
*/
struct tpm_buf {
- u32 flags;
- u32 length;
- u8 *data;
+ u8 flags;
+ u16 length;
+ u16 capacity;
u8 handles;
+ u8 data[];
};
enum tpm2_object_attributes {
@@ -415,12 +418,11 @@ struct tpm2_hash {
unsigned int tpm_id;
};
-int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
+void tpm_buf_init(struct tpm_buf *buf, u16 buf_size);
+void tpm_buf_init_sized(struct tpm_buf *buf, u16 buf_size);
void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
-int tpm_buf_init_sized(struct tpm_buf *buf);
void tpm_buf_reset_sized(struct tpm_buf *buf);
-void tpm_buf_destroy(struct tpm_buf *buf);
-u32 tpm_buf_length(struct tpm_buf *buf);
+u16 tpm_buf_length(struct tpm_buf *buf);
void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length);
void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value);
void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value);
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index 13513819991e..6e03fa7227e4 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -317,9 +317,8 @@ static int TSS_checkhmac2(unsigned char *buffer,
* For key specific tpm requests, we will generate and send our
* own TPM command packets using the drivers send function.
*/
-static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
+static int trusted_tpm_send(struct tpm_buf *buf)
{
- struct tpm_buf buf;
int rc;
if (!chip)
@@ -329,12 +328,9 @@ static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
if (rc)
return rc;
- buf.flags = 0;
- buf.length = buflen;
- buf.data = cmd;
- dump_tpm_buf(cmd);
- rc = tpm_transmit_cmd(chip, &buf, 4, "sending data");
- dump_tpm_buf(cmd);
+ dump_tpm_buf(buf->data);
+ rc = tpm_transmit_cmd(chip, buf, 4, "sending data");
+ dump_tpm_buf(buf->data);
if (rc > 0)
/* TPM error */
@@ -380,7 +376,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
tpm_buf_append_u32(tb, handle);
tpm_buf_append(tb, ononce, TPM_NONCE_SIZE);
- ret = trusted_tpm_send(tb->data, tb->length);
+ ret = trusted_tpm_send(tb);
if (ret < 0)
return ret;
@@ -404,7 +400,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
return -ENODEV;
tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
- ret = trusted_tpm_send(tb->data, tb->length);
+ ret = trusted_tpm_send(tb);
if (ret < 0)
return ret;
@@ -513,7 +509,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
tpm_buf_append_u8(tb, cont);
tpm_buf_append(tb, td->pubauth, SHA1_DIGEST_SIZE);
- ret = trusted_tpm_send(tb->data, tb->length);
+ ret = trusted_tpm_send(tb);
if (ret < 0)
goto out;
@@ -604,7 +600,7 @@ static int tpm_unseal(struct tpm_buf *tb,
tpm_buf_append_u8(tb, cont);
tpm_buf_append(tb, authdata2, SHA1_DIGEST_SIZE);
- ret = trusted_tpm_send(tb->data, tb->length);
+ ret = trusted_tpm_send(tb);
if (ret < 0) {
pr_info("authhmac failed (%d)\n", ret);
return ret;
@@ -631,23 +627,23 @@ static int tpm_unseal(struct tpm_buf *tb,
static int key_seal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
- struct tpm_buf tb;
int ret;
- ret = tpm_buf_init(&tb, 0, 0);
- if (ret)
- return ret;
+ struct tpm_buf *tb __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!tb)
+ return -ENOMEM;
+
+ tpm_buf_init(tb, TPM_BUFSIZE);
/* include migratable flag at end of sealed key */
p->key[p->key_len] = p->migratable;
- ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
+ ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
p->key, p->key_len + 1, p->blob, &p->blob_len,
o->blobauth, o->pcrinfo, o->pcrinfo_len);
if (ret < 0)
pr_info("srkseal failed (%d)\n", ret);
- tpm_buf_destroy(&tb);
return ret;
}
@@ -657,14 +653,15 @@ static int key_seal(struct trusted_key_payload *p,
static int key_unseal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
- struct tpm_buf tb;
int ret;
- ret = tpm_buf_init(&tb, 0, 0);
- if (ret)
- return ret;
+ struct tpm_buf *tb __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!tb)
+ return -ENOMEM;
+
+ tpm_buf_init(tb, TPM_BUFSIZE);
- ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
+ ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
o->blobauth, p->key, &p->key_len);
if (ret < 0)
pr_info("srkunseal failed (%d)\n", ret);
@@ -672,7 +669,6 @@ static int key_unseal(struct trusted_key_payload *p,
/* pull migratable flag out of sealed key */
p->migratable = p->key[--p->key_len];
- tpm_buf_destroy(&tb);
return ret;
}
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 6340823f8b53..6f5c34b885fb 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -234,7 +234,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_options *options)
{
off_t offset = TPM_HEADER_SIZE;
- struct tpm_buf buf, sized;
+ struct tpm_buf *buf __free(kfree) = NULL;
+ struct tpm_buf *sized __free(kfree) = NULL;
int blob_len = 0;
int hash;
u32 flags;
@@ -255,97 +256,100 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
if (rc)
goto out_put;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
- if (rc) {
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
tpm2_end_auth_session(chip);
goto out_put;
}
- rc = tpm_buf_init_sized(&sized);
- if (rc) {
- tpm_buf_destroy(&buf);
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
+
+ sized = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!sized) {
+ rc = -ENOMEM;
tpm2_end_auth_session(chip);
goto out_put;
}
- rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
+ tpm_buf_init_sized(sized, TPM_BUFSIZE);
+
+ rc = tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
if (rc)
goto out;
- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_DECRYPT,
options->keyauth, TPM_DIGEST_SIZE);
/* sensitive */
- tpm_buf_append_u16(&sized, options->blobauth_len);
+ tpm_buf_append_u16(sized, options->blobauth_len);
if (options->blobauth_len)
- tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
+ tpm_buf_append(sized, options->blobauth, options->blobauth_len);
- tpm_buf_append_u16(&sized, payload->key_len);
- tpm_buf_append(&sized, payload->key, payload->key_len);
- tpm_buf_append(&buf, sized.data, sized.length);
+ tpm_buf_append_u16(sized, payload->key_len);
+ tpm_buf_append(sized, payload->key, payload->key_len);
+ tpm_buf_append(buf, sized->data, sized->length);
/* public */
- tpm_buf_reset_sized(&sized);
- tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);
- tpm_buf_append_u16(&sized, hash);
+ tpm_buf_reset_sized(sized);
+ tpm_buf_append_u16(sized, TPM_ALG_KEYEDHASH);
+ tpm_buf_append_u16(sized, hash);
/* key properties */
flags = 0;
flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
- tpm_buf_append_u32(&sized, flags);
+ tpm_buf_append_u32(sized, flags);
/* policy */
- tpm_buf_append_u16(&sized, options->policydigest_len);
+ tpm_buf_append_u16(sized, options->policydigest_len);
if (options->policydigest_len)
- tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
+ tpm_buf_append(sized, options->policydigest, options->policydigest_len);
/* public parameters */
- tpm_buf_append_u16(&sized, TPM_ALG_NULL);
- tpm_buf_append_u16(&sized, 0);
+ tpm_buf_append_u16(sized, TPM_ALG_NULL);
+ tpm_buf_append_u16(sized, 0);
- tpm_buf_append(&buf, sized.data, sized.length);
+ tpm_buf_append(buf, sized->data, sized->length);
/* outside info */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* creation PCR */
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, 0);
- if (buf.flags & TPM_BUF_OVERFLOW) {
+ if (buf->flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG;
tpm2_end_auth_session(chip);
goto out;
}
- rc = tpm_buf_fill_hmac_session(chip, &buf);
+ rc = tpm_buf_fill_hmac_session(chip, buf);
if (rc)
goto out;
- rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ rc = tpm_transmit_cmd(chip, buf, 4, "sealing data");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (rc)
goto out;
- blob_len = tpm_buf_read_u32(&buf, &offset);
- if (blob_len > MAX_BLOB_SIZE || buf.flags & TPM_BUF_BOUNDARY_ERROR) {
+ blob_len = tpm_buf_read_u32(buf, &offset);
+ if (blob_len > MAX_BLOB_SIZE || buf->flags & TPM_BUF_BOUNDARY_ERROR) {
rc = -E2BIG;
goto out;
}
- if (buf.length - offset < blob_len) {
+ if (buf->length - offset < blob_len) {
rc = -EFAULT;
goto out;
}
- blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
+ blob_len = tpm2_key_encode(payload, options, &buf->data[offset], blob_len);
if (blob_len < 0)
rc = blob_len;
out:
- tpm_buf_destroy(&sized);
- tpm_buf_destroy(&buf);
-
if (!rc)
payload->blob_len = blob_len;
@@ -373,7 +377,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
u32 *blob_handle)
{
u8 *blob_ref __free(kfree) = NULL;
- struct tpm_buf buf;
+ struct tpm_buf *buf __free(kfree) = NULL;
unsigned int private_len;
unsigned int public_len;
unsigned int blob_len;
@@ -427,39 +431,38 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
if (rc)
return rc;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
- if (rc) {
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
tpm2_end_auth_session(chip);
- return rc;
+ return -ENOMEM;
}
- rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
+
+ rc = tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
if (rc)
- goto out;
+ return rc;
- tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
+ tpm_buf_append_hmac_session(chip, buf, 0, options->keyauth,
TPM_DIGEST_SIZE);
- tpm_buf_append(&buf, blob, blob_len);
+ tpm_buf_append(buf, blob, blob_len);
- if (buf.flags & TPM_BUF_OVERFLOW) {
- rc = -E2BIG;
+ if (buf->flags & TPM_BUF_OVERFLOW) {
tpm2_end_auth_session(chip);
- goto out;
+ return -E2BIG;
}
- rc = tpm_buf_fill_hmac_session(chip, &buf);
+ rc = tpm_buf_fill_hmac_session(chip, buf);
if (rc)
- goto out;
+ return rc;
- rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ rc = tpm_transmit_cmd(chip, buf, 4, "loading blob");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (!rc)
*blob_handle = be32_to_cpup(
- (__be32 *) &buf.data[TPM_HEADER_SIZE]);
-
-out:
- tpm_buf_destroy(&buf);
+ (__be32 *)&buf->data[TPM_HEADER_SIZE]);
return tpm_ret_to_err(rc);
}
@@ -482,7 +485,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
u32 blob_handle)
{
struct tpm_header *head;
- struct tpm_buf buf;
+ struct tpm_buf *buf __free(kfree) = NULL;
u16 data_len;
int offset;
u8 *data;
@@ -492,18 +495,21 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
if (rc)
return rc;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
- if (rc) {
+ buf = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
tpm2_end_auth_session(chip);
- return rc;
+ return -ENOMEM;
}
- rc = tpm_buf_append_name(chip, &buf, blob_handle, NULL);
+ tpm_buf_init(buf, TPM_BUFSIZE);
+ tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
+
+ rc = tpm_buf_append_name(chip, buf, blob_handle, NULL);
if (rc)
- goto out;
+ return rc;
if (!options->policyhandle) {
- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT,
options->blobauth,
options->blobauth_len);
} else {
@@ -518,39 +524,36 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
* could repeat our actions with the exfiltrated
* password.
*/
- tpm2_buf_append_auth(&buf, options->policyhandle,
+ tpm2_buf_append_auth(buf, options->policyhandle,
NULL /* nonce */, 0, 0,
options->blobauth, options->blobauth_len);
if (tpm2_chip_auth(chip)) {
- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT, NULL, 0);
+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT,
+ NULL, 0);
} else {
- offset = buf.handles * 4 + TPM_HEADER_SIZE;
- head = (struct tpm_header *)buf.data;
- if (tpm_buf_length(&buf) == offset)
+ offset = buf->handles * 4 + TPM_HEADER_SIZE;
+ head = (struct tpm_header *)buf->data;
+ if (tpm_buf_length(buf) == offset)
head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
}
}
- rc = tpm_buf_fill_hmac_session(chip, &buf);
+ rc = tpm_buf_fill_hmac_session(chip, buf);
if (rc)
- goto out;
+ return rc;
- rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ rc = tpm_transmit_cmd(chip, buf, 6, "unsealing");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (!rc) {
data_len = be16_to_cpup(
- (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
- if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) {
- rc = -EFAULT;
- goto out;
- }
+ (__be16 *)&buf->data[TPM_HEADER_SIZE + 4]);
+ if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE)
+ return -EFAULT;
- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
- rc = -EFAULT;
- goto out;
- }
- data = &buf.data[TPM_HEADER_SIZE + 6];
+ if (tpm_buf_length(buf) < TPM_HEADER_SIZE + 6 + data_len)
+ return -EFAULT;
+ data = &buf->data[TPM_HEADER_SIZE + 6];
if (payload->old_format) {
/* migratable flag is at the end of the key */
@@ -567,8 +570,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
}
}
-out:
- tpm_buf_destroy(&buf);
return tpm_ret_to_err(rc);
}
--
2.47.3
^ permalink raw reply related
* [linux-next:master] BUILD REGRESSION 550604d6c9b9efc8d068aff94dc301694a7afdee
From: kernel test robot @ 2026-05-22 0:33 UTC (permalink / raw)
To: Andrew Morton
Cc: Linux Memory Management List, amd-gfx, dri-devel, kexec, keyrings,
linux-aio, linux-block, linux-fsdevel, linux-gpio, linux-hexagon,
linux-modules, linux-nfs, linux-perf-users, linux-riscv,
linux-security-module, linux-serial, linux-um, linuxppc-dev,
netdev, sparclinux, Mark Brown
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
branch HEAD: 550604d6c9b9efc8d068aff94dc301694a7afdee Add linux-next specific files for 20260521
Error/Warning (recently discovered and may have been fixed):
https://lore.kernel.org/oe-kbuild-all/202605212104.SAIMqegX-lkp@intel.com
https://lore.kernel.org/oe-kbuild-all/202605220247.dQAHslyv-lkp@intel.com
https://lore.kernel.org/oe-kbuild-all/202605220312.Pu7UO05u-lkp@intel.com
https://lore.kernel.org/oe-kbuild-all/202605220631.ugDr2VPb-lkp@intel.com
/usr/bin/ld: sound/soc/codecs/es9356.o:(.rodata+0x2c30): undefined reference to `sdca_asoc_q78_get_volsw'
/usr/bin/ld: sound/soc/codecs/es9356.o:(.rodata+0x2c38): undefined reference to `sdca_asoc_q78_put_volsw'
arch/hexagon/kernel/syscalltab.c:19:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/powerpc/kernel/pci_64.c:226:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/powerpc/kernel/rtas.c:1850:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/powerpc/kernel/signal_32.c:990:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/powerpc/kernel/signal_64.c:657:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/powerpc/kernel/sys_ppc32.c:70:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/powerpc/kernel/syscalls.c:52:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/riscv/kernel/sys_hwprobe.c:606:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/riscv/kernel/sys_riscv.c:43:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/sparc/kernel/sys_sparc32.c:54:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/sparc/kernel/sys_sparc_64.c:351:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
arch/x86/um/syscalls_64.c:43:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
block/ioprio.c:65:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_crat.c:1830:26: error: cannot take the address of an rvalue of type 'int'
drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_crat.c:1830:27: error: call to undeclared function 'cpu_data'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_crat.c:1833:23: error: use of undeclared identifier 'X86_VENDOR_AMD'
drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_crat.c:1833:7: error: incomplete definition of type 'struct cpuinfo_x86'
drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_topology.c:2353:41: error: member reference base type 'int' is not a structure or union
drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_topology.c:2353:9: error: call to undeclared function 'cpu_data'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c:152:68: warning: '%d' directive output may be truncated writing between 1 and 11 bytes into a region of size 7 [-Wformat-truncation=]
drivers/gpu/drm/scheduler/tests/tests_scheduler.c:675:10: error: initializer element is not a compile-time constant
drivers/pinctrl/pinctrl-generic.c:130:5: error: redefinition of 'pinctrl_generic_pins_function_dt_node_to_map'
drivers/pinctrl/pinctrl-generic.c:20:5: error: conflicting types for 'pinctrl_generic_to_map'; have 'int(struct pinctrl_dev *, struct device_node *, struct device_node *, struct pinctrl_map **, unsigned int *, unsigned int *, const char **, unsigned int, const char **, unsigned int *, unsigned int)'
fs/aio.c:1436:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/d_path.c:413:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/eventfd.c:414:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/eventpoll.c:2200:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/eventpoll.c:2483:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/exec.c:1924:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/exec.c:1925:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/fcntl.c:587:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/fhandle.c:129:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/file.c:818:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/file.c:819:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/file_attr.c:374:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/fsopen.c:120:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/ioctl.c:583:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/locks.c:2214:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/locks.c:2280:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/namei.c:5186:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/namei.c:5197:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/namespace.c:2068:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/namespace.c:2073:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/notify/inotify/inotify_user.c:720:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/open.c:152:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/pipe.c:1054:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/pipe.c:1055:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/read_write.c:412:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/readdir.c:215:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/readdir.c:304:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/select.c:722:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/select.c:733:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/signalfd.c:299:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/splice.c:1578:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/stat.c:420:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/stat.c:505:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/statfs.c:191:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/sync.c:148:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/timerfd.c:394:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/timerfd.c:424:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/utimes.c:142:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/xattr.c:732:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
fs/xattr.c:735:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
ipc/msg.c:315:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
ipc/sem.c:624:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
ipc/shm.c:847:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
ipc/shm.c:849:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/capability.c:137:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/events/core.c:13844:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/events/core.c:13853:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/exec_domain.c:38:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/exit.c:1082:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/exit.c:1112:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/fork.c:1785:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/fork.c:1808:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/futex/syscalls.c:28:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/groups.c:161:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/kcmp.c:135:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/kexec.c:242:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/module/main.c:804:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/nsproxy.c:569:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/nstree.c:763:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/pid.c:695:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/printk/printk.c:1853:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/ptrace.c:1388:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/ptrace.c:1415:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/reboot.c:728:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/rseq.c:547:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/sched/membarrier.c:634:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/sched/membarrier.c:636:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/sched/syscalls.c:132:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/seccomp.c:2126:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/signal.c:3319:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/sys.c:259:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/hrtimer.c:2381:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/hrtimer.c:2466:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/hrtimer.c:2487:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/itimer.c:113:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/posix-stubs.c:26:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/posix-timers.c:566:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/posix-timers.c:574:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/time.c:105:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/time.c:140:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/time/time.c:62:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
kernel/uid16.c:23:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
ld.lld: error: undefined symbol: sdca_asoc_q78_get_volsw
ld.lld: error: undefined symbol: sdca_asoc_q78_put_volsw
mm/fadvise.c:200:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/filemap.c:4713:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/filemap.c:4718:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/madvise.c:2013:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/madvise.c:2029:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/memfd.c:505:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/mincore.c:292:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/mlock.c:665:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/mmap.c:116:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/mprotect.c:985:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/mremap.c:2023:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/msync.c:32:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/oom_kill.c:1195:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/process_vm_access.c:292:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/readahead.c:736:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/readahead.c:760:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/swapfile.c:2903:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
mm/swapfile.c:3124:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
net/socket.c:1818:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
net/socket.c:1833:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
security/keys/compat.c:17:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
security/keys/keyctl.c:74:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
security/landlock/syscalls.c:203:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
security/lsm_syscalls.c:57:1: error: unknown warning group '-Wattribute-alias', ignored [-Werror,-Wunknown-warning-option]
Unverified Error/Warning (likely false positive, kindly check if interested):
Warning: block/blk-map.c:366 Excess function parameter 'op' description in 'bio_copy_kern'
csky-linux-ld: sound/soc/codecs/es9356.o:(.rodata+0x16c8): undefined reference to `sdca_asoc_q78_get_volsw'
csky-linux-ld: sound/soc/codecs/es9356.o:(.rodata+0x16cc): undefined reference to `sdca_asoc_q78_put_volsw'
drivers/android/binder_alloc.c:389:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/auxdisplay/panel.c:1508:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/base/regmap/regmap-debugfs.c:180:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/char/xillybus/xillybus_core.c:425:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/dma/qcom/hidma.c:389:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c:2853:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c:357:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c:295:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/gpu/drm/udl/udl_main.c:260:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/gpu/drm/xe/xe_sched_job.c:162:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/greybus/es2.c:1428:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/hwmon/ibmpex.c:433:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/media/i2c/ds90ub960.c:4790:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/mtd/parsers/redboot.c:304:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/mtd/spi-nor/core.c:1645:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/net/ethernet/mellanox/mlx5/core/cmd.c:1508:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/scsi/aacraid/commsup.c:1928:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/scsi/aacraid/dpcsup.c:216:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/thunderbolt/stream.c:1388:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/tty/serial/max310x.c:1727:24: error: incompatible pointer types passing 'struct i2c_driver *' to parameter of type 'struct spi_driver *' [-Wincompatible-pointer-types]
drivers/tty/serial/max310x.c:1727:25: error: use of undeclared identifier 'max310x_spi_driver'; did you mean 'max310x_i2c_driver'?
drivers/tty/serial/max310x.c:1727:32: error: 'max310x_spi_driver' undeclared (first use in this function); did you mean 'max310x_i2c_driver'?
drivers/tty/serial/max310x.c:1745:25: error: 'max310x_spi_driver' undeclared (first use in this function); did you mean 'max310x_i2c_driver'?
drivers/tty/serial/max310x.c:1745:32: error: 'max310x_spi_driver' undeclared (first use in this function); did you mean 'max310x_i2c_driver'?
drivers/usb/host/xhci-mem.c:866:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/usb/misc/usbtest.c:1416:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
drivers/usb/serial/usb_wwan.c:501:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
fs/btrfs/file.c:3288:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
fs/btrfs/inode.c:8975:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
fs/isofs/inode.c:1267:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
fs/nilfs2/recovery.c:397:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
fs/xfs/scrub/bitmap.c:116:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
kernel/bpf/syscall.c:3797:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
kernel/events/core.c:12131:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
kernel/trace/ring_buffer.c:2348:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
ld.lld: error: call to __compiletime_assert_537 marked "dontcall-error": BUILD_BUG_ON failed: 21 - 1 != HWEIGHT32( (VALID_OPENAT2_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | __FMODE_EXEC)
lib/raid/raid6/powerpc/altivec1.c:37:16: sparse: sparse: Trying to use reserved word 'signed' as identifier
lib/raid/raid6/powerpc/altivec1.c:37:16: sparse: sparse: two or more data types in declaration specifiers
lib/raid/raid6/powerpc/altivec2.c:37:16: sparse: sparse: Trying to use reserved word 'signed' as identifier
lib/raid/raid6/powerpc/altivec2.c:37:16: sparse: sparse: two or more data types in declaration specifiers
lib/raid/raid6/powerpc/altivec4.c:37:16: sparse: sparse: Trying to use reserved word 'signed' as identifier
lib/raid/raid6/powerpc/altivec4.c:37:16: sparse: sparse: two or more data types in declaration specifiers
lib/raid/raid6/powerpc/altivec8.c:37:16: sparse: sparse: Trying to use reserved word 'signed' as identifier
lib/raid/raid6/powerpc/altivec8.c:37:16: sparse: sparse: two or more data types in declaration specifiers
net/bluetooth/mgmt.c:4400:1: internal compiler error: in final_scan_insn_1, at final.cc:2813
Error/Warning ids grouped by kconfigs:
recent_errors
|-- alpha-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- alpha-allyesconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- alpha-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- alpha-randconfig-r052-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arc-allmodconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arc-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arc-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm-allyesconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm-defconfig
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- block-ioprio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-aio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-d_path.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventpoll.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-exec.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fcntl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fhandle.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file_attr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fsopen.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-ioctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-locks.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namei.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namespace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-notify-inotify-inotify_user.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-open.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-pipe.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-read_write.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-readdir.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-select.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-signalfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-splice.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-stat.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-statfs.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-sync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-timerfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-utimes.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-xattr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-msg.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-sem.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-shm.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-capability.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-events-core.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exec_domain.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exit.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-fork.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-futex-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-groups.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-kcmp.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-kexec.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-module-main.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nsproxy.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nstree.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-pid.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-printk-printk.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-ptrace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-reboot.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-rseq.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-membarrier.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-seccomp.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-signal.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sys.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-hrtimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-itimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-posix-timers.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-time.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-uid16.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-fadvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-filemap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-madvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-memfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mincore.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mlock.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mmap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mprotect.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mremap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-msync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-oom_kill.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-process_vm_access.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-readahead.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-swapfile.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- net-socket.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- security-keys-keyctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- arm-randconfig-001-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- block-ioprio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- arm-randconfig-002-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm-randconfig-004-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm-randconfig-r062-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- block-ioprio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-d_path.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventpoll.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-exec.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fcntl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file_attr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fsopen.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-ioctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namei.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namespace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-notify-inotify-inotify_user.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-open.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-pipe.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-read_write.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-readdir.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-select.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-signalfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-splice.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-stat.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-statfs.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-sync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-utimes.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-xattr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-msg.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-sem.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-shm.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-capability.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-events-core.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exec_domain.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exit.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-fork.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-futex-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-groups.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-module-main.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nsproxy.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nstree.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-pid.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-printk-printk.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-ptrace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-reboot.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-rseq.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-membarrier.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-signal.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sys.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-hrtimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-itimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-posix-timers.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-time.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-uid16.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-fadvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-filemap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-madvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-memfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mincore.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mlock.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mmap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mprotect.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mremap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-msync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-oom_kill.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-process_vm_access.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-readahead.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- net-socket.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- security-keys-keyctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- arm64-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm64-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm64-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm64-randconfig-003-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm64-randconfig-004
| |-- ld.lld:error:undefined-symbol:sdca_asoc_q78_get_volsw
| `-- ld.lld:error:undefined-symbol:sdca_asoc_q78_put_volsw
|-- arm64-randconfig-004-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- arm64-randconfig-r072-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- csky-allmodconfig
| `-- drivers-thunderbolt-stream.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
|-- csky-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- csky-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- csky-randconfig-001-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- drivers-base-regmap-regmap-debugfs.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-gpu-drm-nouveau-nvkm-subdev-acr-base.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-gpu-drm-nouveau-nvkm-subdev-iccsense-base.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-gpu-drm-udl-udl_main.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-gpu-drm-xe-xe_sched_job.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-greybus-es2.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-mtd-parsers-redboot.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-scsi-aacraid-commsup.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-scsi-aacraid-dpcsup.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-usb-host-xhci-mem.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-usb-misc-usbtest.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-usb-serial-usb_wwan.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- fs-btrfs-file.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- fs-btrfs-inode.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- fs-isofs-inode.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- fs-nilfs2-recovery.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| `-- fs-xfs-scrub-bitmap.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
|-- csky-randconfig-002-20260521
| |-- csky-linux-ld:sound-soc-codecs-es9356.o:(.rodata):undefined-reference-to-sdca_asoc_q78_get_volsw
| |-- csky-linux-ld:sound-soc-codecs-es9356.o:(.rodata):undefined-reference-to-sdca_asoc_q78_put_volsw
| |-- drivers-android-binder_alloc.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-auxdisplay-panel.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-char-xillybus-xillybus_core.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-hwmon-ibmpex.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-media-i2c-ds90ub960.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-mtd-spi-nor-core.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- kernel-events-core.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| `-- kernel-trace-ring_buffer.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
|-- csky-randconfig-r062-20260521
| |-- drivers-dma-qcom-hidma.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-gpu-drm-amd-amdgpu-dce_v10_0.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- drivers-net-ethernet-mellanox-mlx5-core-cmd.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| |-- kernel-bpf-syscall.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
| `-- net-bluetooth-mgmt.c:internal-compiler-error:in-final_scan_insn_1-at-final.cc
|-- hexagon-allmodconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- hexagon-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- hexagon-defconfig
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- arch-hexagon-kernel-syscalltab.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- hexagon-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- hexagon-randconfig-002
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-buildonly-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-buildonly-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-buildonly-randconfig-003
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-buildonly-randconfig-003-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- drivers-tty-serial-max31.c:error:use-of-undeclared-identifier-max31_spi_driver
|-- i386-buildonly-randconfig-004
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-buildonly-randconfig-005-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-buildonly-randconfig-006-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-002
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-002-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-003-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-004
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-005
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-006-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-007
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-051-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-052-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-054-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- drivers-tty-serial-max31.c:error:max31_spi_driver-undeclared-(first-use-in-this-function)
|-- i386-randconfig-062-20260522
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- i386-randconfig-063-20260522
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- loongarch-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- loongarch-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- loongarch-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- loongarch-randconfig-002
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- m68k-allmodconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- m68k-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- m68k-allyesconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- m68k-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- microblaze-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- microblaze-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- microblaze-randconfig-r061-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- mips-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- mips-randconfig-r071-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- kernel-time-posix-stubs.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- security-keys-keyctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- nios2-allmodconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- nios2-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- nios2-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- nios2-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- nios2-randconfig-002
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- nios2-randconfig-r054-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- openrisc-allmodconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- openrisc-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- parisc-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- parisc-allyesconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- parisc-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- parisc-randconfig-r073-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- parisc64-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- powerpc-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- powerpc-randconfig-r063-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- powerpc-randconfig-r064-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- powerpc-sam440ep_defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- powerpc64-randconfig-r061-20260522
| |-- arch-powerpc-kernel-pci_64.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- arch-powerpc-kernel-rtas.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- arch-powerpc-kernel-signal_32.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- arch-powerpc-kernel-signal_64.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- arch-powerpc-kernel-sys_ppc32.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- arch-powerpc-kernel-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- powerpc64-randconfig-r131-20260521
| |-- lib-raid-raid6-powerpc-altivec1.c:sparse:sparse:Trying-to-use-reserved-word-signed-as-identifier
| |-- lib-raid-raid6-powerpc-altivec1.c:sparse:sparse:two-or-more-data-types-in-declaration-specifiers
| |-- lib-raid-raid6-powerpc-altivec2.c:sparse:sparse:Trying-to-use-reserved-word-signed-as-identifier
| |-- lib-raid-raid6-powerpc-altivec2.c:sparse:sparse:two-or-more-data-types-in-declaration-specifiers
| |-- lib-raid-raid6-powerpc-altivec4.c:sparse:sparse:Trying-to-use-reserved-word-signed-as-identifier
| |-- lib-raid-raid6-powerpc-altivec4.c:sparse:sparse:two-or-more-data-types-in-declaration-specifiers
| |-- lib-raid-raid6-powerpc-altivec8.c:sparse:sparse:Trying-to-use-reserved-word-signed-as-identifier
| `-- lib-raid-raid6-powerpc-altivec8.c:sparse:sparse:two-or-more-data-types-in-declaration-specifiers
|-- riscv-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- riscv-allyesconfig
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- drivers-gpu-drm-scheduler-tests-tests_scheduler.c:error:initializer-element-is-not-a-compile-time-constant
|-- riscv-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- riscv-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- riscv-randconfig-002
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- riscv-randconfig-002-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- riscv-randconfig-r131-20260521
| |-- arch-riscv-kernel-sys_hwprobe.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- arch-riscv-kernel-sys_riscv.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- ld.lld:error:call-to-__compiletime_assert_NNN-marked-dontcall-error:BUILD_BUG_ON-failed:HWEIGHT32(-(VALID_OPENAT2_FLAGS-(O_NONBLOCK-O_NDELAY))-__FMODE_EXEC)
|-- s390-allmodconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- s390-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- s390-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- s390-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- s390-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- s390-randconfig-002-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- s390-randconfig-r064-20260522
| `-- drivers-tty-serial-max31.c:error:incompatible-pointer-types-passing-struct-i2c_driver-to-parameter-of-type-struct-spi_driver
|-- sh-allmodconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sh-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sh-allyesconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sh-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sh-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sh-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sh-randconfig-002
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sh-randconfig-002-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc-randconfig-002
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc-randconfig-002-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc64-allmodconfig
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- arch-sparc-kernel-sys_sparc32.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- arch-sparc-kernel-sys_sparc_64.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- block-ioprio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-aio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-d_path.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventpoll.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-exec.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fcntl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fhandle.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file_attr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fsopen.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-ioctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-locks.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namei.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namespace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-notify-inotify-inotify_user.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-open.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-pipe.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-read_write.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-readdir.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-select.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-signalfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-splice.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-stat.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-statfs.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-sync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-timerfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-utimes.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-xattr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-msg.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-sem.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- ipc-shm.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-capability.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-events-core.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exec_domain.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exit.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-fork.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-futex-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-groups.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-kcmp.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-module-main.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nsproxy.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nstree.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-pid.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-printk-printk.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-ptrace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-reboot.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-membarrier.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-seccomp.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-signal.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sys.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-hrtimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-itimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-posix-timers.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-time.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-uid16.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-fadvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-filemap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-madvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-memfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mincore.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mlock.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mmap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mprotect.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mremap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-msync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-oom_kill.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-process_vm_access.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-readahead.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-swapfile.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- net-socket.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- security-keys-compat.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- security-landlock-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- security-lsm_syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- sparc64-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc64-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- sparc64-randconfig-001-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- drivers-tty-serial-max31.c:error:max31_spi_driver-undeclared-(first-use-in-this-function)
|-- sparc64-randconfig-002
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- arch-sparc-kernel-sys_sparc32.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- arch-sparc-kernel-sys_sparc_64.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- block-ioprio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-aio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-d_path.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventpoll.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-exec.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fcntl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fhandle.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file_attr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fsopen.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-ioctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-locks.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namei.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namespace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-notify-inotify-inotify_user.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-open.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-pipe.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-read_write.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-readdir.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-select.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-signalfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-splice.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-stat.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-statfs.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-sync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-timerfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-utimes.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-xattr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-capability.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-events-core.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exec_domain.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exit.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-fork.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-futex-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-groups.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-kcmp.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nsproxy.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nstree.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-pid.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-printk-printk.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-ptrace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-reboot.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-membarrier.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-seccomp.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-signal.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sys.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-hrtimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-itimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-posix-timers.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-time.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-uid16.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-fadvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-filemap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-madvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mincore.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mlock.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mmap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mprotect.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mremap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-msync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-oom_kill.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-process_vm_access.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-readahead.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- net-socket.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- security-keys-compat.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- security-keys-keyctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- security-lsm_syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- sparc64-randconfig-002-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- drivers-tty-serial-max31.c:error:max31_spi_driver-undeclared-(first-use-in-this-function)
|-- um-allmodconfig
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- drivers-gpu-drm-amd-amdgpu-..-amdkfd-kfd_crat.c:error:call-to-undeclared-function-cpu_data-ISO-C99-and-later-do-not-support-implicit-function-declarations
| |-- drivers-gpu-drm-amd-amdgpu-..-amdkfd-kfd_crat.c:error:cannot-take-the-address-of-an-rvalue-of-type-int
| |-- drivers-gpu-drm-amd-amdgpu-..-amdkfd-kfd_crat.c:error:incomplete-definition-of-type-struct-cpuinfo_x86
| |-- drivers-gpu-drm-amd-amdgpu-..-amdkfd-kfd_crat.c:error:use-of-undeclared-identifier-X86_VENDOR_AMD
| |-- drivers-gpu-drm-amd-amdgpu-..-amdkfd-kfd_topology.c:error:call-to-undeclared-function-cpu_data-ISO-C99-and-later-do-not-support-implicit-function-declarations
| `-- drivers-gpu-drm-amd-amdgpu-..-amdkfd-kfd_topology.c:error:member-reference-base-type-int-is-not-a-structure-or-union
|-- um-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- um-allyesconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- um-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- um-i386_defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- um-randconfig-001
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- block-ioprio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-d_path.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventpoll.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-exec.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fcntl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fhandle.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file_attr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fsopen.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-ioctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namei.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namespace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-open.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-pipe.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-read_write.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-readdir.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-select.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-splice.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-stat.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-statfs.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-sync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-timerfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-utimes.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-xattr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exec_domain.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exit.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-fork.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-kcmp.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nsproxy.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nstree.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-pid.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-printk-printk.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-ptrace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-reboot.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-signal.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sys.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-hrtimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-posix-stubs.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-time.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mincore.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mlock.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mmap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mprotect.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mremap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-msync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-oom_kill.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-process_vm_access.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-readahead.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- net-socket.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- security-keys-keyctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- um-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- um-randconfig-002
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- arch-x86-um-syscalls_64.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- block-ioprio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-aio.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-d_path.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-eventpoll.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-exec.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fcntl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fhandle.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-file_attr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-fsopen.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-ioctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-locks.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namei.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-namespace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-notify-inotify-inotify_user.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-open.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-pipe.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-read_write.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-readdir.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-select.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-signalfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-splice.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-stat.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-statfs.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-sync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-timerfd.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-utimes.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- fs-xattr.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-capability.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exec_domain.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-exit.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-fork.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-futex-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-groups.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-module-main.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nsproxy.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-nstree.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-pid.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-printk-printk.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-ptrace.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-reboot.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-membarrier.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sched-syscalls.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-seccomp.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-signal.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-sys.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-hrtimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-itimer.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-posix-timers.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-time-time.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- kernel-uid16.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-fadvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-filemap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-madvise.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mincore.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mlock.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mmap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mprotect.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-mremap.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-msync.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-oom_kill.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-process_vm_access.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-readahead.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| |-- mm-swapfile.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
| `-- security-keys-keyctl.c:error:unknown-warning-group-Wattribute-alias-ignored-Werror-Wunknown-warning-option
|-- um-randconfig-002-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- drivers-tty-serial-max31.c:error:max31_spi_driver-undeclared-(first-use-in-this-function)
| |-- usr-bin-ld:sound-soc-codecs-es9356.o:(.rodata):undefined-reference-to-sdca_asoc_q78_get_volsw
| `-- usr-bin-ld:sound-soc-codecs-es9356.o:(.rodata):undefined-reference-to-sdca_asoc_q78_put_volsw
|-- um-randconfig-r053-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- um-x86_64_defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-buildonly-randconfig-002-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-buildonly-randconfig-003-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-buildonly-randconfig-004-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| |-- drivers-gpu-drm-amd-amdgpu-jpeg_v2_5.c:warning:d-directive-output-may-be-truncated-writing-between-and-bytes-into-a-region-of-size
| |-- drivers-pinctrl-pinctrl-generic.c:error:conflicting-types-for-pinctrl_generic_to_map-have-int(struct-pinctrl_dev-struct-device_node-struct-device_node-struct-pinctrl_map-unsigned-int-unsigned-int-cons
| |-- drivers-pinctrl-pinctrl-generic.c:error:redefinition-of-pinctrl_generic_pins_function_dt_node_to_map
| `-- drivers-tty-serial-max31.c:error:max31_spi_driver-undeclared-(first-use-in-this-function)
|-- x86_64-buildonly-randconfig-005-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-defconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-kexec
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-001-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-002-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-004-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-006-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-011-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-012-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-013-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-014-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-015-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-016-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-071
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-071-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- drivers-pinctrl-pinctrl-generic.c:error:redefinition-of-pinctrl_generic_pins_function_dt_node_to_map
|-- x86_64-randconfig-072
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-072-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-073-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-074
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-074-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-075
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-076
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-076-20260521
| `-- drivers-pinctrl-pinctrl-generic.c:error:redefinition-of-pinctrl_generic_pins_function_dt_node_to_map
|-- x86_64-randconfig-101
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-101-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-102
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-102-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-103
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-104
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-104-20260521
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-121-20260522
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-122-20260522
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-randconfig-123-20260522
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- drivers-pinctrl-pinctrl-generic.c:error:redefinition-of-pinctrl_generic_pins_function_dt_node_to_map
|-- x86_64-randconfig-161
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-rhel-9.4
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-rhel-9.4-bpf
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-rhel-9.4-func
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-rhel-9.4-kselftests
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-rhel-9.4-kunit
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- x86_64-rhel-9.4-ltp
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- xtensa-allnoconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- xtensa-allyesconfig
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- xtensa-randconfig-001
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
|-- xtensa-randconfig-001-20260521
| |-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
| `-- drivers-tty-serial-max31.c:error:max31_spi_driver-undeclared-(first-use-in-this-function)
|-- xtensa-randconfig-002
| `-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
`-- xtensa-randconfig-002-20260521
`-- Warning:block-blk-map.c-Excess-function-parameter-op-description-in-bio_copy_kern
elapsed time: 724m
configs tested: 282
configs skipped: 11
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig clang-16
arc allmodconfig gcc-15.2.0
arc allnoconfig gcc-15.2.0
arc allyesconfig clang-23
arc allyesconfig gcc-15.2.0
arc defconfig gcc-15.2.0
arc randconfig-001 gcc-8.5.0
arc randconfig-001-20260521 gcc-13.4.0
arc randconfig-001-20260521 gcc-8.5.0
arc randconfig-002 gcc-8.5.0
arc randconfig-002-20260521 gcc-12.5.0
arc randconfig-002-20260521 gcc-8.5.0
arm allnoconfig clang-23
arm allnoconfig gcc-15.2.0
arm allyesconfig clang-16
arm allyesconfig gcc-15.2.0
arm defconfig clang-23
arm defconfig gcc-15.2.0
arm randconfig-001 gcc-8.5.0
arm randconfig-001-20260521 clang-23
arm randconfig-001-20260521 gcc-8.5.0
arm randconfig-002 gcc-11.5.0
arm randconfig-002-20260521 gcc-12.5.0
arm randconfig-002-20260521 gcc-8.5.0
arm randconfig-003 clang-20
arm randconfig-003-20260521 gcc-13.4.0
arm randconfig-003-20260521 gcc-8.5.0
arm randconfig-004 gcc-14.3.0
arm randconfig-004-20260521 gcc-8.5.0
arm64 allmodconfig clang-19
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001-20260521 clang-23
arm64 randconfig-001-20260521 gcc-8.5.0
arm64 randconfig-002-20260521 gcc-8.5.0
arm64 randconfig-003-20260521 gcc-8.5.0
arm64 randconfig-004-20260521 gcc-8.5.0
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001-20260521 gcc-15.2.0
csky randconfig-001-20260521 gcc-8.5.0
csky randconfig-002-20260521 gcc-15.2.0
csky randconfig-002-20260521 gcc-8.5.0
hexagon allmodconfig clang-17
hexagon allmodconfig gcc-15.2.0
hexagon allnoconfig clang-23
hexagon allnoconfig gcc-15.2.0
hexagon defconfig clang-23
hexagon defconfig gcc-15.2.0
hexagon randconfig-001 gcc-11.5.0
hexagon randconfig-001-20260521 clang-23
hexagon randconfig-001-20260521 gcc-11.5.0
hexagon randconfig-002 gcc-11.5.0
hexagon randconfig-002-20260521 clang-23
hexagon randconfig-002-20260521 gcc-11.5.0
i386 allmodconfig clang-20
i386 allmodconfig gcc-14
i386 allnoconfig gcc-14
i386 allnoconfig gcc-15.2.0
i386 allyesconfig clang-20
i386 allyesconfig gcc-14
i386 buildonly-randconfig-001 clang-20
i386 buildonly-randconfig-001-20260521 clang-20
i386 buildonly-randconfig-001-20260522 clang-20
i386 buildonly-randconfig-002 clang-20
i386 buildonly-randconfig-002-20260521 clang-20
i386 buildonly-randconfig-002-20260522 gcc-14
i386 buildonly-randconfig-003 clang-20
i386 buildonly-randconfig-003-20260521 clang-20
i386 buildonly-randconfig-003-20260522 clang-20
i386 buildonly-randconfig-004 clang-20
i386 buildonly-randconfig-004-20260521 clang-20
i386 buildonly-randconfig-004-20260522 gcc-14
i386 buildonly-randconfig-005 clang-20
i386 buildonly-randconfig-005-20260521 clang-20
i386 buildonly-randconfig-005-20260522 clang-20
i386 buildonly-randconfig-006 clang-20
i386 buildonly-randconfig-006-20260521 clang-20
i386 buildonly-randconfig-006-20260522 gcc-13
i386 defconfig clang-20
i386 defconfig gcc-15.2.0
i386 randconfig-001-20260521 clang-20
i386 randconfig-002-20260521 gcc-14
i386 randconfig-003-20260521 clang-20
i386 randconfig-004-20260521 gcc-14
i386 randconfig-005-20260521 clang-20
i386 randconfig-006-20260521 clang-20
i386 randconfig-007-20260521 clang-20
i386 randconfig-011-20260521 gcc-14
i386 randconfig-012-20260521 clang-20
i386 randconfig-013-20260521 gcc-13
i386 randconfig-014-20260521 gcc-14
i386 randconfig-015-20260521 gcc-14
i386 randconfig-016-20260521 clang-20
i386 randconfig-017-20260521 clang-20
loongarch allmodconfig clang-19
loongarch allmodconfig clang-23
loongarch allnoconfig clang-23
loongarch allnoconfig gcc-15.2.0
loongarch defconfig clang-19
loongarch randconfig-001 gcc-11.5.0
loongarch randconfig-001-20260521 gcc-11.5.0
loongarch randconfig-001-20260521 gcc-12.5.0
loongarch randconfig-002 gcc-11.5.0
loongarch randconfig-002-20260521 gcc-11.5.0
loongarch randconfig-002-20260521 gcc-15.2.0
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig clang-16
m68k allyesconfig gcc-15.2.0
m68k defconfig clang-19
m68k defconfig gcc-15.2.0
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig clang-19
microblaze defconfig gcc-15.2.0
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
nios2 allmodconfig clang-23
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig clang-23
nios2 allnoconfig gcc-11.5.0
nios2 defconfig clang-19
nios2 defconfig gcc-11.5.0
nios2 randconfig-001 gcc-11.5.0
nios2 randconfig-001-20260521 gcc-11.5.0
nios2 randconfig-002 gcc-11.5.0
nios2 randconfig-002-20260521 gcc-11.5.0
openrisc allmodconfig clang-23
openrisc allmodconfig gcc-15.2.0
openrisc allnoconfig clang-23
openrisc allnoconfig gcc-15.2.0
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-23
parisc allnoconfig gcc-15.2.0
parisc allyesconfig clang-19
parisc allyesconfig gcc-15.2.0
parisc defconfig gcc-15.2.0
parisc randconfig-001-20260521 gcc-12.5.0
parisc randconfig-002-20260521 gcc-15.2.0
parisc64 defconfig clang-19
parisc64 defconfig gcc-15.2.0
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-23
powerpc allnoconfig gcc-15.2.0
powerpc randconfig-001-20260521 clang-23
powerpc randconfig-002-20260521 clang-17
powerpc sam440ep_defconfig gcc-15.2.0
powerpc64 randconfig-001-20260521 clang-23
powerpc64 randconfig-002-20260521 gcc-12.5.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allnoconfig gcc-15.2.0
riscv allyesconfig clang-16
riscv defconfig gcc-15.2.0
riscv randconfig-001 gcc-15.2.0
riscv randconfig-001-20260521 clang-23
riscv randconfig-001-20260521 gcc-15.2.0
riscv randconfig-002 gcc-15.2.0
riscv randconfig-002-20260521 gcc-13.4.0
riscv randconfig-002-20260521 gcc-15.2.0
s390 allmodconfig clang-18
s390 allmodconfig clang-19
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 defconfig gcc-15.2.0
s390 randconfig-001 gcc-15.2.0
s390 randconfig-001-20260521 gcc-15.2.0
s390 randconfig-001-20260521 gcc-8.5.0
s390 randconfig-002 gcc-15.2.0
s390 randconfig-002-20260521 clang-17
s390 randconfig-002-20260521 gcc-15.2.0
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-23
sh allnoconfig gcc-15.2.0
sh allyesconfig clang-19
sh allyesconfig gcc-15.2.0
sh defconfig gcc-14
sh defconfig gcc-15.2.0
sh randconfig-001 gcc-15.2.0
sh randconfig-001-20260521 gcc-15.2.0
sh randconfig-002 gcc-15.2.0
sh randconfig-002-20260521 gcc-12.5.0
sh randconfig-002-20260521 gcc-15.2.0
sh rsk7264_defconfig gcc-15.2.0
sparc allnoconfig clang-23
sparc allnoconfig gcc-15.2.0
sparc defconfig gcc-15.2.0
sparc randconfig-001 gcc-8.5.0
sparc randconfig-001-20260521 gcc-8.5.0
sparc randconfig-002 gcc-8.5.0
sparc randconfig-002-20260521 gcc-8.5.0
sparc64 allmodconfig clang-23
sparc64 defconfig clang-20
sparc64 defconfig gcc-14
sparc64 randconfig-001 gcc-8.5.0
sparc64 randconfig-001-20260521 gcc-8.5.0
sparc64 randconfig-002 gcc-8.5.0
sparc64 randconfig-002-20260521 gcc-8.5.0
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-14
um allyesconfig gcc-15.2.0
um defconfig clang-23
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001 gcc-8.5.0
um randconfig-001-20260521 gcc-14
um randconfig-001-20260521 gcc-8.5.0
um randconfig-002 gcc-8.5.0
um randconfig-002-20260521 gcc-14
um randconfig-002-20260521 gcc-8.5.0
um x86_64_defconfig clang-23
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-20
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260521 clang-20
x86_64 buildonly-randconfig-001-20260521 gcc-12
x86_64 buildonly-randconfig-002-20260521 clang-20
x86_64 buildonly-randconfig-002-20260521 gcc-14
x86_64 buildonly-randconfig-003-20260521 clang-20
x86_64 buildonly-randconfig-004-20260521 clang-20
x86_64 buildonly-randconfig-004-20260521 gcc-14
x86_64 buildonly-randconfig-005-20260521 clang-20
x86_64 buildonly-randconfig-006-20260521 clang-20
x86_64 defconfig gcc-14
x86_64 kexec clang-20
x86_64 randconfig-001-20260521 clang-20
x86_64 randconfig-002-20260521 clang-20
x86_64 randconfig-003-20260521 clang-20
x86_64 randconfig-003-20260521 gcc-14
x86_64 randconfig-004-20260521 clang-20
x86_64 randconfig-005-20260521 clang-20
x86_64 randconfig-006-20260521 clang-20
x86_64 randconfig-011-20260521 clang-20
x86_64 randconfig-011-20260521 gcc-14
x86_64 randconfig-012-20260521 clang-20
x86_64 randconfig-012-20260521 gcc-14
x86_64 randconfig-013-20260521 clang-20
x86_64 randconfig-013-20260521 gcc-14
x86_64 randconfig-014-20260521 clang-20
x86_64 randconfig-014-20260521 gcc-14
x86_64 randconfig-015-20260521 clang-20
x86_64 randconfig-015-20260521 gcc-14
x86_64 randconfig-016-20260521 gcc-14
x86_64 randconfig-071 gcc-14
x86_64 randconfig-071-20260521 clang-20
x86_64 randconfig-072 gcc-14
x86_64 randconfig-072-20260521 clang-20
x86_64 randconfig-073 clang-20
x86_64 randconfig-073-20260521 clang-20
x86_64 randconfig-074 gcc-14
x86_64 randconfig-074-20260521 gcc-14
x86_64 randconfig-075 gcc-13
x86_64 randconfig-075-20260521 clang-20
x86_64 randconfig-076 clang-20
x86_64 randconfig-076-20260521 clang-20
x86_64 rhel-9.4 clang-20
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-20
x86_64 rhel-9.4-kselftests clang-20
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-23
xtensa allnoconfig gcc-15.2.0
xtensa allyesconfig clang-23
xtensa allyesconfig gcc-15.2.0
xtensa randconfig-001 gcc-8.5.0
xtensa randconfig-001-20260521 gcc-8.5.0
xtensa randconfig-002 gcc-8.5.0
xtensa randconfig-002-20260521 gcc-11.5.0
xtensa randconfig-002-20260521 gcc-8.5.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
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