Skip to content

[rlc-10/6.12.0-211.60.1.el10_2] Multiple patches tested (4 commits) - #1698

Merged
PlaidCat merged 5 commits into
rlc-10/6.12.0-211.60.1.el10_2from
{maple}_rlc-10/6.12.0-211.60.1.el10_2
Oct 14, 2026
Merged

PlaidCat merged 5 commits into
rlc-10/6.12.0-211.60.1.el10_2from
{maple}_rlc-10/6.12.0-211.60.1.el10_2

Conversation

@ciq-kernel-automation

Copy link
Copy Markdown

Summary

This PR has been automatically created after successful completion of all CI stages.

Commit Message(s)

exec: Cleanup POSIX timers right after de_thread()

cve CVE-2026-98260
commit-author Hyunwoo Kim <imv4bel@gmail.com>
commit acb03d3881818581052924a9bbbe92b8741ed448
commit-source-sha 75aa08b93c65766040f9ca99f41ac85ad22596b6
commit-source linux-6.18.y
upstream-diff |
    Context due to missing unrelated change:
    af7bb0d2ca4 ("exec: fix the racy usage of fs_struct->in_exec")
futex: Fix race on the initial mm->futex.phash.ref allocation

cve CVE-2026-80775
commit-author Hyunwoo Kim <imv4bel@gmail.com>
commit bde0238083647381d4747355c5a19115a3422b96
commit-source-sha 86d12b34bafc9a4c271a9edefea88855a934d6e5
commit-source linux-6.18.y
posix-timers: Target group sigqueue to current task only if not exiting

cve-pre CVE-2026-98256
commit-author Frederic Weisbecker <frederic@kernel.org>
commit 63dffecfba3eddcf67a8f76d80e0c141f93d44a5
signal: Prevent exec() race

cve CVE-2026-98256
commit-author Thomas Gleixner <tglx@kernel.org>
commit d2710c8d938ae6a825a6463158e6e6f31eac792a
commit-source-sha 621c365739828900f32a0c1cdfe5387528a62176
commit-source linux-6.18.y
upstream-diff |
    Conflict in exit_signals() due to missing commit:
    2b1642b8810 ("signal: Move MMCID exit out of sighand lock")
    however this is part of a much larger rewrite of sched/mmcid
    https://lore.kernel.org/all/20251119172549.706439391@linutronix.de/
    Too invasive to backport.  Keeping sched_mm_cid_exit_signals(tsk)
    at the top of the new scoped_guard() prior to
    tsk->flags |= PF_EXITING keep the original ordering of both the now
    defunct early-exit path and the locked path.

Test Results

✅ Build Stage

Architecture Build Time Total Time
x86_64 33m 11s 34m 3s
aarch64 26m 55s 27m 37s

✅ Boot Verification

✅ Kernel Selftests

Architecture Passed Failed Compared Against Status
x86_64 428 64 rlc-10/6.12.0-211.60.1.el10_2 ⚠️ No baseline available
aarch64 375 60 rlc-10/6.12.0-211.60.1.el10_2 ⚠️ No baseline available

✅ LTP Results

Architecture Passed Failed Compared Against Status
x86_64 1478 80 rlc-10/6.12.0-211.60.1.el10_2 ⚠️ No baseline available
aarch64 1451 81 rlc-10/6.12.0-211.60.1.el10_2 ⚠️ No baseline available

🤖 This PR was automatically generated by GitHub Actions
Run ID: 38477642548

cve CVE-2026-98260
commit-author Hyunwoo Kim <imv4bel@gmail.com>
commit acb03d3
commit-source-sha 75aa08b
commit-source linux-6.18.y
upstream-diff |
    Context due to missing unrelated change:
    af7bb0d ("exec: fix the racy usage of fs_struct->in_exec")

commit acb03d3 upstream.

A per-thread CPU timer holds a reference to the PID of the thread it is
attached to and, while it is armed, its node is queued in that thread's
posix_cputimers. The task is looked up by that PID.

