Recreate RHEL 6.12.0-211.22.1 from CS10/upstream backports

Add the RHEL 211.21.1..211.22.1 backports (1288-1351) from centos-stream-10 and
upstream stable, on top of 211.20.1. Bump pkgrelease and specrelease to 211.22.1.
(The redhat/ automotive rebuild-changelog tooling change is omitted: it patches
redhat/scripts not present in this build base and does not affect the kernel.)
This commit is contained in:
Andrew Lukoshko 2026-06-11 10:33:04 +00:00
parent 4223cf37dd
commit 0eab958d1f
65 changed files with 11923 additions and 2 deletions

View File

@ -0,0 +1,90 @@
From 3453882f36c40d2339267093676585a89808a73d Mon Sep 17 00:00:00 2001
From: Xiang Mei <xmei5@asu.edu>
Date: Thu, 26 Mar 2026 00:55:53 -0700
Subject: [PATCH] net: bonding: fix use-after-free in bond_xmit_broadcast()
commit 2884bf72fb8f03409e423397319205de48adca16 upstream.
bond_xmit_broadcast() reuses the original skb for the last slave
(determined by bond_is_last_slave()) and clones it for others.
Concurrent slave enslave/release can mutate the slave list during
RCU-protected iteration, changing which slave is "last" mid-loop.
This causes the original skb to be double-consumed (double-freed).
Replace the racy bond_is_last_slave() check with a simple index
comparison (i + 1 == slaves_count) against the pre-snapshot slave
count taken via READ_ONCE() before the loop. This preserves the
zero-copy optimization for the last slave while making the "last"
determination stable against concurrent list mutations.
The UAF can trigger the following crash:
==================================================================
BUG: KASAN: slab-use-after-free in skb_clone
Read of size 8 at addr ffff888100ef8d40 by task exploit/147
CPU: 1 UID: 0 PID: 147 Comm: exploit Not tainted 7.0.0-rc3+ #4 PREEMPTLAZY
Call Trace:
<TASK>
dump_stack_lvl (lib/dump_stack.c:123)
print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
kasan_report (mm/kasan/report.c:597)
skb_clone (include/linux/skbuff.h:1724 include/linux/skbuff.h:1792 include/linux/skbuff.h:3396 net/core/skbuff.c:2108)
bond_xmit_broadcast (drivers/net/bonding/bond_main.c:5334)
bond_start_xmit (drivers/net/bonding/bond_main.c:5567 drivers/net/bonding/bond_main.c:5593)
dev_hard_start_xmit (include/linux/netdevice.h:5325 include/linux/netdevice.h:5334 net/core/dev.c:3871 net/core/dev.c:3887)
__dev_queue_xmit (include/linux/netdevice.h:3601 net/core/dev.c:4838)
ip6_finish_output2 (include/net/neighbour.h:540 include/net/neighbour.h:554 net/ipv6/ip6_output.c:136)
ip6_finish_output (net/ipv6/ip6_output.c:208 net/ipv6/ip6_output.c:219)
ip6_output (net/ipv6/ip6_output.c:250)
ip6_send_skb (net/ipv6/ip6_output.c:1985)
udp_v6_send_skb (net/ipv6/udp.c:1442)
udpv6_sendmsg (net/ipv6/udp.c:1733)
__sys_sendto (net/socket.c:730 net/socket.c:742 net/socket.c:2206)
__x64_sys_sendto (net/socket.c:2209)
do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
</TASK>
Allocated by task 147:
Freed by task 147:
The buggy address belongs to the object at ffff888100ef8c80
which belongs to the cache skbuff_head_cache of size 224
The buggy address is located 192 bytes inside of
freed 224-byte region [ffff888100ef8c80, ffff888100ef8d60)
Memory state around the buggy address:
ffff888100ef8c00: fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc
ffff888100ef8c80: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff888100ef8d00: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
^
ffff888100ef8d80: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
ffff888100ef8e00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
Fixes: 4e5bd03ae346 ("net: bonding: fix bond_xmit_broadcast return value error bug")
Reported-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Link: https://patch.msgid.link/20260326075553.3960562-1-xmei5@asu.edu
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kevin Berry <kpberry@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 294d00f..67fd0c4 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -5401,7 +5401,7 @@ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb,
if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP))
continue;
- if (bond_is_last_slave(bond, slave)) {
+ if (i + 1 == slaves_count) {
skb2 = skb;
skb_used = true;
} else {

View File

@ -0,0 +1,123 @@
From ac9c3524e6b15adece8493a0db2444e83b3de591 Mon Sep 17 00:00:00 2001
From: Mete Durlu <mdurlu@redhat.com>
Date: Fri, 20 Mar 2026 15:05:43 +0100
Subject: [PATCH] s390/pci: Avoid deadlock between PCI error recovery and mlx5
crdump
JIRA: https://issues.redhat.com/browse/RHEL-157932
commit 0fd20f65df6aa430454a0deed8f43efa91c54835
Author: Gerd Bayer <gbayer@linux.ibm.com>
Date: Thu Oct 16 11:27:03 2025 +0200
s390/pci: Avoid deadlock between PCI error recovery and mlx5 crdump
Do not block PCI config accesses through pci_cfg_access_lock() when
executing the s390 variant of PCI error recovery: Acquire just
device_lock() instead of pci_dev_lock() as powerpc's EEH and
generig PCI AER processing do.
During error recovery testing a pair of tasks was reported to be hung:
mlx5_core 0000:00:00.1: mlx5_health_try_recover:338:(pid 5553): health recovery flow aborted, PCI reads still not working
INFO: task kmcheck:72 blocked for more than 122 seconds.
Not tainted 5.14.0-570.12.1.bringup7.el9.s390x #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:kmcheck state:D stack:0 pid:72 tgid:72 ppid:2 flags:0x00000000
Call Trace:
[<000000065256f030>] __schedule+0x2a0/0x590
[<000000065256f356>] schedule+0x36/0xe0
[<000000065256f572>] schedule_preempt_disabled+0x22/0x30
[<0000000652570a94>] __mutex_lock.constprop.0+0x484/0x8a8
[<000003ff800673a4>] mlx5_unload_one+0x34/0x58 [mlx5_core]
[<000003ff8006745c>] mlx5_pci_err_detected+0x94/0x140 [mlx5_core]
[<0000000652556c5a>] zpci_event_attempt_error_recovery+0xf2/0x398
[<0000000651b9184a>] __zpci_event_error+0x23a/0x2c0
INFO: task kworker/u1664:6:1514 blocked for more than 122 seconds.
Not tainted 5.14.0-570.12.1.bringup7.el9.s390x #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:kworker/u1664:6 state:D stack:0 pid:1514 tgid:1514 ppid:2 flags:0x00000000
Workqueue: mlx5_health0000:00:00.0 mlx5_fw_fatal_reporter_err_work [mlx5_core]
Call Trace:
[<000000065256f030>] __schedule+0x2a0/0x590
[<000000065256f356>] schedule+0x36/0xe0
[<0000000652172e28>] pci_wait_cfg+0x80/0xe8
[<0000000652172f94>] pci_cfg_access_lock+0x74/0x88
[<000003ff800916b6>] mlx5_vsc_gw_lock+0x36/0x178 [mlx5_core]
[<000003ff80098824>] mlx5_crdump_collect+0x34/0x1c8 [mlx5_core]
[<000003ff80074b62>] mlx5_fw_fatal_reporter_dump+0x6a/0xe8 [mlx5_core]
[<0000000652512242>] devlink_health_do_dump.part.0+0x82/0x168
[<0000000652513212>] devlink_health_report+0x19a/0x230
[<000003ff80075a12>] mlx5_fw_fatal_reporter_err_work+0xba/0x1b0 [mlx5_core]
No kernel log of the exact same error with an upstream kernel is
available - but the very same deadlock situation can be constructed there,
too:
- task: kmcheck
mlx5_unload_one() tries to acquire devlink lock while the PCI error
recovery code has set pdev->block_cfg_access by way of
pci_cfg_access_lock()
- task: kworker
mlx5_crdump_collect() tries to set block_cfg_access through
pci_cfg_access_lock() while devlink_health_report() had acquired
the devlink lock.
A similar deadlock situation can be reproduced by requesting a
crdump with
> devlink health dump show pci/<BDF> reporter fw_fatal
while PCI error recovery is executed on the same <BDF> physical function
by mlx5_core's pci_error_handlers. On s390 this can be injected with
> zpcictl --reset-fw <BDF>
Tests with this patch failed to reproduce that second deadlock situation,
the devlink command is rejected with "kernel answers: Permission denied" -
and we get a kernel log message of:
mlx5_core 1ed0:00:00.1: mlx5_crdump_collect:50:(pid 254382): crdump: failed to lock vsc gw err -5
because the config read of VSC_SEMAPHORE is rejected by the underlying
hardware.
Two prior attempts to address this issue have been discussed and
ultimately rejected [see link], with the primary argument that s390's
implementation of PCI error recovery is imposing restrictions that
neither powerpc's EEH nor PCI AER handling need. Tests show that PCI
error recovery on s390 is running to completion even without blocking
access to PCI config space.
Link: https://lore.kernel.org/all/20251007144826.2825134-1-gbayer@linux.ibm.com/
Cc: stable@vger.kernel.org
Fixes: 4cdf2f4e24ff ("s390/pci: implement minimal PCI error recovery")
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Gerd Bayer <gbayer@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Mete Durlu <mdurlu@redhat.com>
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c
index d930416d4c90..da0de34d2e5c 100644
--- a/arch/s390/pci/pci_event.c
+++ b/arch/s390/pci/pci_event.c
@@ -187,7 +187,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev)
* is unbound or probed and that userspace can't access its
* configuration space while we perform recovery.
*/
- pci_dev_lock(pdev);
+ device_lock(&pdev->dev);
if (pdev->error_state == pci_channel_io_perm_failure) {
ers_res = PCI_ERS_RESULT_DISCONNECT;
goto out_unlock;
@@ -254,7 +254,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev)
if (driver->err_handler->resume)
driver->err_handler->resume(pdev);
out_unlock:
- pci_dev_unlock(pdev);
+ device_unlock(&pdev->dev);
zpci_report_status(zdev, "recovery", status_str);
return ers_res;
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,138 @@
From 9837d44c3a8c7908fca4a3e4ef2e753b43b2e7da Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Mon, 27 Apr 2026 17:18:26 +0200
Subject: [PATCH] ice: fix stats array overflow when VF requests more queues
JIRA: https://redhat.atlassian.net/browse/RHEL-163186
Upstream status: Posted: https://lore.kernel.org/netdev/20260427151827.43342-1-mschmidt@redhat.com/
When a VF increases its queue count via VIRTCHNL_OP_REQUEST_QUEUES,
ice_vc_request_qs_msg() sets vf->num_req_qs and triggers a VF reset.
The reset calls ice_vf_reconfig_vsi(), which does ice_vsi_decfg()
followed by ice_vsi_cfg(). ice_vsi_decfg() does not free the per-ring
stats arrays. Inside ice_vsi_cfg_def(), ice_vsi_set_num_qs() updates
alloc_txq/alloc_rxq to the new larger value, but
ice_vsi_alloc_stat_arrays() returns early because the stats already
exist. ice_vsi_alloc_ring_stats() then iterates using the new larger
alloc_txq and writes beyond the bounds of the old, smaller
tx_ring_stats/rx_ring_stats pointer arrays, corrupting adjacent SLUB
metadata.
KASAN detects the bug:
==================================================================
BUG: KASAN: slab-out-of-bounds in ice_vsi_alloc_ring_stats+0x385/0x4a0 [ice]
Read of size 8 at addr ffff88810affea60 by task kworker/u131:7/221
CPU: 24 UID: 0 PID: 221 Comm: kworker/u131:7 Not tainted 7.1.0-rc1+ #1 PREEMPT(lazy)
...
Workqueue: ice ice_service_task [ice]
Call Trace:
<TASK>
...
kasan_report+0xd7/0x120
ice_vsi_alloc_ring_stats+0x385/0x4a0 [ice]
ice_vsi_cfg_def+0x12e2/0x2060 [ice]
ice_vsi_cfg+0xb5/0x3c0 [ice]
ice_reset_vf+0x858/0xf80 [ice]
ice_vc_request_qs_msg+0x1da/0x290 [ice]
ice_vc_process_vf_msg+0xb15/0x1430 [ice]
__ice_clean_ctrlq+0x70d/0x9d0 [ice]
ice_service_task+0x840/0xf20 [ice]
process_one_work+0x690/0xff0
worker_thread+0x4d9/0xd20
kthread+0x322/0x410
ret_from_fork+0x332/0x660
ret_from_fork_asm+0x1a/0x30
</TASK>
Allocated by task 2439:
kasan_save_stack+0x1c/0x40
kasan_save_track+0x10/0x30
__kasan_kmalloc+0x96/0xb0
__kmalloc_noprof+0x1d8/0x580
ice_vsi_cfg_def+0x115c/0x2060 [ice]
ice_vsi_cfg+0xb5/0x3c0 [ice]
ice_vsi_setup+0x180/0x320 [ice]
ice_start_vfs+0x1f3/0x590 [ice]
ice_ena_vfs+0x66d/0x798 [ice]
ice_sriov_configure.cold+0xe4/0x121 [ice]
sriov_numvfs_store+0x279/0x480
kernfs_fop_write_iter+0x331/0x4f0
vfs_write+0x4c4/0xe40
ksys_write+0x10c/0x240
do_syscall_64+0xd9/0x650
entry_SYSCALL_64_after_hwframe+0x76/0x7e
The buggy address belongs to the object at ffff88810affea40
which belongs to the cache kmalloc-32 of size 32
The buggy address is located 0 bytes to the right of
allocated 32-byte region [ffff88810affea40, ffff88810affea60)
...
==================================================================
ice_vsi_rebuild() handles this correctly by calling
ice_vsi_realloc_stat_arrays() before reconfiguration, but
ice_vf_reconfig_vsi() was missing this call.
Fix by calling ice_vsi_realloc_stat_arrays() in ice_vf_reconfig_vsi()
before ice_vsi_decfg(), mirroring the ice_vsi_rebuild() pattern. Set
vsi->req_txq/req_rxq from vf->num_req_qs so the realloc function knows
the target array size.
See the linked RHEL Jira item for a reproducer.
Fixes: 2a2cb4c6c181 ("ice: replace ice_vf_recreate_vsi() with ice_vf_reconfig_vsi()")
Closes: https://redhat.atlassian.net/browse/RHEL-164321
Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
Assisted-by: Claude:claude-opus-4-6 semcode
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 26496eaed981..7bc5a7009cbb 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -3017,7 +3017,7 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi,
* ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones
* @vsi: VSI pointer
*/
-static int
+int
ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
{
u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq;
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index 2cb1eb98b9da..fce6f633f506 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -66,6 +66,7 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked);
void ice_vsi_decfg(struct ice_vsi *vsi);
void ice_dis_vsi(struct ice_vsi *vsi, bool locked);
+int ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi);
int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags);
int ice_vsi_cfg(struct ice_vsi *vsi);
struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf);
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index de9e81ccee66..fd71dd10eb38 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -268,6 +268,13 @@ static int ice_vf_reconfig_vsi(struct ice_vf *vf)
vsi->flags = ICE_VSI_FLAG_NO_INIT;
+ vsi->req_txq = vf->num_req_qs;
+ vsi->req_rxq = vf->num_req_qs;
+
+ err = ice_vsi_realloc_stat_arrays(vsi);
+ if (err)
+ return err;
+
ice_vsi_decfg(vsi);
ice_fltr_remove_all(vsi);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,57 @@
From 8ac29c454e865adf7b65a4f83d28177e0ecb1dca Mon Sep 17 00:00:00 2001
From: Ming Lei <ming.lei@redhat.com>
Date: Wed, 26 Nov 2025 17:06:31 +0100
Subject: [PATCH] s390/dasd: Fix gendisk parent after copy pair swap
JIRA: https://issues.redhat.com/browse/RHEL-144763
commit c943bfc6afb8d0e781b9b7406f36caa8bbf95cb9
Author: Stefan Haberland <sth@linux.ibm.com>
Date: Wed Nov 26 17:06:31 2025 +0100
s390/dasd: Fix gendisk parent after copy pair swap
After a copy pair swap the block device's "device" symlink points to
the secondary CCW device, but the gendisk's parent remained the
primary, leaving /sys/block/<dasdx> under the wrong parent.
Move the gendisk to the secondary's device with device_move(), keeping
the sysfs topology consistent after the swap.
Fixes: 413862caad6f ("s390/dasd: add copy pair swap capability")
Cc: stable@vger.kernel.org #6.1
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 1ebe589b5185..78fef8959c78 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -6149,6 +6149,7 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
struct dasd_copy_relation *copy;
struct dasd_block *block;
struct gendisk *gdp;
+ int rc;
copy = device->copy;
if (!copy)
@@ -6183,6 +6184,13 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
/* swap blocklayer device link */
gdp = block->gdp;
dasd_add_link_to_gendisk(gdp, secondary);
+ rc = device_move(disk_to_dev(gdp), &secondary->cdev->dev, DPM_ORDER_NONE);
+ if (rc) {
+ dev_err(&primary->cdev->dev,
+ "copy_pair_swap: moving blockdevice parent %s->%s failed (%d)\n",
+ dev_name(&primary->cdev->dev),
+ dev_name(&secondary->cdev->dev), rc);
+ }
/* re-enable device */
dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,54 @@
From 98d247e4eac9e5a06678190715d9f9d86902aa9c Mon Sep 17 00:00:00 2001
From: Mete Durlu <mdurlu@redhat.com>
Date: Fri, 27 Mar 2026 13:20:49 +0100
Subject: [PATCH] s390/dasd: Move quiesce state with pprc swap
JIRA: https://issues.redhat.com/browse/RHEL-161531
commit 40e9cd4ae8ec43b107ed2bff422a8fa39dcf4e4b
Author: Stefan Haberland <sth@linux.ibm.com>
Date: Tue Mar 10 15:23:29 2026 +0100
s390/dasd: Move quiesce state with pprc swap
Quiesce and resume is a mechanism to suspend operations on DASD devices.
In the context of a controlled copy pair swap operation, the quiesce
operation is usually issued before the actual swap and a resume
afterwards.
During the swap operation, the underlying device is exchanged. Therefore,
the quiesce flag must be moved to the secondary device to ensure a
consistent quiesce state after the swap.
The secondary device itself cannot be suspended separately because there
is no separate block device representation for it.
Fixes: 413862caad6f ("s390/dasd: add copy pair swap capability")
Cc: stable@vger.kernel.org #6.1
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Link: https://patch.msgid.link/20260310142330.4080106-2-sth@linux.ibm.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Mete Durlu <mdurlu@redhat.com>
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 78fef8959c78..c6d825109f53 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -6192,6 +6192,11 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
dev_name(&secondary->cdev->dev), rc);
}
+ if (primary->stopped & DASD_STOPPED_QUIESCE) {
+ dasd_device_set_stop_bits(secondary, DASD_STOPPED_QUIESCE);
+ dasd_device_remove_stop_bits(primary, DASD_STOPPED_QUIESCE);
+ }
+
/* re-enable device */
dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC);
dasd_device_remove_stop_bits(secondary, DASD_STOPPED_PPRC);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,83 @@
From 2435d419304a1e5bfc93947d3c6a7902b49aadcc Mon Sep 17 00:00:00 2001
From: Mete Durlu <mdurlu@redhat.com>
Date: Fri, 27 Mar 2026 13:20:52 +0100
Subject: [PATCH] s390/dasd: Copy detected format information to secondary
device
JIRA: https://issues.redhat.com/browse/RHEL-161531
commit 4c527c7e030672efd788d0806d7a68972a7ba3c1
Author: Stefan Haberland <sth@linux.ibm.com>
Date: Tue Mar 10 15:23:30 2026 +0100
s390/dasd: Copy detected format information to secondary device
During online processing for a DASD device an IO operation is started to
determine the format of the device. CDL format contains specifically
sized blocks at the beginning of the disk.
For a PPRC secondary device no real IO operation is possible therefore
this IO request can not be started and this step is skipped for online
processing of secondary devices. This is generally fine since the
secondary is a copy of the primary device.
In case of an additional partition detection that is run after a swap
operation the format information is needed to properly drive partition
detection IO.
Currently the information is not passed leading to IO errors during
partition detection and a wrongly detected partition table which in turn
might lead to data corruption on the disk with the wrong partition table.
Fix by passing the format information from primary to secondary device.
Fixes: 413862caad6f ("s390/dasd: add copy pair swap capability")
Cc: stable@vger.kernel.org #6.1
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Acked-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Link: https://patch.msgid.link/20260310142330.4080106-3-sth@linux.ibm.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Mete Durlu <mdurlu@redhat.com>
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index c6d825109f53..0d874d92a099 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -6145,6 +6145,7 @@ static void copy_pair_set_active(struct dasd_copy_relation *copy, char *new_busi
static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid,
char *sec_busid)
{
+ struct dasd_eckd_private *prim_priv, *sec_priv;
struct dasd_device *primary, *secondary;
struct dasd_copy_relation *copy;
struct dasd_block *block;
@@ -6165,6 +6166,9 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
if (!secondary)
return DASD_COPYPAIRSWAP_SECONDARY;
+ prim_priv = primary->private;
+ sec_priv = secondary->private;
+
/*
* usually the device should be quiesced for swap
* for paranoia stop device and requeue requests again
@@ -6197,6 +6201,13 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
dasd_device_remove_stop_bits(primary, DASD_STOPPED_QUIESCE);
}
+ /*
+ * The secondary device never got through format detection, but since it
+ * is a copy of the primary device, the format is exactly the same;
+ * therefore, the detected layout can simply be copied.
+ */
+ sec_priv->uses_cdl = prim_priv->uses_cdl;
+
/* re-enable device */
dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC);
dasd_device_remove_stop_bits(secondary, DASD_STOPPED_PPRC);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,55 @@
From 9478c166c46934160135e197b049b5a05753f2ad Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@redhat.com>
Date: Thu, 21 Nov 2024 11:46:01 +1000
Subject: [PATCH] nouveau/gsp: drop WARN_ON in ACPI probes
These WARN_ONs seem to trigger a lot, and we don't seem to have a
plan to fix them, so just drop them, as they are most likely
harmless.
Cc: stable@vger.kernel.org
Fixes: 176fdcbddfd2 ("drm/nouveau/gsp/r535: add support for booting GSP-RM")
Signed-off-by: Dave Airlie <airlied@redhat.com>
Link: https://patch.msgid.link/20241121014601.229391-1-airlied@gmail.com
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
index 7fb13434c051..a575a8dbf727 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
@@ -737,8 +737,8 @@ r535_gsp_acpi_caps(acpi_handle handle, CAPS_METHOD_DATA *caps)
if (!obj)
goto done;
- if (WARN_ON(obj->type != ACPI_TYPE_BUFFER) ||
- WARN_ON(obj->buffer.length != 4))
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length != 4)
goto done;
caps->status = 0;
@@ -773,8 +773,8 @@ r535_gsp_acpi_jt(acpi_handle handle, JT_METHOD_DATA *jt)
if (!obj)
goto done;
- if (WARN_ON(obj->type != ACPI_TYPE_BUFFER) ||
- WARN_ON(obj->buffer.length != 4))
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length != 4)
goto done;
jt->status = 0;
@@ -861,8 +861,8 @@ r535_gsp_acpi_dod(acpi_handle handle, DOD_METHOD_DATA *dod)
_DOD = output.pointer;
- if (WARN_ON(_DOD->type != ACPI_TYPE_PACKAGE) ||
- WARN_ON(_DOD->package.count > ARRAY_SIZE(dod->acpiIdList)))
+ if (_DOD->type != ACPI_TYPE_PACKAGE ||
+ _DOD->package.count > ARRAY_SIZE(dod->acpiIdList))
return;
for (int i = 0; i < _DOD->package.count; i++) {
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,77 @@
From c9a44a91015ff6116ef4dfb6e2c752e5366b2d32 Mon Sep 17 00:00:00 2001
From: Davide Caratti <dcaratti@redhat.com>
Date: Mon, 27 Apr 2026 12:58:46 +0200
Subject: [PATCH] can: raw: fix ro->uniq use-after-free in raw_rcv()
JIRA: https://redhat.atlassian.net/browse/RHEL-170766
CVE: CVE-2026-31532
Upstream Status: net-next.git commit a535a9217ca3f2fccedaafb2fddb4c48f27d36dc
commit a535a9217ca3f2fccedaafb2fddb4c48f27d36dc
Author: Samuel Page <sam@bynar.io>
Date: Wed Apr 8 15:30:13 2026 +0100
can: raw: fix ro->uniq use-after-free in raw_rcv()
raw_release() unregisters raw CAN receive filters via can_rx_unregister(),
but receiver deletion is deferred with call_rcu(). This leaves a window
where raw_rcv() may still be running in an RCU read-side critical section
after raw_release() frees ro->uniq, leading to a use-after-free of the
percpu uniq storage.
Move free_percpu(ro->uniq) out of raw_release() and into a raw-specific
socket destructor. can_rx_unregister() takes an extra reference to the
socket and only drops it from the RCU callback, so freeing uniq from
sk_destruct ensures the percpu area is not released until the relevant
callbacks have drained.
Fixes: 514ac99c64b2 ("can: fix multiple delivery of a single CAN frame for overlapping CAN filters")
Cc: stable@vger.kernel.org # v4.1+
Assisted-by: Bynario AI
Signed-off-by: Samuel Page <sam@bynar.io>
Link: https://patch.msgid.link/26ec626d-cae7-4418-9782-7198864d070c@bynar.io
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
[mkl: applied manually]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
diff --git a/net/can/raw.c b/net/can/raw.c
index 2aab0398e444..c7e392fad11a 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -360,6 +360,14 @@ static int raw_notifier(struct notifier_block *nb, unsigned long msg,
return NOTIFY_DONE;
}
+static void raw_sock_destruct(struct sock *sk)
+{
+ struct raw_sock *ro = raw_sk(sk);
+
+ free_percpu(ro->uniq);
+ can_sock_destruct(sk);
+}
+
static int raw_init(struct sock *sk)
{
struct raw_sock *ro = raw_sk(sk);
@@ -386,6 +394,8 @@ static int raw_init(struct sock *sk)
if (unlikely(!ro->uniq))
return -ENOMEM;
+ sk->sk_destruct = raw_sock_destruct;
+
/* set notifier */
spin_lock(&raw_notifier_lock);
list_add_tail(&ro->notifier, &raw_notifier_list);
@@ -433,7 +443,6 @@ static int raw_release(struct socket *sock)
ro->bound = 0;
ro->dev = NULL;
ro->count = 0;
- free_percpu(ro->uniq);
sock_orphan(sk);
sock->sk = NULL;
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,70 @@
From ce3e488188bb7c00b8ccdba07c6ccfb98d7384a2 Mon Sep 17 00:00:00 2001
From: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
Date: Tue, 28 Apr 2026 18:31:31 +0000
Subject: [PATCH] erofs: add GFP_NOIO in the bio completion if needed
JIRA: https://redhat.atlassian.net/browse/RHEL-171687
CVE: CVE-2026-31467
commit c23df30915f83e7257c8625b690a1cece94142a0
Author: Jiucheng Xu <jiucheng.xu@amlogic.com>
Date: Wed Mar 11 17:11:31 2026 +0800
erofs: add GFP_NOIO in the bio completion if needed
The bio completion path in the process context (e.g. dm-verity)
will directly call into decompression rather than trigger another
workqueue context for minimal scheduling latencies, which can
then call vm_map_ram() with GFP_KERNEL.
Due to insufficient memory, vm_map_ram() may generate memory
swapping I/O, which can cause submit_bio_wait to deadlock
in some scenarios.
Trimmed down the call stack, as follows:
f2fs_submit_read_io
submit_bio //bio_list is initialized.
mmc_blk_mq_recovery
z_erofs_endio
vm_map_ram
__pte_alloc_kernel
__alloc_pages_direct_reclaim
shrink_folio_list
__swap_writepage
submit_bio_wait //bio_list is non-NULL, hang!!!
Use memalloc_noio_{save,restore}() to wrap up this path.
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Jiucheng Xu <jiucheng.xu@amlogic.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index db1f13663cd5..cfde72fcd548 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -1337,6 +1337,7 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
int bios)
{
struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
+ int gfp_flag;
/* wake up the caller thread for sync decompression */
if (io->sync) {
@@ -1370,7 +1371,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
return;
}
+ gfp_flag = memalloc_noio_save();
z_erofs_decompressqueue_work(&io->u.work);
+ memalloc_noio_restore(gfp_flag);
}
static void z_erofs_fill_bio_vec(struct bio_vec *bvec,
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,90 @@
From ee288dfa7ea837c1ffe68fd01e54d422e02f0fc4 Mon Sep 17 00:00:00 2001
From: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
Date: Mon, 4 May 2026 08:33:31 +0000
Subject: [PATCH] ALSA: 6fire: fix use-after-free on disconnect
JIRA: https://redhat.atlassian.net/browse/RHEL-172974
CVE: CVE-2026-31581
commit b9c826916fdce6419b94eb0cd8810fdac18c2386
Author: Berk Cem Goksel <berkcgoksel@gmail.com>
Date: Fri Apr 10 08:13:41 2026 +0300
ALSA: 6fire: fix use-after-free on disconnect
In usb6fire_chip_abort(), the chip struct is allocated as the card's
private data (via snd_card_new with sizeof(struct sfire_chip)). When
snd_card_free_when_closed() is called and no file handles are open, the
card and embedded chip are freed synchronously. The subsequent
chip->card = NULL write then hits freed slab memory.
Call trace:
usb6fire_chip_abort sound/usb/6fire/chip.c:59 [inline]
usb6fire_chip_disconnect+0x348/0x358 sound/usb/6fire/chip.c:182
usb_unbind_interface+0x1a8/0x88c drivers/usb/core/driver.c:458
...
hub_event+0x1a04/0x4518 drivers/usb/core/hub.c:5953
Fix by moving the card lifecycle out of usb6fire_chip_abort() and into
usb6fire_chip_disconnect(). The card pointer is saved in a local
before any teardown, snd_card_disconnect() is called first to prevent
new opens, URBs are aborted while chip is still valid, and
snd_card_free_when_closed() is called last so chip is never accessed
after the card may be freed.
Fixes: a0810c3d6dd2 ("ALSA: 6fire: Release resources at card release")
Cc: stable@vger.kernel.org
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Signed-off-by: Berk Cem Goksel <berkcgoksel@gmail.com>
Link: https://patch.msgid.link/20260410051341.1069716-1-berkcgoksel@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
index 5ff78814e687..874f6cd503ca 100644
--- a/sound/usb/6fire/chip.c
+++ b/sound/usb/6fire/chip.c
@@ -53,11 +53,6 @@ static void usb6fire_chip_abort(struct sfire_chip *chip)
usb6fire_comm_abort(chip);
if (chip->control)
usb6fire_control_abort(chip);
- if (chip->card) {
- snd_card_disconnect(chip->card);
- snd_card_free_when_closed(chip->card);
- chip->card = NULL;
- }
}
}
@@ -168,6 +163,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
static void usb6fire_chip_disconnect(struct usb_interface *intf)
{
struct sfire_chip *chip;
+ struct snd_card *card;
chip = usb_get_intfdata(intf);
if (chip) { /* if !chip, fw upload has been performed */
@@ -178,8 +174,19 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf)
chips[chip->regidx] = NULL;
}
+ /*
+ * Save card pointer before teardown.
+ * snd_card_free_when_closed() may free card (and
+ * the embedded chip) immediately, so it must be
+ * called last and chip must not be accessed after.
+ */
+ card = chip->card;
chip->shutdown = true;
+ if (card)
+ snd_card_disconnect(card);
usb6fire_chip_abort(chip);
+ if (card)
+ snd_card_free_when_closed(card);
}
}
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,54 @@
From 1063515ce15ff31065c4e7f8265f4c2fd3c54876 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Thu, 26 Mar 2026 15:51:38 +0000
Subject: [PATCH] ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
[ Upstream commit 2edfa31769a4add828a7e604b21cb82aaaa05925 ]
Oskar Kjos reported the following problem.
ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
value. __ip_options_echo() then reads optlen from attacker-controlled
packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
Also add minimal IPv4 header validation (version == 4, ihl >= 5).
Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 9f1b66bb513c..f0a8350eb52e 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -601,11 +601,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (!skb2)
return 0;
+ /* Remove debris left by IPv6 stack. */
+ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
+
skb_dst_drop(skb2);
skb_pull(skb2, offset);
skb_reset_network_header(skb2);
eiph = ip_hdr(skb2);
+ if (eiph->version != 4 || eiph->ihl < 5)
+ goto out;
/* Try to guess incoming interface */
rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,79 @@
From 4babc2d9fda2df43823b85d08a0180b68f1b0854 Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Tue, 21 Apr 2026 15:16:33 +0200
Subject: [PATCH] ipv6: rpl: reserve mac_len headroom when recompressed SRH
grows
commit 9e6bf146b55999a095bb14f73a843942456d1adc upstream.
ipv6_rpl_srh_rcv() decompresses an RFC 6554 Source Routing Header, swaps
the next segment into ipv6_hdr->daddr, recompresses, then pulls the old
header and pushes the new one plus the IPv6 header back. The
recompressed header can be larger than the received one when the swap
reduces the common-prefix length the segments share with daddr (CmprI=0,
CmprE>0, seg[0][0] != daddr[0] gives the maximum +8 bytes).
pskb_expand_head() was gated on segments_left == 0, so on earlier
segments the push consumed unchecked headroom. Once skb_push() leaves
fewer than skb->mac_len bytes in front of data,
skb_mac_header_rebuild()'s call to:
skb_set_mac_header(skb, -skb->mac_len);
will store (data - head) - mac_len into the u16 mac_header field, which
wraps to ~65530, and the following memmove() writes mac_len bytes ~64KiB
past skb->head.
A single AF_INET6/SOCK_RAW/IPV6_HDRINCL packet over lo with a two
segment type-3 SRH (CmprI=0, CmprE=15) reaches headroom 8 after one
pass; KASAN reports a 14-byte OOB write in ipv6_rthdr_rcv.
Fix this by expanding the head whenever the remaining room is less than
the push size plus mac_len, and request that much extra so the rebuilt
MAC header fits afterwards.
Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr")
Cc: stable <stable@kernel.org>
Reported-by: Anthropic
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://patch.msgid.link/2026042133-gout-unvented-1bd9@gregkh
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 8a30dd83cf0b..d09ae48030b3 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -491,6 +491,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
struct net *net = dev_net(skb->dev);
struct inet6_dev *idev;
struct ipv6hdr *oldhdr;
+ unsigned int chdr_len;
unsigned char *buf;
int accept_rpl_seg;
int i, err;
@@ -594,8 +595,10 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
skb_pull(skb, ((hdr->hdrlen + 1) << 3));
skb_postpull_rcsum(skb, oldhdr,
sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3));
- if (unlikely(!hdr->segments_left)) {
- if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0,
+ chdr_len = sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3);
+ if (unlikely(!hdr->segments_left ||
+ skb_headroom(skb) < chdr_len + skb->mac_len)) {
+ if (pskb_expand_head(skb, chdr_len + skb->mac_len, 0,
GFP_ATOMIC)) {
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
@@ -605,7 +608,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
oldhdr = ipv6_hdr(skb);
}
- skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr));
+ skb_push(skb, chdr_len);
skb_reset_network_header(skb);
skb_mac_header_rebuild(skb);
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,119 @@
From 95ceb7510d751e76b068573ecbb2030cbd73852b Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Tue, 2 Jun 2026 11:09:13 +0200
Subject: [PATCH] fs: constify file ptr in backing_file accessor helpers
JIRA: https://issues.redhat.com/browse/RHEL-179440
commit 4e301d858af17ae2ce56886296e5458c5a08219a
Author: Amir Goldstein <amir73il@gmail.com>
Date: Sat Jun 7 13:53:03 2025 +0200
fs: constify file ptr in backing_file accessor helpers
Add internal helper backing_file_set_user_path() for the only
two cases that need to modify backing_file fields.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://lore.kernel.org/20250607115304.2521155-2-amir73il@gmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/fs/backing-file.c b/fs/backing-file.c
index 09a9be945d45..892361c31c3d 100644
--- a/fs/backing-file.c
+++ b/fs/backing-file.c
@@ -41,7 +41,7 @@ struct file *backing_file_open(const struct path *user_path, int flags,
return f;
path_get(user_path);
- *backing_file_user_path(f) = *user_path;
+ backing_file_set_user_path(f, user_path);
error = vfs_open(real_path, f);
if (error) {
fput(f);
@@ -65,7 +65,7 @@ struct file *backing_tmpfile_open(const struct path *user_path, int flags,
return f;
path_get(user_path);
- *backing_file_user_path(f) = *user_path;
+ backing_file_set_user_path(f, user_path);
error = vfs_tmpfile(real_idmap, real_parentpath, f, mode);
if (error) {
fput(f);
diff --git a/fs/file_table.c b/fs/file_table.c
index 15a3593c6ece..9979efb9a380 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -53,17 +53,20 @@ struct backing_file {
};
};
-static inline struct backing_file *backing_file(struct file *f)
-{
- return container_of(f, struct backing_file, file);
-}
+#define backing_file(f) container_of(f, struct backing_file, file)
-struct path *backing_file_user_path(struct file *f)
+struct path *backing_file_user_path(const struct file *f)
{
return &backing_file(f)->user_path;
}
EXPORT_SYMBOL_GPL(backing_file_user_path);
+void backing_file_set_user_path(struct file *f, const struct path *path)
+{
+ backing_file(f)->user_path = *path;
+}
+EXPORT_SYMBOL_GPL(backing_file_set_user_path);
+
static inline void file_free(struct file *f)
{
security_file_free(f);
diff --git a/fs/internal.h b/fs/internal.h
index dd13dfde4adb..67e2e164c647 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -100,6 +100,7 @@ extern void chroot_fs_refs(const struct path *, const struct path *);
struct file *alloc_empty_file(int flags, const struct cred *cred);
struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
+void backing_file_set_user_path(struct file *f, const struct path *path);
static inline void file_put_write_access(struct file *file)
{
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 83ddabaa0ac3..04309befc557 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2793,7 +2793,7 @@ struct file *dentry_open(const struct path *path, int flags,
const struct cred *creds);
struct file *dentry_create(const struct path *path, int flags, umode_t mode,
const struct cred *cred);
-struct path *backing_file_user_path(struct file *f);
+struct path *backing_file_user_path(const struct file *f);
/*
* When mmapping a file on a stackable filesystem (e.g., overlayfs), the file
@@ -2805,14 +2805,14 @@ struct path *backing_file_user_path(struct file *f);
* by fstat() on that same fd.
*/
/* Get the path to display in /proc/<pid>/maps */
-static inline const struct path *file_user_path(struct file *f)
+static inline const struct path *file_user_path(const struct file *f)
{
if (unlikely(f->f_mode & FMODE_BACKING))
return backing_file_user_path(f);
return &f->f_path;
}
/* Get the inode whose inode number to display in /proc/<pid>/maps */
-static inline const struct inode *file_user_inode(struct file *f)
+static inline const struct inode *file_user_inode(const struct file *f)
{
if (unlikely(f->f_mode & FMODE_BACKING))
return d_inode(backing_file_user_path(f)->dentry);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,122 @@
From 6a5de58e1181a41f95ac002a27d95f1dbf5933c9 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Fri, 29 May 2026 17:24:58 +0200
Subject: [PATCH] lsm: split the notifier code out into lsm_notifier.c
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit a5e7c17c810052e94dae36f1a976a052f4490458
Author: Paul Moore <paul@paul-moore.com>
Date: Mon Feb 10 19:20:58 2025 -0500
lsm: split the notifier code out into lsm_notifier.c
In an effort to decompose security/security.c somewhat to make it less
twisted and unwieldy, pull out the LSM notifier code into a new file
as it is fairly well self-contained.
No code changes.
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/Makefile b/security/Makefile
index cc0982214b84..c7a3f1cb2fd5 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) += lsm_syscalls.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
-obj-$(CONFIG_SECURITY) += security.o
+obj-$(CONFIG_SECURITY) += security.o lsm_notifier.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/
diff --git a/security/lsm_notifier.c b/security/lsm_notifier.c
new file mode 100644
index 000000000000..c92fad5d57d4
--- /dev/null
+++ b/security/lsm_notifier.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM notifier functions
+ *
+ */
+
+#include <linux/notifier.h>
+#include <linux/security.h>
+
+static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
+
+int call_blocking_lsm_notifier(enum lsm_event event, void *data)
+{
+ return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
+ event, data);
+}
+EXPORT_SYMBOL(call_blocking_lsm_notifier);
+
+int register_blocking_lsm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
+ nb);
+}
+EXPORT_SYMBOL(register_blocking_lsm_notifier);
+
+int unregister_blocking_lsm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
+ nb);
+}
+EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
diff --git a/security/security.c b/security/security.c
index 4535ba7d0208..9a5f9a2f8ff3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -91,8 +91,6 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
-static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
-
static struct kmem_cache *lsm_file_cache;
static struct kmem_cache *lsm_inode_cache;
@@ -649,27 +647,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
}
}
-int call_blocking_lsm_notifier(enum lsm_event event, void *data)
-{
- return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
- event, data);
-}
-EXPORT_SYMBOL(call_blocking_lsm_notifier);
-
-int register_blocking_lsm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
- nb);
-}
-EXPORT_SYMBOL(register_blocking_lsm_notifier);
-
-int unregister_blocking_lsm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
- nb);
-}
-EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
-
/**
* lsm_blob_alloc - allocate a composite blob
* @dest: the destination for the blob
--
2.50.1 (Apple Git-155)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
From 204c54d19e2c1e71bf75a49bb07d965bee634401 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Fri, 29 May 2026 17:43:36 +0200
Subject: [PATCH] lsm: consolidate lsm_allowed() and prepare_lsm() into
lsm_prepare()
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
Conflicts:
- conflict due to 5816bf4273ed ("lsm,selinux: Add LSM blob support for
BPF objects"), which is not backported
commit e02578561d47567be26e603c6d27c10a5aa4c2c4
Author: Paul Moore <paul@paul-moore.com>
Date: Tue Feb 11 12:19:47 2025 -0500
lsm: consolidate lsm_allowed() and prepare_lsm() into lsm_prepare()
Simplify and consolidate the lsm_allowed() and prepare_lsm() functions
into a new function, lsm_prepare().
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index aa64e3437d25..719835ec8f0a 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -123,22 +123,6 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
is_enabled(lsm) ? "enabled" : "disabled");
}
-/* Is an LSM allowed to be initialized? */
-static bool __init lsm_allowed(struct lsm_info *lsm)
-{
- /* Skip if the LSM is disabled. */
- if (!is_enabled(lsm))
- return false;
-
- /* Not allowed if another exclusive LSM already initialized. */
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
- init_debug("exclusive disabled: %s\n", lsm->name);
- return false;
- }
-
- return true;
-}
-
static void __init lsm_set_blob_size(int *need, int *lbs)
{
int offset;
@@ -151,51 +135,50 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
*need = offset;
}
-static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+/**
+ * lsm_prepare - Prepare the LSM framework for a new LSM
+ * @lsm: LSM definition
+ */
+static void __init lsm_prepare(struct lsm_info *lsm)
{
- if (!needed)
+ struct lsm_blob_sizes *blobs;
+
+ if (!is_enabled(lsm)) {
+ set_enabled(lsm, false);
return;
+ } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+ init_debug("exclusive disabled: %s\n", lsm->name);
+ set_enabled(lsm, false);
+ return;
+ }
- lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
- lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
- lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
- /*
- * The inode blob gets an rcu_head in addition to
- * what the modules might need.
- */
- if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
+ /* Mark the LSM as enabled. */
+ set_enabled(lsm, true);
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+ init_debug("exclusive chosen: %s\n", lsm->name);
+ exclusive = lsm;
+ }
+
+ /* Register the LSM blob sizes. */
+ blobs = lsm->blobs;
+ lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
+ lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
+ /* inode blob gets an rcu_head in addition to LSM blobs. */
+ if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
blob_sizes.lbs_inode = sizeof(struct rcu_head);
- lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
- lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
- lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
- lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
- lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
- lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
- lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
- lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
- lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
- lsm_set_blob_size(&needed->lbs_xattr_count,
+ lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
+ lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
+ lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
+ lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
+ lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
+ lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
+ lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
+ lsm_set_blob_size(&blobs->lbs_xattr_count,
&blob_sizes.lbs_xattr_count);
- lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
-}
-
-/* Prepare LSM for initialization. */
-static void __init prepare_lsm(struct lsm_info *lsm)
-{
- int enabled = lsm_allowed(lsm);
-
- /* Record enablement (to handle any following exclusive LSMs). */
- set_enabled(lsm, enabled);
-
- /* If enabled, do pre-initialization work. */
- if (enabled) {
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
- exclusive = lsm;
- init_debug("exclusive chosen: %s\n", lsm->name);
- }
-
- lsm_set_blob_sizes(lsm->blobs);
- }
+ lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
}
/* Initialize a given LSM, if it is enabled. */
@@ -358,7 +341,7 @@ static void __init ordered_lsm_init(void)
ordered_lsm_parse(builtin_lsm_order, "builtin");
for (lsm = ordered_lsms; *lsm; lsm++)
- prepare_lsm(*lsm);
+ lsm_prepare(*lsm);
report_lsm_order();
@@ -503,7 +486,7 @@ int __init early_security_init(void)
for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
- prepare_lsm(lsm);
+ lsm_prepare(lsm);
initialize_lsm(lsm);
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,172 @@
From 92ed776aa54bac14d013ad9b08ad44b7ed8af0ea Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Fri, 29 May 2026 18:31:38 +0200
Subject: [PATCH] lsm: introduce looping macros for the initialization code
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 37f788f65528611f4482e2135d11ca34afb25828
Author: Paul Moore <paul@paul-moore.com>
Date: Wed Apr 9 17:59:42 2025 -0400
lsm: introduce looping macros for the initialization code
There are three common for loop patterns in the LSM initialization code
to loop through the ordered LSM list and the registered "early" LSMs.
This patch implements these loop patterns as macros to help simplify the
code and reduce the chance for errors.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 719835ec8f0a..2424975ca0eb 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -32,6 +32,15 @@ static __initdata bool debug;
pr_info(__VA_ARGS__); \
} while (0)
+#define lsm_order_for_each(iter) \
+ for ((iter) = ordered_lsms; *(iter); (iter)++)
+#define lsm_for_each_raw(iter) \
+ for ((iter) = __start_lsm_info; \
+ (iter) < __end_lsm_info; (iter)++)
+#define lsm_early_for_each_raw(iter) \
+ for ((iter) = __start_early_lsm_info; \
+ (iter) < __end_early_lsm_info; (iter)++)
+
static int lsm_append(const char *new, char **result);
/* Save user chosen LSM */
@@ -96,9 +105,10 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
{
struct lsm_info **check;
- for (check = ordered_lsms; *check; check++)
+ lsm_order_for_each(check) {
if (*check == lsm)
return true;
+ }
return false;
}
@@ -206,7 +216,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
char *sep, *name, *next;
/* LSM_ORDER_FIRST is always first. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_FIRST)
append_ordered_lsm(lsm, " first");
}
@@ -221,8 +231,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
* if the selected one was separately disabled: disable
* all non-matching Legacy Major LSMs.
*/
- for (major = __start_lsm_info; major < __end_lsm_info;
- major++) {
+ lsm_for_each_raw(major) {
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
strcmp(major->name, chosen_major_lsm) != 0) {
set_enabled(major, false);
@@ -238,7 +247,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
while ((name = strsep(&next, ",")) != NULL) {
bool found = false;
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (strcmp(lsm->name, name) == 0) {
if (lsm->order == LSM_ORDER_MUTABLE)
append_ordered_lsm(lsm, origin);
@@ -253,7 +262,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
/* Process "security=", if given. */
if (chosen_major_lsm) {
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (exists_ordered_lsm(lsm))
continue;
if (strcmp(lsm->name, chosen_major_lsm) == 0)
@@ -262,13 +271,13 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
}
/* LSM_ORDER_LAST is always last. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_LAST)
append_ordered_lsm(lsm, " last");
}
/* Disable all LSMs not in the ordered list. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ lsm_for_each_raw(lsm) {
if (exists_ordered_lsm(lsm))
continue;
set_enabled(lsm, false);
@@ -287,13 +296,14 @@ static void __init report_lsm_order(void)
pr_info("initializing lsm=");
/* Report each enabled LSM name, comma separated. */
- for (early = __start_early_lsm_info;
- early < __end_early_lsm_info; early++)
+ lsm_early_for_each_raw(early) {
if (is_enabled(early))
pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
- for (lsm = ordered_lsms; *lsm; lsm++)
+ }
+ lsm_order_for_each(lsm) {
if (is_enabled(*lsm))
pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+ }
pr_cont("\n");
}
@@ -340,8 +350,9 @@ static void __init ordered_lsm_init(void)
} else
ordered_lsm_parse(builtin_lsm_order, "builtin");
- for (lsm = ordered_lsms; *lsm; lsm++)
+ lsm_order_for_each(lsm) {
lsm_prepare(*lsm);
+ }
report_lsm_order();
@@ -376,8 +387,9 @@ static void __init ordered_lsm_init(void)
lsm_early_cred((struct cred *) current->cred);
lsm_early_task(current);
- for (lsm = ordered_lsms; *lsm; lsm++)
+ lsm_order_for_each(lsm) {
initialize_lsm(*lsm);
+ }
}
static bool match_last_lsm(const char *list, const char *lsm)
@@ -483,7 +495,7 @@ int __init early_security_init(void)
if (early_security_initialized)
return 0;
- for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+ lsm_early_for_each_raw(lsm) {
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
lsm_prepare(lsm);
@@ -511,7 +523,7 @@ int __init security_init(void)
* Append the names of the early LSM modules now that kmalloc() is
* available
*/
- for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+ lsm_early_for_each_raw(lsm) {
init_debug(" early started: %s (%s)\n", lsm->name,
is_enabled(lsm) ? "enabled" : "disabled");
if (lsm->enabled)
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,86 @@
From 4190f2549074d006122a76cdcb2a5b361d59d650 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:20:31 +0200
Subject: [PATCH] lsm: integrate report_lsm_order() code into caller
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit cb1513db7a6ed82d22853608d78bbf72ad8c67c1
Author: Paul Moore <paul@paul-moore.com>
Date: Sat Jul 12 16:10:15 2025 -0400
lsm: integrate report_lsm_order() code into caller
With only one caller of report_lsm_order(), insert the function's code
directly into the caller and ger rid of report_lsm_order().
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 2424975ca0eb..fc40d37c3321 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -288,26 +288,6 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
kfree(sep);
}
-static void __init report_lsm_order(void)
-{
- struct lsm_info **lsm, *early;
- int first = 0;
-
- pr_info("initializing lsm=");
-
- /* Report each enabled LSM name, comma separated. */
- lsm_early_for_each_raw(early) {
- if (is_enabled(early))
- pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
- }
- lsm_order_for_each(lsm) {
- if (is_enabled(*lsm))
- pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
- }
-
- pr_cont("\n");
-}
-
/**
* lsm_early_cred - during initialization allocate a composite cred blob
* @cred: the cred that needs a blob
@@ -338,7 +318,9 @@ static void __init lsm_early_task(struct task_struct *task)
static void __init ordered_lsm_init(void)
{
+ unsigned int first = 0;
struct lsm_info **lsm;
+ struct lsm_info *early;
if (chosen_lsm_order) {
if (chosen_major_lsm) {
@@ -354,7 +336,16 @@ static void __init ordered_lsm_init(void)
lsm_prepare(*lsm);
}
- report_lsm_order();
+ pr_info("initializing lsm=");
+ lsm_early_for_each_raw(early) {
+ if (is_enabled(early))
+ pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
+ }
+ lsm_order_for_each(lsm) {
+ if (is_enabled(*lsm))
+ pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+ }
+ pr_cont("\n");
init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
init_debug("file blob size = %d\n", blob_sizes.lbs_file);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,82 @@
From 7a7bb4c213345231e80b7545d00bcee30e62fd94 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:20:32 +0200
Subject: [PATCH] lsm: integrate lsm_early_cred() and lsm_early_task() into
caller
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 92ed3500c9a91f43e094c9b8fb4bab9976565d74
Author: Paul Moore <paul@paul-moore.com>
Date: Sat Jul 12 16:27:39 2025 -0400
lsm: integrate lsm_early_cred() and lsm_early_task() into caller
With only one caller of lsm_early_cred() and lsm_early_task(), insert
the functions' code directly into the caller and ger rid of the two
functions.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index fc40d37c3321..19eac2b39f2b 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -288,34 +288,6 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
kfree(sep);
}
-/**
- * lsm_early_cred - during initialization allocate a composite cred blob
- * @cred: the cred that needs a blob
- *
- * Allocate the cred blob for all the modules
- */
-static void __init lsm_early_cred(struct cred *cred)
-{
- int rc = lsm_cred_alloc(cred, GFP_KERNEL);
-
- if (rc)
- panic("%s: Early cred alloc failed.\n", __func__);
-}
-
-/**
- * lsm_early_task - during initialization allocate a composite task blob
- * @task: the task that needs a blob
- *
- * Allocate the task blob for all the modules
- */
-static void __init lsm_early_task(struct task_struct *task)
-{
- int rc = lsm_task_alloc(task);
-
- if (rc)
- panic("%s: Early task alloc failed.\n", __func__);
-}
-
static void __init ordered_lsm_init(void)
{
unsigned int first = 0;
@@ -376,8 +348,11 @@ static void __init ordered_lsm_init(void)
blob_sizes.lbs_inode, 0,
SLAB_PANIC, NULL);
- lsm_early_cred((struct cred *) current->cred);
- lsm_early_task(current);
+ if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
+ panic("%s: early cred alloc failed.\n", __func__);
+ if (lsm_task_alloc(current))
+ panic("%s: early task alloc failed.\n", __func__);
+
lsm_order_for_each(lsm) {
initialize_lsm(*lsm);
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,63 @@
From c2e5c69d0c70768dc6cd10ab0a5704ebb2545967 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:20:32 +0200
Subject: [PATCH] lsm: rename ordered_lsm_init() to lsm_init_ordered()
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit faabedcd6e88ca1f65ef45d711d2e0c7288fd551
Author: Paul Moore <paul@paul-moore.com>
Date: Tue Feb 11 12:59:30 2025 -0500
lsm: rename ordered_lsm_init() to lsm_init_ordered()
The new name more closely fits the rest of the naming scheme in
security/lsm_init.c. This patch also adds a trivial comment block to
the top of the function.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 19eac2b39f2b..a590a785f724 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -288,7 +288,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
kfree(sep);
}
-static void __init ordered_lsm_init(void)
+/**
+ * lsm_init_ordered - Initialize the ordered LSMs
+ */
+static void __init lsm_init_ordered(void)
{
unsigned int first = 0;
struct lsm_info **lsm;
@@ -336,9 +339,6 @@ static void __init ordered_lsm_init(void)
init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
- /*
- * Create any kmem_caches needed for blobs
- */
if (blob_sizes.lbs_file)
lsm_file_cache = kmem_cache_create("lsm_file_cache",
blob_sizes.lbs_file, 0,
@@ -497,7 +497,7 @@ int __init security_init(void)
}
/* Load LSMs in specified order. */
- ordered_lsm_init();
+ lsm_init_ordered();
return 0;
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,363 @@
From 369918c7a55af0dc1d94780d5fde14536636ace1 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:20:33 +0200
Subject: [PATCH] lsm: replace the name field with a pointer to the lsm_id
struct
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 9f9dc69e06ecbc61e7a50b823b82a78daf130dc0
Author: Paul Moore <paul@paul-moore.com>
Date: Wed Feb 12 14:45:06 2025 -0500
lsm: replace the name field with a pointer to the lsm_id struct
Reduce the duplication between the lsm_id struct and the DEFINE_LSM()
definition by linking the lsm_id struct directly into the individual
LSM's DEFINE_LSM() instance.
Linking the lsm_id into the LSM definition also allows us to simplify
the security_add_hooks() function by removing the code which populates
the lsm_idlist[] array and moving it into the normal LSM startup code
where the LSM list is parsed and the individual LSMs are enabled,
making for a cleaner implementation with less overhead at boot.
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index eeb4bfd60b79..4cd17c9a229f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -149,7 +149,7 @@ enum lsm_order {
};
struct lsm_info {
- const char *name; /* Required. */
+ const struct lsm_id *id;
enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
unsigned long flags; /* Optional: flags describing LSM */
int *enabled; /* Optional: controlled by CONFIG_LSM */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 248d68624b35..6b5742e60454 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -2275,7 +2275,7 @@ static int __init apparmor_init(void)
}
DEFINE_LSM(apparmor) = {
- .name = "apparmor",
+ .id = &apparmor_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &apparmor_enabled,
.blobs = &apparmor_blob_sizes,
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index db759025abe1..40efde233f3a 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -33,7 +33,7 @@ struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
};
DEFINE_LSM(bpf) = {
- .name = "bpf",
+ .id = &bpf_lsmid,
.init = bpf_lsm_init,
.blobs = &bpf_lsm_blob_sizes
};
diff --git a/security/commoncap.c b/security/commoncap.c
index cefad323a0b1..7d0b5a58d4e1 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1470,7 +1470,7 @@ static int __init capability_init(void)
}
DEFINE_LSM(capability) = {
- .name = "capability",
+ .id = &capability_lsmid,
.order = LSM_ORDER_FIRST,
.init = capability_init,
};
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 377e57e9084f..bb0f8631195e 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1175,7 +1175,7 @@ struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
};
DEFINE_LSM(evm) = {
- .name = "evm",
+ .id = &evm_lsmid,
.init = init_evm_lsm,
.order = LSM_ORDER_LAST,
.blobs = &evm_blob_sizes,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 66aa7bc8d76d..c60a9b1082d4 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1222,7 +1222,7 @@ struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
};
DEFINE_LSM(ima) = {
- .name = "ima",
+ .id = &ima_lsmid,
.init = init_ima_lsm,
.order = LSM_ORDER_LAST,
.blobs = &ima_blob_sizes,
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 4317134cb0da..2426441181dc 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -92,7 +92,7 @@ static int __init ipe_init(void)
}
DEFINE_LSM(ipe) = {
- .name = "ipe",
+ .id = &ipe_lsmid,
.init = ipe_init,
.blobs = &ipe_blobs,
};
diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index 28519a45b11f..460c5b79d957 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -43,7 +43,7 @@ static int __init landlock_init(void)
}
DEFINE_LSM(LANDLOCK_NAME) = {
- .name = LANDLOCK_NAME,
+ .id = &landlock_lsmid,
.init = landlock_init,
.blobs = &landlock_blob_sizes,
};
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 02144ec39f43..92c9618e38ad 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -271,7 +271,7 @@ static int __init loadpin_init(void)
}
DEFINE_LSM(loadpin) = {
- .name = "loadpin",
+ .id = &loadpin_lsmid,
.init = loadpin_init,
};
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index ddf496f7fca5..c27aaee60da3 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -169,6 +169,6 @@ DEFINE_EARLY_LSM(lockdown) = {
#else
DEFINE_LSM(lockdown) = {
#endif
- .name = "lockdown",
+ .id = &lockdown_lsmid,
.init = lockdown_lsm_init,
};
diff --git a/security/lsm_init.c b/security/lsm_init.c
index a590a785f724..e5faf6be44fb 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -127,9 +127,10 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
/* Enable this LSM, if it is not already set. */
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
- ordered_lsms[last_lsm++] = lsm;
+ ordered_lsms[last_lsm] = lsm;
+ lsm_idlist[last_lsm++] = lsm->id;
- init_debug("%s ordered: %s (%s)\n", from, lsm->name,
+ init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
is_enabled(lsm) ? "enabled" : "disabled");
}
@@ -157,7 +158,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
set_enabled(lsm, false);
return;
} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
- init_debug("exclusive disabled: %s\n", lsm->name);
+ init_debug("exclusive disabled: %s\n", lsm->id->name);
set_enabled(lsm, false);
return;
}
@@ -165,7 +166,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
/* Mark the LSM as enabled. */
set_enabled(lsm, true);
if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
- init_debug("exclusive chosen: %s\n", lsm->name);
+ init_debug("exclusive chosen: %s\n", lsm->id->name);
exclusive = lsm;
}
@@ -197,9 +198,9 @@ static void __init initialize_lsm(struct lsm_info *lsm)
if (is_enabled(lsm)) {
int ret;
- init_debug("initializing %s\n", lsm->name);
+ init_debug("initializing %s\n", lsm->id->name);
ret = lsm->init();
- WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
+ WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
}
}
@@ -233,10 +234,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
*/
lsm_for_each_raw(major) {
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
- strcmp(major->name, chosen_major_lsm) != 0) {
+ strcmp(major->id->name, chosen_major_lsm) != 0) {
set_enabled(major, false);
init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
- chosen_major_lsm, major->name);
+ chosen_major_lsm, major->id->name);
}
}
}
@@ -248,7 +249,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
bool found = false;
lsm_for_each_raw(lsm) {
- if (strcmp(lsm->name, name) == 0) {
+ if (strcmp(lsm->id->name, name) == 0) {
if (lsm->order == LSM_ORDER_MUTABLE)
append_ordered_lsm(lsm, origin);
found = true;
@@ -265,7 +266,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
lsm_for_each_raw(lsm) {
if (exists_ordered_lsm(lsm))
continue;
- if (strcmp(lsm->name, chosen_major_lsm) == 0)
+ if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
append_ordered_lsm(lsm, "security=");
}
}
@@ -282,7 +283,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
continue;
set_enabled(lsm, false);
init_debug("%s skipped: %s (not in requested order)\n",
- origin, lsm->name);
+ origin, lsm->id->name);
}
kfree(sep);
@@ -314,11 +315,13 @@ static void __init lsm_init_ordered(void)
pr_info("initializing lsm=");
lsm_early_for_each_raw(early) {
if (is_enabled(early))
- pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
+ pr_cont("%s%s",
+ first++ == 0 ? "" : ",", early->id->name);
}
lsm_order_for_each(lsm) {
if (is_enabled(*lsm))
- pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+ pr_cont("%s%s",
+ first++ == 0 ? "" : ",", (*lsm)->id->name);
}
pr_cont("\n");
@@ -426,18 +429,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
{
int i;
- /*
- * A security module may call security_add_hooks() more
- * than once during initialization, and LSM initialization
- * is serialized. Landlock is one such case.
- * Look at the previous entry, if there is one, for duplication.
- */
- if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
- if (lsm_active_cnt >= MAX_LSM_COUNT)
- panic("%s Too many LSMs registered.\n", __func__);
- lsm_idlist[lsm_active_cnt++] = lsmid;
- }
-
for (i = 0; i < count; i++) {
hooks[i].lsmid = lsmid;
lsm_static_call_init(&hooks[i]);
@@ -490,10 +481,10 @@ int __init security_init(void)
* available
*/
lsm_early_for_each_raw(lsm) {
- init_debug(" early started: %s (%s)\n", lsm->name,
+ init_debug(" early started: %s (%s)\n", lsm->id->name,
is_enabled(lsm) ? "enabled" : "disabled");
if (lsm->enabled)
- lsm_append(lsm->name, &lsm_names);
+ lsm_append(lsm->id->name, &lsm_names);
}
/* Load LSMs in specified order. */
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index 1ba564f097f5..9a7c68d4e642 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -287,6 +287,6 @@ static int __init safesetid_security_init(void)
}
DEFINE_LSM(safesetid_security_init) = {
+ .id = &safesetid_lsmid,
.init = safesetid_security_init,
- .name = "safesetid",
};
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1bc947e2b0e7..a2323c6daafe 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7480,7 +7480,7 @@ void selinux_complete_init(void)
/* SELinux requires early initialization in order to label
all processes and objects when they are created. */
DEFINE_LSM(selinux) = {
- .name = "selinux",
+ .id = &selinux_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &selinux_enabled_boot,
.blobs = &selinux_blob_sizes,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 7c8b06e974bb..43546723f600 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5318,7 +5318,7 @@ static __init int smack_init(void)
* all processes and objects when they are created.
*/
DEFINE_LSM(smack) = {
- .name = "smack",
+ .id = &smack_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.blobs = &smack_blob_sizes,
.init = smack_init,
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index fa08d78162bb..3c6964ea7ace 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -615,7 +615,7 @@ static int __init tomoyo_init(void)
}
DEFINE_LSM(tomoyo) = {
- .name = "tomoyo",
+ .id = &tomoyo_lsmid,
.enabled = &tomoyo_enabled,
.flags = LSM_FLAG_LEGACY_MAJOR,
.blobs = &tomoyo_blob_sizes,
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 54bd5f535ac1..f546176dd2fc 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -483,6 +483,6 @@ static int __init yama_init(void)
}
DEFINE_LSM(yama) = {
- .name = "yama",
+ .id = &yama_lsmid,
.init = yama_init,
};
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,226 @@
From f212d5ad65c47cf954187a1d3ed14db6127b3727 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:20:33 +0200
Subject: [PATCH] lsm: rename the lsm order variables for consistency
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 592b104f9b516b2c22cb23a2f4c34486fdb21bae
Author: Paul Moore <paul@paul-moore.com>
Date: Tue Feb 11 17:13:26 2025 -0500
lsm: rename the lsm order variables for consistency
Rename the builtin_lsm_order variable to lsm_order_builtin,
chosen_lsm_order to lsm_order_cmdline, chosen_major_lsm to
lsm_order_legacy, ordered_lsms[] to lsm_order[], and exclusive
to lsm_exclusive.
This patch also renames the associated kernel command line parsing
functions and adds some basic function comment blocks. The parsing
function choose_major_lsm() was renamed to lsm_choose_security(),
choose_lsm_order() to lsm_choose_lsm(), and enable_debug() to
lsm_debug_enable().
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index e5faf6be44fb..171b2b047bdc 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -16,14 +16,14 @@ char *lsm_names;
extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
-/* Boot-time LSM user choice */
-static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
-static __initdata const char *chosen_lsm_order;
-static __initdata const char *chosen_major_lsm;
+/* Build and boot-time LSM ordering. */
+static __initconst const char *const lsm_order_builtin = CONFIG_LSM;
+static __initdata const char *lsm_order_cmdline;
+static __initdata const char *lsm_order_legacy;
/* Ordered list of LSMs to initialize. */
-static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
-static __initdata struct lsm_info *exclusive;
+static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
+static __initdata struct lsm_info *lsm_exclusive;
static __initdata bool debug;
#define init_debug(...) \
@@ -33,7 +33,7 @@ static __initdata bool debug;
} while (0)
#define lsm_order_for_each(iter) \
- for ((iter) = ordered_lsms; *(iter); (iter)++)
+ for ((iter) = lsm_order; *(iter); (iter)++)
#define lsm_for_each_raw(iter) \
for ((iter) = __start_lsm_info; \
(iter) < __end_lsm_info; (iter)++)
@@ -41,31 +41,41 @@ static __initdata bool debug;
for ((iter) = __start_early_lsm_info; \
(iter) < __end_early_lsm_info; (iter)++)
-static int lsm_append(const char *new, char **result);
-
-/* Save user chosen LSM */
-static int __init choose_major_lsm(char *str)
+/**
+ * lsm_choose_security - Legacy "major" LSM selection
+ * @str: kernel command line parameter
+ */
+static int __init lsm_choose_security(char *str)
{
- chosen_major_lsm = str;
+ lsm_order_legacy = str;
return 1;
}
-__setup("security=", choose_major_lsm);
+__setup("security=", lsm_choose_security);
-/* Explicitly choose LSM initialization order. */
-static int __init choose_lsm_order(char *str)
+/**
+ * lsm_choose_lsm - Modern LSM selection
+ * @str: kernel command line parameter
+ */
+static int __init lsm_choose_lsm(char *str)
{
- chosen_lsm_order = str;
+ lsm_order_cmdline = str;
return 1;
}
-__setup("lsm=", choose_lsm_order);
+__setup("lsm=", lsm_choose_lsm);
-/* Enable LSM order debugging. */
-static int __init enable_debug(char *str)
+/**
+ * lsm_debug_enable - Enable LSM framework debugging
+ * @str: kernel command line parameter
+ *
+ * Currently we only provide debug info during LSM initialization, but we may
+ * want to expand this in the future.
+ */
+static int __init lsm_debug_enable(char *str)
{
debug = true;
return 1;
}
-__setup("lsm.debug", enable_debug);
+__setup("lsm.debug", lsm_debug_enable);
/* Mark an LSM's enabled flag. */
static int lsm_enabled_true __initdata = 1;
@@ -127,7 +137,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
/* Enable this LSM, if it is not already set. */
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
- ordered_lsms[last_lsm] = lsm;
+ lsm_order[last_lsm] = lsm;
lsm_idlist[last_lsm++] = lsm->id;
init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
@@ -157,7 +167,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
if (!is_enabled(lsm)) {
set_enabled(lsm, false);
return;
- } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+ } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
init_debug("exclusive disabled: %s\n", lsm->id->name);
set_enabled(lsm, false);
return;
@@ -165,9 +175,9 @@ static void __init lsm_prepare(struct lsm_info *lsm)
/* Mark the LSM as enabled. */
set_enabled(lsm, true);
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
init_debug("exclusive chosen: %s\n", lsm->id->name);
- exclusive = lsm;
+ lsm_exclusive = lsm;
}
/* Register the LSM blob sizes. */
@@ -223,7 +233,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
}
/* Process "security=", if given. */
- if (chosen_major_lsm) {
+ if (lsm_order_legacy) {
struct lsm_info *major;
/*
@@ -234,10 +244,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
*/
lsm_for_each_raw(major) {
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
- strcmp(major->id->name, chosen_major_lsm) != 0) {
+ strcmp(major->id->name, lsm_order_legacy) != 0) {
set_enabled(major, false);
init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
- chosen_major_lsm, major->id->name);
+ lsm_order_legacy, major->id->name);
}
}
}
@@ -262,11 +272,11 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
}
/* Process "security=", if given. */
- if (chosen_major_lsm) {
+ if (lsm_order_legacy) {
lsm_for_each_raw(lsm) {
if (exists_ordered_lsm(lsm))
continue;
- if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
+ if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
append_ordered_lsm(lsm, "security=");
}
}
@@ -298,15 +308,15 @@ static void __init lsm_init_ordered(void)
struct lsm_info **lsm;
struct lsm_info *early;
- if (chosen_lsm_order) {
- if (chosen_major_lsm) {
+ if (lsm_order_cmdline) {
+ if (lsm_order_legacy) {
pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
- chosen_major_lsm, chosen_lsm_order);
- chosen_major_lsm = NULL;
+ lsm_order_legacy, lsm_order_cmdline);
+ lsm_order_legacy = NULL;
}
- ordered_lsm_parse(chosen_lsm_order, "cmdline");
+ ordered_lsm_parse(lsm_order_cmdline, "cmdline");
} else
- ordered_lsm_parse(builtin_lsm_order, "builtin");
+ ordered_lsm_parse(lsm_order_builtin, "builtin");
lsm_order_for_each(lsm) {
lsm_prepare(*lsm);
@@ -472,9 +482,9 @@ int __init security_init(void)
{
struct lsm_info *lsm;
- init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
- init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order);
- init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
+ init_debug("legacy security=%s\n", lsm_order_legacy ? : " *unspecified*");
+ init_debug(" CONFIG_LSM=%s\n", lsm_order_builtin);
+ init_debug("boot arg lsm=%s\n", lsm_order_cmdline ? : " *unspecified*");
/*
* Append the names of the early LSM modules now that kmalloc() is
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,102 @@
From c4c061449d1ae617402680b00ab006b1e0ee2c2c Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:20:34 +0200
Subject: [PATCH] lsm: rework lsm_active_cnt and lsm_idlist[]
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 250898ca335f337bc032a9693dc0a30a1cb85825
Author: Paul Moore <paul@paul-moore.com>
Date: Wed Feb 12 15:36:51 2025 -0500
lsm: rework lsm_active_cnt and lsm_idlist[]
Move the LSM active count and lsm_id list declarations out of a header
that is visible across the kernel and into a header that is limited to
the LSM framework. This not only helps keep the include/linux headers
smaller and cleaner, it helps prevent misuse of these variables.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/include/linux/security.h b/include/linux/security.h
index 3254f74457f7..2db88ddbe9a9 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -167,8 +167,6 @@ struct lsm_prop {
};
extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
-extern u32 lsm_active_cnt;
-extern const struct lsm_id *lsm_idlist[];
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
diff --git a/security/lsm.h b/security/lsm.h
index 0e1731bad4a7..dbe755c45e57 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -7,6 +7,11 @@
#define _LSM_H_
#include <linux/lsm_hooks.h>
+#include <linux/lsm_count.h>
+
+/* List of configured LSMs */
+extern unsigned int lsm_active_cnt;
+extern const struct lsm_id *lsm_idlist[];
/* LSM blob configuration */
extern struct lsm_blob_sizes blob_sizes;
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 171b2b047bdc..e7afc74caa2b 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -214,12 +214,6 @@ static void __init initialize_lsm(struct lsm_info *lsm)
}
}
-/*
- * Current index to use while initializing the lsm id list.
- */
-u32 lsm_active_cnt __ro_after_init;
-const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
-
/* Populate ordered LSMs list from comma-separated LSM name list. */
static void __init ordered_lsm_parse(const char *order, const char *origin)
{
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 8440948a690c..5648b1f0ce9c 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -17,6 +17,8 @@
#include <linux/lsm_hooks.h>
#include <uapi/linux/lsm.h>
+#include "lsm.h"
+
/**
* lsm_name_to_attr - map an LSM attribute name to its ID
* @name: name of the attribute
diff --git a/security/security.c b/security/security.c
index 6040891f4588..6f20f44c8d13 100644
--- a/security/security.c
+++ b/security/security.c
@@ -74,6 +74,9 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
+unsigned int lsm_active_cnt __ro_after_init;
+const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
+
struct lsm_blob_sizes blob_sizes;
struct kmem_cache *lsm_file_cache;
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,184 @@
From e84cf2768df37393453e8bb645555e360761056c Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:20:34 +0200
Subject: [PATCH] lsm: get rid of the lsm_names list and do some cleanup
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 935d508d4d7ab9d19c603bd7eb2937249551d507
Author: Paul Moore <paul@paul-moore.com>
Date: Thu Feb 13 17:34:12 2025 -0500
lsm: get rid of the lsm_names list and do some cleanup
The LSM currently has a lot of code to maintain a list of the currently
active LSMs in a human readable string, with the only user being the
"/sys/kernel/security/lsm" code. Let's drop all of that code and
generate the string on first use and then cache it for subsequent use.
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 4cd17c9a229f..bc477fb20d02 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -169,7 +169,6 @@ struct lsm_info {
/* DO NOT tamper with these variables outside of the LSM framework */
-extern char *lsm_names;
extern struct lsm_static_calls_table static_calls_table __ro_after_init;
/**
diff --git a/security/inode.c b/security/inode.c
index da3ab44c8e57..6f3caab37ab2 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -22,6 +22,8 @@
#include <linux/lsm_hooks.h>
#include <linux/magic.h>
+#include "lsm.h"
+
static struct vfsmount *mount;
static int mount_count;
@@ -339,12 +341,49 @@ void securityfs_recursive_remove(struct dentry *dentry)
EXPORT_SYMBOL_GPL(securityfs_recursive_remove);
#ifdef CONFIG_SECURITY
+#include <linux/spinlock.h>
+
static struct dentry *lsm_dentry;
+
static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
loff_t *ppos)
{
- return simple_read_from_buffer(buf, count, ppos, lsm_names,
- strlen(lsm_names));
+ int i;
+ static char *str;
+ static size_t len;
+ static DEFINE_SPINLOCK(lock);
+
+ /* NOTE: we never free or modify the string once it is set */
+
+ if (unlikely(!str || !len)) {
+ char *str_tmp;
+ size_t len_tmp = 0;
+
+ for (i = 0; i < lsm_active_cnt; i++)
+ /* the '+ 1' accounts for either a comma or a NUL */
+ len_tmp += strlen(lsm_idlist[i]->name) + 1;
+
+ str_tmp = kmalloc(len_tmp, GFP_KERNEL);
+ if (!str_tmp)
+ return -ENOMEM;
+ str_tmp[0] = '\0';
+
+ for (i = 0; i < lsm_active_cnt; i++) {
+ if (i > 0)
+ strcat(str_tmp, ",");
+ strcat(str_tmp, lsm_idlist[i]->name);
+ }
+
+ spin_lock(&lock);
+ if (!str) {
+ str = str_tmp;
+ len = len_tmp - 1;
+ } else
+ kfree(str_tmp);
+ spin_unlock(&lock);
+ }
+
+ return simple_read_from_buffer(buf, count, ppos, str, len);
}
static const struct file_operations lsm_ops = {
diff --git a/security/lsm_init.c b/security/lsm_init.c
index e7afc74caa2b..7c244a309a35 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -10,8 +10,6 @@
#include "lsm.h"
-char *lsm_names;
-
/* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
@@ -365,42 +363,6 @@ static void __init lsm_init_ordered(void)
}
}
-static bool match_last_lsm(const char *list, const char *lsm)
-{
- const char *last;
-
- if (WARN_ON(!list || !lsm))
- return false;
- last = strrchr(list, ',');
- if (last)
- /* Pass the comma, strcmp() will check for '\0' */
- last++;
- else
- last = list;
- return !strcmp(last, lsm);
-}
-
-static int lsm_append(const char *new, char **result)
-{
- char *cp;
-
- if (*result == NULL) {
- *result = kstrdup(new, GFP_KERNEL);
- if (*result == NULL)
- return -ENOMEM;
- } else {
- /* Check if it is the last registered name */
- if (match_last_lsm(*result, new))
- return 0;
- cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
- if (cp == NULL)
- return -ENOMEM;
- kfree(*result);
- *result = cp;
- }
- return 0;
-}
-
static void __init lsm_static_call_init(struct security_hook_list *hl)
{
struct lsm_static_call *scall = hl->scalls;
@@ -437,15 +399,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
hooks[i].lsmid = lsmid;
lsm_static_call_init(&hooks[i]);
}
-
- /*
- * Don't try to append during early_security_init(), we'll come back
- * and fix this up afterwards.
- */
- if (slab_is_available()) {
- if (lsm_append(lsmid->name, &lsm_names) < 0)
- panic("%s - Cannot get early memory.\n", __func__);
- }
}
int __init early_security_init(void)
@@ -487,8 +440,6 @@ int __init security_init(void)
lsm_early_for_each_raw(lsm) {
init_debug(" early started: %s (%s)\n", lsm->id->name,
is_enabled(lsm) ? "enabled" : "disabled");
- if (lsm->enabled)
- lsm_append(lsm->id->name, &lsm_names);
}
/* Load LSMs in specified order. */
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,179 @@
From d52cc6c688625151f1b39aa7b2b5c532b47a2211 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:26:49 +0200
Subject: [PATCH] lsm: rework the LSM enable/disable setter/getter functions
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 2d67172612fd9df2c4d08533515ef483cb526dd9
Author: Paul Moore <paul@paul-moore.com>
Date: Thu Apr 10 22:04:26 2025 -0400
lsm: rework the LSM enable/disable setter/getter functions
In addition to style changes, rename set_enabled() to lsm_enabled_set()
and is_enabled() to lsm_is_enabled() to better fit within the LSM
initialization code.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 7c244a309a35..9929d1a61634 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -10,6 +10,10 @@
#include "lsm.h"
+/* LSM enabled constants. */
+static __initdata int lsm_enabled_true = 1;
+static __initdata int lsm_enabled_false = 0;
+
/* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
@@ -75,37 +79,33 @@ static int __init lsm_debug_enable(char *str)
}
__setup("lsm.debug", lsm_debug_enable);
-/* Mark an LSM's enabled flag. */
-static int lsm_enabled_true __initdata = 1;
-static int lsm_enabled_false __initdata = 0;
-static void __init set_enabled(struct lsm_info *lsm, bool enabled)
+/**
+ * lsm_enabled_set - Mark a LSM as enabled
+ * @lsm: LSM definition
+ * @enabled: enabled flag
+ */
+static void __init lsm_enabled_set(struct lsm_info *lsm, bool enabled)
{
/*
* When an LSM hasn't configured an enable variable, we can use
* a hard-coded location for storing the default enabled state.
*/
- if (!lsm->enabled) {
- if (enabled)
- lsm->enabled = &lsm_enabled_true;
- else
- lsm->enabled = &lsm_enabled_false;
- } else if (lsm->enabled == &lsm_enabled_true) {
- if (!enabled)
- lsm->enabled = &lsm_enabled_false;
- } else if (lsm->enabled == &lsm_enabled_false) {
- if (enabled)
- lsm->enabled = &lsm_enabled_true;
+ if (!lsm->enabled ||
+ lsm->enabled == &lsm_enabled_true ||
+ lsm->enabled == &lsm_enabled_false) {
+ lsm->enabled = enabled ? &lsm_enabled_true : &lsm_enabled_false;
} else {
*lsm->enabled = enabled;
}
}
-static inline bool is_enabled(struct lsm_info *lsm)
+/**
+ * lsm_is_enabled - Determine if a LSM is enabled
+ * @lsm: LSM definition
+ */
+static inline bool lsm_is_enabled(struct lsm_info *lsm)
{
- if (!lsm->enabled)
- return false;
-
- return *lsm->enabled;
+ return (lsm->enabled ? *lsm->enabled : false);
}
/* Is an LSM already listed in the ordered LSMs list? */
@@ -139,7 +139,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
lsm_idlist[last_lsm++] = lsm->id;
init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
- is_enabled(lsm) ? "enabled" : "disabled");
+ lsm_is_enabled(lsm) ? "enabled" : "disabled");
}
static void __init lsm_set_blob_size(int *need, int *lbs)
@@ -162,17 +162,17 @@ static void __init lsm_prepare(struct lsm_info *lsm)
{
struct lsm_blob_sizes *blobs;
- if (!is_enabled(lsm)) {
- set_enabled(lsm, false);
+ if (!lsm_is_enabled(lsm)) {
+ lsm_enabled_set(lsm, false);
return;
} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
init_debug("exclusive disabled: %s\n", lsm->id->name);
- set_enabled(lsm, false);
+ lsm_enabled_set(lsm, false);
return;
}
/* Mark the LSM as enabled. */
- set_enabled(lsm, true);
+ lsm_enabled_set(lsm, true);
if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
init_debug("exclusive chosen: %s\n", lsm->id->name);
lsm_exclusive = lsm;
@@ -203,7 +203,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
/* Initialize a given LSM, if it is enabled. */
static void __init initialize_lsm(struct lsm_info *lsm)
{
- if (is_enabled(lsm)) {
+ if (lsm_is_enabled(lsm)) {
int ret;
init_debug("initializing %s\n", lsm->id->name);
@@ -237,7 +237,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
lsm_for_each_raw(major) {
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
strcmp(major->id->name, lsm_order_legacy) != 0) {
- set_enabled(major, false);
+ lsm_enabled_set(major, false);
init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
lsm_order_legacy, major->id->name);
}
@@ -283,7 +283,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
lsm_for_each_raw(lsm) {
if (exists_ordered_lsm(lsm))
continue;
- set_enabled(lsm, false);
+ lsm_enabled_set(lsm, false);
init_debug("%s skipped: %s (not in requested order)\n",
origin, lsm->id->name);
}
@@ -316,12 +316,12 @@ static void __init lsm_init_ordered(void)
pr_info("initializing lsm=");
lsm_early_for_each_raw(early) {
- if (is_enabled(early))
+ if (lsm_is_enabled(early))
pr_cont("%s%s",
first++ == 0 ? "" : ",", early->id->name);
}
lsm_order_for_each(lsm) {
- if (is_enabled(*lsm))
+ if (lsm_is_enabled(*lsm))
pr_cont("%s%s",
first++ == 0 ? "" : ",", (*lsm)->id->name);
}
@@ -439,7 +439,7 @@ int __init security_init(void)
*/
lsm_early_for_each_raw(lsm) {
init_debug(" early started: %s (%s)\n", lsm->id->name,
- is_enabled(lsm) ? "enabled" : "disabled");
+ lsm_is_enabled(lsm) ? "enabled" : "disabled");
}
/* Load LSMs in specified order. */
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,71 @@
From f5d2029482544f20f0ef5652593a120262b8a96e Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:26:50 +0200
Subject: [PATCH] lsm: rename exists_ordered_lsm() to lsm_order_exists()
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit a748372a282ae1e23d5d4b14a3e190c28764cfd2
Author: Paul Moore <paul@paul-moore.com>
Date: Sun Jul 13 17:37:56 2025 -0400
lsm: rename exists_ordered_lsm() to lsm_order_exists()
Also add a header comment block to the function.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 9929d1a61634..bee12c553820 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -108,8 +108,11 @@ static inline bool lsm_is_enabled(struct lsm_info *lsm)
return (lsm->enabled ? *lsm->enabled : false);
}
-/* Is an LSM already listed in the ordered LSMs list? */
-static bool __init exists_ordered_lsm(struct lsm_info *lsm)
+/**
+ * lsm_order_exists - Determine if a LSM exists in the ordered list
+ * @lsm: LSM definition
+ */
+static bool __init lsm_order_exists(struct lsm_info *lsm)
{
struct lsm_info **check;
@@ -126,7 +129,7 @@ static int last_lsm __initdata;
static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
{
/* Ignore duplicate selections. */
- if (exists_ordered_lsm(lsm))
+ if (lsm_order_exists(lsm))
return;
if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
@@ -266,7 +269,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
/* Process "security=", if given. */
if (lsm_order_legacy) {
lsm_for_each_raw(lsm) {
- if (exists_ordered_lsm(lsm))
+ if (lsm_order_exists(lsm))
continue;
if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
append_ordered_lsm(lsm, "security=");
@@ -281,7 +284,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
/* Disable all LSMs not in the ordered list. */
lsm_for_each_raw(lsm) {
- if (exists_ordered_lsm(lsm))
+ if (lsm_order_exists(lsm))
continue;
lsm_enabled_set(lsm, false);
init_debug("%s skipped: %s (not in requested order)\n",
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,170 @@
From 2fad39b00bffc92249f43dfa2db89c89b640bcc2 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:26:50 +0200
Subject: [PATCH] lsm: rename/rework append_ordered_lsm() into
lsm_order_append()
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 24a9c58978ee368cbd796a03cb6e8ade6e0b6f5f
Author: Paul Moore <paul@paul-moore.com>
Date: Wed Jul 16 15:04:10 2025 -0400
lsm: rename/rework append_ordered_lsm() into lsm_order_append()
Rename append_ordered_lsm() to lsm_order_append() to better match
convention and do some rework. The rework includes moving the
LSM_FLAG_EXCLUSIVE logic from lsm_prepare() to lsm_order_append()
in order to consolidate the individual LSM append/activation code,
and adding logic to skip appending explicitly disabled LSMs to the
active LSM list.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index bee12c553820..30ed62311565 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -124,24 +124,48 @@ static bool __init lsm_order_exists(struct lsm_info *lsm)
return false;
}
-/* Append an LSM to the list of ordered LSMs to initialize. */
-static int last_lsm __initdata;
-static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
+/**
+ * lsm_order_append - Append a LSM to the ordered list
+ * @lsm: LSM definition
+ * @src: source of the addition
+ *
+ * Append @lsm to the enabled LSM array after ensuring that it hasn't been
+ * explicitly disabled, is a duplicate entry, or would run afoul of the
+ * LSM_FLAG_EXCLUSIVE logic.
+ */
+static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
{
/* Ignore duplicate selections. */
if (lsm_order_exists(lsm))
return;
- if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
- return;
+ /* Skip explicitly disabled LSMs. */
+ if (lsm->enabled && !lsm_is_enabled(lsm))
+ goto out;
- /* Enable this LSM, if it is not already set. */
- if (!lsm->enabled)
- lsm->enabled = &lsm_enabled_true;
- lsm_order[last_lsm] = lsm;
- lsm_idlist[last_lsm++] = lsm->id;
+ if (WARN(lsm_active_cnt == MAX_LSM_COUNT,
+ "%s: out of LSM static calls!?\n", src)) {
+ lsm_enabled_set(lsm, false);
+ goto out;
+ }
+
+ if (lsm->flags & LSM_FLAG_EXCLUSIVE) {
+ if (lsm_exclusive) {
+ init_debug("exclusive disabled: %s\n", lsm->id->name);
+ lsm_enabled_set(lsm, false);
+ goto out;
+ } else {
+ init_debug("exclusive chosen: %s\n", lsm->id->name);
+ lsm_exclusive = lsm;
+ }
+ }
- init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
+ lsm_enabled_set(lsm, true);
+ lsm_order[lsm_active_cnt] = lsm;
+ lsm_idlist[lsm_active_cnt++] = lsm->id;
+
+out:
+ init_debug("%s ordered: %s (%s)\n", src, lsm->id->name,
lsm_is_enabled(lsm) ? "enabled" : "disabled");
}
@@ -163,26 +187,12 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
*/
static void __init lsm_prepare(struct lsm_info *lsm)
{
- struct lsm_blob_sizes *blobs;
+ struct lsm_blob_sizes *blobs = lsm->blobs;
- if (!lsm_is_enabled(lsm)) {
- lsm_enabled_set(lsm, false);
- return;
- } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
- init_debug("exclusive disabled: %s\n", lsm->id->name);
- lsm_enabled_set(lsm, false);
+ if (!blobs)
return;
- }
-
- /* Mark the LSM as enabled. */
- lsm_enabled_set(lsm, true);
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
- init_debug("exclusive chosen: %s\n", lsm->id->name);
- lsm_exclusive = lsm;
- }
/* Register the LSM blob sizes. */
- blobs = lsm->blobs;
lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
@@ -224,7 +234,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
/* LSM_ORDER_FIRST is always first. */
lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_FIRST)
- append_ordered_lsm(lsm, " first");
+ lsm_order_append(lsm, " first");
}
/* Process "security=", if given. */
@@ -256,7 +266,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
lsm_for_each_raw(lsm) {
if (strcmp(lsm->id->name, name) == 0) {
if (lsm->order == LSM_ORDER_MUTABLE)
- append_ordered_lsm(lsm, origin);
+ lsm_order_append(lsm, origin);
found = true;
}
}
@@ -272,14 +282,14 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
if (lsm_order_exists(lsm))
continue;
if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
- append_ordered_lsm(lsm, "security=");
+ lsm_order_append(lsm, "security=");
}
}
/* LSM_ORDER_LAST is always last. */
lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_LAST)
- append_ordered_lsm(lsm, " last");
+ lsm_order_append(lsm, " last");
}
/* Disable all LSMs not in the ordered list. */
@@ -413,8 +423,8 @@ int __init early_security_init(void)
return 0;
lsm_early_for_each_raw(lsm) {
- if (!lsm->enabled)
- lsm->enabled = &lsm_enabled_true;
+ lsm_enabled_set(lsm, true);
+ lsm_order_append(lsm, "early");
lsm_prepare(lsm);
initialize_lsm(lsm);
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,166 @@
From 9a0e65bba0a4f8b08943349600337bc08612db41 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:26:51 +0200
Subject: [PATCH] lsm: rename/rework ordered_lsm_parse() to lsm_order_parse()
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 752db06571816a3870b17814882425318b5ec0ef
Author: Paul Moore <paul@paul-moore.com>
Date: Sun Jul 13 17:51:12 2025 -0400
lsm: rename/rework ordered_lsm_parse() to lsm_order_parse()
Rename ordered_lsm_parse() to lsm_order_parse() for the sake of
consistency with the other LSM initialization routines, and also
do some minor rework of the function. Aside from some minor style
decisions, the majority of the rework involved shuffling the order
of the LSM_FLAG_LEGACY and LSM_ORDER_FIRST code so that the
LSM_FLAG_LEGACY checks are handled first; it is important to note
that this doesn't affect the order in which the LSMs are registered.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 30ed62311565..d159981ad0a2 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -225,83 +225,75 @@ static void __init initialize_lsm(struct lsm_info *lsm)
}
}
-/* Populate ordered LSMs list from comma-separated LSM name list. */
-static void __init ordered_lsm_parse(const char *order, const char *origin)
+/**
+ * lsm_order_parse - Parse the comma delimited LSM list
+ * @list: LSM list
+ * @src: source of the list
+ */
+static void __init lsm_order_parse(const char *list, const char *src)
{
struct lsm_info *lsm;
char *sep, *name, *next;
- /* LSM_ORDER_FIRST is always first. */
- lsm_for_each_raw(lsm) {
- if (lsm->order == LSM_ORDER_FIRST)
- lsm_order_append(lsm, " first");
- }
-
- /* Process "security=", if given. */
+ /* Handle any Legacy LSM exclusions if one was specified. */
if (lsm_order_legacy) {
- struct lsm_info *major;
-
/*
- * To match the original "security=" behavior, this
- * explicitly does NOT fallback to another Legacy Major
- * if the selected one was separately disabled: disable
- * all non-matching Legacy Major LSMs.
+ * To match the original "security=" behavior, this explicitly
+ * does NOT fallback to another Legacy Major if the selected
+ * one was separately disabled: disable all non-matching
+ * Legacy Major LSMs.
*/
- lsm_for_each_raw(major) {
- if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
- strcmp(major->id->name, lsm_order_legacy) != 0) {
- lsm_enabled_set(major, false);
+ lsm_for_each_raw(lsm) {
+ if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) &&
+ strcmp(lsm->id->name, lsm_order_legacy)) {
+ lsm_enabled_set(lsm, false);
init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
- lsm_order_legacy, major->id->name);
+ lsm_order_legacy, lsm->id->name);
}
}
}
- sep = kstrdup(order, GFP_KERNEL);
+ /* LSM_ORDER_FIRST */
+ lsm_for_each_raw(lsm) {
+ if (lsm->order == LSM_ORDER_FIRST)
+ lsm_order_append(lsm, "first");
+ }
+
+ /* Normal or "mutable" LSMs */
+ sep = kstrdup(list, GFP_KERNEL);
next = sep;
/* Walk the list, looking for matching LSMs. */
while ((name = strsep(&next, ",")) != NULL) {
- bool found = false;
-
lsm_for_each_raw(lsm) {
- if (strcmp(lsm->id->name, name) == 0) {
- if (lsm->order == LSM_ORDER_MUTABLE)
- lsm_order_append(lsm, origin);
- found = true;
- }
+ if (!strcmp(lsm->id->name, name) &&
+ lsm->order == LSM_ORDER_MUTABLE)
+ lsm_order_append(lsm, src);
}
-
- if (!found)
- init_debug("%s ignored: %s (not built into kernel)\n",
- origin, name);
}
+ kfree(sep);
- /* Process "security=", if given. */
+ /* Legacy LSM if specified. */
if (lsm_order_legacy) {
lsm_for_each_raw(lsm) {
- if (lsm_order_exists(lsm))
- continue;
- if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
- lsm_order_append(lsm, "security=");
+ if (!strcmp(lsm->id->name, lsm_order_legacy))
+ lsm_order_append(lsm, src);
}
}
- /* LSM_ORDER_LAST is always last. */
+ /* LSM_ORDER_LAST */
lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_LAST)
- lsm_order_append(lsm, " last");
+ lsm_order_append(lsm, "last");
}
- /* Disable all LSMs not in the ordered list. */
+ /* Disable all LSMs not previously enabled. */
lsm_for_each_raw(lsm) {
if (lsm_order_exists(lsm))
continue;
lsm_enabled_set(lsm, false);
init_debug("%s skipped: %s (not in requested order)\n",
- origin, lsm->id->name);
+ src, lsm->id->name);
}
-
- kfree(sep);
}
/**
@@ -319,9 +311,9 @@ static void __init lsm_init_ordered(void)
lsm_order_legacy, lsm_order_cmdline);
lsm_order_legacy = NULL;
}
- ordered_lsm_parse(lsm_order_cmdline, "cmdline");
+ lsm_order_parse(lsm_order_cmdline, "cmdline");
} else
- ordered_lsm_parse(lsm_order_builtin, "builtin");
+ lsm_order_parse(lsm_order_builtin, "builtin");
lsm_order_for_each(lsm) {
lsm_prepare(*lsm);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,148 @@
From 7cbba38d94b554ea452c90264ea4f7b03ef18498 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Fri, 29 May 2026 18:37:27 +0200
Subject: [PATCH] lsm: cleanup the LSM blob size code
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
Conflicts:
- conflict due to 5816bf4273ed ("lsm,selinux: Add LSM blob support for
BPF objects"), which is not backported
commit 291271e691740003021cf5b48fa7cf7e3371eaa7
Author: Paul Moore <paul@paul-moore.com>
Date: Tue Feb 11 17:49:11 2025 -0500
lsm: cleanup the LSM blob size code
Convert the lsm_blob_size fields to unsigned integers as there is no
current need for them to be negative, change "lsm_set_blob_size()" to
"lsm_blob_size_update()" to better reflect reality, and perform some
other minor cleanups to the associated code.
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index bc477fb20d02..a7ecb0791a0f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -102,20 +102,20 @@ struct security_hook_list {
* Security blob size or offset data.
*/
struct lsm_blob_sizes {
- int lbs_cred;
- int lbs_file;
- int lbs_ib;
- int lbs_inode;
- int lbs_sock;
- int lbs_superblock;
- int lbs_ipc;
- int lbs_key;
- int lbs_msg_msg;
- int lbs_perf_event;
- int lbs_task;
- int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
- int lbs_tun_dev;
- int lbs_bdev;
+ unsigned int lbs_cred;
+ unsigned int lbs_file;
+ unsigned int lbs_ib;
+ unsigned int lbs_inode;
+ unsigned int lbs_sock;
+ unsigned int lbs_superblock;
+ unsigned int lbs_ipc;
+ unsigned int lbs_key;
+ unsigned int lbs_msg_msg;
+ unsigned int lbs_perf_event;
+ unsigned int lbs_task;
+ unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
+ unsigned int lbs_tun_dev;
+ unsigned int lbs_bdev;
};
/*
diff --git a/security/lsm_init.c b/security/lsm_init.c
index d159981ad0a2..bc9191b53305 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -169,16 +169,22 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
lsm_is_enabled(lsm) ? "enabled" : "disabled");
}
-static void __init lsm_set_blob_size(int *need, int *lbs)
+/**
+ * lsm_blob_size_update - Update the LSM blob size and offset information
+ * @sz_req: the requested additional blob size
+ * @sz_cur: the existing blob size
+ */
+static void __init lsm_blob_size_update(unsigned int *sz_req,
+ unsigned int *sz_cur)
{
- int offset;
+ unsigned int offset;
- if (*need <= 0)
+ if (*sz_req == 0)
return;
- offset = ALIGN(*lbs, sizeof(void *));
- *lbs = offset + *need;
- *need = offset;
+ offset = ALIGN(*sz_cur, sizeof(void *));
+ *sz_cur = offset + *sz_req;
+ *sz_req = offset;
}
/**
@@ -193,24 +199,27 @@ static void __init lsm_prepare(struct lsm_info *lsm)
return;
/* Register the LSM blob sizes. */
- lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
- lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
- lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
+ blobs = lsm->blobs;
+ lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
+ lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
/* inode blob gets an rcu_head in addition to LSM blobs. */
if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
blob_sizes.lbs_inode = sizeof(struct rcu_head);
- lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
- lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
- lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
- lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
- lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
- lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
- lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
- lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
- lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
- lsm_set_blob_size(&blobs->lbs_xattr_count,
- &blob_sizes.lbs_xattr_count);
- lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
+ lsm_blob_size_update(&blobs->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
+ lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
+ lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_blob_size_update(&blobs->lbs_perf_event,
+ &blob_sizes.lbs_perf_event);
+ lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
+ lsm_blob_size_update(&blobs->lbs_superblock,
+ &blob_sizes.lbs_superblock);
+ lsm_blob_size_update(&blobs->lbs_task, &blob_sizes.lbs_task);
+ lsm_blob_size_update(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
+ lsm_blob_size_update(&blobs->lbs_xattr_count,
+ &blob_sizes.lbs_xattr_count);
+ lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
}
/* Initialize a given LSM, if it is enabled. */
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,88 @@
From 800c1228fa046d32687562f80731aa1cda374657 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:28:42 +0200
Subject: [PATCH] lsm: cleanup initialize_lsm() and rename to lsm_init_single()
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 27be5600fe852c52d5b70f4ac9406879b39c864e
Author: Paul Moore <paul@paul-moore.com>
Date: Tue Feb 11 18:24:04 2025 -0500
lsm: cleanup initialize_lsm() and rename to lsm_init_single()
Rename initialize_lsm() to be more consistent with the rest of the LSM
initialization changes and rework the function itself to better fit
with the "exit on fail" coding pattern.
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index bc9191b53305..8cf53a48f37c 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -169,6 +169,7 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
lsm_is_enabled(lsm) ? "enabled" : "disabled");
}
+
/**
* lsm_blob_size_update - Update the LSM blob size and offset information
* @sz_req: the requested additional blob size
@@ -222,16 +223,20 @@ static void __init lsm_prepare(struct lsm_info *lsm)
lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
}
-/* Initialize a given LSM, if it is enabled. */
-static void __init initialize_lsm(struct lsm_info *lsm)
+/**
+ * lsm_init_single - Initialize a given LSM
+ * @lsm: LSM definition
+ */
+static void __init lsm_init_single(struct lsm_info *lsm)
{
- if (lsm_is_enabled(lsm)) {
- int ret;
+ int ret;
- init_debug("initializing %s\n", lsm->id->name);
- ret = lsm->init();
- WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
- }
+ if (!lsm_is_enabled(lsm))
+ return;
+
+ init_debug("initializing %s\n", lsm->id->name);
+ ret = lsm->init();
+ WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
}
/**
@@ -373,7 +378,7 @@ static void __init lsm_init_ordered(void)
panic("%s: early task alloc failed.\n", __func__);
lsm_order_for_each(lsm) {
- initialize_lsm(*lsm);
+ lsm_init_single(*lsm);
}
}
@@ -427,7 +432,7 @@ int __init early_security_init(void)
lsm_enabled_set(lsm, true);
lsm_order_append(lsm, "early");
lsm_prepare(lsm);
- initialize_lsm(lsm);
+ lsm_init_single(lsm);
}
early_security_initialized = true;
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,236 @@
From 4b0683928d38d0fd4d8ce409bb75adfb669b9eb7 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:28:42 +0200
Subject: [PATCH] lsm: fold lsm_init_ordered() into security_init()
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
Conflicts:
- conflict due to 5816bf4273ed ("lsm,selinux: Add LSM blob support for
BPF objects"), which is not backported
commit 45a41d1394aa2ed0305f0560f93bb87be7192481
Author: Paul Moore <paul@paul-moore.com>
Date: Wed Feb 12 18:10:37 2025 -0500
lsm: fold lsm_init_ordered() into security_init()
With only security_init() calling lsm_init_ordered, it makes little
sense to keep lsm_init_ordered() as a standalone function. Fold
lsm_init_ordered() into security_init().
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 8cf53a48f37c..560ce78f3493 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -18,6 +18,9 @@ static __initdata int lsm_enabled_false = 0;
extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
+/* Number of "early" LSMs */
+static __initdata unsigned int lsm_count_early;
+
/* Build and boot-time LSM ordering. */
static __initconst const char *const lsm_order_builtin = CONFIG_LSM;
static __initdata const char *lsm_order_cmdline;
@@ -169,7 +172,6 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
lsm_is_enabled(lsm) ? "enabled" : "disabled");
}
-
/**
* lsm_blob_size_update - Update the LSM blob size and offset information
* @sz_req: the requested additional blob size
@@ -310,78 +312,6 @@ static void __init lsm_order_parse(const char *list, const char *src)
}
}
-/**
- * lsm_init_ordered - Initialize the ordered LSMs
- */
-static void __init lsm_init_ordered(void)
-{
- unsigned int first = 0;
- struct lsm_info **lsm;
- struct lsm_info *early;
-
- if (lsm_order_cmdline) {
- if (lsm_order_legacy) {
- pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
- lsm_order_legacy, lsm_order_cmdline);
- lsm_order_legacy = NULL;
- }
- lsm_order_parse(lsm_order_cmdline, "cmdline");
- } else
- lsm_order_parse(lsm_order_builtin, "builtin");
-
- lsm_order_for_each(lsm) {
- lsm_prepare(*lsm);
- }
-
- pr_info("initializing lsm=");
- lsm_early_for_each_raw(early) {
- if (lsm_is_enabled(early))
- pr_cont("%s%s",
- first++ == 0 ? "" : ",", early->id->name);
- }
- lsm_order_for_each(lsm) {
- if (lsm_is_enabled(*lsm))
- pr_cont("%s%s",
- first++ == 0 ? "" : ",", (*lsm)->id->name);
- }
- pr_cont("\n");
-
- init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
- init_debug("file blob size = %d\n", blob_sizes.lbs_file);
- init_debug("ib blob size = %d\n", blob_sizes.lbs_ib);
- init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
- init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
-#ifdef CONFIG_KEYS
- init_debug("key blob size = %d\n", blob_sizes.lbs_key);
-#endif /* CONFIG_KEYS */
- init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
- init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
- init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
- init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
- init_debug("task blob size = %d\n", blob_sizes.lbs_task);
- init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
- init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
- init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
-
- if (blob_sizes.lbs_file)
- lsm_file_cache = kmem_cache_create("lsm_file_cache",
- blob_sizes.lbs_file, 0,
- SLAB_PANIC, NULL);
- if (blob_sizes.lbs_inode)
- lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
- blob_sizes.lbs_inode, 0,
- SLAB_PANIC, NULL);
-
- if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
- panic("%s: early cred alloc failed.\n", __func__);
- if (lsm_task_alloc(current))
- panic("%s: early task alloc failed.\n", __func__);
-
- lsm_order_for_each(lsm) {
- lsm_init_single(*lsm);
- }
-}
-
static void __init lsm_static_call_init(struct security_hook_list *hl)
{
struct lsm_static_call *scall = hl->scalls;
@@ -433,6 +363,7 @@ int __init early_security_init(void)
lsm_order_append(lsm, "early");
lsm_prepare(lsm);
lsm_init_single(lsm);
+ lsm_count_early++;
}
early_security_initialized = true;
@@ -440,29 +371,85 @@ int __init early_security_init(void)
}
/**
- * security_init - initializes the security framework
+ * security_init - Initializes the LSM framework
*
* This should be called early in the kernel initialization sequence.
*/
int __init security_init(void)
{
- struct lsm_info *lsm;
+ unsigned int cnt;
+ struct lsm_info **lsm;
+ struct lsm_info *early;
+ unsigned int first = 0;
init_debug("legacy security=%s\n", lsm_order_legacy ? : " *unspecified*");
init_debug(" CONFIG_LSM=%s\n", lsm_order_builtin);
init_debug("boot arg lsm=%s\n", lsm_order_cmdline ? : " *unspecified*");
- /*
- * Append the names of the early LSM modules now that kmalloc() is
- * available
- */
- lsm_early_for_each_raw(lsm) {
- init_debug(" early started: %s (%s)\n", lsm->id->name,
- lsm_is_enabled(lsm) ? "enabled" : "disabled");
+ if (lsm_order_cmdline) {
+ if (lsm_order_legacy) {
+ pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
+ lsm_order_legacy, lsm_order_cmdline);
+ lsm_order_legacy = NULL;
+ }
+ lsm_order_parse(lsm_order_cmdline, "cmdline");
+ } else
+ lsm_order_parse(lsm_order_builtin, "builtin");
+
+ lsm_order_for_each(lsm)
+ lsm_prepare(*lsm);
+
+ pr_info("initializing lsm=");
+ lsm_early_for_each_raw(early) {
+ if (lsm_is_enabled(early))
+ pr_cont("%s%s",
+ first++ == 0 ? "" : ",", early->id->name);
+ }
+ lsm_order_for_each(lsm) {
+ if (lsm_is_enabled(*lsm))
+ pr_cont("%s%s",
+ first++ == 0 ? "" : ",", (*lsm)->id->name);
}
+ pr_cont("\n");
+
+ init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
+ init_debug("file blob size = %d\n", blob_sizes.lbs_file);
+ init_debug("ib blob size = %d\n", blob_sizes.lbs_ib);
+ init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
+ init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+ init_debug("key blob size = %d\n", blob_sizes.lbs_key);
+#endif /* CONFIG_KEYS */
+ init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
+ init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
+ init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+ init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
+ init_debug("task blob size = %d\n", blob_sizes.lbs_task);
+ init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
+ init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
+ init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
+
+ if (blob_sizes.lbs_file)
+ lsm_file_cache = kmem_cache_create("lsm_file_cache",
+ blob_sizes.lbs_file, 0,
+ SLAB_PANIC, NULL);
+ if (blob_sizes.lbs_inode)
+ lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+ blob_sizes.lbs_inode, 0,
+ SLAB_PANIC, NULL);
- /* Load LSMs in specified order. */
- lsm_init_ordered();
+ if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
+ panic("%s: early cred alloc failed.\n", __func__);
+ if (lsm_task_alloc(current))
+ panic("%s: early task alloc failed.\n", __func__);
+
+ cnt = 0;
+ lsm_order_for_each(lsm) {
+ /* skip the "early" LSMs as they have already been setup */
+ if (cnt++ < lsm_count_early)
+ continue;
+ lsm_init_single(*lsm);
+ }
return 0;
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,70 @@
From 5a8181960a7f242505b8b6782253a87545aec9d3 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:28:43 +0200
Subject: [PATCH] lsm: add/tweak function header comment blocks in lsm_init.c
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
commit 450705334f698990804b470437f3014cee979486
Author: Paul Moore <paul@paul-moore.com>
Date: Wed Feb 12 18:17:03 2025 -0500
lsm: add/tweak function header comment blocks in lsm_init.c
Add function header comments for lsm_static_call_init() and
early_security_init(), tweak the existing comment block for
security_add_hooks().
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 560ce78f3493..a7eeeca2cb67 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -312,6 +312,10 @@ static void __init lsm_order_parse(const char *list, const char *src)
}
}
+/**
+ * lsm_static_call_init - Initialize a LSM's static calls
+ * @hl: LSM hook list
+ */
static void __init lsm_static_call_init(struct security_hook_list *hl)
{
struct lsm_static_call *scall = hl->scalls;
@@ -332,12 +336,12 @@ static void __init lsm_static_call_init(struct security_hook_list *hl)
}
/**
- * security_add_hooks - Add a modules hooks to the hook lists.
- * @hooks: the hooks to add
- * @count: the number of hooks to add
- * @lsmid: the identification information for the security module
+ * security_add_hooks - Add a LSM's hooks to the LSM framework's hook lists
+ * @hooks: LSM hooks to add
+ * @count: number of hooks to add
+ * @lsmid: identification information for the LSM
*
- * Each LSM has to register its hooks with the infrastructure.
+ * Each LSM has to register its hooks with the LSM framework.
*/
void __init security_add_hooks(struct security_hook_list *hooks, int count,
const struct lsm_id *lsmid)
@@ -350,6 +354,9 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
}
}
+/**
+ * early_security_init - Initialize the early LSMs
+ */
int __init early_security_init(void)
{
struct lsm_info *lsm;
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,299 @@
From 455eabf0b6cf32582a8f485f2628a4e0a90fe398 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Mon, 1 Jun 2026 10:30:41 +0200
Subject: [PATCH] lsm: cleanup the debug and console output in lsm_init.c
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
Conflicts:
- conflict due to 5816bf4273ed ("lsm,selinux: Add LSM blob support for
BPF objects"), which is not backported
commit 5137e583ba2635b82667dc63cb35305750420411
Author: Paul Moore <paul@paul-moore.com>
Date: Wed Feb 12 18:20:01 2025 -0500
lsm: cleanup the debug and console output in lsm_init.c
Move away from an init specific init_debug() macro to a more general
lsm_pr()/lsm_pr_cont()/lsm_pr_dbg() set of macros that are available
both before and after init. In the process we do a number of minor
changes to improve the LSM initialization output and cleanup the code
somewhat.
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/lsm.h b/security/lsm.h
index dbe755c45e57..8dc267977ae0 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -6,9 +6,20 @@
#ifndef _LSM_H_
#define _LSM_H_
+#include <linux/printk.h>
#include <linux/lsm_hooks.h>
#include <linux/lsm_count.h>
+/* LSM debugging */
+extern bool lsm_debug;
+#define lsm_pr(...) pr_info(__VA_ARGS__)
+#define lsm_pr_cont(...) pr_cont(__VA_ARGS__)
+#define lsm_pr_dbg(...) \
+ do { \
+ if (lsm_debug) \
+ pr_info(__VA_ARGS__); \
+ } while (0)
+
/* List of configured LSMs */
extern unsigned int lsm_active_cnt;
extern const struct lsm_id *lsm_idlist[];
diff --git a/security/lsm_init.c b/security/lsm_init.c
index a7eeeca2cb67..bef21da72c16 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -30,13 +30,6 @@ static __initdata const char *lsm_order_legacy;
static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
static __initdata struct lsm_info *lsm_exclusive;
-static __initdata bool debug;
-#define init_debug(...) \
- do { \
- if (debug) \
- pr_info(__VA_ARGS__); \
- } while (0)
-
#define lsm_order_for_each(iter) \
for ((iter) = lsm_order; *(iter); (iter)++)
#define lsm_for_each_raw(iter) \
@@ -77,7 +70,7 @@ __setup("lsm=", lsm_choose_lsm);
*/
static int __init lsm_debug_enable(char *str)
{
- debug = true;
+ lsm_debug = true;
return 1;
}
__setup("lsm.debug", lsm_debug_enable);
@@ -143,22 +136,28 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
return;
/* Skip explicitly disabled LSMs. */
- if (lsm->enabled && !lsm_is_enabled(lsm))
- goto out;
+ if (lsm->enabled && !lsm_is_enabled(lsm)) {
+ lsm_pr_dbg("skip previously disabled LSM %s:%s\n",
+ src, lsm->id->name);
+ return;
+ }
- if (WARN(lsm_active_cnt == MAX_LSM_COUNT,
- "%s: out of LSM static calls!?\n", src)) {
+ if (lsm_active_cnt == MAX_LSM_COUNT) {
+ pr_warn("exceeded maximum LSM count on %s:%s\n",
+ src, lsm->id->name);
lsm_enabled_set(lsm, false);
- goto out;
+ return;
}
if (lsm->flags & LSM_FLAG_EXCLUSIVE) {
if (lsm_exclusive) {
- init_debug("exclusive disabled: %s\n", lsm->id->name);
+ lsm_pr_dbg("skip exclusive LSM conflict %s:%s\n",
+ src, lsm->id->name);
lsm_enabled_set(lsm, false);
- goto out;
+ return;
} else {
- init_debug("exclusive chosen: %s\n", lsm->id->name);
+ lsm_pr_dbg("select exclusive LSM %s:%s\n",
+ src, lsm->id->name);
lsm_exclusive = lsm;
}
}
@@ -167,9 +166,7 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
lsm_order[lsm_active_cnt] = lsm;
lsm_idlist[lsm_active_cnt++] = lsm->id;
-out:
- init_debug("%s ordered: %s (%s)\n", src, lsm->id->name,
- lsm_is_enabled(lsm) ? "enabled" : "disabled");
+ lsm_pr_dbg("enabling LSM %s:%s\n", src, lsm->id->name);
}
/**
@@ -236,7 +233,7 @@ static void __init lsm_init_single(struct lsm_info *lsm)
if (!lsm_is_enabled(lsm))
return;
- init_debug("initializing %s\n", lsm->id->name);
+ lsm_pr_dbg("initializing %s\n", lsm->id->name);
ret = lsm->init();
WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
}
@@ -263,8 +260,8 @@ static void __init lsm_order_parse(const char *list, const char *src)
if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) &&
strcmp(lsm->id->name, lsm_order_legacy)) {
lsm_enabled_set(lsm, false);
- init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
- lsm_order_legacy, lsm->id->name);
+ lsm_pr_dbg("skip legacy LSM conflict %s:%s\n",
+ src, lsm->id->name);
}
}
}
@@ -307,8 +304,7 @@ static void __init lsm_order_parse(const char *list, const char *src)
if (lsm_order_exists(lsm))
continue;
lsm_enabled_set(lsm, false);
- init_debug("%s skipped: %s (not in requested order)\n",
- src, lsm->id->name);
+ lsm_pr_dbg("skip disabled LSM %s:%s\n", src, lsm->id->name);
}
}
@@ -316,7 +312,7 @@ static void __init lsm_order_parse(const char *list, const char *src)
* lsm_static_call_init - Initialize a LSM's static calls
* @hl: LSM hook list
*/
-static void __init lsm_static_call_init(struct security_hook_list *hl)
+static int __init lsm_static_call_init(struct security_hook_list *hl)
{
struct lsm_static_call *scall = hl->scalls;
int i;
@@ -328,11 +324,12 @@ static void __init lsm_static_call_init(struct security_hook_list *hl)
hl->hook.lsm_func_addr);
scall->hl = hl;
static_branch_enable(scall->active);
- return;
+ return 0;
}
scall++;
}
- panic("%s - Ran out of static slots.\n", __func__);
+
+ return -ENOSPC;
}
/**
@@ -350,7 +347,9 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
for (i = 0; i < count; i++) {
hooks[i].lsmid = lsmid;
- lsm_static_call_init(&hooks[i]);
+ if (lsm_static_call_init(&hooks[i]))
+ panic("exhausted LSM callback slots with LSM %s\n",
+ lsmid->name);
}
}
@@ -386,19 +385,16 @@ int __init security_init(void)
{
unsigned int cnt;
struct lsm_info **lsm;
- struct lsm_info *early;
- unsigned int first = 0;
- init_debug("legacy security=%s\n", lsm_order_legacy ? : " *unspecified*");
- init_debug(" CONFIG_LSM=%s\n", lsm_order_builtin);
- init_debug("boot arg lsm=%s\n", lsm_order_cmdline ? : " *unspecified*");
+ if (lsm_debug) {
+ lsm_pr("built-in LSM list: %s\n", lsm_order_builtin);
+ lsm_pr("legacy LSM parameter: %s\n", lsm_order_legacy);
+ lsm_pr("boot LSM parameter: %s\n", lsm_order_cmdline);
+ }
if (lsm_order_cmdline) {
- if (lsm_order_legacy) {
- pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
- lsm_order_legacy, lsm_order_cmdline);
+ if (lsm_order_legacy)
lsm_order_legacy = NULL;
- }
lsm_order_parse(lsm_order_cmdline, "cmdline");
} else
lsm_order_parse(lsm_order_builtin, "builtin");
@@ -406,35 +402,22 @@ int __init security_init(void)
lsm_order_for_each(lsm)
lsm_prepare(*lsm);
- pr_info("initializing lsm=");
- lsm_early_for_each_raw(early) {
- if (lsm_is_enabled(early))
- pr_cont("%s%s",
- first++ == 0 ? "" : ",", early->id->name);
- }
- lsm_order_for_each(lsm) {
- if (lsm_is_enabled(*lsm))
- pr_cont("%s%s",
- first++ == 0 ? "" : ",", (*lsm)->id->name);
+ if (lsm_debug) {
+ lsm_pr("blob(cred) size %d\n", blob_sizes.lbs_cred);
+ lsm_pr("blob(file) size %d\n", blob_sizes.lbs_file);
+ lsm_pr("blob(ib) size %d\n", blob_sizes.lbs_ib);
+ lsm_pr("blob(inode) size %d\n", blob_sizes.lbs_inode);
+ lsm_pr("blob(ipc) size %d\n", blob_sizes.lbs_ipc);
+ lsm_pr("blob(key) size %d\n", blob_sizes.lbs_key);
+ lsm_pr("blob(msg_msg)_size %d\n", blob_sizes.lbs_msg_msg);
+ lsm_pr("blob(sock) size %d\n", blob_sizes.lbs_sock);
+ lsm_pr("blob(superblock) size %d\n", blob_sizes.lbs_superblock);
+ lsm_pr("blob(perf_event) size %d\n", blob_sizes.lbs_perf_event);
+ lsm_pr("blob(task) size %d\n", blob_sizes.lbs_task);
+ lsm_pr("blob(tun_dev) size %d\n", blob_sizes.lbs_tun_dev);
+ lsm_pr("blob(xattr) count %d\n", blob_sizes.lbs_xattr_count);
+ lsm_pr("blob(bdev) size %d\n", blob_sizes.lbs_bdev);
}
- pr_cont("\n");
-
- init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
- init_debug("file blob size = %d\n", blob_sizes.lbs_file);
- init_debug("ib blob size = %d\n", blob_sizes.lbs_ib);
- init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
- init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
-#ifdef CONFIG_KEYS
- init_debug("key blob size = %d\n", blob_sizes.lbs_key);
-#endif /* CONFIG_KEYS */
- init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
- init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
- init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
- init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
- init_debug("task blob size = %d\n", blob_sizes.lbs_task);
- init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
- init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
- init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
if (blob_sizes.lbs_file)
lsm_file_cache = kmem_cache_create("lsm_file_cache",
@@ -446,9 +429,9 @@ int __init security_init(void)
SLAB_PANIC, NULL);
if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
- panic("%s: early cred alloc failed.\n", __func__);
+ panic("early LSM cred alloc failed\n");
if (lsm_task_alloc(current))
- panic("%s: early task alloc failed.\n", __func__);
+ panic("early LSM task alloc failed\n");
cnt = 0;
lsm_order_for_each(lsm) {
diff --git a/security/security.c b/security/security.c
index 6f20f44c8d13..56c48725e334 100644
--- a/security/security.c
+++ b/security/security.c
@@ -74,6 +74,8 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
+bool lsm_debug __ro_after_init;
+
unsigned int lsm_active_cnt __ro_after_init;
const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,88 @@
From 1367930b371086acec799dd7062ce70dae049608 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Tue, 2 Jun 2026 10:09:51 +0200
Subject: [PATCH] fs: prepare for adding LSM blob to backing_file
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
Conflicts:
- fs/file_table.c: trivial context fuzz
commit 880bd496ec72a6dcb00cb70c430ef752ba242ae7
Author: Amir Goldstein <amir73il@gmail.com>
Date: Mon Mar 30 10:27:51 2026 +0200
fs: prepare for adding LSM blob to backing_file
In preparation to adding LSM blob to backing_file struct, factor out
helpers init_backing_file() and backing_file_free().
Cc: stable@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-unionfs@vger.kernel.org
Cc: linux-erofs@lists.ozlabs.org
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
[PM: use the term "LSM blob", fix comment style to match file]
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/fs/file_table.c b/fs/file_table.c
index 9979efb9a380..4b4d50a1d9da 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -67,6 +67,12 @@ void backing_file_set_user_path(struct file *f, const struct path *path)
}
EXPORT_SYMBOL_GPL(backing_file_set_user_path);
+static inline void backing_file_free(struct backing_file *ff)
+{
+ path_put(&ff->user_path);
+ kmem_cache_free(bfilp_cachep, ff);
+}
+
static inline void file_free(struct file *f)
{
security_file_free(f);
@@ -74,8 +80,7 @@ static inline void file_free(struct file *f)
percpu_counter_dec(&nr_files);
put_cred(f->f_cred);
if (unlikely(f->f_mode & FMODE_BACKING)) {
- path_put(backing_file_user_path(f));
- kmem_cache_free(bfilp_cachep, backing_file(f));
+ backing_file_free(backing_file(f));
} else {
kmem_cache_free(filp_cachep, f);
}
@@ -278,6 +283,12 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)
return f;
}
+static int init_backing_file(struct backing_file *ff)
+{
+ memset(&ff->user_path, 0, sizeof(ff->user_path));
+ return 0;
+}
+
/*
* Variant of alloc_empty_file() that allocates a backing_file container
* and doesn't check and modify nr_files.
@@ -300,7 +311,14 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
return ERR_PTR(error);
}
+ /* The f_mode flags must be set before fput(). */
ff->file.f_mode |= FMODE_BACKING | FMODE_NOACCOUNT;
+ error = init_backing_file(ff);
+ if (unlikely(error)) {
+ fput(&ff->file);
+ return ERR_PTR(error);
+ }
+
return &ff->file;
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,569 @@
From c2685f8b7b4392f68d8492a331de2f544cc80a8b Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Tue, 2 Jun 2026 10:36:28 +0200
Subject: [PATCH] lsm: add backing_file LSM hooks
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
Conflicts:
- fs/backing-file.c: adjust backing_file_mmap() to downstream state (missing
scoped guards)
- fs/erofs/ishare.c: hunk dropped, files not in RHEL10
- fs/overlayfs/dir.c: adjust to different indentation
- fs/overlayfs/file.c: adjust to different indentation
commit 6af36aeb147a06dea47c49859cd6ca5659aeb987
Author: Paul Moore <paul@paul-moore.com>
Date: Fri Dec 19 13:18:22 2025 -0500
lsm: add backing_file LSM hooks
Stacked filesystems such as overlayfs do not currently provide the
necessary mechanisms for LSMs to properly enforce access controls on the
mmap() and mprotect() operations. In order to resolve this gap, a LSM
security blob is being added to the backing_file struct and the following
new LSM hooks are being created:
security_backing_file_alloc()
security_backing_file_free()
security_mmap_backing_file()
The first two hooks are to manage the lifecycle of the LSM security blob
in the backing_file struct, while the third provides a new mmap() access
control point for the underlying backing file. It is also expected that
LSMs will likely want to update their security_file_mprotect() callback
to address issues with their mprotect() controls, but that does not
require a change to the security_file_mprotect() LSM hook.
There are a three other small changes to support these new LSM hooks:
* Pass the user file associated with a backing file down to
alloc_empty_backing_file() so it can be included in the
security_backing_file_alloc() hook.
* Add getter and setter functions for the backing_file struct LSM blob
as the backing_file struct remains private to fs/file_table.c.
* Constify the file struct field in the LSM common_audit_data struct to
better support LSMs that need to pass a const file struct pointer into
the common LSM audit code.
Thanks to Arnd Bergmann for identifying the missing EXPORT_SYMBOL_GPL()
and supplying a fixup.
Cc: stable@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-unionfs@vger.kernel.org
Cc: linux-erofs@lists.ozlabs.org
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/fs/backing-file.c b/fs/backing-file.c
index 892361c31c3d..bb7ecb0fc3ae 100644
--- a/fs/backing-file.c
+++ b/fs/backing-file.c
@@ -12,6 +12,7 @@
#include <linux/backing-file.h>
#include <linux/splice.h>
#include <linux/mm.h>
+#include <linux/security.h>
#include "internal.h"
@@ -29,14 +30,15 @@
* returned file into a container structure that also stores the stacked
* file's path, which can be retrieved using backing_file_user_path().
*/
-struct file *backing_file_open(const struct path *user_path, int flags,
+struct file *backing_file_open(const struct file *user_file, int flags,
const struct path *real_path,
const struct cred *cred)
{
+ const struct path *user_path = &user_file->f_path;
struct file *f;
int error;
- f = alloc_empty_backing_file(flags, cred);
+ f = alloc_empty_backing_file(flags, cred, user_file);
if (IS_ERR(f))
return f;
@@ -52,15 +54,16 @@ struct file *backing_file_open(const struct path *user_path, int flags,
}
EXPORT_SYMBOL_GPL(backing_file_open);
-struct file *backing_tmpfile_open(const struct path *user_path, int flags,
+struct file *backing_tmpfile_open(const struct file *user_file, int flags,
const struct path *real_parentpath,
umode_t mode, const struct cred *cred)
{
struct mnt_idmap *real_idmap = mnt_idmap(real_parentpath->mnt);
+ const struct path *user_path = &user_file->f_path;
struct file *f;
int error;
- f = alloc_empty_backing_file(flags, cred);
+ f = alloc_empty_backing_file(flags, cred, user_file);
if (IS_ERR(f))
return f;
@@ -339,6 +342,11 @@ int backing_file_mmap(struct file *file, struct vm_area_struct *vma,
vma_set_file(vma, file);
old_cred = override_creds(ctx->cred);
+ ret = security_mmap_backing_file(vma, file, ctx->user_file);
+ if (ret) {
+ revert_creds(old_cred);
+ return ret;
+ }
ret = call_mmap(vma->vm_file, vma);
revert_creds(old_cred);
diff --git a/fs/file_table.c b/fs/file_table.c
index 4b4d50a1d9da..0a7f25596d57 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -51,6 +51,9 @@ struct backing_file {
struct path user_path;
freeptr_t bf_freeptr;
};
+#ifdef CONFIG_SECURITY
+ void *security;
+#endif
};
#define backing_file(f) container_of(f, struct backing_file, file)
@@ -67,8 +70,21 @@ void backing_file_set_user_path(struct file *f, const struct path *path)
}
EXPORT_SYMBOL_GPL(backing_file_set_user_path);
+#ifdef CONFIG_SECURITY
+void *backing_file_security(const struct file *f)
+{
+ return backing_file(f)->security;
+}
+
+void backing_file_set_security(struct file *f, void *security)
+{
+ backing_file(f)->security = security;
+}
+#endif /* CONFIG_SECURITY */
+
static inline void backing_file_free(struct backing_file *ff)
{
+ security_backing_file_free(&ff->file);
path_put(&ff->user_path);
kmem_cache_free(bfilp_cachep, ff);
}
@@ -283,10 +299,12 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)
return f;
}
-static int init_backing_file(struct backing_file *ff)
+static int init_backing_file(struct backing_file *ff,
+ const struct file *user_file)
{
memset(&ff->user_path, 0, sizeof(ff->user_path));
- return 0;
+ backing_file_set_security(&ff->file, NULL);
+ return security_backing_file_alloc(&ff->file, user_file);
}
/*
@@ -296,7 +314,8 @@ static int init_backing_file(struct backing_file *ff)
* This is only for kernel internal use, and the allocate file must not be
* installed into file tables or such.
*/
-struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
+struct file *alloc_empty_backing_file(int flags, const struct cred *cred,
+ const struct file *user_file)
{
struct backing_file *ff;
int error;
@@ -313,7 +332,7 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
/* The f_mode flags must be set before fput(). */
ff->file.f_mode |= FMODE_BACKING | FMODE_NOACCOUNT;
- error = init_backing_file(ff);
+ error = init_backing_file(ff, user_file);
if (unlikely(error)) {
fput(&ff->file);
return ERR_PTR(error);
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
index bbac547dfcb3..91a43c4939ec 100644
--- a/fs/fuse/passthrough.c
+++ b/fs/fuse/passthrough.c
@@ -321,7 +321,7 @@ struct fuse_backing *fuse_passthrough_open(struct file *file,
goto out;
/* Allocate backing file per fuse file to store fuse path */
- backing_file = backing_file_open(&file->f_path, file->f_flags,
+ backing_file = backing_file_open(file, file->f_flags,
&fb->file->f_path, fb->cred);
err = PTR_ERR(backing_file);
if (IS_ERR(backing_file)) {
diff --git a/fs/internal.h b/fs/internal.h
index 67e2e164c647..049c800a3b16 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -99,7 +99,8 @@ extern void chroot_fs_refs(const struct path *, const struct path *);
*/
struct file *alloc_empty_file(int flags, const struct cred *cred);
struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
-struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
+struct file *alloc_empty_backing_file(int flags, const struct cred *cred,
+ const struct file *user_file);
void backing_file_set_user_path(struct file *f, const struct path *path);
static inline void file_put_write_access(struct file *file)
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index ab65e98a1def..1c8009bf194b 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -1320,7 +1320,7 @@ static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
goto out_revert_creds;
ovl_path_upper(dentry->d_parent, &realparentpath);
- realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath,
+ realfile = backing_tmpfile_open(file, flags, &realparentpath,
mode, current_cred());
err = PTR_ERR_OR_ZERO(realfile);
pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err);
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 4444c78e2e0c..84aad9d19bdd 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -48,7 +48,7 @@ static struct file *ovl_open_realfile(const struct file *file,
if (!inode_owner_or_capable(real_idmap, realinode))
flags &= ~O_NOATIME;
- realfile = backing_file_open(&file->f_path, flags, realpath,
+ realfile = backing_file_open(file, flags, realpath,
current_cred());
}
revert_creds(old_cred);
diff --git a/include/linux/backing-file.h b/include/linux/backing-file.h
index 2eed0ffb5e8f..cd18acd7ac5b 100644
--- a/include/linux/backing-file.h
+++ b/include/linux/backing-file.h
@@ -19,10 +19,10 @@ struct backing_file_ctx {
void (*end_write)(struct file *, loff_t, ssize_t);
};
-struct file *backing_file_open(const struct path *user_path, int flags,
+struct file *backing_file_open(const struct file *user_file, int flags,
const struct path *real_path,
const struct cred *cred);
-struct file *backing_tmpfile_open(const struct path *user_path, int flags,
+struct file *backing_tmpfile_open(const struct file *user_file, int flags,
const struct path *real_parentpath,
umode_t mode, const struct cred *cred);
ssize_t backing_file_read_iter(struct file *file, struct iov_iter *iter,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 04309befc557..975afa36e9aa 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2795,6 +2795,19 @@ struct file *dentry_create(const struct path *path, int flags, umode_t mode,
const struct cred *cred);
struct path *backing_file_user_path(const struct file *f);
+#ifdef CONFIG_SECURITY
+void *backing_file_security(const struct file *f);
+void backing_file_set_security(struct file *f, void *security);
+#else
+static inline void *backing_file_security(const struct file *f)
+{
+ return NULL;
+}
+static inline void backing_file_set_security(struct file *f, void *security)
+{
+}
+#endif /* CONFIG_SECURITY */
+
/*
* When mmapping a file on a stackable filesystem (e.g., overlayfs), the file
* stored in ->vm_file is a backing file whose f_inode is on the underlying
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 97a8b21eb033..c0a2839253fa 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -93,7 +93,7 @@ struct common_audit_data {
#endif
char *kmod_name;
struct lsm_ioctlop_audit *op;
- struct file *file;
+ const struct file *file;
struct lsm_ibpkey_audit *ibpkey;
struct lsm_ibendport_audit *ibendport;
int reason;
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 27d599bde74a..e06665ae5102 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -189,6 +189,9 @@ LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
LSM_HOOK(int, 0, file_alloc_security, struct file *file)
LSM_HOOK(void, LSM_RET_VOID, file_release, struct file *file)
LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
+LSM_HOOK(int, 0, backing_file_alloc, struct file *backing_file,
+ const struct file *user_file)
+LSM_HOOK(void, LSM_RET_VOID, backing_file_free, struct file *backing_file)
LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd,
unsigned long arg)
LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd,
@@ -196,6 +199,8 @@ LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd,
LSM_HOOK(int, 0, mmap_addr, unsigned long addr)
LSM_HOOK(int, 0, mmap_file, struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags)
+LSM_HOOK(int, 0, mmap_backing_file, struct vm_area_struct *vma,
+ struct file *backing_file, struct file *user_file)
LSM_HOOK(int, 0, file_mprotect, struct vm_area_struct *vma,
unsigned long reqprot, unsigned long prot)
LSM_HOOK(int, 0, file_lock, struct file *file, unsigned int cmd)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index a7ecb0791a0f..f1c6db9c0cff 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -104,6 +104,7 @@ struct security_hook_list {
struct lsm_blob_sizes {
unsigned int lbs_cred;
unsigned int lbs_file;
+ unsigned int lbs_backing_file;
unsigned int lbs_ib;
unsigned int lbs_inode;
unsigned int lbs_sock;
diff --git a/include/linux/security.h b/include/linux/security.h
index 2db88ddbe9a9..0a2ef373267b 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -487,11 +487,17 @@ int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
void security_file_release(struct file *file);
void security_file_free(struct file *file);
+int security_backing_file_alloc(struct file *backing_file,
+ const struct file *user_file);
+void security_backing_file_free(struct file *backing_file);
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int security_file_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg);
int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags);
+int security_mmap_backing_file(struct vm_area_struct *vma,
+ struct file *backing_file,
+ struct file *user_file);
int security_mmap_addr(unsigned long addr);
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot);
@@ -1147,6 +1153,15 @@ static inline void security_file_release(struct file *file)
static inline void security_file_free(struct file *file)
{ }
+static inline int security_backing_file_alloc(struct file *backing_file,
+ const struct file *user_file)
+{
+ return 0;
+}
+
+static inline void security_backing_file_free(struct file *backing_file)
+{ }
+
static inline int security_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -1166,6 +1181,13 @@ static inline int security_mmap_file(struct file *file, unsigned long prot,
return 0;
}
+static inline int security_mmap_backing_file(struct vm_area_struct *vma,
+ struct file *backing_file,
+ struct file *user_file)
+{
+ return 0;
+}
+
static inline int security_mmap_addr(unsigned long addr)
{
return cap_mmap_addr(addr);
diff --git a/security/lsm.h b/security/lsm.h
index 8dc267977ae0..c3a1a9cd121e 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -29,6 +29,7 @@ extern struct lsm_blob_sizes blob_sizes;
/* LSM blob caches */
extern struct kmem_cache *lsm_file_cache;
+extern struct kmem_cache *lsm_backing_file_cache;
extern struct kmem_cache *lsm_inode_cache;
/* LSM blob allocators */
diff --git a/security/lsm_init.c b/security/lsm_init.c
index bef21da72c16..31bc9e2d0f5d 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -202,6 +202,8 @@ static void __init lsm_prepare(struct lsm_info *lsm)
blobs = lsm->blobs;
lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
+ lsm_blob_size_update(&blobs->lbs_backing_file,
+ &blob_sizes.lbs_backing_file);
lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
/* inode blob gets an rcu_head in addition to LSM blobs. */
if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
@@ -405,6 +407,8 @@ int __init security_init(void)
if (lsm_debug) {
lsm_pr("blob(cred) size %d\n", blob_sizes.lbs_cred);
lsm_pr("blob(file) size %d\n", blob_sizes.lbs_file);
+ lsm_pr("blob(backing_file) size %d\n",
+ blob_sizes.lbs_backing_file);
lsm_pr("blob(ib) size %d\n", blob_sizes.lbs_ib);
lsm_pr("blob(inode) size %d\n", blob_sizes.lbs_inode);
lsm_pr("blob(ipc) size %d\n", blob_sizes.lbs_ipc);
@@ -423,6 +427,11 @@ int __init security_init(void)
lsm_file_cache = kmem_cache_create("lsm_file_cache",
blob_sizes.lbs_file, 0,
SLAB_PANIC, NULL);
+ if (blob_sizes.lbs_backing_file)
+ lsm_backing_file_cache = kmem_cache_create(
+ "lsm_backing_file_cache",
+ blob_sizes.lbs_backing_file,
+ 0, SLAB_PANIC, NULL);
if (blob_sizes.lbs_inode)
lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
blob_sizes.lbs_inode, 0,
diff --git a/security/security.c b/security/security.c
index 56c48725e334..d9a645d0038e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -82,6 +82,7 @@ const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
struct lsm_blob_sizes blob_sizes;
struct kmem_cache *lsm_file_cache;
+struct kmem_cache *lsm_backing_file_cache;
struct kmem_cache *lsm_inode_cache;
#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
@@ -173,6 +174,30 @@ static int lsm_file_alloc(struct file *file)
return 0;
}
+/**
+ * lsm_backing_file_alloc - allocate a composite backing file blob
+ * @backing_file: the backing file
+ *
+ * Allocate the backing file blob for all the modules.
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_backing_file_alloc(struct file *backing_file)
+{
+ void *blob;
+
+ if (!lsm_backing_file_cache) {
+ backing_file_set_security(backing_file, NULL);
+ return 0;
+ }
+
+ blob = kmem_cache_zalloc(lsm_backing_file_cache, GFP_KERNEL);
+ backing_file_set_security(backing_file, blob);
+ if (!blob)
+ return -ENOMEM;
+ return 0;
+}
+
/**
* lsm_blob_alloc - allocate a composite blob
* @dest: the destination for the blob
@@ -2350,6 +2375,57 @@ void security_file_free(struct file *file)
}
}
+/**
+ * security_backing_file_alloc() - Allocate and setup a backing file blob
+ * @backing_file: the backing file
+ * @user_file: the associated user visible file
+ *
+ * Allocate a backing file LSM blob and perform any necessary initialization of
+ * the LSM blob. There will be some operations where the LSM will not have
+ * access to @user_file after this point, so any important state associated
+ * with @user_file that is important to the LSM should be captured in the
+ * backing file's LSM blob.
+ *
+ * LSM's should avoid taking a reference to @user_file in this hook as it will
+ * result in problems later when the system attempts to drop/put the file
+ * references due to a circular dependency.
+ *
+ * Return: Return 0 if the hook is successful, negative values otherwise.
+ */
+int security_backing_file_alloc(struct file *backing_file,
+ const struct file *user_file)
+{
+ int rc;
+
+ rc = lsm_backing_file_alloc(backing_file);
+ if (rc)
+ return rc;
+ rc = call_int_hook(backing_file_alloc, backing_file, user_file);
+ if (unlikely(rc))
+ security_backing_file_free(backing_file);
+
+ return rc;
+}
+
+/**
+ * security_backing_file_free() - Free a backing file blob
+ * @backing_file: the backing file
+ *
+ * Free any LSM state associate with a backing file's LSM blob, including the
+ * blob itself.
+ */
+void security_backing_file_free(struct file *backing_file)
+{
+ void *blob = backing_file_security(backing_file);
+
+ call_void_hook(backing_file_free, backing_file);
+
+ if (blob) {
+ backing_file_set_security(backing_file, NULL);
+ kmem_cache_free(lsm_backing_file_cache, blob);
+ }
+}
+
/**
* security_file_ioctl() - Check if an ioctl is allowed
* @file: associated file
@@ -2438,6 +2514,32 @@ int security_mmap_file(struct file *file, unsigned long prot,
flags);
}
+/**
+ * security_mmap_backing_file - Check if mmap'ing a backing file is allowed
+ * @vma: the vm_area_struct for the mmap'd region
+ * @backing_file: the backing file being mmap'd
+ * @user_file: the user file being mmap'd
+ *
+ * Check permissions for a mmap operation on a stacked filesystem. This hook
+ * is called after the security_mmap_file() and is responsible for authorizing
+ * the mmap on @backing_file. It is important to note that the mmap operation
+ * on @user_file has already been authorized and the @vma->vm_file has been
+ * set to @backing_file.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_mmap_backing_file(struct vm_area_struct *vma,
+ struct file *backing_file,
+ struct file *user_file)
+{
+ /* recommended by the stackable filesystem devs */
+ if (WARN_ON_ONCE(!(backing_file->f_mode & FMODE_BACKING)))
+ return -EIO;
+
+ return call_int_hook(mmap_backing_file, vma, backing_file, user_file);
+}
+EXPORT_SYMBOL_GPL(security_mmap_backing_file);
+
/**
* security_mmap_addr() - Check if mmap'ing an address is allowed
* @addr: address
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,429 @@
From d3989d6fe668083ccd03e1cc73a46b9ed88edd54 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Tue, 2 Jun 2026 10:26:36 +0200
Subject: [PATCH] selinux: fix overlayfs mmap() and mprotect() access checks
JIRA: https://issues.redhat.com/browse/RHEL-179440
CVE: CVE-2026-46054
Conflicts:
- security/selinux/hooks.c: trivial context fuzz
commit 82544d36b1729153c8aeb179e84750f0c085d3b1
Author: Paul Moore <paul@paul-moore.com>
Date: Thu Jan 1 17:19:18 2026 -0500
selinux: fix overlayfs mmap() and mprotect() access checks
The existing SELinux security model for overlayfs is to allow access if
the current task is able to access the top level file (the "user" file)
and the mounter's credentials are sufficient to access the lower
level file (the "backing" file). Unfortunately, the current code does
not properly enforce these access controls for both mmap() and mprotect()
operations on overlayfs filesystems.
This patch makes use of the newly created security_mmap_backing_file()
LSM hook to provide the missing backing file enforcement for mmap()
operations, and leverages the backing file API and new LSM blob to
provide the necessary information to properly enforce the mprotect()
access controls.
Cc: stable@vger.kernel.org
Acked-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a2323c6daafe..853cf9cee2ec 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1724,49 +1724,72 @@ static inline int file_path_has_perm(const struct cred *cred,
static int bpf_fd_pass(const struct file *file, u32 sid);
#endif
-/* Check whether a task can use an open file descriptor to
- access an inode in a given way. Check access to the
- descriptor itself, and then use dentry_has_perm to
- check a particular permission to the file.
- Access to the descriptor is implicitly granted if it
- has the same SID as the process. If av is zero, then
- access to the file is not checked, e.g. for cases
- where only the descriptor is affected like seek. */
-static int file_has_perm(const struct cred *cred,
- struct file *file,
- u32 av)
+static int __file_has_perm(const struct cred *cred, const struct file *file,
+ u32 av, bool bf_user_file)
+
{
- struct file_security_struct *fsec = selinux_file(file);
- struct inode *inode = file_inode(file);
struct common_audit_data ad;
- u32 sid = cred_sid(cred);
+ struct inode *inode;
+ u32 ssid = cred_sid(cred);
+ u32 tsid_fd;
int rc;
- ad.type = LSM_AUDIT_DATA_FILE;
- ad.u.file = file;
+ if (bf_user_file) {
+ struct backing_file_security_struct *bfsec;
+ const struct path *path;
- if (sid != fsec->sid) {
- rc = avc_has_perm(sid, fsec->sid,
- SECCLASS_FD,
- FD__USE,
- &ad);
+ if (WARN_ON(!(file->f_mode & FMODE_BACKING)))
+ return -EIO;
+
+ bfsec = selinux_backing_file(file);
+ path = backing_file_user_path(file);
+ tsid_fd = bfsec->uf_sid;
+ inode = d_inode(path->dentry);
+
+ ad.type = LSM_AUDIT_DATA_PATH;
+ ad.u.path = *path;
+ } else {
+ struct file_security_struct *fsec = selinux_file(file);
+
+ tsid_fd = fsec->sid;
+ inode = file_inode(file);
+
+ ad.type = LSM_AUDIT_DATA_FILE;
+ ad.u.file = file;
+ }
+
+ if (ssid != tsid_fd) {
+ rc = avc_has_perm(ssid, tsid_fd, SECCLASS_FD, FD__USE, &ad);
if (rc)
- goto out;
+ return rc;
}
#ifdef CONFIG_BPF_SYSCALL
- rc = bpf_fd_pass(file, cred_sid(cred));
+ /* regardless of backing vs user file, use the underlying file here */
+ rc = bpf_fd_pass(file, ssid);
if (rc)
return rc;
#endif
/* av is zero if only checking access to the descriptor. */
- rc = 0;
if (av)
- rc = inode_has_perm(cred, inode, av, &ad);
+ return inode_has_perm(cred, inode, av, &ad);
-out:
- return rc;
+ return 0;
+}
+
+/* Check whether a task can use an open file descriptor to
+ access an inode in a given way. Check access to the
+ descriptor itself, and then use dentry_has_perm to
+ check a particular permission to the file.
+ Access to the descriptor is implicitly granted if it
+ has the same SID as the process. If av is zero, then
+ access to the file is not checked, e.g. for cases
+ where only the descriptor is affected like seek. */
+static inline int file_has_perm(const struct cred *cred,
+ const struct file *file, u32 av)
+{
+ return __file_has_perm(cred, file, av, false);
}
/*
@@ -3656,6 +3679,17 @@ static int selinux_file_alloc_security(struct file *file)
return 0;
}
+static int selinux_backing_file_alloc(struct file *backing_file,
+ const struct file *user_file)
+{
+ struct backing_file_security_struct *bfsec;
+
+ bfsec = selinux_backing_file(backing_file);
+ bfsec->uf_sid = selinux_file(user_file)->sid;
+
+ return 0;
+}
+
/*
* Check whether a task has the ioctl permission and cmd
* operation to an inode.
@@ -3773,42 +3807,55 @@ static int selinux_file_ioctl_compat(struct file *file, unsigned int cmd,
static int default_noexec __ro_after_init;
-static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
+static int __file_map_prot_check(const struct cred *cred,
+ const struct file *file, unsigned long prot,
+ bool shared, bool bf_user_file)
{
- const struct cred *cred = current_cred();
- u32 sid = cred_sid(cred);
- int rc = 0;
+ struct inode *inode = NULL;
+ bool prot_exec = prot & PROT_EXEC;
+ bool prot_write = prot & PROT_WRITE;
+
+ if (file) {
+ if (bf_user_file)
+ inode = d_inode(backing_file_user_path(file)->dentry);
+ else
+ inode = file_inode(file);
+ }
+
+ if (default_noexec && prot_exec &&
+ (!file || IS_PRIVATE(inode) || (!shared && prot_write))) {
+ int rc;
+ u32 sid = cred_sid(cred);
- if (default_noexec &&
- (prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) ||
- (!shared && (prot & PROT_WRITE)))) {
/*
- * We are making executable an anonymous mapping or a
- * private file mapping that will also be writable.
- * This has an additional check.
+ * We are making executable an anonymous mapping or a private
+ * file mapping that will also be writable.
*/
- rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
- PROCESS__EXECMEM, NULL);
+ rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__EXECMEM,
+ NULL);
if (rc)
- goto error;
+ return rc;
}
if (file) {
- /* read access is always possible with a mapping */
+ /* "read" always possible, "write" only if shared */
u32 av = FILE__READ;
-
- /* write access only matters if the mapping is shared */
- if (shared && (prot & PROT_WRITE))
+ if (shared && prot_write)
av |= FILE__WRITE;
-
- if (prot & PROT_EXEC)
+ if (prot_exec)
av |= FILE__EXECUTE;
- return file_has_perm(cred, file, av);
+ return __file_has_perm(cred, file, av, bf_user_file);
}
-error:
- return rc;
+ return 0;
+}
+
+static inline int file_map_prot_check(const struct cred *cred,
+ const struct file *file,
+ unsigned long prot, bool shared)
+{
+ return __file_map_prot_check(cred, file, prot, shared, false);
}
static int selinux_mmap_addr(unsigned long addr)
@@ -3824,36 +3871,80 @@ static int selinux_mmap_addr(unsigned long addr)
return rc;
}
-static int selinux_mmap_file(struct file *file,
- unsigned long reqprot __always_unused,
- unsigned long prot, unsigned long flags)
+static int selinux_mmap_file_common(const struct cred *cred, struct file *file,
+ unsigned long prot, bool shared)
{
- struct common_audit_data ad;
- int rc;
-
if (file) {
+ int rc;
+ struct common_audit_data ad;
+
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
- rc = inode_has_perm(current_cred(), file_inode(file),
- FILE__MAP, &ad);
+ rc = inode_has_perm(cred, file_inode(file), FILE__MAP, &ad);
if (rc)
return rc;
}
- return file_map_prot_check(file, prot,
- (flags & MAP_TYPE) == MAP_SHARED);
+ return file_map_prot_check(cred, file, prot, shared);
+}
+
+static int selinux_mmap_file(struct file *file,
+ unsigned long reqprot __always_unused,
+ unsigned long prot, unsigned long flags)
+{
+ return selinux_mmap_file_common(current_cred(), file, prot,
+ (flags & MAP_TYPE) == MAP_SHARED);
+}
+
+/**
+ * selinux_mmap_backing_file - Check mmap permissions on a backing file
+ * @vma: memory region
+ * @backing_file: stacked filesystem backing file
+ * @user_file: user visible file
+ *
+ * This is called after selinux_mmap_file() on stacked filesystems, and it
+ * is this function's responsibility to verify access to @backing_file and
+ * setup the SELinux state for possible later use in the mprotect() code path.
+ *
+ * By the time this function is called, mmap() access to @user_file has already
+ * been authorized and @vma->vm_file has been set to point to @backing_file.
+ *
+ * Return zero on success, negative values otherwise.
+ */
+static int selinux_mmap_backing_file(struct vm_area_struct *vma,
+ struct file *backing_file,
+ struct file *user_file __always_unused)
+{
+ unsigned long prot = 0;
+
+ /* translate vma->vm_flags perms into PROT perms */
+ if (vma->vm_flags & VM_READ)
+ prot |= PROT_READ;
+ if (vma->vm_flags & VM_WRITE)
+ prot |= PROT_WRITE;
+ if (vma->vm_flags & VM_EXEC)
+ prot |= PROT_EXEC;
+
+ return selinux_mmap_file_common(backing_file->f_cred, backing_file,
+ prot, vma->vm_flags & VM_SHARED);
}
static int selinux_file_mprotect(struct vm_area_struct *vma,
unsigned long reqprot __always_unused,
unsigned long prot)
{
+ int rc;
const struct cred *cred = current_cred();
u32 sid = cred_sid(cred);
+ const struct file *file = vma->vm_file;
+ bool backing_file;
+ bool shared = vma->vm_flags & VM_SHARED;
+
+ /* check if we need to trigger the "backing files are awful" mode */
+ backing_file = file && (file->f_mode & FMODE_BACKING);
if (default_noexec &&
(prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
- int rc = 0;
/*
* We don't use the vma_is_initial_heap() helper as it has
* a history of problems and is currently broken on systems
@@ -3867,11 +3958,15 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
vma->vm_end <= vma->vm_mm->brk) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL);
- } else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
+ if (rc)
+ return rc;
+ } else if (!file && (vma_is_initial_stack(vma) ||
vma_is_stack_for_current(vma))) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECSTACK, NULL);
- } else if (vma->vm_file && vma->anon_vma) {
+ if (rc)
+ return rc;
+ } else if (file && vma->anon_vma) {
/*
* We are making executable a file mapping that has
* had some COW done. Since pages might have been
@@ -3879,13 +3974,29 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
* modified content. This typically should only
* occur for text relocations.
*/
- rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
+ rc = __file_has_perm(cred, file, FILE__EXECMOD,
+ backing_file);
+ if (rc)
+ return rc;
+ if (backing_file) {
+ rc = file_has_perm(file->f_cred, file,
+ FILE__EXECMOD);
+ if (rc)
+ return rc;
+ }
}
+ }
+
+ rc = __file_map_prot_check(cred, file, prot, shared, backing_file);
+ if (rc)
+ return rc;
+ if (backing_file) {
+ rc = file_map_prot_check(file->f_cred, file, prot, shared);
if (rc)
return rc;
}
- return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
+ return 0;
}
static int selinux_file_lock(struct file *file, unsigned int cmd)
@@ -6996,6 +7107,7 @@ static void selinux_bpf_token_free(struct bpf_token *token)
struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_cred = sizeof(struct task_security_struct),
.lbs_file = sizeof(struct file_security_struct),
+ .lbs_backing_file = sizeof(struct backing_file_security_struct),
.lbs_inode = sizeof(struct inode_security_struct),
.lbs_ipc = sizeof(struct ipc_security_struct),
.lbs_key = sizeof(struct key_security_struct),
@@ -7201,9 +7313,11 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
+ LSM_HOOK_INIT(backing_file_alloc, selinux_backing_file_alloc),
LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat),
LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
+ LSM_HOOK_INIT(mmap_backing_file, selinux_mmap_backing_file),
LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
LSM_HOOK_INIT(file_lock, selinux_file_lock),
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index c88cae81ee4c..dc42282a2c05 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -61,6 +61,10 @@ struct file_security_struct {
u32 pseqno; /* Policy seqno at the time of file open */
};
+struct backing_file_security_struct {
+ u32 uf_sid; /* associated user file fsec->sid */
+};
+
struct superblock_security_struct {
u32 sid; /* SID of file system superblock */
u32 def_sid; /* default SID for labeling */
@@ -159,6 +163,13 @@ static inline struct file_security_struct *selinux_file(const struct file *file)
return file->f_security + selinux_blob_sizes.lbs_file;
}
+static inline struct backing_file_security_struct *
+selinux_backing_file(const struct file *backing_file)
+{
+ void *blob = backing_file_security(backing_file);
+ return blob + selinux_blob_sizes.lbs_backing_file;
+}
+
static inline struct inode_security_struct *
selinux_inode(const struct inode *inode)
{
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,70 @@
From 7a4465d25de718e57ced42030bc7194017ee4f64 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:33:16 +0200
Subject: [PATCH] scripts/sorttable: fix orc_sort_cmp() to maintain symmetry
and transitivity
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 0210d251162f4033350a94a43f95b1c39ec84a90
Author: Kuan-Wei Chiu <visitorckw@gmail.com>
Date: Thu Dec 26 22:03:32 2024 +0800
scripts/sorttable: fix orc_sort_cmp() to maintain symmetry and transitivity
The orc_sort_cmp() function, used with qsort(), previously violated the
symmetry and transitivity rules required by the C standard. Specifically,
when both entries are ORC_TYPE_UNDEFINED, it could result in both a < b
and b < a, which breaks the required symmetry and transitivity. This can
lead to undefined behavior and incorrect sorting results, potentially
causing memory corruption in glibc implementations [1].
Symmetry: If x < y, then y > x.
Transitivity: If x < y and y < z, then x < z.
Fix the comparison logic to return 0 when both entries are
ORC_TYPE_UNDEFINED, ensuring compliance with qsort() requirements.
Link: https://www.qualys.com/2024/01/30/qsort.txt [1]
Link: https://lkml.kernel.org/r/20241226140332.2670689-1-visitorckw@gmail.com
Fixes: 57fa18994285 ("scripts/sorttable: Implement build-time ORC unwind table sorting")
Fixes: fb799447ae29 ("x86,objtool: Split UNWIND_HINT_EMPTY in two")
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
Cc: Ching-Chun (Jim) Huang <jserv@ccns.ncku.edu.tw>
Cc: <chuang@cs.nycu.edu.tw>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shile Zhang <shile.zhang@linux.alibaba.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index 7bd0184380d3..a7c5445baf00 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -110,7 +110,7 @@ static inline unsigned long orc_ip(const int *ip)
static int orc_sort_cmp(const void *_a, const void *_b)
{
- struct orc_entry *orc_a;
+ struct orc_entry *orc_a, *orc_b;
const int *a = g_orc_ip_table + *(int *)_a;
const int *b = g_orc_ip_table + *(int *)_b;
unsigned long a_val = orc_ip(a);
@@ -128,6 +128,9 @@ static int orc_sort_cmp(const void *_a, const void *_b)
* whitelisted .o files which didn't get objtool generation.
*/
orc_a = g_orc_table + (a - g_orc_ip_table);
+ orc_b = g_orc_table + (b - g_orc_ip_table);
+ if (orc_a->type == ORC_TYPE_UNDEFINED && orc_b->type == ORC_TYPE_UNDEFINED)
+ return 0;
return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1;
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,104 @@
From 90e4b4c6300522c4494664bc95285cb94e137b17 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:21:58 +0200
Subject: [PATCH] scripts/sorttable: Remove unused macro defines
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 28b24394c6e9a3166fcb4480cba054562526657c
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:12 2025 -0500
scripts/sorttable: Remove unused macro defines
The code of sorttable.h was copied from the recordmcount.h which defined
a bunch of Elf MACROs so that they could be used between 32bit and 64bit
functions. But there's several MACROs that sorttable.h does not use but
was copied over. Remove them to clean up the code.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162344.128870118@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index a7c5445baf00..14d0c4d843e8 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -27,19 +27,10 @@
#undef Elf_Ehdr
#undef Elf_Shdr
#undef Elf_Rel
-#undef Elf_Rela
#undef Elf_Sym
-#undef ELF_R_SYM
-#undef Elf_r_sym
-#undef ELF_R_INFO
-#undef Elf_r_info
-#undef ELF_ST_BIND
#undef ELF_ST_TYPE
-#undef fn_ELF_R_SYM
-#undef fn_ELF_R_INFO
#undef uint_t
#undef _r
-#undef _w
#ifdef SORTTABLE_64
# define extable_ent_size 16
@@ -52,19 +43,10 @@
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Shdr Elf64_Shdr
# define Elf_Rel Elf64_Rel
-# define Elf_Rela Elf64_Rela
# define Elf_Sym Elf64_Sym
-# define ELF_R_SYM ELF64_R_SYM
-# define Elf_r_sym Elf64_r_sym
-# define ELF_R_INFO ELF64_R_INFO
-# define Elf_r_info Elf64_r_info
-# define ELF_ST_BIND ELF64_ST_BIND
# define ELF_ST_TYPE ELF64_ST_TYPE
-# define fn_ELF_R_SYM fn_ELF64_R_SYM
-# define fn_ELF_R_INFO fn_ELF64_R_INFO
# define uint_t uint64_t
# define _r r8
-# define _w w8
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
@@ -76,19 +58,10 @@
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Shdr Elf32_Shdr
# define Elf_Rel Elf32_Rel
-# define Elf_Rela Elf32_Rela
# define Elf_Sym Elf32_Sym
-# define ELF_R_SYM ELF32_R_SYM
-# define Elf_r_sym Elf32_r_sym
-# define ELF_R_INFO ELF32_R_INFO
-# define Elf_r_info Elf32_r_info
-# define ELF_ST_BIND ELF32_ST_BIND
# define ELF_ST_TYPE ELF32_ST_TYPE
-# define fn_ELF_R_SYM fn_ELF32_R_SYM
-# define fn_ELF_R_INFO fn_ELF32_R_INFO
# define uint_t uint32_t
# define _r r
-# define _w w
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,102 @@
From 3e1ec2703946dbf8d8f658865fc5c601e3a2cdea Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:02 +0200
Subject: [PATCH] scripts/sorttable: Remove unused write functions
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 4f48a28b37d594dab38092514a42ae9f4b781553
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:13 2025 -0500
scripts/sorttable: Remove unused write functions
The code of sorttable.h was copied from the recordmcount.h which defined
various write functions for different sizes (2, 4, 8 byte lengths). But
sorttable only uses the 4 byte writes. Remove the extra versions as they
are not used.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162344.314385504@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 83cdb843d92f..4dcdbf7a5e26 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -68,8 +68,6 @@ static uint32_t (*r)(const uint32_t *);
static uint16_t (*r2)(const uint16_t *);
static uint64_t (*r8)(const uint64_t *);
static void (*w)(uint32_t, uint32_t *);
-static void (*w2)(uint16_t, uint16_t *);
-static void (*w8)(uint64_t, uint64_t *);
typedef void (*table_sort_t)(char *, int);
/*
@@ -146,31 +144,11 @@ static void wbe(uint32_t val, uint32_t *x)
put_unaligned_be32(val, x);
}
-static void w2be(uint16_t val, uint16_t *x)
-{
- put_unaligned_be16(val, x);
-}
-
-static void w8be(uint64_t val, uint64_t *x)
-{
- put_unaligned_be64(val, x);
-}
-
static void wle(uint32_t val, uint32_t *x)
{
put_unaligned_le32(val, x);
}
-static void w2le(uint16_t val, uint16_t *x)
-{
- put_unaligned_le16(val, x);
-}
-
-static void w8le(uint64_t val, uint64_t *x)
-{
- put_unaligned_le64(val, x);
-}
-
/*
* Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
* the way to -256..-1, to avoid conflicting with real section
@@ -277,16 +255,12 @@ static int do_file(char const *const fname, void *addr)
r2 = r2le;
r8 = r8le;
w = wle;
- w2 = w2le;
- w8 = w8le;
break;
case ELFDATA2MSB:
r = rbe;
r2 = r2be;
r8 = r8be;
w = wbe;
- w2 = w2be;
- w8 = w8be;
break;
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,118 @@
From b0006591a4fb4d08bab55e02d904a225bb97f803 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:06 +0200
Subject: [PATCH] scripts/sorttable: Remove unneeded Elf_Rel
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 6f2c2f93a190467cebd6ebd03feb49514fead5ca
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:14 2025 -0500
scripts/sorttable: Remove unneeded Elf_Rel
The code had references to initialize the Elf_Rel relocation tables, but
it was never used. Remove it.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162344.515342233@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index 14d0c4d843e8..18d07fdb2716 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -26,7 +26,6 @@
#undef Elf_Addr
#undef Elf_Ehdr
#undef Elf_Shdr
-#undef Elf_Rel
#undef Elf_Sym
#undef ELF_ST_TYPE
#undef uint_t
@@ -42,7 +41,6 @@
# define Elf_Addr Elf64_Addr
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Shdr Elf64_Shdr
-# define Elf_Rel Elf64_Rel
# define Elf_Sym Elf64_Sym
# define ELF_ST_TYPE ELF64_ST_TYPE
# define uint_t uint64_t
@@ -57,7 +55,6 @@
# define Elf_Addr Elf32_Addr
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Shdr Elf32_Shdr
-# define Elf_Rel Elf32_Rel
# define Elf_Sym Elf32_Sym
# define ELF_ST_TYPE ELF32_ST_TYPE
# define uint_t uint32_t
@@ -248,14 +245,10 @@ static int do_sort(Elf_Ehdr *ehdr,
Elf32_Word *symtab_shndx = NULL;
Elf_Sym *sort_needed_sym = NULL;
Elf_Shdr *sort_needed_sec;
- Elf_Rel *relocs = NULL;
- int relocs_size = 0;
uint32_t *sort_needed_loc;
const char *secstrings;
const char *strtab;
char *extab_image;
- int extab_index = 0;
- int i;
int idx;
unsigned int shnum;
unsigned int shstrndx;
@@ -279,23 +272,15 @@ static int do_sort(Elf_Ehdr *ehdr,
if (shnum == SHN_UNDEF)
shnum = _r(&shdr[0].sh_size);
- for (i = 0, s = shdr; s < shdr + shnum; i++, s++) {
+ for (s = shdr; s < shdr + shnum; s++) {
idx = r(&s->sh_name);
- if (!strcmp(secstrings + idx, "__ex_table")) {
+ if (!strcmp(secstrings + idx, "__ex_table"))
extab_sec = s;
- extab_index = i;
- }
if (!strcmp(secstrings + idx, ".symtab"))
symtab_sec = s;
if (!strcmp(secstrings + idx, ".strtab"))
strtab_sec = s;
- if ((r(&s->sh_type) == SHT_REL ||
- r(&s->sh_type) == SHT_RELA) &&
- r(&s->sh_info) == extab_index) {
- relocs = (void *)ehdr + _r(&s->sh_offset);
- relocs_size = _r(&s->sh_size);
- }
if (r(&s->sh_type) == SHT_SYMTAB_SHNDX)
symtab_shndx = (Elf32_Word *)((const char *)ehdr +
_r(&s->sh_offset));
@@ -397,10 +382,6 @@ static int do_sort(Elf_Ehdr *ehdr,
extable_ent_size, compare_extable);
}
- /* If there were relocations, we no longer need them. */
- if (relocs)
- memset(relocs, 0, relocs_size);
-
/* find the flag main_extable_sort_needed */
for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,65 @@
From 8b98d95b2f3df8cdec1154dcce05f292bdde59d0 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:10 +0200
Subject: [PATCH] scripts/sorttable: Have the ORC code use the _r() functions
to read
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 66990c003306c240d570b3ba274ec4f68cf18c91
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:15 2025 -0500
scripts/sorttable: Have the ORC code use the _r() functions to read
The ORC code reads the section information directly from the file. This
currently works because the default read function is for 64bit little
endian machines. But if for some reason that ever changes, this will
break. Instead of having a surprise breakage, use the _r() functions that
will read the values from the file properly.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162344.721480386@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index 18d07fdb2716..58f7ab5f5644 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -299,14 +299,14 @@ static int do_sort(Elf_Ehdr *ehdr,
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* locate the ORC unwind tables */
if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
- orc_ip_size = s->sh_size;
+ orc_ip_size = _r(&s->sh_size);
g_orc_ip_table = (int *)((void *)ehdr +
- s->sh_offset);
+ _r(&s->sh_offset));
}
if (!strcmp(secstrings + idx, ".orc_unwind")) {
- orc_size = s->sh_size;
+ orc_size = _r(&s->sh_size);
g_orc_table = (struct orc_entry *)((void *)ehdr +
- s->sh_offset);
+ _r(&s->sh_offset));
}
#endif
} /* for loop */
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,132 @@
From 3f3c4e53bd362a76e3a097c1dac3c8975cb99926 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:13 +0200
Subject: [PATCH] scripts/sorttable: Make compare_extable() into two functions
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 7ffc0d0819f438779ed592e2e2e3576f43ce14f0
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:16 2025 -0500
scripts/sorttable: Make compare_extable() into two functions
Instead of having the compare_extable() part of the sorttable.h header
where it get's defined twice, since it is a very simple function, just
define it twice in sorttable.c, and then it can use the proper read
functions for the word size and endianess and the Elf_Addr macro can be
removed from sorttable.h.
Also add a micro optimization. Instead of:
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
That can be shorten to:
if (a < b)
return -1;
return a > b;
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162344.945299671@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 4dcdbf7a5e26..3e2c17e91485 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -173,6 +173,26 @@ static inline unsigned int get_secindex(unsigned int shndx,
return r(&symtab_shndx_start[sym_offs]);
}
+static int compare_extable_32(const void *a, const void *b)
+{
+ Elf32_Addr av = r(a);
+ Elf32_Addr bv = r(b);
+
+ if (av < bv)
+ return -1;
+ return av > bv;
+}
+
+static int compare_extable_64(const void *a, const void *b)
+{
+ Elf64_Addr av = r8(a);
+ Elf64_Addr bv = r8(b);
+
+ if (av < bv)
+ return -1;
+ return av > bv;
+}
+
/* 32 bit and 64 bit are very similar */
#include "sorttable.h"
#define SORTTABLE_64
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index 58f7ab5f5644..36655ff16b39 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -23,7 +23,6 @@
#undef sort_mcount_loc
#undef elf_mcount_loc
#undef do_sort
-#undef Elf_Addr
#undef Elf_Ehdr
#undef Elf_Shdr
#undef Elf_Sym
@@ -38,7 +37,6 @@
# define sort_mcount_loc sort_mcount_loc_64
# define elf_mcount_loc elf_mcount_loc_64
# define do_sort do_sort_64
-# define Elf_Addr Elf64_Addr
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Shdr Elf64_Shdr
# define Elf_Sym Elf64_Sym
@@ -52,7 +50,6 @@
# define sort_mcount_loc sort_mcount_loc_32
# define elf_mcount_loc elf_mcount_loc_32
# define do_sort do_sort_32
-# define Elf_Addr Elf32_Addr
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Shdr Elf32_Shdr
# define Elf_Sym Elf32_Sym
@@ -160,17 +157,6 @@ static void *sort_orctable(void *arg)
}
#endif
-static int compare_extable(const void *a, const void *b)
-{
- Elf_Addr av = _r(a);
- Elf_Addr bv = _r(b);
-
- if (av < bv)
- return -1;
- if (av > bv)
- return 1;
- return 0;
-}
#ifdef MCOUNT_SORT_ENABLED
pthread_t mcount_sort_thread;
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,212 @@
From a9cb56b10f496e1e39543627f47eecda2d65213f Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:16 +0200
Subject: [PATCH] scripts/sorttable: Convert Elf_Ehdr to union
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 157fb5b3cfd2cb5950314f926a76e567fc1921c5
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:17 2025 -0500
scripts/sorttable: Convert Elf_Ehdr to union
In order to remove the double #include of sorttable.h for 64 and 32 bit
to create duplicate functions for both, replace the Elf_Ehdr macro with a
union that defines both Elf64_Ehdr and Elf32_Ehdr, with field e64 for the
64bit version, and e32 for the 32bit version.
Then a macro etype can be used instead to get to the proper value.
This will eventually be replaced with just single functions that can
handle both 32bit and 64bit ELF parsing.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162345.148224465@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 3e2c17e91485..67cbbfc8214d 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -64,6 +64,11 @@
#define EM_LOONGARCH 258
#endif
+typedef union {
+ Elf32_Ehdr e32;
+ Elf64_Ehdr e64;
+} Elf_Ehdr;
+
static uint32_t (*r)(const uint32_t *);
static uint16_t (*r2)(const uint16_t *);
static uint64_t (*r8)(const uint64_t *);
@@ -266,10 +271,10 @@ static void sort_relative_table_with_data(char *extab_image, int image_size)
static int do_file(char const *const fname, void *addr)
{
int rc = -1;
- Elf32_Ehdr *ehdr = addr;
+ Elf_Ehdr *ehdr = addr;
table_sort_t custom_sort = NULL;
- switch (ehdr->e_ident[EI_DATA]) {
+ switch (ehdr->e32.e_ident[EI_DATA]) {
case ELFDATA2LSB:
r = rle;
r2 = r2le;
@@ -284,18 +289,18 @@ static int do_file(char const *const fname, void *addr)
break;
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
- ehdr->e_ident[EI_DATA], fname);
+ ehdr->e32.e_ident[EI_DATA], fname);
return -1;
}
- if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 ||
- (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) ||
- ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
+ if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
+ (r2(&ehdr->e32.e_type) != ET_EXEC && r2(&ehdr->e32.e_type) != ET_DYN) ||
+ ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
return -1;
}
- switch (r2(&ehdr->e_machine)) {
+ switch (r2(&ehdr->e32.e_machine)) {
case EM_386:
case EM_AARCH64:
case EM_LOONGARCH:
@@ -318,14 +323,14 @@ static int do_file(char const *const fname, void *addr)
break;
default:
fprintf(stderr, "unrecognized e_machine %d %s\n",
- r2(&ehdr->e_machine), fname);
+ r2(&ehdr->e32.e_machine), fname);
return -1;
}
- switch (ehdr->e_ident[EI_CLASS]) {
+ switch (ehdr->e32.e_ident[EI_CLASS]) {
case ELFCLASS32:
- if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) ||
- r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
+ if (r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
+ r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
fprintf(stderr,
"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
break;
@@ -334,20 +339,19 @@ static int do_file(char const *const fname, void *addr)
break;
case ELFCLASS64:
{
- Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
- if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) ||
- r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
+ if (r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
+ r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
fprintf(stderr,
"unrecognized ET_EXEC/ET_DYN file: %s\n",
fname);
break;
}
- rc = do_sort_64(ghdr, fname, custom_sort);
+ rc = do_sort_64(ehdr, fname, custom_sort);
}
break;
default:
fprintf(stderr, "unrecognized ELF class %d %s\n",
- ehdr->e_ident[EI_CLASS], fname);
+ ehdr->e32.e_ident[EI_CLASS], fname);
break;
}
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index 36655ff16b39..be8b529498fb 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -23,12 +23,12 @@
#undef sort_mcount_loc
#undef elf_mcount_loc
#undef do_sort
-#undef Elf_Ehdr
#undef Elf_Shdr
#undef Elf_Sym
#undef ELF_ST_TYPE
#undef uint_t
#undef _r
+#undef etype
#ifdef SORTTABLE_64
# define extable_ent_size 16
@@ -37,12 +37,12 @@
# define sort_mcount_loc sort_mcount_loc_64
# define elf_mcount_loc elf_mcount_loc_64
# define do_sort do_sort_64
-# define Elf_Ehdr Elf64_Ehdr
# define Elf_Shdr Elf64_Shdr
# define Elf_Sym Elf64_Sym
# define ELF_ST_TYPE ELF64_ST_TYPE
# define uint_t uint64_t
# define _r r8
+# define etype e64
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
@@ -50,12 +50,12 @@
# define sort_mcount_loc sort_mcount_loc_32
# define elf_mcount_loc elf_mcount_loc_32
# define do_sort do_sort_32
-# define Elf_Ehdr Elf32_Ehdr
# define Elf_Shdr Elf32_Shdr
# define Elf_Sym Elf32_Sym
# define ELF_ST_TYPE ELF32_ST_TYPE
# define uint_t uint32_t
# define _r r
+# define etype e32
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
@@ -222,7 +222,7 @@ static int do_sort(Elf_Ehdr *ehdr,
table_sort_t custom_sort)
{
int rc = -1;
- Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
+ Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->etype.e_shoff));
Elf_Shdr *strtab_sec = NULL;
Elf_Shdr *symtab_sec = NULL;
Elf_Shdr *extab_sec = NULL;
@@ -249,12 +249,12 @@ static int do_sort(Elf_Ehdr *ehdr,
unsigned int orc_num_entries = 0;
#endif
- shstrndx = r2(&ehdr->e_shstrndx);
+ shstrndx = r2(&ehdr->etype.e_shstrndx);
if (shstrndx == SHN_XINDEX)
shstrndx = r(&shdr[0].sh_link);
secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset);
- shnum = r2(&ehdr->e_shnum);
+ shnum = r2(&ehdr->etype.e_shnum);
if (shnum == SHN_UNDEF)
shnum = _r(&shdr[0].sh_size);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,257 @@
From e5bf3a68ca49663c4c12c03dbbb236a86ae7ef45 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:20 +0200
Subject: [PATCH] scripts/sorttable: Replace Elf_Shdr Macro with a union
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 545f6cf8f4c9a268e0bab2637f1d279679befdbf
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:18 2025 -0500
scripts/sorttable: Replace Elf_Shdr Macro with a union
In order to remove the double #include of sorttable.h for 64 and 32 bit
to create duplicate functions for both, replace the Elf_Shdr macro with a
union that defines both Elf64_Shdr and Elf32_Shdr, with field e64 for the
64bit version, and e32 for the 32bit version.
It can then use the macro etype to get the proper value.
This will eventually be replaced with just single functions that can
handle both 32bit and 64bit ELF parsing.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162345.339462681@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 67cbbfc8214d..94497b8ab04c 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -69,6 +69,11 @@ typedef union {
Elf64_Ehdr e64;
} Elf_Ehdr;
+typedef union {
+ Elf32_Shdr e32;
+ Elf64_Shdr e64;
+} Elf_Shdr;
+
static uint32_t (*r)(const uint32_t *);
static uint16_t (*r2)(const uint16_t *);
static uint64_t (*r8)(const uint64_t *);
@@ -198,6 +203,11 @@ static int compare_extable_64(const void *a, const void *b)
return av > bv;
}
+static inline void *get_index(void *start, int entsize, int index)
+{
+ return start + (entsize * index);
+}
+
/* 32 bit and 64 bit are very similar */
#include "sorttable.h"
#define SORTTABLE_64
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index be8b529498fb..3daf37bb6b9a 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -23,7 +23,6 @@
#undef sort_mcount_loc
#undef elf_mcount_loc
#undef do_sort
-#undef Elf_Shdr
#undef Elf_Sym
#undef ELF_ST_TYPE
#undef uint_t
@@ -37,7 +36,6 @@
# define sort_mcount_loc sort_mcount_loc_64
# define elf_mcount_loc elf_mcount_loc_64
# define do_sort do_sort_64
-# define Elf_Shdr Elf64_Shdr
# define Elf_Sym Elf64_Sym
# define ELF_ST_TYPE ELF64_ST_TYPE
# define uint_t uint64_t
@@ -50,7 +48,6 @@
# define sort_mcount_loc sort_mcount_loc_32
# define elf_mcount_loc elf_mcount_loc_32
# define do_sort do_sort_32
-# define Elf_Shdr Elf32_Shdr
# define Elf_Sym Elf32_Sym
# define ELF_ST_TYPE ELF32_ST_TYPE
# define uint_t uint32_t
@@ -171,8 +168,8 @@ struct elf_mcount_loc {
static void *sort_mcount_loc(void *arg)
{
struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
- uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->sh_addr)
- + _r(&(emloc->init_data_sec)->sh_offset);
+ uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->etype.sh_addr)
+ + _r(&(emloc->init_data_sec)->etype.sh_offset);
uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
unsigned char *start_loc = (void *)emloc->ehdr + offset;
@@ -222,10 +219,11 @@ static int do_sort(Elf_Ehdr *ehdr,
table_sort_t custom_sort)
{
int rc = -1;
- Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->etype.e_shoff));
+ Elf_Shdr *shdr_start;
Elf_Shdr *strtab_sec = NULL;
Elf_Shdr *symtab_sec = NULL;
Elf_Shdr *extab_sec = NULL;
+ Elf_Shdr *string_sec;
Elf_Sym *sym;
const Elf_Sym *symtab;
Elf32_Word *symtab_shndx = NULL;
@@ -235,7 +233,10 @@ static int do_sort(Elf_Ehdr *ehdr,
const char *secstrings;
const char *strtab;
char *extab_image;
+ int sort_need_index;
+ int shentsize;
int idx;
+ int i;
unsigned int shnum;
unsigned int shstrndx;
#ifdef MCOUNT_SORT_ENABLED
@@ -249,34 +250,40 @@ static int do_sort(Elf_Ehdr *ehdr,
unsigned int orc_num_entries = 0;
#endif
+ shdr_start = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->etype.e_shoff));
+ shentsize = r2(&ehdr->etype.e_shentsize);
+
shstrndx = r2(&ehdr->etype.e_shstrndx);
if (shstrndx == SHN_XINDEX)
- shstrndx = r(&shdr[0].sh_link);
- secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset);
+ shstrndx = r(&shdr_start->etype.sh_link);
+ string_sec = get_index(shdr_start, shentsize, shstrndx);
+ secstrings = (const char *)ehdr + _r(&string_sec->etype.sh_offset);
shnum = r2(&ehdr->etype.e_shnum);
if (shnum == SHN_UNDEF)
- shnum = _r(&shdr[0].sh_size);
+ shnum = _r(&shdr_start->etype.sh_size);
+
+ for (i = 0; i < shnum; i++) {
+ Elf_Shdr *shdr = get_index(shdr_start, shentsize, i);
- for (s = shdr; s < shdr + shnum; s++) {
- idx = r(&s->sh_name);
+ idx = r(&shdr->etype.sh_name);
if (!strcmp(secstrings + idx, "__ex_table"))
- extab_sec = s;
+ extab_sec = shdr;
if (!strcmp(secstrings + idx, ".symtab"))
- symtab_sec = s;
+ symtab_sec = shdr;
if (!strcmp(secstrings + idx, ".strtab"))
- strtab_sec = s;
+ strtab_sec = shdr;
- if (r(&s->sh_type) == SHT_SYMTAB_SHNDX)
+ if (r(&shdr->etype.sh_type) == SHT_SYMTAB_SHNDX)
symtab_shndx = (Elf32_Word *)((const char *)ehdr +
- _r(&s->sh_offset));
+ _r(&shdr->etype.sh_offset));
#ifdef MCOUNT_SORT_ENABLED
/* locate the .init.data section in vmlinux */
if (!strcmp(secstrings + idx, ".init.data")) {
get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc);
mstruct.ehdr = ehdr;
- mstruct.init_data_sec = s;
+ mstruct.init_data_sec = shdr;
mstruct.start_mcount_loc = _start_mcount_loc;
mstruct.stop_mcount_loc = _stop_mcount_loc;
}
@@ -285,14 +292,14 @@ static int do_sort(Elf_Ehdr *ehdr,
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* locate the ORC unwind tables */
if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
- orc_ip_size = _r(&s->sh_size);
+ orc_ip_size = _r(&shdr->etype.sh_size);
g_orc_ip_table = (int *)((void *)ehdr +
- _r(&s->sh_offset));
+ _r(&shdr->etype.sh_offset));
}
if (!strcmp(secstrings + idx, ".orc_unwind")) {
- orc_size = _r(&s->sh_size);
+ orc_size = _r(&shdr->etype.sh_size);
g_orc_table = (struct orc_entry *)((void *)ehdr +
- _r(&s->sh_offset));
+ _r(&shdr->etype.sh_offset));
}
#endif
} /* for loop */
@@ -355,22 +362,22 @@ static int do_sort(Elf_Ehdr *ehdr,
goto out;
}
- extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
- strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
+ extab_image = (void *)ehdr + _r(&extab_sec->etype.sh_offset);
+ strtab = (const char *)ehdr + _r(&strtab_sec->etype.sh_offset);
symtab = (const Elf_Sym *)((const char *)ehdr +
- _r(&symtab_sec->sh_offset));
+ _r(&symtab_sec->etype.sh_offset));
if (custom_sort) {
- custom_sort(extab_image, _r(&extab_sec->sh_size));
+ custom_sort(extab_image, _r(&extab_sec->etype.sh_size));
} else {
- int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
+ int num_entries = _r(&extab_sec->etype.sh_size) / extable_ent_size;
qsort(extab_image, num_entries,
extable_ent_size, compare_extable);
}
/* find the flag main_extable_sort_needed */
- for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
- sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
+ for (sym = (void *)ehdr + _r(&symtab_sec->etype.sh_offset);
+ sym < sym + _r(&symtab_sec->etype.sh_size) / sizeof(Elf_Sym);
sym++) {
if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
continue;
@@ -388,13 +395,14 @@ static int do_sort(Elf_Ehdr *ehdr,
goto out;
}
- sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx),
- sort_needed_sym - symtab,
- symtab_shndx)];
+ sort_need_index = get_secindex(r2(&sym->st_shndx),
+ sort_needed_sym - symtab,
+ symtab_shndx);
+ sort_needed_sec = get_index(shdr_start, shentsize, sort_need_index);
sort_needed_loc = (void *)ehdr +
- _r(&sort_needed_sec->sh_offset) +
+ _r(&sort_needed_sec->etype.sh_offset) +
_r(&sort_needed_sym->st_value) -
- _r(&sort_needed_sec->sh_addr);
+ _r(&sort_needed_sec->etype.sh_addr);
/* extable has been sorted, clear the flag */
w(0, sort_needed_loc);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,141 @@
From d95dcd72b2a2511fa93a2b185611cba7f4624f7c Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:23 +0200
Subject: [PATCH] scripts/sorttable: Convert Elf_Sym MACRO over to a union
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 200d015e73b4da69bcd8212a7c58695452b12bad
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:19 2025 -0500
scripts/sorttable: Convert Elf_Sym MACRO over to a union
In order to remove the double #include of sorttable.h for 64 and 32 bit
to create duplicate functions for both, replace the Elf_Sym macro with a
union that defines both Elf64_Sym and Elf32_Sym, with field e64 for the
64bit version, and e32 for the 32bit version.
It can then use the macro etype to get the proper value.
This will eventually be replaced with just single functions that can
handle both 32bit and 64bit ELF parsing.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162345.528626969@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 94497b8ab04c..57792cf2aa89 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -74,6 +74,11 @@ typedef union {
Elf64_Shdr e64;
} Elf_Shdr;
+typedef union {
+ Elf32_Sym e32;
+ Elf64_Sym e64;
+} Elf_Sym;
+
static uint32_t (*r)(const uint32_t *);
static uint16_t (*r2)(const uint16_t *);
static uint64_t (*r8)(const uint64_t *);
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index 3daf37bb6b9a..cd4429c8a9f4 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -23,7 +23,6 @@
#undef sort_mcount_loc
#undef elf_mcount_loc
#undef do_sort
-#undef Elf_Sym
#undef ELF_ST_TYPE
#undef uint_t
#undef _r
@@ -36,7 +35,6 @@
# define sort_mcount_loc sort_mcount_loc_64
# define elf_mcount_loc elf_mcount_loc_64
# define do_sort do_sort_64
-# define Elf_Sym Elf64_Sym
# define ELF_ST_TYPE ELF64_ST_TYPE
# define uint_t uint64_t
# define _r r8
@@ -48,7 +46,6 @@
# define sort_mcount_loc sort_mcount_loc_32
# define elf_mcount_loc elf_mcount_loc_32
# define do_sort do_sort_32
-# define Elf_Sym Elf32_Sym
# define ELF_ST_TYPE ELF32_ST_TYPE
# define uint_t uint32_t
# define _r r
@@ -230,10 +227,13 @@ static int do_sort(Elf_Ehdr *ehdr,
Elf_Sym *sort_needed_sym = NULL;
Elf_Shdr *sort_needed_sec;
uint32_t *sort_needed_loc;
+ void *sym_start;
+ void *sym_end;
const char *secstrings;
const char *strtab;
char *extab_image;
int sort_need_index;
+ int symentsize;
int shentsize;
int idx;
int i;
@@ -376,12 +376,15 @@ static int do_sort(Elf_Ehdr *ehdr,
}
/* find the flag main_extable_sort_needed */
- for (sym = (void *)ehdr + _r(&symtab_sec->etype.sh_offset);
- sym < sym + _r(&symtab_sec->etype.sh_size) / sizeof(Elf_Sym);
- sym++) {
- if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
+ sym_start = (void *)ehdr + _r(&symtab_sec->etype.sh_offset);
+ sym_end = sym_start + _r(&symtab_sec->etype.sh_size);
+ symentsize = _r(&symtab_sec->etype.sh_entsize);
+
+ for (sym = sym_start; (void *)sym + symentsize < sym_end;
+ sym = (void *)sym + symentsize) {
+ if (ELF_ST_TYPE(sym->etype.st_info) != STT_OBJECT)
continue;
- if (!strcmp(strtab + r(&sym->st_name),
+ if (!strcmp(strtab + r(&sym->etype.st_name),
"main_extable_sort_needed")) {
sort_needed_sym = sym;
break;
@@ -395,13 +398,13 @@ static int do_sort(Elf_Ehdr *ehdr,
goto out;
}
- sort_need_index = get_secindex(r2(&sym->st_shndx),
- sort_needed_sym - symtab,
+ sort_need_index = get_secindex(r2(&sym->etype.st_shndx),
+ ((void *)sort_needed_sym - (void *)symtab) / symentsize,
symtab_shndx);
sort_needed_sec = get_index(shdr_start, shentsize, sort_need_index);
sort_needed_loc = (void *)ehdr +
_r(&sort_needed_sec->etype.sh_offset) +
- _r(&sort_needed_sym->st_value) -
+ _r(&sort_needed_sym->etype.st_value) -
_r(&sort_needed_sec->etype.sh_addr);
/* extable has been sorted, clear the flag */
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,139 @@
From 1278ee787a87aaaa378d44f173cdae2fb07501ae Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:33 +0200
Subject: [PATCH] scripts/sorttable: Add helper functions for Elf_Ehdr
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 1dfb59a228dde59ad7d99b2fa2104e90004995c7
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:20 2025 -0500
scripts/sorttable: Add helper functions for Elf_Ehdr
In order to remove the double #include of sorttable.h for 64 and 32 bit
to create duplicate functions, add helper functions for Elf_Ehdr. This
will create a function pointer for each helper that will get assigned to
the appropriate function to handle either the 64bit or 32bit version.
This also moves the _r()/r() wrappers for the Elf_Ehdr references that
handle endian and size differences between the different architectures,
into the helper function and out of the open code which is more error
prone.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162345.736369526@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 57792cf2aa89..5dfa734eff09 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -85,6 +85,31 @@ static uint64_t (*r8)(const uint64_t *);
static void (*w)(uint32_t, uint32_t *);
typedef void (*table_sort_t)(char *, int);
+static uint64_t ehdr64_shoff(Elf_Ehdr *ehdr)
+{
+ return r8(&ehdr->e64.e_shoff);
+}
+
+static uint64_t ehdr32_shoff(Elf_Ehdr *ehdr)
+{
+ return r(&ehdr->e32.e_shoff);
+}
+
+#define EHDR_HALF(fn_name) \
+static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \
+{ \
+ return r2(&ehdr->e64.e_##fn_name); \
+} \
+ \
+static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr) \
+{ \
+ return r2(&ehdr->e32.e_##fn_name); \
+}
+
+EHDR_HALF(shentsize)
+EHDR_HALF(shstrndx)
+EHDR_HALF(shnum)
+
/*
* Get the whole file as a programming convenience in order to avoid
* malloc+lseek+read+free of many pieces. If successful, then mmap
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index cd4429c8a9f4..97278c973bc9 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -27,6 +27,10 @@
#undef uint_t
#undef _r
#undef etype
+#undef ehdr_shoff
+#undef ehdr_shentsize
+#undef ehdr_shstrndx
+#undef ehdr_shnum
#ifdef SORTTABLE_64
# define extable_ent_size 16
@@ -39,6 +43,10 @@
# define uint_t uint64_t
# define _r r8
# define etype e64
+# define ehdr_shoff ehdr64_shoff
+# define ehdr_shentsize ehdr64_shentsize
+# define ehdr_shstrndx ehdr64_shstrndx
+# define ehdr_shnum ehdr64_shnum
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
@@ -50,6 +58,10 @@
# define uint_t uint32_t
# define _r r
# define etype e32
+# define ehdr_shoff ehdr32_shoff
+# define ehdr_shentsize ehdr32_shentsize
+# define ehdr_shstrndx ehdr32_shstrndx
+# define ehdr_shnum ehdr32_shnum
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
@@ -250,16 +262,16 @@ static int do_sort(Elf_Ehdr *ehdr,
unsigned int orc_num_entries = 0;
#endif
- shdr_start = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->etype.e_shoff));
- shentsize = r2(&ehdr->etype.e_shentsize);
+ shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr));
+ shentsize = ehdr_shentsize(ehdr);
- shstrndx = r2(&ehdr->etype.e_shstrndx);
+ shstrndx = ehdr_shstrndx(ehdr);
if (shstrndx == SHN_XINDEX)
shstrndx = r(&shdr_start->etype.sh_link);
string_sec = get_index(shdr_start, shentsize, shstrndx);
secstrings = (const char *)ehdr + _r(&string_sec->etype.sh_offset);
- shnum = r2(&ehdr->etype.e_shnum);
+ shnum = ehdr_shnum(ehdr);
if (shnum == SHN_UNDEF)
shnum = _r(&shdr_start->etype.sh_size);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,253 @@
From a5efd249d8b52767833dcd9ca0b7f8f5470cf289 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:40 +0200
Subject: [PATCH] scripts/sorttable: Add helper functions for Elf_Shdr
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 67afb7f504400e5b4e5ff895459fbb3eb63d4450
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:21 2025 -0500
scripts/sorttable: Add helper functions for Elf_Shdr
In order to remove the double #include of sorttable.h for 64 and 32 bit
to create duplicate functions, add helper functions for Elf_Shdr. This
will create a function pointer for each helper that will get assigned to
the appropriate function to handle either the 64bit or 32bit version.
This also moves the _r()/r() wrappers for the Elf_Shdr references that
handle endian and size differences between the different architectures,
into the helper function and out of the open code which is more error
prone.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162345.940924221@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 5dfa734eff09..b2b96ff261d6 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -110,6 +110,48 @@ EHDR_HALF(shentsize)
EHDR_HALF(shstrndx)
EHDR_HALF(shnum)
+#define SHDR_WORD(fn_name) \
+static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return r(&shdr->e64.sh_##fn_name); \
+} \
+ \
+static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return r(&shdr->e32.sh_##fn_name); \
+}
+
+#define SHDR_ADDR(fn_name) \
+static uint64_t shdr64_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return r8(&shdr->e64.sh_##fn_name); \
+} \
+ \
+static uint64_t shdr32_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return r(&shdr->e32.sh_##fn_name); \
+}
+
+#define SHDR_WORD(fn_name) \
+static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return r(&shdr->e64.sh_##fn_name); \
+} \
+ \
+static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return r(&shdr->e32.sh_##fn_name); \
+}
+
+SHDR_ADDR(addr)
+SHDR_ADDR(offset)
+SHDR_ADDR(size)
+SHDR_ADDR(entsize)
+
+SHDR_WORD(link)
+SHDR_WORD(name)
+SHDR_WORD(type)
+
/*
* Get the whole file as a programming convenience in order to avoid
* malloc+lseek+read+free of many pieces. If successful, then mmap
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index 97278c973bc9..af3a5f0209a3 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -31,6 +31,13 @@
#undef ehdr_shentsize
#undef ehdr_shstrndx
#undef ehdr_shnum
+#undef shdr_addr
+#undef shdr_offset
+#undef shdr_link
+#undef shdr_size
+#undef shdr_name
+#undef shdr_type
+#undef shdr_entsize
#ifdef SORTTABLE_64
# define extable_ent_size 16
@@ -47,6 +54,13 @@
# define ehdr_shentsize ehdr64_shentsize
# define ehdr_shstrndx ehdr64_shstrndx
# define ehdr_shnum ehdr64_shnum
+# define shdr_addr shdr64_addr
+# define shdr_offset shdr64_offset
+# define shdr_link shdr64_link
+# define shdr_size shdr64_size
+# define shdr_name shdr64_name
+# define shdr_type shdr64_type
+# define shdr_entsize shdr64_entsize
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
@@ -62,6 +76,13 @@
# define ehdr_shentsize ehdr32_shentsize
# define ehdr_shstrndx ehdr32_shstrndx
# define ehdr_shnum ehdr32_shnum
+# define shdr_addr shdr32_addr
+# define shdr_offset shdr32_offset
+# define shdr_link shdr32_link
+# define shdr_size shdr32_size
+# define shdr_name shdr32_name
+# define shdr_type shdr32_type
+# define shdr_entsize shdr32_entsize
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
@@ -177,8 +198,8 @@ struct elf_mcount_loc {
static void *sort_mcount_loc(void *arg)
{
struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
- uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->etype.sh_addr)
- + _r(&(emloc->init_data_sec)->etype.sh_offset);
+ uint_t offset = emloc->start_mcount_loc - shdr_addr(emloc->init_data_sec)
+ + shdr_offset(emloc->init_data_sec);
uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
unsigned char *start_loc = (void *)emloc->ehdr + offset;
@@ -267,18 +288,18 @@ static int do_sort(Elf_Ehdr *ehdr,
shstrndx = ehdr_shstrndx(ehdr);
if (shstrndx == SHN_XINDEX)
- shstrndx = r(&shdr_start->etype.sh_link);
+ shstrndx = shdr_link(shdr_start);
string_sec = get_index(shdr_start, shentsize, shstrndx);
- secstrings = (const char *)ehdr + _r(&string_sec->etype.sh_offset);
+ secstrings = (const char *)ehdr + shdr_offset(string_sec);
shnum = ehdr_shnum(ehdr);
if (shnum == SHN_UNDEF)
- shnum = _r(&shdr_start->etype.sh_size);
+ shnum = shdr_size(shdr_start);
for (i = 0; i < shnum; i++) {
Elf_Shdr *shdr = get_index(shdr_start, shentsize, i);
- idx = r(&shdr->etype.sh_name);
+ idx = shdr_name(shdr);
if (!strcmp(secstrings + idx, "__ex_table"))
extab_sec = shdr;
if (!strcmp(secstrings + idx, ".symtab"))
@@ -286,9 +307,9 @@ static int do_sort(Elf_Ehdr *ehdr,
if (!strcmp(secstrings + idx, ".strtab"))
strtab_sec = shdr;
- if (r(&shdr->etype.sh_type) == SHT_SYMTAB_SHNDX)
+ if (shdr_type(shdr) == SHT_SYMTAB_SHNDX)
symtab_shndx = (Elf32_Word *)((const char *)ehdr +
- _r(&shdr->etype.sh_offset));
+ shdr_offset(shdr));
#ifdef MCOUNT_SORT_ENABLED
/* locate the .init.data section in vmlinux */
@@ -304,14 +325,14 @@ static int do_sort(Elf_Ehdr *ehdr,
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* locate the ORC unwind tables */
if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
- orc_ip_size = _r(&shdr->etype.sh_size);
+ orc_ip_size = shdr_size(shdr);
g_orc_ip_table = (int *)((void *)ehdr +
- _r(&shdr->etype.sh_offset));
+ shdr_offset(shdr));
}
if (!strcmp(secstrings + idx, ".orc_unwind")) {
- orc_size = _r(&shdr->etype.sh_size);
+ orc_size = shdr_size(shdr);
g_orc_table = (struct orc_entry *)((void *)ehdr +
- _r(&shdr->etype.sh_offset));
+ shdr_offset(shdr));
}
#endif
} /* for loop */
@@ -374,23 +395,22 @@ static int do_sort(Elf_Ehdr *ehdr,
goto out;
}
- extab_image = (void *)ehdr + _r(&extab_sec->etype.sh_offset);
- strtab = (const char *)ehdr + _r(&strtab_sec->etype.sh_offset);
- symtab = (const Elf_Sym *)((const char *)ehdr +
- _r(&symtab_sec->etype.sh_offset));
+ extab_image = (void *)ehdr + shdr_offset(extab_sec);
+ strtab = (const char *)ehdr + shdr_offset(strtab_sec);
+ symtab = (const Elf_Sym *)((const char *)ehdr + shdr_offset(symtab_sec));
if (custom_sort) {
- custom_sort(extab_image, _r(&extab_sec->etype.sh_size));
+ custom_sort(extab_image, shdr_size(extab_sec));
} else {
- int num_entries = _r(&extab_sec->etype.sh_size) / extable_ent_size;
+ int num_entries = shdr_size(extab_sec) / extable_ent_size;
qsort(extab_image, num_entries,
extable_ent_size, compare_extable);
}
/* find the flag main_extable_sort_needed */
- sym_start = (void *)ehdr + _r(&symtab_sec->etype.sh_offset);
- sym_end = sym_start + _r(&symtab_sec->etype.sh_size);
- symentsize = _r(&symtab_sec->etype.sh_entsize);
+ sym_start = (void *)ehdr + shdr_offset(symtab_sec);
+ sym_end = sym_start + shdr_size(symtab_sec);
+ symentsize = shdr_entsize(symtab_sec);
for (sym = sym_start; (void *)sym + symentsize < sym_end;
sym = (void *)sym + symentsize) {
@@ -415,9 +435,9 @@ static int do_sort(Elf_Ehdr *ehdr,
symtab_shndx);
sort_needed_sec = get_index(shdr_start, shentsize, sort_need_index);
sort_needed_loc = (void *)ehdr +
- _r(&sort_needed_sec->etype.sh_offset) +
+ shdr_offset(sort_needed_sec) +
_r(&sort_needed_sym->etype.st_value) -
- _r(&sort_needed_sec->etype.sh_addr);
+ shdr_addr(sort_needed_sec);
/* extable has been sorted, clear the flag */
w(0, sort_needed_loc);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,203 @@
From 133d6f7d2c3e689e3191bf973e07819dda085f60 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:43 +0200
Subject: [PATCH] scripts/sorttable: Add helper functions for Elf_Sym
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 17bed33ac12f011f4695059960e1b1d6457229a7
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:22 2025 -0500
scripts/sorttable: Add helper functions for Elf_Sym
In order to remove the double #include of sorttable.h for 64 and 32 bit
to create duplicate functions, add helper functions for Elf_Sym. This
will create a function pointer for each helper that will get assigned to
the appropriate function to handle either the 64bit or 32bit version.
This also removes the last references of etype and _r() macros from the
sorttable.h file as their references are now just defined in the
appropriate architecture version of the helper functions. All read
functions now exist in the helper functions which makes it easier to
maintain, as the helper functions define the necessary architecture sizes.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162346.185740651@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index b2b96ff261d6..20615de18276 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -152,6 +152,53 @@ SHDR_WORD(link)
SHDR_WORD(name)
SHDR_WORD(type)
+#define SYM_ADDR(fn_name) \
+static uint64_t sym64_##fn_name(Elf_Sym *sym) \
+{ \
+ return r8(&sym->e64.st_##fn_name); \
+} \
+ \
+static uint64_t sym32_##fn_name(Elf_Sym *sym) \
+{ \
+ return r(&sym->e32.st_##fn_name); \
+}
+
+#define SYM_WORD(fn_name) \
+static uint32_t sym64_##fn_name(Elf_Sym *sym) \
+{ \
+ return r(&sym->e64.st_##fn_name); \
+} \
+ \
+static uint32_t sym32_##fn_name(Elf_Sym *sym) \
+{ \
+ return r(&sym->e32.st_##fn_name); \
+}
+
+#define SYM_HALF(fn_name) \
+static uint16_t sym64_##fn_name(Elf_Sym *sym) \
+{ \
+ return r2(&sym->e64.st_##fn_name); \
+} \
+ \
+static uint16_t sym32_##fn_name(Elf_Sym *sym) \
+{ \
+ return r2(&sym->e32.st_##fn_name); \
+}
+
+static uint8_t sym64_type(Elf_Sym *sym)
+{
+ return ELF64_ST_TYPE(sym->e64.st_info);
+}
+
+static uint8_t sym32_type(Elf_Sym *sym)
+{
+ return ELF32_ST_TYPE(sym->e32.st_info);
+}
+
+SYM_ADDR(value)
+SYM_WORD(name)
+SYM_HALF(shndx)
+
/*
* Get the whole file as a programming convenience in order to avoid
* malloc+lseek+read+free of many pieces. If successful, then mmap
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index af3a5f0209a3..ef7e5161db31 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -23,10 +23,7 @@
#undef sort_mcount_loc
#undef elf_mcount_loc
#undef do_sort
-#undef ELF_ST_TYPE
#undef uint_t
-#undef _r
-#undef etype
#undef ehdr_shoff
#undef ehdr_shentsize
#undef ehdr_shstrndx
@@ -38,6 +35,10 @@
#undef shdr_name
#undef shdr_type
#undef shdr_entsize
+#undef sym_type
+#undef sym_name
+#undef sym_value
+#undef sym_shndx
#ifdef SORTTABLE_64
# define extable_ent_size 16
@@ -46,10 +47,7 @@
# define sort_mcount_loc sort_mcount_loc_64
# define elf_mcount_loc elf_mcount_loc_64
# define do_sort do_sort_64
-# define ELF_ST_TYPE ELF64_ST_TYPE
# define uint_t uint64_t
-# define _r r8
-# define etype e64
# define ehdr_shoff ehdr64_shoff
# define ehdr_shentsize ehdr64_shentsize
# define ehdr_shstrndx ehdr64_shstrndx
@@ -61,6 +59,10 @@
# define shdr_name shdr64_name
# define shdr_type shdr64_type
# define shdr_entsize shdr64_entsize
+# define sym_type sym64_type
+# define sym_name sym64_name
+# define sym_value sym64_value
+# define sym_shndx sym64_shndx
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
@@ -68,10 +70,7 @@
# define sort_mcount_loc sort_mcount_loc_32
# define elf_mcount_loc elf_mcount_loc_32
# define do_sort do_sort_32
-# define ELF_ST_TYPE ELF32_ST_TYPE
# define uint_t uint32_t
-# define _r r
-# define etype e32
# define ehdr_shoff ehdr32_shoff
# define ehdr_shentsize ehdr32_shentsize
# define ehdr_shstrndx ehdr32_shstrndx
@@ -83,6 +82,10 @@
# define shdr_name shdr32_name
# define shdr_type shdr32_type
# define shdr_entsize shdr32_entsize
+# define sym_type sym32_type
+# define sym_name sym32_name
+# define sym_value sym32_value
+# define sym_shndx sym32_shndx
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
@@ -414,9 +417,9 @@ static int do_sort(Elf_Ehdr *ehdr,
for (sym = sym_start; (void *)sym + symentsize < sym_end;
sym = (void *)sym + symentsize) {
- if (ELF_ST_TYPE(sym->etype.st_info) != STT_OBJECT)
+ if (sym_type(sym) != STT_OBJECT)
continue;
- if (!strcmp(strtab + r(&sym->etype.st_name),
+ if (!strcmp(strtab + sym_name(sym),
"main_extable_sort_needed")) {
sort_needed_sym = sym;
break;
@@ -430,14 +433,13 @@ static int do_sort(Elf_Ehdr *ehdr,
goto out;
}
- sort_need_index = get_secindex(r2(&sym->etype.st_shndx),
+ sort_need_index = get_secindex(sym_shndx(sym),
((void *)sort_needed_sym - (void *)symtab) / symentsize,
symtab_shndx);
sort_needed_sec = get_index(shdr_start, shentsize, sort_need_index);
sort_needed_loc = (void *)ehdr +
shdr_offset(sort_needed_sec) +
- _r(&sort_needed_sym->etype.st_value) -
- shdr_addr(sort_needed_sec);
+ sym_value(sort_needed_sym) - shdr_addr(sort_needed_sec);
/* extable has been sorted, clear the flag */
w(0, sort_needed_loc);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,140 @@
From daa2ce334210ed3ebb054d2f8097312ac7a60ae4 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:22:46 +0200
Subject: [PATCH] scripts/sorttable: Use uint64_t for mcount sorting
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 1b649e6ab8dc9188d82c64069493afe66ca0edad
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:23 2025 -0500
scripts/sorttable: Use uint64_t for mcount sorting
The mcount sorting defines uint_t to uint64_t on 64bit architectures and
uint32_t on 32bit architectures. It can work with just using uint64_t as
that will hold the values of both, and they are not used to point into the
ELF file.
sizeof(uint_t) is used for defining the size of the mcount_loc section.
Instead of using a type, define long_size and use that instead. This will
allow the header code to be moved into the C file as generic functions and
not need to include sorttable.h twice, once for 64bit and once for 32bit.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162346.373528925@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index ef7e5161db31..17a8541a10d6 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -23,7 +23,6 @@
#undef sort_mcount_loc
#undef elf_mcount_loc
#undef do_sort
-#undef uint_t
#undef ehdr_shoff
#undef ehdr_shentsize
#undef ehdr_shstrndx
@@ -39,6 +38,7 @@
#undef sym_name
#undef sym_value
#undef sym_shndx
+#undef long_size
#ifdef SORTTABLE_64
# define extable_ent_size 16
@@ -47,7 +47,6 @@
# define sort_mcount_loc sort_mcount_loc_64
# define elf_mcount_loc elf_mcount_loc_64
# define do_sort do_sort_64
-# define uint_t uint64_t
# define ehdr_shoff ehdr64_shoff
# define ehdr_shentsize ehdr64_shentsize
# define ehdr_shstrndx ehdr64_shstrndx
@@ -63,6 +62,7 @@
# define sym_name sym64_name
# define sym_value sym64_value
# define sym_shndx sym64_shndx
+# define long_size 8
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
@@ -70,7 +70,6 @@
# define sort_mcount_loc sort_mcount_loc_32
# define elf_mcount_loc elf_mcount_loc_32
# define do_sort do_sort_32
-# define uint_t uint32_t
# define ehdr_shoff ehdr32_shoff
# define ehdr_shentsize ehdr32_shentsize
# define ehdr_shstrndx ehdr32_shstrndx
@@ -86,6 +85,7 @@
# define sym_name sym32_name
# define sym_value sym32_value
# define sym_shndx sym32_shndx
+# define long_size 4
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
@@ -193,25 +193,25 @@ pthread_t mcount_sort_thread;
struct elf_mcount_loc {
Elf_Ehdr *ehdr;
Elf_Shdr *init_data_sec;
- uint_t start_mcount_loc;
- uint_t stop_mcount_loc;
+ uint64_t start_mcount_loc;
+ uint64_t stop_mcount_loc;
};
/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
static void *sort_mcount_loc(void *arg)
{
struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
- uint_t offset = emloc->start_mcount_loc - shdr_addr(emloc->init_data_sec)
+ uint64_t offset = emloc->start_mcount_loc - shdr_addr(emloc->init_data_sec)
+ shdr_offset(emloc->init_data_sec);
- uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
+ uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
unsigned char *start_loc = (void *)emloc->ehdr + offset;
- qsort(start_loc, count/sizeof(uint_t), sizeof(uint_t), compare_extable);
+ qsort(start_loc, count/long_size, long_size, compare_extable);
return NULL;
}
/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
-static void get_mcount_loc(uint_t *_start, uint_t *_stop)
+static void get_mcount_loc(uint64_t *_start, uint64_t *_stop)
{
FILE *file_start, *file_stop;
char start_buff[20];
@@ -277,8 +277,8 @@ static int do_sort(Elf_Ehdr *ehdr,
unsigned int shstrndx;
#ifdef MCOUNT_SORT_ENABLED
struct elf_mcount_loc mstruct = {0};
- uint_t _start_mcount_loc = 0;
- uint_t _stop_mcount_loc = 0;
+ uint64_t _start_mcount_loc = 0;
+ uint64_t _stop_mcount_loc = 0;
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
unsigned int orc_ip_size = 0;
--
2.50.1 (Apple Git-155)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,196 @@
From 0e6fd4e629cfcaf1a4f04e2c9e39e8b5776890a2 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:36:32 +0200
Subject: [PATCH] scripts/sorttable: Get start/stop_mcount_loc from ELF file
directly
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 4acda8edefa1ce66d3de845f1c12745721cd14c3
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Sun Jan 5 11:22:25 2025 -0500
scripts/sorttable: Get start/stop_mcount_loc from ELF file directly
The get_mcount_loc() does a cheesy trick to find the start_mcount_loc and
stop_mcount_loc values. That trick is:
file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r");
and
file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r");
Those values are stored in the Elf symbol table. Use that to capture those
values. Using the symbol table is more efficient and more robust. The
above could fail if another variable had "start_mcount" or "stop_mcount"
as part of its name.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/20250105162346.817157047@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index ff9b60fc0dd8..656c1e9b5ad9 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -472,42 +472,41 @@ static void *sort_mcount_loc(void *arg)
}
/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
-static void get_mcount_loc(uint64_t *_start, uint64_t *_stop)
+static void get_mcount_loc(struct elf_mcount_loc *emloc, Elf_Shdr *symtab_sec,
+ const char *strtab)
{
- FILE *file_start, *file_stop;
- char start_buff[20];
- char stop_buff[20];
- int len = 0;
+ Elf_Sym *sym, *end_sym;
+ int symentsize = shdr_entsize(symtab_sec);
+ int found = 0;
+
+ sym = (void *)emloc->ehdr + shdr_offset(symtab_sec);
+ end_sym = (void *)sym + shdr_size(symtab_sec);
+
+ while (sym < end_sym) {
+ if (!strcmp(strtab + sym_name(sym), "__start_mcount_loc")) {
+ emloc->start_mcount_loc = sym_value(sym);
+ if (++found == 2)
+ break;
+ } else if (!strcmp(strtab + sym_name(sym), "__stop_mcount_loc")) {
+ emloc->stop_mcount_loc = sym_value(sym);
+ if (++found == 2)
+ break;
+ }
+ sym = (void *)sym + symentsize;
+ }
- file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r");
- if (!file_start) {
+ if (!emloc->start_mcount_loc) {
fprintf(stderr, "get start_mcount_loc error!");
return;
}
- file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r");
- if (!file_stop) {
+ if (!emloc->stop_mcount_loc) {
fprintf(stderr, "get stop_mcount_loc error!");
- pclose(file_start);
return;
}
-
- while (fgets(start_buff, sizeof(start_buff), file_start) != NULL) {
- len = strlen(start_buff);
- start_buff[len - 1] = '\0';
- }
- *_start = strtoul(start_buff, NULL, 16);
-
- while (fgets(stop_buff, sizeof(stop_buff), file_stop) != NULL) {
- len = strlen(stop_buff);
- stop_buff[len - 1] = '\0';
- }
- *_stop = strtoul(stop_buff, NULL, 16);
-
- pclose(file_start);
- pclose(file_stop);
}
#endif
+
static int do_sort(Elf_Ehdr *ehdr,
char const *const fname,
table_sort_t custom_sort)
@@ -538,8 +537,6 @@ static int do_sort(Elf_Ehdr *ehdr,
unsigned int shstrndx;
#ifdef MCOUNT_SORT_ENABLED
struct elf_mcount_loc mstruct = {0};
- uint64_t _start_mcount_loc = 0;
- uint64_t _stop_mcount_loc = 0;
#endif
#ifdef UNWINDER_ORC_ENABLED
unsigned int orc_ip_size = 0;
@@ -577,13 +574,8 @@ static int do_sort(Elf_Ehdr *ehdr,
#ifdef MCOUNT_SORT_ENABLED
/* locate the .init.data section in vmlinux */
- if (!strcmp(secstrings + idx, ".init.data")) {
- get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc);
- mstruct.ehdr = ehdr;
+ if (!strcmp(secstrings + idx, ".init.data"))
mstruct.init_data_sec = shdr;
- mstruct.start_mcount_loc = _start_mcount_loc;
- mstruct.stop_mcount_loc = _stop_mcount_loc;
- }
#endif
#ifdef UNWINDER_ORC_ENABLED
@@ -627,23 +619,6 @@ static int do_sort(Elf_Ehdr *ehdr,
goto out;
}
#endif
-
-#ifdef MCOUNT_SORT_ENABLED
- if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) {
- fprintf(stderr,
- "incomplete mcount's sort in file: %s\n",
- fname);
- goto out;
- }
-
- /* create thread to sort mcount_loc concurrently */
- if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
- fprintf(stderr,
- "pthread_create mcount_sort_thread failed '%s': %s\n",
- strerror(errno), fname);
- goto out;
- }
-#endif
if (!extab_sec) {
fprintf(stderr, "no __ex_table in file: %s\n", fname);
goto out;
@@ -663,6 +638,26 @@ static int do_sort(Elf_Ehdr *ehdr,
strtab = (const char *)ehdr + shdr_offset(strtab_sec);
symtab = (const Elf_Sym *)((const char *)ehdr + shdr_offset(symtab_sec));
+#ifdef MCOUNT_SORT_ENABLED
+ mstruct.ehdr = ehdr;
+ get_mcount_loc(&mstruct, symtab_sec, strtab);
+
+ if (!mstruct.init_data_sec || !mstruct.start_mcount_loc || !mstruct.stop_mcount_loc) {
+ fprintf(stderr,
+ "incomplete mcount's sort in file: %s\n",
+ fname);
+ goto out;
+ }
+
+ /* create thread to sort mcount_loc concurrently */
+ if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
+ fprintf(stderr,
+ "pthread_create mcount_sort_thread failed '%s': %s\n",
+ strerror(errno), fname);
+ goto out;
+ }
+#endif
+
if (custom_sort) {
custom_sort(extab_image, shdr_size(extab_sec));
} else {
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,327 @@
From 1ca873e533dd7f3f3abd7518a7c356fa7bb6ef91 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:52:42 +0200
Subject: [PATCH] scripts/sorttable: Use a structure of function pointers for
elf helpers
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 1e5f6771c247b28135307058d2cfe3b0153733dc
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Fri Jan 10 07:54:59 2025 -0500
scripts/sorttable: Use a structure of function pointers for elf helpers
Instead of having a series of function pointers that gets assigned to the
Elf64 or Elf32 versions, put them all into a single structure and use
that. Add the helper function that chooses the structure into the macros
that build the different versions of the elf functions.
Link: https://lore.kernel.org/all/CAHk-=wiafEyX7UgOeZgvd6fvuByE5WXUPh9599kwOc_d-pdeug@mail.gmail.com/
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Link: https://lore.kernel.org/20250110075459.13d4b94c@gandalf.local.home
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 656c1e9b5ad9..9f41575afd7a 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -85,6 +85,25 @@ static uint64_t (*r8)(const uint64_t *);
static void (*w)(uint32_t, uint32_t *);
typedef void (*table_sort_t)(char *, int);
+static struct elf_funcs {
+ int (*compare_extable)(const void *a, const void *b);
+ uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr);
+ uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr);
+ uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr);
+ uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr);
+ uint64_t (*shdr_addr)(Elf_Shdr *shdr);
+ uint64_t (*shdr_offset)(Elf_Shdr *shdr);
+ uint64_t (*shdr_size)(Elf_Shdr *shdr);
+ uint64_t (*shdr_entsize)(Elf_Shdr *shdr);
+ uint32_t (*shdr_link)(Elf_Shdr *shdr);
+ uint32_t (*shdr_name)(Elf_Shdr *shdr);
+ uint32_t (*shdr_type)(Elf_Shdr *shdr);
+ uint8_t (*sym_type)(Elf_Sym *sym);
+ uint32_t (*sym_name)(Elf_Sym *sym);
+ uint64_t (*sym_value)(Elf_Sym *sym);
+ uint16_t (*sym_shndx)(Elf_Sym *sym);
+} e;
+
static uint64_t ehdr64_shoff(Elf_Ehdr *ehdr)
{
return r8(&ehdr->e64.e_shoff);
@@ -95,6 +114,11 @@ static uint64_t ehdr32_shoff(Elf_Ehdr *ehdr)
return r(&ehdr->e32.e_shoff);
}
+static uint64_t ehdr_shoff(Elf_Ehdr *ehdr)
+{
+ return e.ehdr_shoff(ehdr);
+}
+
#define EHDR_HALF(fn_name) \
static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \
{ \
@@ -104,6 +128,11 @@ static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \
static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr) \
{ \
return r2(&ehdr->e32.e_##fn_name); \
+} \
+ \
+static uint16_t ehdr_##fn_name(Elf_Ehdr *ehdr) \
+{ \
+ return e.ehdr_##fn_name(ehdr); \
}
EHDR_HALF(shentsize)
@@ -119,6 +148,11 @@ static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \
static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \
{ \
return r(&shdr->e32.sh_##fn_name); \
+} \
+ \
+static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return e.shdr_##fn_name(shdr); \
}
#define SHDR_ADDR(fn_name) \
@@ -130,6 +164,11 @@ static uint64_t shdr64_##fn_name(Elf_Shdr *shdr) \
static uint64_t shdr32_##fn_name(Elf_Shdr *shdr) \
{ \
return r(&shdr->e32.sh_##fn_name); \
+} \
+ \
+static uint64_t shdr_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return e.shdr_##fn_name(shdr); \
}
#define SHDR_WORD(fn_name) \
@@ -141,6 +180,10 @@ static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \
static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \
{ \
return r(&shdr->e32.sh_##fn_name); \
+} \
+static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \
+{ \
+ return e.shdr_##fn_name(shdr); \
}
SHDR_ADDR(addr)
@@ -161,6 +204,11 @@ static uint64_t sym64_##fn_name(Elf_Sym *sym) \
static uint64_t sym32_##fn_name(Elf_Sym *sym) \
{ \
return r(&sym->e32.st_##fn_name); \
+} \
+ \
+static uint64_t sym_##fn_name(Elf_Sym *sym) \
+{ \
+ return e.sym_##fn_name(sym); \
}
#define SYM_WORD(fn_name) \
@@ -172,6 +220,11 @@ static uint32_t sym64_##fn_name(Elf_Sym *sym) \
static uint32_t sym32_##fn_name(Elf_Sym *sym) \
{ \
return r(&sym->e32.st_##fn_name); \
+} \
+ \
+static uint32_t sym_##fn_name(Elf_Sym *sym) \
+{ \
+ return e.sym_##fn_name(sym); \
}
#define SYM_HALF(fn_name) \
@@ -183,6 +236,11 @@ static uint16_t sym64_##fn_name(Elf_Sym *sym) \
static uint16_t sym32_##fn_name(Elf_Sym *sym) \
{ \
return r2(&sym->e32.st_##fn_name); \
+} \
+ \
+static uint16_t sym_##fn_name(Elf_Sym *sym) \
+{ \
+ return e.sym_##fn_name(sym); \
}
static uint8_t sym64_type(Elf_Sym *sym)
@@ -195,6 +253,11 @@ static uint8_t sym32_type(Elf_Sym *sym)
return ELF32_ST_TYPE(sym->e32.st_info);
}
+static uint8_t sym_type(Elf_Sym *sym)
+{
+ return e.sym_type(sym);
+}
+
SYM_ADDR(value)
SYM_WORD(name)
SYM_HALF(shndx)
@@ -322,29 +385,16 @@ static int compare_extable_64(const void *a, const void *b)
return av > bv;
}
+static int compare_extable(const void *a, const void *b)
+{
+ return e.compare_extable(a, b);
+}
+
static inline void *get_index(void *start, int entsize, int index)
{
return start + (entsize * index);
}
-
-static int (*compare_extable)(const void *a, const void *b);
-static uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr);
-static uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr);
-static uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr);
-static uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr);
-static uint64_t (*shdr_addr)(Elf_Shdr *shdr);
-static uint64_t (*shdr_offset)(Elf_Shdr *shdr);
-static uint64_t (*shdr_size)(Elf_Shdr *shdr);
-static uint64_t (*shdr_entsize)(Elf_Shdr *shdr);
-static uint32_t (*shdr_link)(Elf_Shdr *shdr);
-static uint32_t (*shdr_name)(Elf_Shdr *shdr);
-static uint32_t (*shdr_type)(Elf_Shdr *shdr);
-static uint8_t (*sym_type)(Elf_Sym *sym);
-static uint32_t (*sym_name)(Elf_Sym *sym);
-static uint64_t (*sym_value)(Elf_Sym *sym);
-static uint16_t (*sym_shndx)(Elf_Sym *sym);
-
static int extable_ent_size;
static int long_size;
@@ -864,7 +914,30 @@ static int do_file(char const *const fname, void *addr)
}
switch (ehdr->e32.e_ident[EI_CLASS]) {
- case ELFCLASS32:
+ case ELFCLASS32: {
+ struct elf_funcs efuncs = {
+ .compare_extable = compare_extable_32,
+ .ehdr_shoff = ehdr32_shoff,
+ .ehdr_shentsize = ehdr32_shentsize,
+ .ehdr_shstrndx = ehdr32_shstrndx,
+ .ehdr_shnum = ehdr32_shnum,
+ .shdr_addr = shdr32_addr,
+ .shdr_offset = shdr32_offset,
+ .shdr_link = shdr32_link,
+ .shdr_size = shdr32_size,
+ .shdr_name = shdr32_name,
+ .shdr_type = shdr32_type,
+ .shdr_entsize = shdr32_entsize,
+ .sym_type = sym32_type,
+ .sym_name = sym32_name,
+ .sym_value = sym32_value,
+ .sym_shndx = sym32_shndx,
+ };
+
+ e = efuncs;
+ long_size = 4;
+ extable_ent_size = 8;
+
if (r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
fprintf(stderr,
@@ -872,26 +945,32 @@ static int do_file(char const *const fname, void *addr)
return -1;
}
- compare_extable = compare_extable_32;
- ehdr_shoff = ehdr32_shoff;
- ehdr_shentsize = ehdr32_shentsize;
- ehdr_shstrndx = ehdr32_shstrndx;
- ehdr_shnum = ehdr32_shnum;
- shdr_addr = shdr32_addr;
- shdr_offset = shdr32_offset;
- shdr_link = shdr32_link;
- shdr_size = shdr32_size;
- shdr_name = shdr32_name;
- shdr_type = shdr32_type;
- shdr_entsize = shdr32_entsize;
- sym_type = sym32_type;
- sym_name = sym32_name;
- sym_value = sym32_value;
- sym_shndx = sym32_shndx;
- long_size = 4;
- extable_ent_size = 8;
+ }
break;
- case ELFCLASS64:
+ case ELFCLASS64: {
+ struct elf_funcs efuncs = {
+ .compare_extable = compare_extable_64,
+ .ehdr_shoff = ehdr64_shoff,
+ .ehdr_shentsize = ehdr64_shentsize,
+ .ehdr_shstrndx = ehdr64_shstrndx,
+ .ehdr_shnum = ehdr64_shnum,
+ .shdr_addr = shdr64_addr,
+ .shdr_offset = shdr64_offset,
+ .shdr_link = shdr64_link,
+ .shdr_size = shdr64_size,
+ .shdr_name = shdr64_name,
+ .shdr_type = shdr64_type,
+ .shdr_entsize = shdr64_entsize,
+ .sym_type = sym64_type,
+ .sym_name = sym64_name,
+ .sym_value = sym64_value,
+ .sym_shndx = sym64_shndx,
+ };
+
+ e = efuncs;
+ long_size = 8;
+ extable_ent_size = 16;
+
if (r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
fprintf(stderr,
@@ -900,25 +979,7 @@ static int do_file(char const *const fname, void *addr)
return -1;
}
- compare_extable = compare_extable_64;
- ehdr_shoff = ehdr64_shoff;
- ehdr_shentsize = ehdr64_shentsize;
- ehdr_shstrndx = ehdr64_shstrndx;
- ehdr_shnum = ehdr64_shnum;
- shdr_addr = shdr64_addr;
- shdr_offset = shdr64_offset;
- shdr_link = shdr64_link;
- shdr_size = shdr64_size;
- shdr_name = shdr64_name;
- shdr_type = shdr64_type;
- shdr_entsize = shdr64_entsize;
- sym_type = sym64_type;
- sym_name = sym64_name;
- sym_value = sym64_value;
- sym_shndx = sym64_shndx;
- long_size = 8;
- extable_ent_size = 16;
-
+ }
break;
default:
fprintf(stderr, "unrecognized ELF class %d %s\n",
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,373 @@
From 4b605df96d9249250134a81573caa2ab136e0ce8 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:55:45 +0200
Subject: [PATCH] arm64: scripts/sorttable: Implement sorting mcount_loc at
boot for arm64
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
Conflicts: Context change from missing commit a762e9267dca ("ftrace:
Add CONFIG_HAVE_FTRACE_GRAPH_FUNC")
commit b3d09d06e052e1d754645acea4e4d1e96f81c934
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 18 14:59:19 2025 -0500
arm64: scripts/sorttable: Implement sorting mcount_loc at boot for arm64
The mcount_loc section holds the addresses of the functions that get
patched by ftrace when enabling function callbacks. It can contain tens of
thousands of entries. These addresses must be sorted. If they are not
sorted at compile time, they are sorted at boot. Sorting at boot does take
some time and does have a small impact on boot performance.
x86 and arm32 have the addresses in the mcount_loc section of the ELF
file. But for arm64, the section just contains zeros. The .rela.dyn
Elf_Rela section holds the addresses and they get patched at boot during
the relocation phase.
In order to sort these addresses, the Elf_Rela needs to be updated instead
of the location in the binary that holds the mcount_loc section. Have the
sorttable code, allocate an array to hold the functions, load the
addresses from the Elf_Rela entries, sort them, then put them back in
order into the Elf_rela entries so that they will be sorted at boot up
without having to sort them during boot up.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/20250218200022.373319428@goodmis.org
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
(cherry picked from commit b3d09d06e052e1d754645acea4e4d1e96f81c934)
Assisted-by: Patchpal
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 534daec407ef..add6005c5e8b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -219,6 +219,7 @@ config ARM64
if DYNAMIC_FTRACE_WITH_ARGS
select HAVE_SAMPLE_FTRACE_DIRECT
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
+ select HAVE_BUILDTIME_MCOUNT_SORT
select HAVE_EFFICIENT_UNALIGNED_ACCESS
select HAVE_GUP_FAST
select HAVE_FTRACE_MCOUNT_RECORD
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 9f41575afd7a..4a34c275123e 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -28,6 +28,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
@@ -79,10 +80,16 @@ typedef union {
Elf64_Sym e64;
} Elf_Sym;
+typedef union {
+ Elf32_Rela e32;
+ Elf64_Rela e64;
+} Elf_Rela;
+
static uint32_t (*r)(const uint32_t *);
static uint16_t (*r2)(const uint16_t *);
static uint64_t (*r8)(const uint64_t *);
static void (*w)(uint32_t, uint32_t *);
+static void (*w8)(uint64_t, uint64_t *);
typedef void (*table_sort_t)(char *, int);
static struct elf_funcs {
@@ -102,6 +109,10 @@ static struct elf_funcs {
uint32_t (*sym_name)(Elf_Sym *sym);
uint64_t (*sym_value)(Elf_Sym *sym);
uint16_t (*sym_shndx)(Elf_Sym *sym);
+ uint64_t (*rela_offset)(Elf_Rela *rela);
+ uint64_t (*rela_info)(Elf_Rela *rela);
+ uint64_t (*rela_addend)(Elf_Rela *rela);
+ void (*rela_write_addend)(Elf_Rela *rela, uint64_t val);
} e;
static uint64_t ehdr64_shoff(Elf_Ehdr *ehdr)
@@ -262,6 +273,38 @@ SYM_ADDR(value)
SYM_WORD(name)
SYM_HALF(shndx)
+#define __maybe_unused __attribute__((__unused__))
+
+#define RELA_ADDR(fn_name) \
+static uint64_t rela64_##fn_name(Elf_Rela *rela) \
+{ \
+ return r8((uint64_t *)&rela->e64.r_##fn_name); \
+} \
+ \
+static uint64_t rela32_##fn_name(Elf_Rela *rela) \
+{ \
+ return r((uint32_t *)&rela->e32.r_##fn_name); \
+} \
+ \
+static uint64_t __maybe_unused rela_##fn_name(Elf_Rela *rela) \
+{ \
+ return e.rela_##fn_name(rela); \
+}
+
+RELA_ADDR(offset)
+RELA_ADDR(info)
+RELA_ADDR(addend)
+
+static void rela64_write_addend(Elf_Rela *rela, uint64_t val)
+{
+ w8(val, (uint64_t *)&rela->e64.r_addend);
+}
+
+static void rela32_write_addend(Elf_Rela *rela, uint64_t val)
+{
+ w(val, (uint32_t *)&rela->e32.r_addend);
+}
+
/*
* Get the whole file as a programming convenience in order to avoid
* malloc+lseek+read+free of many pieces. If successful, then mmap
@@ -341,6 +384,16 @@ static void wle(uint32_t val, uint32_t *x)
put_unaligned_le32(val, x);
}
+static void w8be(uint64_t val, uint64_t *x)
+{
+ put_unaligned_be64(val, x);
+}
+
+static void w8le(uint64_t val, uint64_t *x)
+{
+ put_unaligned_le64(val, x);
+}
+
/*
* Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
* the way to -256..-1, to avoid conflicting with real section
@@ -398,13 +451,12 @@ static inline void *get_index(void *start, int entsize, int index)
static int extable_ent_size;
static int long_size;
+#define ERRSTR_MAXSZ 256
#ifdef UNWINDER_ORC_ENABLED
/* ORC unwinder only support X86_64 */
#include <asm/orc_types.h>
-#define ERRSTR_MAXSZ 256
-
static char g_err[ERRSTR_MAXSZ];
static int *g_orc_ip_table;
static struct orc_entry *g_orc_table;
@@ -499,7 +551,19 @@ static void *sort_orctable(void *arg)
#endif
#ifdef MCOUNT_SORT_ENABLED
+
+/* Only used for sorting mcount table */
+static void rela_write_addend(Elf_Rela *rela, uint64_t val)
+{
+ e.rela_write_addend(rela, val);
+}
+
static pthread_t mcount_sort_thread;
+static bool sort_reloc;
+
+static long rela_type;
+
+static char m_err[ERRSTR_MAXSZ];
struct elf_mcount_loc {
Elf_Ehdr *ehdr;
@@ -508,6 +572,103 @@ struct elf_mcount_loc {
uint64_t stop_mcount_loc;
};
+/* Sort the relocations not the address itself */
+static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
+{
+ Elf_Shdr *shdr_start;
+ Elf_Rela *rel;
+ unsigned int shnum;
+ unsigned int count;
+ int shentsize;
+ void *vals;
+ void *ptr;
+
+ shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr));
+ shentsize = ehdr_shentsize(ehdr);
+
+ vals = malloc(long_size * size);
+ if (!vals) {
+ snprintf(m_err, ERRSTR_MAXSZ, "Failed to allocate sort array");
+ pthread_exit(m_err);
+ return NULL;
+ }
+
+ ptr = vals;
+
+ shnum = ehdr_shnum(ehdr);
+ if (shnum == SHN_UNDEF)
+ shnum = shdr_size(shdr_start);
+
+ for (int i = 0; i < shnum; i++) {
+ Elf_Shdr *shdr = get_index(shdr_start, shentsize, i);
+ void *end;
+
+ if (shdr_type(shdr) != SHT_RELA)
+ continue;
+
+ rel = (void *)ehdr + shdr_offset(shdr);
+ end = (void *)rel + shdr_size(shdr);
+
+ for (; (void *)rel < end; rel = (void *)rel + shdr_entsize(shdr)) {
+ uint64_t offset = rela_offset(rel);
+
+ if (offset >= start_loc && offset < start_loc + size) {
+ if (ptr + long_size > vals + size) {
+ free(vals);
+ snprintf(m_err, ERRSTR_MAXSZ,
+ "Too many relocations");
+ pthread_exit(m_err);
+ return NULL;
+ }
+
+ /* Make sure this has the correct type */
+ if (rela_info(rel) != rela_type) {
+ free(vals);
+ snprintf(m_err, ERRSTR_MAXSZ,
+ "rela has type %lx but expected %lx\n",
+ (long)rela_info(rel), rela_type);
+ pthread_exit(m_err);
+ return NULL;
+ }
+
+ if (long_size == 4)
+ *(uint32_t *)ptr = rela_addend(rel);
+ else
+ *(uint64_t *)ptr = rela_addend(rel);
+ ptr += long_size;
+ }
+ }
+ }
+ count = ptr - vals;
+ qsort(vals, count / long_size, long_size, compare_extable);
+
+ ptr = vals;
+ for (int i = 0; i < shnum; i++) {
+ Elf_Shdr *shdr = get_index(shdr_start, shentsize, i);
+ void *end;
+
+ if (shdr_type(shdr) != SHT_RELA)
+ continue;
+
+ rel = (void *)ehdr + shdr_offset(shdr);
+ end = (void *)rel + shdr_size(shdr);
+
+ for (; (void *)rel < end; rel = (void *)rel + shdr_entsize(shdr)) {
+ uint64_t offset = rela_offset(rel);
+
+ if (offset >= start_loc && offset < start_loc + size) {
+ if (long_size == 4)
+ rela_write_addend(rel, *(uint32_t *)ptr);
+ else
+ rela_write_addend(rel, *(uint64_t *)ptr);
+ ptr += long_size;
+ }
+ }
+ }
+ free(vals);
+ return NULL;
+}
+
/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
static void *sort_mcount_loc(void *arg)
{
@@ -517,6 +678,9 @@ static void *sort_mcount_loc(void *arg)
uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
unsigned char *start_loc = (void *)emloc->ehdr + offset;
+ if (sort_reloc)
+ return sort_relocs(emloc->ehdr, emloc->start_mcount_loc, count);
+
qsort(start_loc, count/long_size, long_size, compare_extable);
return NULL;
}
@@ -866,12 +1030,14 @@ static int do_file(char const *const fname, void *addr)
r2 = r2le;
r8 = r8le;
w = wle;
+ w8 = w8le;
break;
case ELFDATA2MSB:
r = rbe;
r2 = r2be;
r8 = r8be;
w = wbe;
+ w8 = w8be;
break;
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
@@ -887,8 +1053,13 @@ static int do_file(char const *const fname, void *addr)
}
switch (r2(&ehdr->e32.e_machine)) {
- case EM_386:
case EM_AARCH64:
+#ifdef MCOUNT_SORT_ENABLED
+ sort_reloc = true;
+ rela_type = 0x403;
+#endif
+ /* fallthrough */
+ case EM_386:
case EM_LOONGARCH:
case EM_RISCV:
case EM_S390:
@@ -932,6 +1103,10 @@ static int do_file(char const *const fname, void *addr)
.sym_name = sym32_name,
.sym_value = sym32_value,
.sym_shndx = sym32_shndx,
+ .rela_offset = rela32_offset,
+ .rela_info = rela32_info,
+ .rela_addend = rela32_addend,
+ .rela_write_addend = rela32_write_addend,
};
e = efuncs;
@@ -965,6 +1140,10 @@ static int do_file(char const *const fname, void *addr)
.sym_name = sym64_name,
.sym_value = sym64_value,
.sym_shndx = sym64_shndx,
+ .rela_offset = rela64_offset,
+ .rela_info = rela64_info,
+ .rela_addend = rela64_addend,
+ .rela_write_addend = rela64_write_addend,
};
e = efuncs;
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,103 @@
From 93c8c28c2ce439d598d5fd49d10a4bd5cb0401ea Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:57:27 +0200
Subject: [PATCH] scripts/sorttable: Have mcount rela sort use direct values
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit a0265659322540d656727b9e132edfb6f06b6c1a
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 18 14:59:20 2025 -0500
scripts/sorttable: Have mcount rela sort use direct values
The mcount_loc sorting for when the values are stored in the Elf_Rela
entries uses the compare_extable() function to do the compares in the
qsort(). That function does handle byte swapping if the machine being
compiled for is a different endian than the host machine. But the
sort_relocs() function sorts an array that pulled in the values from the
Elf_Rela section and has already done the swapping.
Create two new compare functions that will sort the direct values. One
will sort 32 bit values and the other will sort the 64 bit value. One of
these will be assigned to a compare_values function pointer and that will
be used for sorting the Elf_Rela mcount values.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/20250218200022.538888594@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 4a34c275123e..f62a91d8af0a 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -552,6 +552,28 @@ static void *sort_orctable(void *arg)
#ifdef MCOUNT_SORT_ENABLED
+static int compare_values_64(const void *a, const void *b)
+{
+ uint64_t av = *(uint64_t *)a;
+ uint64_t bv = *(uint64_t *)b;
+
+ if (av < bv)
+ return -1;
+ return av > bv;
+}
+
+static int compare_values_32(const void *a, const void *b)
+{
+ uint32_t av = *(uint32_t *)a;
+ uint32_t bv = *(uint32_t *)b;
+
+ if (av < bv)
+ return -1;
+ return av > bv;
+}
+
+static int (*compare_values)(const void *a, const void *b);
+
/* Only used for sorting mcount table */
static void rela_write_addend(Elf_Rela *rela, uint64_t val)
{
@@ -583,6 +605,8 @@ static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
void *vals;
void *ptr;
+ compare_values = long_size == 4 ? compare_values_32 : compare_values_64;
+
shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr));
shentsize = ehdr_shentsize(ehdr);
@@ -640,7 +664,7 @@ static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
}
}
count = ptr - vals;
- qsort(vals, count / long_size, long_size, compare_extable);
+ qsort(vals, count / long_size, long_size, compare_values);
ptr = vals;
for (int i = 0; i < shnum; i++) {
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,239 @@
From d39567e1f737a3f1959b0597eeeba7bdf25d0249 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:57:34 +0200
Subject: [PATCH] scripts/sorttable: Always use an array for the mcount_loc
sorting
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 5fb964f5ba53afda0e2b6dbc00b8205461ffe04a
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 18 14:59:21 2025 -0500
scripts/sorttable: Always use an array for the mcount_loc sorting
The sorting of the mcount_loc section is done directly to the section for
x86 and arm32 but it uses a separate array for arm64 as arm64 has the
values for the mcount_loc stored in the rela sections of the vmlinux ELF
file.
In order to use the same code to remove weak functions, always use a
separate array to do the sorting. This requires splitting up the filling
of the array into one function and the placing the contents of the array
back into the rela sections or into the mcount_loc section into a separate
file.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/20250218200022.710676551@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index f62a91d8af0a..ec02a2852efb 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -594,31 +594,19 @@ struct elf_mcount_loc {
uint64_t stop_mcount_loc;
};
-/* Sort the relocations not the address itself */
-static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
+/* Fill the array with the content of the relocs */
+static int fill_relocs(void *ptr, uint64_t size, Elf_Ehdr *ehdr, uint64_t start_loc)
{
Elf_Shdr *shdr_start;
Elf_Rela *rel;
unsigned int shnum;
- unsigned int count;
+ unsigned int count = 0;
int shentsize;
- void *vals;
- void *ptr;
-
- compare_values = long_size == 4 ? compare_values_32 : compare_values_64;
+ void *array_end = ptr + size;
shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr));
shentsize = ehdr_shentsize(ehdr);
- vals = malloc(long_size * size);
- if (!vals) {
- snprintf(m_err, ERRSTR_MAXSZ, "Failed to allocate sort array");
- pthread_exit(m_err);
- return NULL;
- }
-
- ptr = vals;
-
shnum = ehdr_shnum(ehdr);
if (shnum == SHN_UNDEF)
shnum = shdr_size(shdr_start);
@@ -637,22 +625,18 @@ static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
uint64_t offset = rela_offset(rel);
if (offset >= start_loc && offset < start_loc + size) {
- if (ptr + long_size > vals + size) {
- free(vals);
+ if (ptr + long_size > array_end) {
snprintf(m_err, ERRSTR_MAXSZ,
"Too many relocations");
- pthread_exit(m_err);
- return NULL;
+ return -1;
}
/* Make sure this has the correct type */
if (rela_info(rel) != rela_type) {
- free(vals);
snprintf(m_err, ERRSTR_MAXSZ,
"rela has type %lx but expected %lx\n",
(long)rela_info(rel), rela_type);
- pthread_exit(m_err);
- return NULL;
+ return -1;
}
if (long_size == 4)
@@ -660,13 +644,28 @@ static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
else
*(uint64_t *)ptr = rela_addend(rel);
ptr += long_size;
+ count++;
}
}
}
- count = ptr - vals;
- qsort(vals, count / long_size, long_size, compare_values);
+ return count;
+}
+
+/* Put the sorted vals back into the relocation elements */
+static void replace_relocs(void *ptr, uint64_t size, Elf_Ehdr *ehdr, uint64_t start_loc)
+{
+ Elf_Shdr *shdr_start;
+ Elf_Rela *rel;
+ unsigned int shnum;
+ int shentsize;
+
+ shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr));
+ shentsize = ehdr_shentsize(ehdr);
+
+ shnum = ehdr_shnum(ehdr);
+ if (shnum == SHN_UNDEF)
+ shnum = shdr_size(shdr_start);
- ptr = vals;
for (int i = 0; i < shnum; i++) {
Elf_Shdr *shdr = get_index(shdr_start, shentsize, i);
void *end;
@@ -689,8 +688,32 @@ static void *sort_relocs(Elf_Ehdr *ehdr, uint64_t start_loc, uint64_t size)
}
}
}
- free(vals);
- return NULL;
+}
+
+static int fill_addrs(void *ptr, uint64_t size, void *addrs)
+{
+ void *end = ptr + size;
+ int count = 0;
+
+ for (; ptr < end; ptr += long_size, addrs += long_size, count++) {
+ if (long_size == 4)
+ *(uint32_t *)ptr = r(addrs);
+ else
+ *(uint64_t *)ptr = r8(addrs);
+ }
+ return count;
+}
+
+static void replace_addrs(void *ptr, uint64_t size, void *addrs)
+{
+ void *end = ptr + size;
+
+ for (; ptr < end; ptr += long_size, addrs += long_size) {
+ if (long_size == 4)
+ w(*(uint32_t *)ptr, addrs);
+ else
+ w8(*(uint64_t *)ptr, addrs);
+ }
}
/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
@@ -699,14 +722,49 @@ static void *sort_mcount_loc(void *arg)
struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
uint64_t offset = emloc->start_mcount_loc - shdr_addr(emloc->init_data_sec)
+ shdr_offset(emloc->init_data_sec);
- uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
+ uint64_t size = emloc->stop_mcount_loc - emloc->start_mcount_loc;
unsigned char *start_loc = (void *)emloc->ehdr + offset;
+ Elf_Ehdr *ehdr = emloc->ehdr;
+ void *e_msg = NULL;
+ void *vals;
+ int count;
+
+ vals = malloc(long_size * size);
+ if (!vals) {
+ snprintf(m_err, ERRSTR_MAXSZ, "Failed to allocate sort array");
+ pthread_exit(m_err);
+ }
if (sort_reloc)
- return sort_relocs(emloc->ehdr, emloc->start_mcount_loc, count);
+ count = fill_relocs(vals, size, ehdr, emloc->start_mcount_loc);
+ else
+ count = fill_addrs(vals, size, start_loc);
+
+ if (count < 0) {
+ e_msg = m_err;
+ goto out;
+ }
+
+ if (count != size / long_size) {
+ snprintf(m_err, ERRSTR_MAXSZ, "Expected %u mcount elements but found %u\n",
+ (int)(size / long_size), count);
+ e_msg = m_err;
+ goto out;
+ }
+
+ compare_values = long_size == 4 ? compare_values_32 : compare_values_64;
+
+ qsort(vals, count, long_size, compare_values);
+
+ if (sort_reloc)
+ replace_relocs(vals, size, ehdr, emloc->start_mcount_loc);
+ else
+ replace_addrs(vals, size, start_loc);
+
+out:
+ free(vals);
- qsort(start_loc, count/long_size, long_size, compare_extable);
- return NULL;
+ pthread_exit(e_msg);
}
/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,316 @@
From 8cde64d5091653560e13e7cd34a385258372db58 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Mon, 1 Jun 2026 15:57:38 +0200
Subject: [PATCH] scripts/sorttable: Zero out weak functions in mcount_loc
table
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit ef378c3b8233855497a414b9d67bf22592c928a4
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 18 14:59:22 2025 -0500
scripts/sorttable: Zero out weak functions in mcount_loc table
When a function is annotated as "weak" and is overridden, the code is not
removed. If it is traced, the fentry/mcount location in the weak function
will be referenced by the "__mcount_loc" section. This will then be added
to the available_filter_functions list. Since only the address of the
functions are listed, to find the name to show, a search of kallsyms is
used.
Since kallsyms will return the function by simply finding the function
that the address is after but before the next function, an address of a
weak function will show up as the function before it. This is because
kallsyms does not save names of weak functions. This has caused issues in
the past, as now the traced weak function will be listed in
available_filter_functions with the name of the function before it.
At best, this will cause the previous function's name to be listed twice.
At worse, if the previous function was marked notrace, it will now show up
as a function that can be traced. Note that it only shows up that it can
be traced but will not be if enabled, which causes confusion.
https://lore.kernel.org/all/20220412094923.0abe90955e5db486b7bca279@kernel.org/
The commit b39181f7c6907 ("ftrace: Add FTRACE_MCOUNT_MAX_OFFSET to avoid
adding weak function") was a workaround to this by checking the function
address before printing its name. If the address was too far from the
function given by the name then instead of printing the name it would
print: __ftrace_invalid_address___<invalid-offset>
The real issue is that these invalid addresses are listed in the ftrace
table look up which available_filter_functions is derived from. A place
holder must be listed in that file because set_ftrace_filter may take a
series of indexes into that file instead of names to be able to do O(1)
lookups to enable filtering (many tools use this method).
Even if kallsyms saved the size of the function, it does not remove the
need of having these place holders. The real solution is to not add a weak
function into the ftrace table in the first place.
To solve this, the sorttable.c code that sorts the mcount regions during
the build is modified to take a "nm -S vmlinux" input, sort it, and any
function listed in the mcount_loc section that is not within a boundary of
the function list given by nm is considered a weak function and is zeroed
out.
Note, this does not mean they will remain zero when booting as KASLR
will still shift those addresses. To handle this, the entries in the
mcount_loc section will be ignored if they are zero or match the
kaslr_offset() value.
Before:
~# grep __ftrace_invalid_address___ /sys/kernel/tracing/available_filter_functions | wc -l
551
After:
~# grep __ftrace_invalid_address___ /sys/kernel/tracing/available_filter_functions | wc -l
0
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/20250218200022.883095980@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 57b8fad660cf..792c57d1f0b9 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -7052,6 +7052,7 @@ static int ftrace_process_locs(struct module *mod,
unsigned long count;
unsigned long *p;
unsigned long addr;
+ unsigned long kaslr;
unsigned long flags = 0; /* Shut up gcc */
int ret = -ENOMEM;
@@ -7100,6 +7101,9 @@ static int ftrace_process_locs(struct module *mod,
ftrace_pages->next = start_pg;
}
+ /* For zeroed locations that were shifted for core kernel */
+ kaslr = !mod ? kaslr_offset() : 0;
+
p = start;
pg = start_pg;
while (p < end) {
@@ -7111,7 +7115,7 @@ static int ftrace_process_locs(struct module *mod,
* object files to satisfy alignments.
* Skip any NULL pointers.
*/
- if (!addr) {
+ if (!addr || addr == kaslr) {
skipped++;
continue;
}
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index cdf16029fc58..8619ae612997 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -174,12 +174,14 @@ mksysmap()
sorttable()
{
- ${objtree}/scripts/sorttable ${1}
+ ${NM} -S ${1} > .tmp_vmlinux.nm-sort
+ ${objtree}/scripts/sorttable -s .tmp_vmlinux.nm-sort ${1}
}
cleanup()
{
rm -f .btf.*
+ rm -f .tmp_vmlinux.nm-sort
rm -f System.map
rm -f vmlinux
rm -f vmlinux.map
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index ec02a2852efb..23c7e0e6c024 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -580,6 +580,98 @@ static void rela_write_addend(Elf_Rela *rela, uint64_t val)
e.rela_write_addend(rela, val);
}
+struct func_info {
+ uint64_t addr;
+ uint64_t size;
+};
+
+/* List of functions created by: nm -S vmlinux */
+static struct func_info *function_list;
+static int function_list_size;
+
+/* Allocate functions in 1k blocks */
+#define FUNC_BLK_SIZE 1024
+#define FUNC_BLK_MASK (FUNC_BLK_SIZE - 1)
+
+static int add_field(uint64_t addr, uint64_t size)
+{
+ struct func_info *fi;
+ int fsize = function_list_size;
+
+ if (!(fsize & FUNC_BLK_MASK)) {
+ fsize += FUNC_BLK_SIZE;
+ fi = realloc(function_list, fsize * sizeof(struct func_info));
+ if (!fi)
+ return -1;
+ function_list = fi;
+ }
+ fi = &function_list[function_list_size++];
+ fi->addr = addr;
+ fi->size = size;
+ return 0;
+}
+
+/* Only return match if the address lies inside the function size */
+static int cmp_func_addr(const void *K, const void *A)
+{
+ uint64_t key = *(const uint64_t *)K;
+ const struct func_info *a = A;
+
+ if (key < a->addr)
+ return -1;
+ return key >= a->addr + a->size;
+}
+
+/* Find the function in function list that is bounded by the function size */
+static int find_func(uint64_t key)
+{
+ return bsearch(&key, function_list, function_list_size,
+ sizeof(struct func_info), cmp_func_addr) != NULL;
+}
+
+static int cmp_funcs(const void *A, const void *B)
+{
+ const struct func_info *a = A;
+ const struct func_info *b = B;
+
+ if (a->addr < b->addr)
+ return -1;
+ return a->addr > b->addr;
+}
+
+static int parse_symbols(const char *fname)
+{
+ FILE *fp;
+ char addr_str[20]; /* Only need 17, but round up to next int size */
+ char size_str[20];
+ char type;
+
+ fp = fopen(fname, "r");
+ if (!fp) {
+ perror(fname);
+ return -1;
+ }
+
+ while (fscanf(fp, "%16s %16s %c %*s\n", addr_str, size_str, &type) == 3) {
+ uint64_t addr;
+ uint64_t size;
+
+ /* Only care about functions */
+ if (type != 't' && type != 'T' && type != 'W')
+ continue;
+
+ addr = strtoull(addr_str, NULL, 16);
+ size = strtoull(size_str, NULL, 16);
+ if (add_field(addr, size) < 0)
+ return -1;
+ }
+ fclose(fp);
+
+ qsort(function_list, function_list_size, sizeof(struct func_info), cmp_funcs);
+
+ return 0;
+}
+
static pthread_t mcount_sort_thread;
static bool sort_reloc;
@@ -752,6 +844,21 @@ static void *sort_mcount_loc(void *arg)
goto out;
}
+ /* zero out any locations not found by function list */
+ if (function_list_size) {
+ for (void *ptr = vals; ptr < vals + size; ptr += long_size) {
+ uint64_t key;
+
+ key = long_size == 4 ? r((uint32_t *)ptr) : r8((uint64_t *)ptr);
+ if (!find_func(key)) {
+ if (long_size == 4)
+ *(uint32_t *)ptr = 0;
+ else
+ *(uint64_t *)ptr = 0;
+ }
+ }
+ }
+
compare_values = long_size == 4 ? compare_values_32 : compare_values_64;
qsort(vals, count, long_size, compare_values);
@@ -801,6 +908,8 @@ static void get_mcount_loc(struct elf_mcount_loc *emloc, Elf_Shdr *symtab_sec,
return;
}
}
+#else /* MCOUNT_SORT_ENABLED */
+static inline int parse_symbols(const char *fname) { return 0; }
#endif
static int do_sort(Elf_Ehdr *ehdr,
@@ -1256,14 +1365,29 @@ int main(int argc, char *argv[])
int i, n_error = 0; /* gcc-4.3.0 false positive complaint */
size_t size = 0;
void *addr = NULL;
+ int c;
+
+ while ((c = getopt(argc, argv, "s:")) >= 0) {
+ switch (c) {
+ case 's':
+ if (parse_symbols(optarg) < 0) {
+ fprintf(stderr, "Could not parse %s\n", optarg);
+ return -1;
+ }
+ break;
+ default:
+ fprintf(stderr, "usage: sorttable [-s nm-file] vmlinux...\n");
+ return 0;
+ }
+ }
- if (argc < 2) {
+ if ((argc - optind) < 1) {
fprintf(stderr, "usage: sorttable vmlinux...\n");
return 0;
}
/* Process each file in turn, allowing deep failure. */
- for (i = 1; i < argc; i++) {
+ for (i = optind; i < argc; i++) {
addr = mmap_file(argv[i], &size);
if (!addr) {
++n_error;
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,78 @@
From fb85259106c9afdbf7808aecc128d41aacab22ea Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Tue, 2 Jun 2026 15:40:50 +0200
Subject: [PATCH] ftrace: Update the mcount_loc check of skipped entries
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 4a3efc6baff931da9a85c6d2e42c87bd9a827399
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 18 14:59:23 2025 -0500
ftrace: Update the mcount_loc check of skipped entries
Now that weak functions turn into skipped entries, update the check to
make sure the amount that was allocated would fit both the entries that
were allocated as well as those that were skipped.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/20250218200023.055162048@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 792c57d1f0b9..4956ad9f9a20 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -7159,7 +7159,28 @@ static int ftrace_process_locs(struct module *mod,
/* We should have used all pages unless we skipped some */
if (pg_unuse) {
- WARN_ON(!skipped);
+ unsigned long pg_remaining, remaining = 0;
+ unsigned long skip;
+
+ /* Count the number of entries unused and compare it to skipped. */
+ pg_remaining = (ENTRIES_PER_PAGE << pg->order) - pg->index;
+
+ if (!WARN(skipped < pg_remaining, "Extra allocated pages for ftrace")) {
+
+ skip = skipped - pg_remaining;
+
+ for (pg = pg_unuse; pg; pg = pg->next)
+ remaining += 1 << pg->order;
+
+ skip = DIV_ROUND_UP(skip, ENTRIES_PER_PAGE);
+
+ /*
+ * Check to see if the number of pages remaining would
+ * just fit the number of entries skipped.
+ */
+ WARN(skip != remaining, "Extra allocated pages for ftrace: %lu with %lu skipped",
+ remaining, skipped);
+ }
/* Need to synchronize with ftrace_location_range() */
synchronize_rcu();
ftrace_free_pages(pg_unuse);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,115 @@
From d705caa45a6f9061420687f3d7d86f28e35881e2 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Tue, 2 Jun 2026 15:40:54 +0200
Subject: [PATCH] ftrace: Have ftrace pages output reflect freed pages
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 264143c4e54412095f4b615e65bf736fc3c60af0
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 18 14:59:24 2025 -0500
ftrace: Have ftrace pages output reflect freed pages
The amount of memory that ftrace uses to save the descriptors to manage
the functions it can trace is shown at output. But if there are a lot of
functions that are skipped because they were weak or the architecture
added holes into the tables, then the extra pages that were allocated are
freed. But these freed pages are not reflected in the numbers shown, and
they can even be inconsistent with what is reported:
ftrace: allocating 57482 entries in 225 pages
ftrace: allocated 224 pages with 3 groups
The above shows the number of original entries that are in the mcount_loc
section and the pages needed to save them (225), but the second output
reflects the number of pages that were actually used. The two should be
consistent as:
ftrace: allocating 56739 entries in 224 pages
ftrace: allocated 224 pages with 3 groups
The above also shows the accurate number of entires that were actually
stored and does not include the entries that were removed.
Cc: bpf <bpf@vger.kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Zheng Yejian <zhengyejian1@huawei.com>
Cc: Martin Kelly <martin.kelly@crowdstrike.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/20250218200023.221100846@goodmis.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 4956ad9f9a20..5e131970a70e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -7054,6 +7054,7 @@ static int ftrace_process_locs(struct module *mod,
unsigned long addr;
unsigned long kaslr;
unsigned long flags = 0; /* Shut up gcc */
+ unsigned long pages;
int ret = -ENOMEM;
count = end - start;
@@ -7061,6 +7062,8 @@ static int ftrace_process_locs(struct module *mod,
if (!count)
return 0;
+ pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);
+
/*
* Sorting mcount in vmlinux at build time depend on
* CONFIG_BUILDTIME_MCOUNT_SORT, while mcount loc in
@@ -7172,6 +7175,8 @@ static int ftrace_process_locs(struct module *mod,
for (pg = pg_unuse; pg; pg = pg->next)
remaining += 1 << pg->order;
+ pages -= remaining;
+
skip = DIV_ROUND_UP(skip, ENTRIES_PER_PAGE);
/*
@@ -7185,6 +7190,13 @@ static int ftrace_process_locs(struct module *mod,
synchronize_rcu();
ftrace_free_pages(pg_unuse);
}
+
+ if (!mod) {
+ count -= skipped;
+ pr_info("ftrace: allocating %ld entries in %ld pages\n",
+ count, pages);
+ }
+
return ret;
}
@@ -7836,9 +7848,6 @@ void __init ftrace_init(void)
goto failed;
}
- pr_info("ftrace: allocating %ld entries in %ld pages\n",
- count, DIV_ROUND_UP(count, ENTRIES_PER_PAGE));
-
ret = ftrace_process_locs(NULL,
__start_mcount_loc,
__stop_mcount_loc);
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,166 @@
From 7a2ec4e50744d195d6a66868ef6f3fb39f15b8b7 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Tue, 2 Jun 2026 15:56:18 +0200
Subject: [PATCH] ftrace: Do not over-allocate ftrace memory
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit be55257fab181b93af38f8c4b1b3cb453a78d742
Author: Guenter Roeck <linux@roeck-us.net>
Date: Tue Jan 13 07:22:42 2026 -0800
ftrace: Do not over-allocate ftrace memory
The pg_remaining calculation in ftrace_process_locs() assumes that
ENTRIES_PER_PAGE multiplied by 2^order equals the actual capacity of the
allocated page group. However, ENTRIES_PER_PAGE is PAGE_SIZE / ENTRY_SIZE
(integer division). When PAGE_SIZE is not a multiple of ENTRY_SIZE (e.g.
4096 / 24 = 170 with remainder 16), high-order allocations (like 256 pages)
have significantly more capacity than 256 * 170. This leads to pg_remaining
being underestimated, which in turn makes skip (derived from skipped -
pg_remaining) larger than expected, causing the WARN(skip != remaining)
to trigger.
Extra allocated pages for ftrace: 2 with 654 skipped
WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7295 ftrace_process_locs+0x5bf/0x5e0
A similar problem in ftrace_allocate_records() can result in allocating
too many pages. This can trigger the second warning in
ftrace_process_locs().
Extra allocated pages for ftrace
WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7276 ftrace_process_locs+0x548/0x580
Use the actual capacity of a page group to determine the number of pages
to allocate. Have ftrace_allocate_pages() return the number of allocated
pages to avoid having to calculate it. Use the actual page group capacity
when validating the number of unused pages due to skipped entries.
Drop the definition of ENTRIES_PER_PAGE since it is no longer used.
Cc: stable@vger.kernel.org
Fixes: 4a3efc6baff93 ("ftrace: Update the mcount_loc check of skipped entries")
Link: https://patch.msgid.link/20260113152243.3557219-1-linux@roeck-us.net
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 5e131970a70e..877f943832c9 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1122,7 +1122,6 @@ struct ftrace_page {
};
#define ENTRY_SIZE sizeof(struct dyn_ftrace)
-#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE)
static struct ftrace_page *ftrace_pages_start;
static struct ftrace_page *ftrace_pages;
@@ -3754,7 +3753,8 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
return 0;
}
-static int ftrace_allocate_records(struct ftrace_page *pg, int count)
+static int ftrace_allocate_records(struct ftrace_page *pg, int count,
+ unsigned long *num_pages)
{
int order;
int pages;
@@ -3764,7 +3764,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
return -EINVAL;
/* We want to fill as much as possible, with no empty pages */
- pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);
+ pages = DIV_ROUND_UP(count * ENTRY_SIZE, PAGE_SIZE);
order = fls(pages) - 1;
again:
@@ -3779,6 +3779,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
}
ftrace_number_of_pages += 1 << order;
+ *num_pages += 1 << order;
ftrace_number_of_groups++;
cnt = (PAGE_SIZE << order) / ENTRY_SIZE;
@@ -3807,12 +3808,14 @@ static void ftrace_free_pages(struct ftrace_page *pages)
}
static struct ftrace_page *
-ftrace_allocate_pages(unsigned long num_to_init)
+ftrace_allocate_pages(unsigned long num_to_init, unsigned long *num_pages)
{
struct ftrace_page *start_pg;
struct ftrace_page *pg;
int cnt;
+ *num_pages = 0;
+
if (!num_to_init)
return NULL;
@@ -3826,7 +3829,7 @@ ftrace_allocate_pages(unsigned long num_to_init)
* waste as little space as possible.
*/
for (;;) {
- cnt = ftrace_allocate_records(pg, num_to_init);
+ cnt = ftrace_allocate_records(pg, num_to_init, num_pages);
if (cnt < 0)
goto free_pages;
@@ -7062,8 +7065,6 @@ static int ftrace_process_locs(struct module *mod,
if (!count)
return 0;
- pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);
-
/*
* Sorting mcount in vmlinux at build time depend on
* CONFIG_BUILDTIME_MCOUNT_SORT, while mcount loc in
@@ -7076,7 +7077,7 @@ static int ftrace_process_locs(struct module *mod,
test_is_sorted(start, count);
}
- start_pg = ftrace_allocate_pages(count);
+ start_pg = ftrace_allocate_pages(count, &pages);
if (!start_pg)
return -ENOMEM;
@@ -7163,27 +7164,27 @@ static int ftrace_process_locs(struct module *mod,
/* We should have used all pages unless we skipped some */
if (pg_unuse) {
unsigned long pg_remaining, remaining = 0;
- unsigned long skip;
+ long skip;
/* Count the number of entries unused and compare it to skipped. */
- pg_remaining = (ENTRIES_PER_PAGE << pg->order) - pg->index;
+ pg_remaining = (PAGE_SIZE << pg->order) / ENTRY_SIZE - pg->index;
if (!WARN(skipped < pg_remaining, "Extra allocated pages for ftrace")) {
skip = skipped - pg_remaining;
- for (pg = pg_unuse; pg; pg = pg->next)
+ for (pg = pg_unuse; pg && skip > 0; pg = pg->next) {
remaining += 1 << pg->order;
+ skip -= (PAGE_SIZE << pg->order) / ENTRY_SIZE;
+ }
pages -= remaining;
- skip = DIV_ROUND_UP(skip, ENTRIES_PER_PAGE);
-
/*
* Check to see if the number of pages remaining would
* just fit the number of entries skipped.
*/
- WARN(skip != remaining, "Extra allocated pages for ftrace: %lu with %lu skipped",
+ WARN(pg || skip > 0, "Extra allocated pages for ftrace: %lu with %lu skipped",
remaining, skipped);
}
/* Need to synchronize with ftrace_location_range() */
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,66 @@
From 611153910e7701fddefdbc91f75953b89e698331 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Tue, 2 Jun 2026 15:56:21 +0200
Subject: [PATCH] ftrace: Test mcount_loc addr before calling
ftrace_call_addr()
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 6eeca746fa5f1dd03c6ee05cb03f5eb1ddda1c81
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 25 13:20:05 2025 -0500
ftrace: Test mcount_loc addr before calling ftrace_call_addr()
The addresses in the mcount_loc can be zeroed and then moved by KASLR
making them invalid addresses. ftrace_call_addr() for ARM 64 expects a
valid address to kernel text. If the addr read from the mcount_loc section
is invalid, it must not call ftrace_call_addr(). Move the addr check
before calling ftrace_call_addr() in ftrace_process_locs().
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/20250225182054.290128736@goodmis.org
Fixes: ef378c3b8233 ("scripts/sorttable: Zero out weak functions in mcount_loc table")
Reported-by: Nathan Chancellor <nathan@kernel.org>
Reported-by: "Arnd Bergmann" <arnd@arndb.de>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Closes: https://lore.kernel.org/all/20250225025631.GA271248@ax162/
Closes: https://lore.kernel.org/all/91523154-072b-437b-bbdc-0b70e9783fd0@app.fastmail.com/
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 877f943832c9..59069b58fcd4 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -7112,7 +7112,9 @@ static int ftrace_process_locs(struct module *mod,
pg = start_pg;
while (p < end) {
unsigned long end_offset;
- addr = ftrace_call_adjust(*p++);
+
+ addr = *p++;
+
/*
* Some architecture linkers will pad between
* the different mcount_loc sections of different
@@ -7124,6 +7126,8 @@ static int ftrace_process_locs(struct module *mod,
continue;
}
+ addr = ftrace_call_adjust(addr);
+
end_offset = (pg->index+1) * sizeof(pg->records[0]);
if (end_offset > PAGE_SIZE << pg->order) {
/* We should have allocated enough */
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,85 @@
From 4460650d8c24b8689e42d47abeff7fe520f911a3 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Tue, 2 Jun 2026 15:56:25 +0200
Subject: [PATCH] ftrace: Check against is_kernel_text() instead of
kaslr_offset()
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit da0f622b344be769ed61e7c1caf95cd0cdb47964
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 25 13:20:06 2025 -0500
ftrace: Check against is_kernel_text() instead of kaslr_offset()
As kaslr_offset() is architecture dependent and also may not be defined by
all architectures, when zeroing out unused weak functions, do not check
against kaslr_offset(), but instead check if the address is within the
kernel text sections. If KASLR added a shift to the zeroed out function,
it would still not be located in the kernel text. This is a more robust
way to test if the text is valid or not.
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: "Arnd Bergmann" <arnd@arndb.de>
Link: https://lore.kernel.org/20250225182054.471759017@goodmis.org
Fixes: ef378c3b8233 ("scripts/sorttable: Zero out weak functions in mcount_loc table")
Reported-by: Nathan Chancellor <nathan@kernel.org>
Reported-by: Mark Brown <broonie@kernel.org>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Closes: https://lore.kernel.org/all/20250224180805.GA1536711@ax162/
Closes: https://lore.kernel.org/all/5225b07b-a9b2-4558-9d5f-aa60b19f6317@sirena.org.uk/
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 59069b58fcd4..63ed9688f491 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -7055,7 +7055,6 @@ static int ftrace_process_locs(struct module *mod,
unsigned long count;
unsigned long *p;
unsigned long addr;
- unsigned long kaslr;
unsigned long flags = 0; /* Shut up gcc */
unsigned long pages;
int ret = -ENOMEM;
@@ -7105,9 +7104,6 @@ static int ftrace_process_locs(struct module *mod,
ftrace_pages->next = start_pg;
}
- /* For zeroed locations that were shifted for core kernel */
- kaslr = !mod ? kaslr_offset() : 0;
-
p = start;
pg = start_pg;
while (p < end) {
@@ -7121,7 +7117,18 @@ static int ftrace_process_locs(struct module *mod,
* object files to satisfy alignments.
* Skip any NULL pointers.
*/
- if (!addr || addr == kaslr) {
+ if (!addr) {
+ skipped++;
+ continue;
+ }
+
+ /*
+ * If this is core kernel, make sure the address is in core
+ * or inittext, as weak functions get zeroed and KASLR can
+ * move them to something other than zero. It just will not
+ * move it to an area where kernel text is.
+ */
+ if (!mod && !(is_kernel_text(addr) || is_kernel_inittext(addr))) {
skipped++;
continue;
}
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,67 @@
From 5c8bd640b0ee1f1e0d7137f122996180f9bd5590 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Tue, 2 Jun 2026 15:56:27 +0200
Subject: [PATCH] scripts/sorttable: Use normal sort if theres no relocs in the
mcount section
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 46514b3c2c17c67cefe84b0c1a59e0aaf6093131
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 25 13:20:07 2025 -0500
scripts/sorttable: Use normal sort if theres no relocs in the mcount section
When ARM 64 is compiled with gcc, the mcount_loc section will be filled
with zeros and the addresses will be located in the Elf_Rela sections. To
sort the mcount_loc section, the addresses from the Elf_Rela need to be
placed into an array and that is sorted.
But when ARM 64 is compiled with clang, it does it the same way as other
architectures and leaves the addresses as is in the mcount_loc section.
To handle both cases, ARM 64 will first try to sort the Elf_Rela section,
and if it doesn't find any functions, it will then fall back to the
sorting of the addresses in the mcount_loc section itself.
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/20250225182054.648398403@goodmis.org
Fixes: b3d09d06e052 ("arm64: scripts/sorttable: Implement sorting mcount_loc at boot for arm64")
Reported-by: "Arnd Bergmann" <arnd@arndb.de>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Closes: https://lore.kernel.org/all/893cd8f1-8585-4d25-bf0f-4197bf872465@app.fastmail.com/
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 23c7e0e6c024..07ad8116bc8d 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -827,9 +827,14 @@ static void *sort_mcount_loc(void *arg)
pthread_exit(m_err);
}
- if (sort_reloc)
+ if (sort_reloc) {
count = fill_relocs(vals, size, ehdr, emloc->start_mcount_loc);
- else
+ /* gcc may use relocs to save the addresses, but clang does not. */
+ if (!count) {
+ count = fill_addrs(vals, size, start_loc);
+ sort_reloc = 0;
+ }
+ } else
count = fill_addrs(vals, size, start_loc);
if (count < 0) {
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,73 @@
From 7d08b5aa28b2bdd1d1bedbd6e8722bf3799dce71 Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Tue, 2 Jun 2026 15:56:31 +0200
Subject: [PATCH] scripts/sorttable: Allow matches to functions before function
entry
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit dc208c69c033d3caba0509da1ae065d2b5ff165f
Author: Steven Rostedt <rostedt@goodmis.org>
Date: Tue Feb 25 13:20:08 2025 -0500
scripts/sorttable: Allow matches to functions before function entry
ARM 64 uses -fpatchable-function-entry=4,2 which adds padding before the
function and the addresses in the mcount_loc point there instead of the
function entry that is returned by nm. In order to find a function from nm
to make sure it's not an unused weak function, the entries in the
mcount_loc section needs to match the entries from nm. Since it can be an
instruction before the entry, add a before_func variable that ARM 64 can
set to 8, and if the mcount_loc entry is within 8 bytes of the nm function
entry, then it will be considered a match.
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: "Arnd Bergmann" <arnd@arndb.de>
Cc: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/20250225182054.815536219@goodmis.org
Fixes: ef378c3b82338 ("scripts/sorttable: Zero out weak functions in mcount_loc table")
Tested-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 07ad8116bc8d..7b4b3714b1af 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -611,13 +611,16 @@ static int add_field(uint64_t addr, uint64_t size)
return 0;
}
+/* Used for when mcount/fentry is before the function entry */
+static int before_func;
+
/* Only return match if the address lies inside the function size */
static int cmp_func_addr(const void *K, const void *A)
{
uint64_t key = *(const uint64_t *)K;
const struct func_info *a = A;
- if (key < a->addr)
+ if (key + before_func < a->addr)
return -1;
return key >= a->addr + a->size;
}
@@ -1253,6 +1256,8 @@ static int do_file(char const *const fname, void *addr)
#ifdef MCOUNT_SORT_ENABLED
sort_reloc = true;
rela_type = 0x403;
+ /* arm64 uses patchable function entry placing before function */
+ before_func = 8;
#endif
/* fallthrough */
case EM_386:
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,55 @@
From 3436470d40a0906b91d65287931fc22524334dba Mon Sep 17 00:00:00 2001
From: Jerome Marchand <jmarchan@redhat.com>
Date: Tue, 2 Jun 2026 15:56:34 +0200
Subject: [PATCH] scripts/sorttable: Fix endianness handling in build-time
mcount sort
JIRA: https://redhat.atlassian.net/browse/RHEL-180193
commit 023f124a64174c47e18340ded7e2a39b96eb9523
Author: Vasily Gorbik <gor@linux.ibm.com>
Date: Wed Apr 2 03:15:35 2025 +0200
scripts/sorttable: Fix endianness handling in build-time mcount sort
Kernel cross-compilation with BUILDTIME_MCOUNT_SORT produces zeroed
mcount values if the build-host endianness does not match the ELF
file endianness.
The mcount values array is converted from ELF file
endianness to build-host endianness during initialization in
fill_relocs()/fill_addrs(). Avoid extra conversion of these values during
weak-function zeroing; otherwise, they do not match nm-parsed addresses
and all mcount values are zeroed out.
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/patch.git-dca31444b0f1.your-ad-here.call-01743554658-ext-8692@work.hours
Fixes: ef378c3b8233 ("scripts/sorttable: Zero out weak functions in mcount_loc table")
Reported-by: Ilya Leoshkevich <iii@linux.ibm.com>
Reported-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Closes: https://lore.kernel.org/all/your-ad-here.call-01743522822-ext-4975@work.hours/
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 7b4b3714b1af..deed676bfe38 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -857,7 +857,7 @@ static void *sort_mcount_loc(void *arg)
for (void *ptr = vals; ptr < vals + size; ptr += long_size) {
uint64_t key;
- key = long_size == 4 ? r((uint32_t *)ptr) : r8((uint64_t *)ptr);
+ key = long_size == 4 ? *(uint32_t *)ptr : *(uint64_t *)ptr;
if (!find_func(key)) {
if (long_size == 4)
*(uint32_t *)ptr = 0;
--
2.50.1 (Apple Git-155)

View File

@ -176,13 +176,13 @@ Summary: The Linux kernel
%define specrpmversion 6.12.0
%define specversion 6.12.0
%define patchversion 6.12
%define pkgrelease 211.7.1
%define pkgrelease 211.22.1
%define kversion 6
%define tarfile_release 6.12.0-211.7.1.el10_2
# This is needed to do merge window version magic
%define patchlevel 12
# This allows pkg_release to have configurable %%{?dist} tag
%define specrelease 211.20.1%{?buildid}%{?dist}
%define specrelease 211.22.1%{?buildid}%{?dist}
# This defines the kabi tarball version
%define kabiversion 6.12.0-211.7.1.el10_2
@ -1322,6 +1322,70 @@ Patch1284: 1284-smb-client-fix-oob-reads-parsing-symlink-error-response.patch
Patch1285: 1285-sched-deadline-fix-dl-server-time-accounting.patch
Patch1286: 1286-redhat-configs-automotive-disable-config-io-uring.patch
Patch1287: 1287-rhel-kabi-dpll-adaptation.patch
Patch1288: 1288-net-bonding-fix-use-after-free-in-bond-xmit-broadcast.patch
Patch1289: 1289-s390-pci-avoid-deadlock-between-pci-error-recovery-and-mlx5-.patch
Patch1290: 1290-ice-fix-stats-array-overflow-when-vf-requests-more-queues.patch
Patch1291: 1291-s390-dasd-fix-gendisk-parent-after-copy-pair-swap.patch
Patch1292: 1292-s390-dasd-move-quiesce-state-with-pprc-swap.patch
Patch1293: 1293-s390-dasd-copy-detected-format-information-to-secondary-devi.patch
Patch1294: 1294-nouveau-gsp-drop-warn-on-in-acpi-probes.patch
Patch1295: 1295-can-raw-fix-ro-uniq-use-after-free-in-raw-rcv.patch
Patch1296: 1296-erofs-add-gfp-noio-in-the-bio-completion-if-needed.patch
Patch1297: 1297-alsa-6fire-fix-use-after-free-on-disconnect.patch
Patch1298: 1298-ip6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch
Patch1299: 1299-ipv6-rpl-reserve-mac-len-headroom-when-recompressed-srh-grow.patch
Patch1300: 1300-fs-constify-file-ptr-in-backing-file-accessor-helpers.patch
Patch1301: 1301-lsm-split-the-notifier-code-out-into-lsm-notifier-c.patch
Patch1302: 1302-lsm-split-the-init-code-out-into-lsm-init-c.patch
Patch1303: 1303-lsm-consolidate-lsm-allowed-and-prepare-lsm-into-lsm-prepare.patch
Patch1304: 1304-lsm-introduce-looping-macros-for-the-initialization-code.patch
Patch1305: 1305-lsm-integrate-report-lsm-order-code-into-caller.patch
Patch1306: 1306-lsm-integrate-lsm-early-cred-and-lsm-early-task-into-caller.patch
Patch1307: 1307-lsm-rename-ordered-lsm-init-to-lsm-init-ordered.patch
Patch1308: 1308-lsm-replace-the-name-field-with-a-pointer-to-the-lsm-id-stru.patch
Patch1309: 1309-lsm-rename-the-lsm-order-variables-for-consistency.patch
Patch1310: 1310-lsm-rework-lsm-active-cnt-and-lsm-idlist.patch
Patch1311: 1311-lsm-get-rid-of-the-lsm-names-list-and-do-some-cleanup.patch
Patch1312: 1312-lsm-rework-the-lsm-enable-disable-setter-getter-functions.patch
Patch1313: 1313-lsm-rename-exists-ordered-lsm-to-lsm-order-exists.patch
Patch1314: 1314-lsm-rename-rework-append-ordered-lsm-into-lsm-order-append.patch
Patch1315: 1315-lsm-rename-rework-ordered-lsm-parse-to-lsm-order-parse.patch
Patch1316: 1316-lsm-cleanup-the-lsm-blob-size-code.patch
Patch1317: 1317-lsm-cleanup-initialize-lsm-and-rename-to-lsm-init-single.patch
Patch1318: 1318-lsm-fold-lsm-init-ordered-into-security-init.patch
Patch1319: 1319-lsm-add-tweak-function-header-comment-blocks-in-lsm-init-c.patch
Patch1320: 1320-lsm-cleanup-the-debug-and-console-output-in-lsm-init-c.patch
Patch1321: 1321-fs-prepare-for-adding-lsm-blob-to-backing-file.patch
Patch1322: 1322-lsm-add-backing-file-lsm-hooks.patch
Patch1323: 1323-selinux-fix-overlayfs-mmap-and-mprotect-access-checks.patch
Patch1324: 1324-scripts-sorttable-fix-orc-sort-cmp-to-maintain-symmetry-and-.patch
Patch1325: 1325-scripts-sorttable-remove-unused-macro-defines.patch
Patch1326: 1326-scripts-sorttable-remove-unused-write-functions.patch
Patch1327: 1327-scripts-sorttable-remove-unneeded-elf-rel.patch
Patch1328: 1328-scripts-sorttable-have-the-orc-code-use-the-r-functions-to-r.patch
Patch1329: 1329-scripts-sorttable-make-compare-extable-into-two-functions.patch
Patch1330: 1330-scripts-sorttable-convert-elf-ehdr-to-union.patch
Patch1331: 1331-scripts-sorttable-replace-elf-shdr-macro-with-a-union.patch
Patch1332: 1332-scripts-sorttable-convert-elf-sym-macro-over-to-a-union.patch
Patch1333: 1333-scripts-sorttable-add-helper-functions-for-elf-ehdr.patch
Patch1334: 1334-scripts-sorttable-add-helper-functions-for-elf-shdr.patch
Patch1335: 1335-scripts-sorttable-add-helper-functions-for-elf-sym.patch
Patch1336: 1336-scripts-sorttable-use-uint64-t-for-mcount-sorting.patch
Patch1337: 1337-scripts-sorttable-move-code-from-sorttable-h-into-sorttable-.patch
Patch1338: 1338-scripts-sorttable-get-start-stop-mcount-loc-from-elf-file-di.patch
Patch1339: 1339-scripts-sorttable-use-a-structure-of-function-pointers-for-e.patch
Patch1340: 1340-arm64-scripts-sorttable-implement-sorting-mcount-loc-at-boot.patch
Patch1341: 1341-scripts-sorttable-have-mcount-rela-sort-use-direct-values.patch
Patch1342: 1342-scripts-sorttable-always-use-an-array-for-the-mcount-loc-sor.patch
Patch1343: 1343-scripts-sorttable-zero-out-weak-functions-in-mcount-loc-tabl.patch
Patch1344: 1344-ftrace-update-the-mcount-loc-check-of-skipped-entries.patch
Patch1345: 1345-ftrace-have-ftrace-pages-output-reflect-freed-pages.patch
Patch1346: 1346-ftrace-do-not-over-allocate-ftrace-memory.patch
Patch1347: 1347-ftrace-test-mcount-loc-addr-before-calling-ftrace-call-addr.patch
Patch1348: 1348-ftrace-check-against-is-kernel-text-instead-of-kaslr-offset.patch
Patch1349: 1349-scripts-sorttable-use-normal-sort-if-theres-no-relocs-in-the.patch
Patch1350: 1350-scripts-sorttable-allow-matches-to-functions-before-function.patch
Patch1351: 1351-scripts-sorttable-fix-endianness-handling-in-build-time-mcou.patch
# END OF PATCH DEFINITIONS
%description
@ -2366,6 +2430,70 @@ ApplyPatch 1284-smb-client-fix-oob-reads-parsing-symlink-error-response.patch
ApplyPatch 1285-sched-deadline-fix-dl-server-time-accounting.patch
ApplyPatch 1286-redhat-configs-automotive-disable-config-io-uring.patch
ApplyPatch 1287-rhel-kabi-dpll-adaptation.patch
ApplyPatch 1288-net-bonding-fix-use-after-free-in-bond-xmit-broadcast.patch
ApplyPatch 1289-s390-pci-avoid-deadlock-between-pci-error-recovery-and-mlx5-.patch
ApplyPatch 1290-ice-fix-stats-array-overflow-when-vf-requests-more-queues.patch
ApplyPatch 1291-s390-dasd-fix-gendisk-parent-after-copy-pair-swap.patch
ApplyPatch 1292-s390-dasd-move-quiesce-state-with-pprc-swap.patch
ApplyPatch 1293-s390-dasd-copy-detected-format-information-to-secondary-devi.patch
ApplyPatch 1294-nouveau-gsp-drop-warn-on-in-acpi-probes.patch
ApplyPatch 1295-can-raw-fix-ro-uniq-use-after-free-in-raw-rcv.patch
ApplyPatch 1296-erofs-add-gfp-noio-in-the-bio-completion-if-needed.patch
ApplyPatch 1297-alsa-6fire-fix-use-after-free-on-disconnect.patch
ApplyPatch 1298-ip6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch
ApplyPatch 1299-ipv6-rpl-reserve-mac-len-headroom-when-recompressed-srh-grow.patch
ApplyPatch 1300-fs-constify-file-ptr-in-backing-file-accessor-helpers.patch
ApplyPatch 1301-lsm-split-the-notifier-code-out-into-lsm-notifier-c.patch
ApplyPatch 1302-lsm-split-the-init-code-out-into-lsm-init-c.patch
ApplyPatch 1303-lsm-consolidate-lsm-allowed-and-prepare-lsm-into-lsm-prepare.patch
ApplyPatch 1304-lsm-introduce-looping-macros-for-the-initialization-code.patch
ApplyPatch 1305-lsm-integrate-report-lsm-order-code-into-caller.patch
ApplyPatch 1306-lsm-integrate-lsm-early-cred-and-lsm-early-task-into-caller.patch
ApplyPatch 1307-lsm-rename-ordered-lsm-init-to-lsm-init-ordered.patch
ApplyPatch 1308-lsm-replace-the-name-field-with-a-pointer-to-the-lsm-id-stru.patch
ApplyPatch 1309-lsm-rename-the-lsm-order-variables-for-consistency.patch
ApplyPatch 1310-lsm-rework-lsm-active-cnt-and-lsm-idlist.patch
ApplyPatch 1311-lsm-get-rid-of-the-lsm-names-list-and-do-some-cleanup.patch
ApplyPatch 1312-lsm-rework-the-lsm-enable-disable-setter-getter-functions.patch
ApplyPatch 1313-lsm-rename-exists-ordered-lsm-to-lsm-order-exists.patch
ApplyPatch 1314-lsm-rename-rework-append-ordered-lsm-into-lsm-order-append.patch
ApplyPatch 1315-lsm-rename-rework-ordered-lsm-parse-to-lsm-order-parse.patch
ApplyPatch 1316-lsm-cleanup-the-lsm-blob-size-code.patch
ApplyPatch 1317-lsm-cleanup-initialize-lsm-and-rename-to-lsm-init-single.patch
ApplyPatch 1318-lsm-fold-lsm-init-ordered-into-security-init.patch
ApplyPatch 1319-lsm-add-tweak-function-header-comment-blocks-in-lsm-init-c.patch
ApplyPatch 1320-lsm-cleanup-the-debug-and-console-output-in-lsm-init-c.patch
ApplyPatch 1321-fs-prepare-for-adding-lsm-blob-to-backing-file.patch
ApplyPatch 1322-lsm-add-backing-file-lsm-hooks.patch
ApplyPatch 1323-selinux-fix-overlayfs-mmap-and-mprotect-access-checks.patch
ApplyPatch 1324-scripts-sorttable-fix-orc-sort-cmp-to-maintain-symmetry-and-.patch
ApplyPatch 1325-scripts-sorttable-remove-unused-macro-defines.patch
ApplyPatch 1326-scripts-sorttable-remove-unused-write-functions.patch
ApplyPatch 1327-scripts-sorttable-remove-unneeded-elf-rel.patch
ApplyPatch 1328-scripts-sorttable-have-the-orc-code-use-the-r-functions-to-r.patch
ApplyPatch 1329-scripts-sorttable-make-compare-extable-into-two-functions.patch
ApplyPatch 1330-scripts-sorttable-convert-elf-ehdr-to-union.patch
ApplyPatch 1331-scripts-sorttable-replace-elf-shdr-macro-with-a-union.patch
ApplyPatch 1332-scripts-sorttable-convert-elf-sym-macro-over-to-a-union.patch
ApplyPatch 1333-scripts-sorttable-add-helper-functions-for-elf-ehdr.patch
ApplyPatch 1334-scripts-sorttable-add-helper-functions-for-elf-shdr.patch
ApplyPatch 1335-scripts-sorttable-add-helper-functions-for-elf-sym.patch
ApplyPatch 1336-scripts-sorttable-use-uint64-t-for-mcount-sorting.patch
ApplyPatch 1337-scripts-sorttable-move-code-from-sorttable-h-into-sorttable-.patch
ApplyPatch 1338-scripts-sorttable-get-start-stop-mcount-loc-from-elf-file-di.patch
ApplyPatch 1339-scripts-sorttable-use-a-structure-of-function-pointers-for-e.patch
ApplyPatch 1340-arm64-scripts-sorttable-implement-sorting-mcount-loc-at-boot.patch
ApplyPatch 1341-scripts-sorttable-have-mcount-rela-sort-use-direct-values.patch
ApplyPatch 1342-scripts-sorttable-always-use-an-array-for-the-mcount-loc-sor.patch
ApplyPatch 1343-scripts-sorttable-zero-out-weak-functions-in-mcount-loc-tabl.patch
ApplyPatch 1344-ftrace-update-the-mcount-loc-check-of-skipped-entries.patch
ApplyPatch 1345-ftrace-have-ftrace-pages-output-reflect-freed-pages.patch
ApplyPatch 1346-ftrace-do-not-over-allocate-ftrace-memory.patch
ApplyPatch 1347-ftrace-test-mcount-loc-addr-before-calling-ftrace-call-addr.patch
ApplyPatch 1348-ftrace-check-against-is-kernel-text-instead-of-kaslr-offset.patch
ApplyPatch 1349-scripts-sorttable-use-normal-sort-if-theres-no-relocs-in-the.patch
ApplyPatch 1350-scripts-sorttable-allow-matches-to-functions-before-function.patch
ApplyPatch 1351-scripts-sorttable-fix-endianness-handling-in-build-time-mcou.patch
# END OF PATCH APPLICATIONS
# Any further pre-build tree manipulations happen here.
@ -4870,6 +4998,78 @@ fi\
#
#
%changelog
* Wed Jun 11 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 6.12.0-211.22.1
- Recreate RHEL 6.12.0-211.22.1 from CentOS Stream 10 and upstream stable backports (1288-1352)
- RHEL changelog for 211.21.1..211.22.1 follows:
* Wed Jun 10 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-211.22.1.el10_2]
- scripts/sorttable: Fix endianness handling in build-time mcount sort (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Allow matches to functions before function entry (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Use normal sort if theres no relocs in the mcount section (Jerome Marchand) [RHEL-180932]
- ftrace: Check against is_kernel_text() instead of kaslr_offset() (Jerome Marchand) [RHEL-180932]
- ftrace: Test mcount_loc addr before calling ftrace_call_addr() (Jerome Marchand) [RHEL-180932]
- ftrace: Do not over-allocate ftrace memory (Jerome Marchand) [RHEL-180932]
- ftrace: Have ftrace pages output reflect freed pages (Jerome Marchand) [RHEL-180932]
- ftrace: Update the mcount_loc check of skipped entries (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Zero out weak functions in mcount_loc table (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Always use an array for the mcount_loc sorting (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Have mcount rela sort use direct values (Jerome Marchand) [RHEL-180932]
- arm64: scripts/sorttable: Implement sorting mcount_loc at boot for arm64 (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Use a structure of function pointers for elf helpers (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Get start/stop_mcount_loc from ELF file directly (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Move code from sorttable.h into sorttable.c (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Use uint64_t for mcount sorting (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Add helper functions for Elf_Sym (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Add helper functions for Elf_Shdr (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Add helper functions for Elf_Ehdr (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Convert Elf_Sym MACRO over to a union (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Replace Elf_Shdr Macro with a union (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Convert Elf_Ehdr to union (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Make compare_extable() into two functions (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Have the ORC code use the _r() functions to read (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Remove unneeded Elf_Rel (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Remove unused write functions (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: Remove unused macro defines (Jerome Marchand) [RHEL-180932]
- scripts/sorttable: fix orc_sort_cmp() to maintain symmetry and transitivity (Jerome Marchand) [RHEL-180932]
- selinux: fix overlayfs mmap() and mprotect() access checks (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: add backing_file LSM hooks (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- fs: prepare for adding LSM blob to backing_file (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: cleanup the debug and console output in lsm_init.c (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: add/tweak function header comment blocks in lsm_init.c (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: fold lsm_init_ordered() into security_init() (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: cleanup initialize_lsm() and rename to lsm_init_single() (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: cleanup the LSM blob size code (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: rename/rework ordered_lsm_parse() to lsm_order_parse() (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: rename/rework append_ordered_lsm() into lsm_order_append() (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: rename exists_ordered_lsm() to lsm_order_exists() (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: rework the LSM enable/disable setter/getter functions (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: get rid of the lsm_names list and do some cleanup (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: rework lsm_active_cnt and lsm_idlist[] (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: rename the lsm order variables for consistency (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: replace the name field with a pointer to the lsm_id struct (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: rename ordered_lsm_init() to lsm_init_ordered() (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: integrate lsm_early_cred() and lsm_early_task() into caller (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: integrate report_lsm_order() code into caller (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: introduce looping macros for the initialization code (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: consolidate lsm_allowed() and prepare_lsm() into lsm_prepare() (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: split the init code out into lsm_init.c (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- lsm: split the notifier code out into lsm_notifier.c (Ondrej Mosnacek) [RHEL-179437] {CVE-2026-46054}
- fs: constify file ptr in backing_file accessor helpers (Ondrej Mosnacek) [RHEL-179437]
- ipv6: rpl: reserve mac_len headroom when recompressed SRH grows (Antoine Tenart) [RHEL-178413] {CVE-2026-43501}
- ip6_tunnel: clear skb2->cb[] in ip4ip6_err() (Guillaume Nault) [RHEL-172651] {CVE-2026-43037}
- ALSA: 6fire: fix use-after-free on disconnect (CKI Backport Bot) [RHEL-172973] {CVE-2026-31581}
- erofs: add GFP_NOIO in the bio completion if needed (CKI Backport Bot) [RHEL-171686] {CVE-2026-31467}
- can: raw: fix ro->uniq use-after-free in raw_rcv() (CKI Backport Bot) [RHEL-170764] {CVE-2026-31532}
- nouveau/gsp: drop WARN_ON in ACPI probes (Gary Guo) [RHEL-167788]
* Thu Jun 04 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-211.21.1.el10_2]
- s390/dasd: Copy detected format information to secondary device (Ramesh Chhetri) [RHEL-176473]
- s390/dasd: Move quiesce state with pprc swap (Ramesh Chhetri) [RHEL-176473]
- s390/dasd: Fix gendisk parent after copy pair swap (Ramesh Chhetri) [RHEL-176473]
- ice: fix stats array overflow when VF requests more queues (Michal Schmidt) [RHEL-177518]
- s390/pci: Avoid deadlock between PCI error recovery and mlx5 crdump (Mircea Dragan) [RHEL-166855]
- net: bonding: fix use-after-free in bond_xmit_broadcast() (CKI Backport Bot) [RHEL-168073] {CVE-2026-31419}
* Sun Jun 07 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 6.12.0-211.20.1
- Recreate RHEL 6.12.0-211.20.1 from CentOS Stream 10 and upstream stable backports (1245-1287)
- smb cifs.spnego now shipped by RHEL too; existing ahead-fix 1105 is identical (RHEL's redundant copy omitted)