When a non-leader thread exec()s, de_thread() changes which task owns
that PID. pid_task(timer->it.cpu.pid, PIDTYPE_PID) then returns NULL,
but the node is still queued on tsk, which is alive. timer_lock_sighand()
takes a failed lookup to mean that the node is already dequeued, so it
has nothing to undo.

begin_new_exec() calls posix_cpu_timers_exit(me) right after
exec_task_namespaces() and that removes the leftover node, so the state
normally stays invisible. But bprm->point_of_no_return is set before
de_thread(), so if unshare_files(), set_mm_exe_file(), exec_mmap() or
exec_task_namespaces() fails, the task dies before it gets there.
exit_itimers() then frees the k_itimer while its node is still queued,
and reaping tsk later erases that freed node from the rbtree.

In short:

      the non-leader thread B           the parent

  timer_create(CLOCK_THREAD_CPUTIME_ID)
  timer_settime()
    arm_timer()            // the node is queued on B
  execve()
    de_thread(B)
      exchange_tids(B, leader)  // B's PID now belongs to the leader
      release_task(leader)
        __exit_signal(leader)
          posix_cpu_timers_exit(leader)  // cleans leader's queue, not B's
          __unhash_process(leader)  // that PID has no task anymore
    exec_mmap()
      mmap_read_lock_killable(old_mm)
                                kill(B, SIGKILL)
      // -EINTR
  get_signal()
    do_exit()
      exit_itimers()
        posix_timer_delete()
          posix_cpu_timer_del()
        posix_timer_unhash_and_free()  // freed while still queued
                                wait4()
                                  release_task(B)
                                    posix_cpu_timers_exit(B)
                                      cleanup_timerqueue()
                                        timerqueue_del()  // use-after-free

Move the POSIX timer cleanup right after de_thread() before any of the
later failure conditions brings the task into do_exit().

[ tglx: Move the cleanup right after de_thread() ]

Fixes: 55e8c8e ("posix-cpu-timers: Store a reference to a pid not a task")
	Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
	Signed-off-by: Thomas Gleixner <tglx@kernel.org>
	Tested-by: Kijo Park <red993688@gmail.com>
	Reviewed-by: Oleg Nesterov <oleg@redhat.com>
	Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
	Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/ao7Q8miiuLAPVnWv@v4bel
Link: https://patch.msgid.link/20260911090541.627712075@kernel.org
	Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 75aa08b)
Signed-off-by: Jonathan Maple <jmaple@ciq.com>
cve CVE-2026-80775
commit-author Hyunwoo Kim <imv4bel@gmail.com>
commit bde0238
commit-source-sha 86d12b3
commit-source linux-6.18.y

commit bde0238 upstream.

futex_hash_allocate() allocates mm->futex.phash.ref without any locking.
Commit d9b0532 ("futex: Move futex_hash_free() back to __mmput()")
moved the allocation here and assumed that the process has just a single
thread at this point.

Commit ee9dce4 ("futex: Drop CLONE_THREAD requirement for private
default hash alloc") widened need_futex_hash_allocate_default() to cover
any CLONE_VM clone, but left out vfork because the parent is suspended and
cannot race.

That no longer holds once vfork is nested. If a vfork child calls vfork
again and is then killed with SIGKILL, the parent is released from its
vfork wait and runs concurrently with the grandchild in the same mm.
Neither of them went through futex_hash_allocate_default().

When both call prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_SET_SLOTS) at the same
time, each one sees mm->futex.phash.ref as NULL and stores its own percpu
counter. Only the last store survives. The counter stored first is no
longer reachable from the mm, so the references on it are not seen by
__futex_ref_atomic_end(). A private hash that still has references is then
considered dead and freed, and a task that still holds one of its buckets
writes into freed memory in futex_q_lock().

Store the counter once with cmpxchg() and let the loser free_percpu() its
own. The initial reference has to be taken before the store, otherwise
another task can install a private hash while the counter is still 0.

Fixes: d9b0532 ("futex: Move futex_hash_free() back to __mmput()")
	Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
	Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
	Signed-off-by: Thomas Gleixner <tglx@kernel.org>
	Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/ansrpP4ImE1MaBY9@v4bel
	Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 86d12b3)
Signed-off-by: Jonathan Maple <jmaple@ciq.com>
cve-pre CVE-2026-98256
commit-author Frederic Weisbecker <frederic@kernel.org>
commit 63dffec

A sigqueue belonging to a posix timer, which target is not a specific
thread but a whole thread group, is preferrably targeted to the current
task if it is part of that thread group.

However nothing prevents a posix timer event from queueing such a
sigqueue from a reaped yet running task. The interruptible code space
between exit_notify() and the final call to schedule() is enough for
posix_timer_fn() hrtimer to fire.

If that happens while the current task is part of the thread group
target, it is proposed to handle it but since its sighand pointer may
have been cleared already, the sigqueue is dropped even if there are
other tasks running within the group that could handle it.

As a result posix timers with thread group wide target may miss signals
when some of their threads are exiting.

Fix this with verifying that the current task hasn't been through
exit_notify() before proposing it as a preferred target so as to ensure
that its sighand is still here and stable.

complete_signal() might still reconsider the choice and find a better
target within the group if current has passed retarget_shared_pending()
already.

Fixes: bcb7ee7 ("posix-timers: Prefer delivery of signals to the current thread")
	Reported-by: Anthony Mallet <anthony.mallet@laas.fr>
	Suggested-by: Oleg Nesterov <oleg@redhat.com>
	Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
	Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
	Acked-by: Oleg Nesterov <oleg@redhat.com>
	Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/all/20241122234811.60455-1-frederic@kernel.org
Closes: https://lore.kernel.org/all/26411.57288.238690.681680@gargle.gargle.HOWL
(cherry picked from commit 63dffec)
Signed-off-by: Jonathan Maple <jmaple@ciq.com>
cve CVE-2026-98256
commit-author Thomas Gleixner <tglx@kernel.org>
commit d2710c8
commit-source-sha 621c365
commit-source linux-6.18.y
upstream-diff |
    Conflict in exit_signals() due to missing commit:
    2b1642b ("signal: Move MMCID exit out of sighand lock")
    however this is part of a much larger rewrite of sched/mmcid
    https://lore.kernel.org/all/20251119172549.706439391@linutronix.de/
    Too invasive to backport.  Keeping sched_mm_cid_exit_signals(tsk)
    at the top of the new scoped_guard() prior to
    tsk->flags |= PF_EXITING keep the original ordering of both the now
    defunct early-exit path and the locked path.

[ Upstream commit d2710c8 ]

Hyunwoo debugged the following KASAN UAF splat:

  BUG: KASAN: slab-use-after-free in __send_signal_locked+0xb27/0xba0
  Write of size 8 at addr ffff888007ed80c8 by task poc/79
  ...
  Call Trace:
   __send_signal_locked+0xb27/0xba0
   do_send_sig_info+0xa7/0x160
   do_send_specific+0x76/0xa0
   __x64_sys_tgkill+0x193/0x270
  ...
  Allocated by task 80:
   do_timer_create+0x1a4/0x1030
   __x64_sys_timer_create+0x145/0x190
  ...
  Freed by task 12:
   kmem_cache_free_bulk+0x1f8/0x4a0
   kvfree_rcu_bulk+0x14f/0x1c0
   kfree_rcu_work+0x128/0x1a0
  ...
  Last potentially related work creation:
   kvfree_call_rcu+0x39/0x390
   __flush_itimer_signals+0x211/0x320
   flush_itimer_signals+0x47/0x90
   begin_new_exec+0xa6b/0x28c0

It turned out that this happens with a non-leader exec() as Hyunwoo
explained:

de_thread() calls exchange_tids() before release_task(leader), so the
struct pid held by a SIGEV_THREAD_ID timer created against the leader's tid
now points to the thread which called execve(). pid_task() returns that
thread and lock_task_sighand() on it succeeds.

If the timer signal is blocked, its sigqueue stays queued on the leader's
task::pending. The next expiry of that timer can then run while
release_task() flushes the queue.

posixtimer_send_sigqueue() checks whether the sigqueue is already queued
with a plain list_empty(), which only reads list_head::next.
list_del_init() is not atomic and INIT_LIST_HEAD() stores list_head::next
before list_head::prev, so the check can pass in between. list_add_tail()
queues the entry on the task::pending of the live thread, and the
list_head::prev store from the flush then overwrites the list_head::prev
link that list_add_tail() has just set.

__flush_itimer_signals() does not undo that either. With list_head::prev
pointing at the entry itself, its list_del_init() only stores the same
values again, so the entry is not removed from the list. It is still there
after the last reference is dropped and the timer is freed by RCU, and the
list_add_tail() of a later tgkill() follows that list_head::prev into the
freed timer.

This problem surfaced with the recent commit which moved the sigqueue flush
out of the sighand lock held region.

Hyonwoo proposed to fix this by using list_del_init_careful(), but that
just papers over the problem. After some disucssions and various attempts
to solve it, Eric pointed out that there is no reason to flush
task::pending late in release_task() and it should be done in
exit_signals() already.

As nothing can collect and deliver signals which are queued in a dying
task's pending queue, there is no reason to delay it further.

But it has to be ensured that no signals can be queued into it after that
point. exit_signals() sets PF_EXITING in task::flags, which can be used as
an indicator for this.

Cure it by:

  - Preventing signal queueing for task private signals (PIDTYPE_PID) when
    the task has PF_EXITING set in __send_signal_locked() and in
    posixtimer_send_sigqueue().

  - Protecting the unlocked setting of PF_EXITING in exit_signals() for the
    task group empty and the group exit case with sighand lock

  - Flushing task::pending signals right there.

    Optimize that by moving the whole pending list to an on-stack list head
    under sighand lock and free the signals without the lock held.

There has been quite some discussion about the lockless flush and the
non-leader exec case on weakly ordered systems. The problem is that a third
party which tries to send a posix timer signal relies on the PID lookup to
find the target task and that lookup might result in the new leader when
the signal was originaly directed to the old leader. In case that the
signal was queued on the old leader then the lockless flush raised a
concern over the following situation:

   old_leader		new_leader              third party

A: flush_list()	// list_del_init() stores to sigqueue

   LOCK (tasklist)
   old_leader->exit_state = EXIT_ZOMBIE;
B: UNLOCK (tasklist)

C:			LOCK (tasklist)
			if (old_leader->exit_state)
			   transfer_tids()
D:			     store PID
						posix_timer_send_sigqueue()
						// Observes #D so t = new_leader
E:						t = get_target()

F:						LOCK (sighand)

G:						   if (list_empty(sigqueue))
							list_add(sigqueue)

The concern was that the third party might observe #D but not observe #A
and therefore would proceed to #G while the list_del() stores (#A) in
flush_list() are not visible yet, which could result in list corruption.

That would be possible if looking at it solely from a RELEASE+ACQUIRE
ordering point of view, but B-C is a UNLOCK+LOCK hand-over, which is not
the same as RELEASE+ACQUIRE:

  RELEASE+ACQUIRE: RCpc,  only the CPUs involved agree on the ordering
  UNLOCK+LOCK:     RCtso, the hand-over is store-ordering

As B-C is UNLOCK+LOCK, which is RCtso and that does impose store order,
A stores must happen before the D store.

Combine with E-F, which has a data dependency from the LOAD to the LOCK and
thereby constraints later LOADs, those sigqueue loads in G that come after
F must in fact observe the A stores.

Fixes: fb3bbcf ("exit: change the release_task() paths to call flush_sigqueue() lockless")
	Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
	Debugged-by: Hyunwoo Kim <imv4bel@gmail.com>
	Suggested-by: "Eric W. Biederman" <ebiederm@xmission.com>
	Signed-off-by: Thomas Gleixner <tglx@kernel.org>
	Tested-by: Kijo Park <red993688@gmail.com>
	Reviewed-by: Oleg Nesterov <oleg@redhat.com>
	Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
	Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260911090541.572536604@kernel.org
Closes: https://patch.msgid.link/aok1rdkBgZsynHZB@v4bel
	Signed-off-by: Sasha Levin <sashal@kernel.org>
	Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 621c365)
Signed-off-by: Jonathan Maple <jmaple@ciq.com>
@ciq-kernel-automation ciq-kernel-automation Bot added the created-by-kernelci Tag PRs that were automatically created when a user branch was pushed to the repo (kernelCI) label Oct 14, 2026
@PlaidCat
PlaidCat requested a review from a team October 14, 2026 17:55
bmastbergen
bmastbergen previously approved these changes Oct 14, 2026

@bmastbergen bmastbergen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥌

@PlaidCat
PlaidCat requested a review from a team October 14, 2026 20:02
Simplifies the workflow to use the reusable workflow defined in main
branch. This reduces duplication and makes the workflow easier to
maintain across multiple branches.

The workflow was renamed because it now includes validation over
and above just checking for upstream fixes

Signed-off-by: Jonathan Maple <jmaple@ciq.com>

@bmastbergen bmastbergen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥌

@bmastbergen
bmastbergen requested a review from a team October 14, 2026 20:22
@github-actions

Copy link
Copy Markdown

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/38631847573

@github-actions

Copy link
Copy Markdown

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/38631852238

@github-actions

Copy link
Copy Markdown

🔍 Diffofdiffs: 3 of 4 backports differ from upstream

View the diffofdiffs report.

Open to anyone signed in to GitHub. Report expires 2027-01-12 20:19 UTC.

# Subject Backport Upstream
1 exec: Cleanup POSIX timers right after de_thread() 55d03135505c acb03d388181
2 futex: Fix race on the initial mm->futex.phash.ref allocation d9c27c381979 bde023808364
3 signal: Prevent exec() race 693509a45d96 d2710c8d938a

1 additional commit has no upstream reference and was not compared.

Checked PR revision 03f447ee1b77 against base b952d8ef5bd5.

@github-actions

Copy link
Copy Markdown

🔍 Diffofdiffs: 3 of 4 backports differ from upstream

View the diffofdiffs report.

Open to anyone signed in to GitHub. Report expires 2027-01-12 20:19 UTC.

# Subject Backport Upstream
1 exec: Cleanup POSIX timers right after de_thread() 55d03135505c acb03d388181
2 futex: Fix race on the initial mm->futex.phash.ref allocation d9c27c381979 bde023808364
3 signal: Prevent exec() race 693509a45d96 d2710c8d938a

1 additional commit has no upstream reference and was not compared.

Checked PR revision 03f447ee1b77 against base b952d8ef5bd5.

@github-actions

Copy link
Copy Markdown

✅ Validation checks completed successfully View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/38631847573

@github-actions

Copy link
Copy Markdown

✅ Validation checks completed successfully View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/38631852238

@kerneltoast kerneltoast left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢

@PlaidCat
PlaidCat merged commit 508a39d into rlc-10/6.12.0-211.60.1.el10_2 Oct 14, 2026
13 checks passed
@PlaidCat
PlaidCat deleted the {maple}_rlc-10/6.12.0-211.60.1.el10_2 branch October 14, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

created-by-kernelci Tag PRs that were automatically created when a user branch was pushed to the repo (kernelCI)

Development

Successfully merging this pull request may close these issues.

3 participants