FAILED: patch "[PATCH] proc: protect ptrace_may_access() with exec_update_lock (part" failed to apply to 6.6-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 6650527444dadc63d84aa939d14ecba4fadb2f69
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026071445-halved-nullify-54b3@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 6650527444dadc63d84aa939d14ecba4fadb2f69 Mon Sep 17 00:00:00 2001
From: Jann Horn <[email protected]>
Date: Mon, 18 May 2026 18:35:15 +0200
Subject: [PATCH] proc: protect ptrace_may_access() with exec_update_lock (part
1)
Fix the easy cases where procfs currently calls ptrace_may_access() without exec_update_lock protection, where the fix is to simply add the extra lock or use mm_access():
- do_task_stat(): grab exec_update_lock
- proc_pid_wchan(): grab exec_update_lock
- proc_map_files_lookup(): use mm_access() instead of get_task_mm()
- proc_map_files_readdir(): use mm_access() instead of get_task_mm()
- proc_ns_get_link(): grab exec_update_lock
- proc_ns_readlink(): grab exec_update_lock
fs/proc/array.c +6 -0
@@ -482,6 +482,11 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,unsigned long flags;int exit_code = task->exit_code;struct signal_struct *sig = task->signal; +int ret; + + ret =down_read_killable (&task->signal->exec_update_lock); +if (ret) +return ret; state = *get_task_state (task); vsize = eip = esp =0 ;
@@ -657,6 +662,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,seq_puts (m," 0" );seq_putc (m,'\n' ); +up_read (&task->signal->exec_update_lock);if (mm)mmput (mm);return 0 ;
fs/proc/base.c +23 -20
103 lines not on this page · raw message
fs/proc/namespaces.c +12 -0
@@ -55,6 +55,10 @@ static const char *proc_ns_get_link(struct dentry *dentry,if (!task)return ERR_PTR (-EACCES ); + error =down_read_killable (&task->signal->exec_update_lock); +if (error) + goto out_put_task; +if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) goto out;
@@ -64,6 +68,8 @@ static const char *proc_ns_get_link(struct dentry *dentry, error =nd_jump_link (&ns_path); out: +up_read (&task->signal->exec_update_lock); +out_put_task:put_task_struct (task);return ERR_PTR (error); }
@@ -80,11 +86,17 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflif (!task)return res; + res =down_read_killable (&task->signal->exec_update_lock); +if (res) + goto out_put_task; +if (ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { res =ns_get_name (name,sizeof (name), task, ns_ops);if (res >=0 ) res =readlink_copy (buffer, buflen, name,strlen (name)); } +up_read (&task->signal->exec_update_lock); +out_put_task:put_task_struct (task);return res; }
Sasha Levin
maintainerPATCH 1/3 seqlock: Introduce scoped_seqlock_read()
From: Peter Zijlstra <[email protected]>
[ Upstream commit cc39f3872c0865bef992b713338df369554fa9e0 ]
The read_seqbegin/need_seqretry/done_seqretry API is cumbersome and error prone. With the new helper the "typical" code like
int seq, nextseq;
unsigned long flags;
nextseq = 0;
do {
seq = nextseq;
flags = read_seqbegin_or_lock_irqsave(&seqlock, &seq);
// read-side critical section
nextseq = 1;
} while (need_seqretry(&seqlock, seq));
done_seqretry_irqrestore(&seqlock, seq, flags);can be rewritten as
scoped_seqlock_read (&seqlock, ss_lock_irqsave) {
// read-side critical section
}Original idea by Oleg Nesterov; with contributions from Linus.
Stable-dep-of: 6650527444da ("proc: protect ptrace_may_access() with exec_update_lock (part 1)")
--- include/linux/seqlock.h | 111 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+)
include/linux/seqlock.h +111 -0
@@ -1266,4 +1266,115 @@ done_seqretry_irqrestore(seqlock_t *lock, int seq, unsigned long flags)if (seq &1 )read_sequnlock_excl_irqrestore (lock, flags); } + +enum ss_state { + ss_done =0 , + ss_lock, + ss_lock_irqsave, + ss_lockless, +}; + +struct ss_tmp { +enum ss_state state; +unsigned long data; +spinlock_t *lock; +spinlock_t *lock_irqsave; +}; + +static inline void __scoped_seqlock_cleanup (struct ss_tmp *sst) +{ +if (sst->lock) +spin_unlock (sst->lock); +if (sst->lock_irqsave) +spin_unlock_irqrestore (sst->lock_irqsave, sst->data); +} + +extern void __scoped_seqlock_invalid_target (void ); + +#if defined(CONFIG_CC_IS_GCC ) &&CONFIG_GCC_VERSION <90000 +/* +* For some reason some GCC-8 architectures (nios2, alpha) have trouble +* determining that the ss_done state is impossible in __scoped_seqlock_next() +* below. +*/ +static inline void __scoped_seqlock_bug (void ) { } +#else +/* +* Canary for compiler optimization -- if the compiler doesn't realize this is +* an impossible state, it very likely generates sub-optimal code here. +*/ +extern void __scoped_seqlock_bug (void ); +#endif + +static inline void +__scoped_seqlock_next (struct ss_tmp *sst,seqlock_t *lock,enum ss_state target) +{ +switch (sst->state) { +case ss_done: +__scoped_seqlock_bug (); +return ; + +case ss_lock: +case ss_lock_irqsave: + sst->state = ss_done; +return ; + +case ss_lockless: +if (!read_seqretry (lock, sst->data)) { + sst->state = ss_done; +return ; + } +break ; + } + +switch (target) { +case ss_done: +__scoped_seqlock_invalid_target (); +return ; + +case ss_lock: + sst->lock = &lock->lock; +spin_lock (sst->lock); + sst->state = ss_lock; +return ; + +case ss_lock_irqsave: + sst->lock_irqsave = &lock->lock; +spin_lock_irqsave (sst->lock_irqsave, sst->data); + sst->state = ss_lock_irqsave; +return ; + +case ss_lockless: + sst->data =read_seqbegin (lock); +return ; + } +} + +#define __scoped_seqlock_read (_seqlock, _target, _s) \ + for (struct ss_tmp _s __cleanup(__scoped_seqlock_cleanup) = \ + { .state = ss_lockless, .data = read_seqbegin(_seqlock) }; \ + _s.state != ss_done; \ + __scoped_seqlock_next(&_s, _seqlock, _target)) + +/** +* scoped_seqlock_read (lock, ss_state) - execute the read side critical +* section without manual sequence +* counter handling or calls to other +* helpers +* @lock: pointer to seqlock_t protecting the data +* @ss_state: one of {ss_lock, ss_lock_irqsave, ss_lockless} indicating +* the type of critical read section +* +* Example: +* +* scoped_seqlock_read (&lock, ss_lock) { +* // read-side critical section +* } +* +* Starts with a lockess pass first. If it fails, restarts the critical +* section with the lock held. +*/ +#define scoped_seqlock_read (_seqlock, _target) \ + __scoped_seqlock_read(_seqlock, _target, __UNIQUE_ID(seqlock)) +#endif /* __LINUX_SEQLOCK_H */
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 seqlock: Change do_task_stat() to use scoped_seqlock_read()
From: Oleg Nesterov <[email protected]>
[ Upstream commit b76f72bea2c601afec81829ea427fc0d20f83216 ]
To simplify the code and make it more readable.
Stable-dep-of: 6650527444da ("proc: protect ptrace_may_access() with exec_update_lock (part 1)")
--- fs/proc/array.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
fs/proc/array.c +2 -7
@@ -483,7 +483,6 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,unsigned long flags;int exit_code = task->exit_code;struct signal_struct *sig = task->signal; -unsigned int seq =1 ; state = *get_task_state (task); vsize = eip = esp =0 ;
@@ -540,10 +539,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,if (permitted && (!whole || num_threads <2 )) wchan = !task_is_running (task); - do { - seq++; /* 2 on the 1st/lockless path, otherwise odd */ - flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq); - + scoped_seqlock_read (&sig->stats_lock, ss_lock_irqsave) { cmin_flt = sig->cmin_flt; cmaj_flt = sig->cmaj_flt; cutime = sig->cutime;
@@ -565,8 +561,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, }rcu_read_unlock (); } - }while (need_seqretry (&sig->stats_lock, seq)); -done_seqretry_irqrestore (&sig->stats_lock, seq, flags); + }if (whole) {thread_group_cputime_adjusted (task, &utime, &stime);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 proc: protect ptrace_may_access() with exec_update_lock (part 1)
In reply to Sasha LevinFrom: Jann Horn <[email protected]>
[ Upstream commit 6650527444dadc63d84aa939d14ecba4fadb2f69 ]
Fix the easy cases where procfs currently calls ptrace_may_access() without exec_update_lock protection, where the fix is to simply add the extra lock or use mm_access():
- do_task_stat(): grab exec_update_lock
- proc_pid_wchan(): grab exec_update_lock
- proc_map_files_lookup(): use mm_access() instead of get_task_mm()
- proc_map_files_readdir(): use mm_access() instead of get_task_mm()
- proc_ns_get_link(): grab exec_update_lock
- proc_ns_readlink(): grab exec_update_lock
--- fs/proc/array.c | 6 ++++++ fs/proc/base.c | 41 ++++++++++++++++++++++------------------- fs/proc/namespaces.c | 12 ++++++++++++ 3 files changed, 40 insertions(+), 19 deletions(-)
fs/proc/array.c +6 -0
@@ -483,6 +483,11 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,unsigned long flags;int exit_code = task->exit_code;struct signal_struct *sig = task->signal; +int ret; + + ret =down_read_killable (&task->signal->exec_update_lock); +if (ret) +return ret; state = *get_task_state (task); vsize = eip = esp =0 ;
@@ -658,6 +663,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,seq_puts (m," 0" );seq_putc (m,'\n' ); +up_read (&task->signal->exec_update_lock);if (mm)mmput (mm);return 0 ;
fs/proc/base.c +22 -19
101 lines not on this page · raw message
fs/proc/namespaces.c +12 -0
@@ -55,6 +55,10 @@ static const char *proc_ns_get_link(struct dentry *dentry,if (!task)return ERR_PTR (-EACCES ); + error =down_read_killable (&task->signal->exec_update_lock); +if (error) + goto out_put_task; +if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) goto out;
@@ -64,6 +68,8 @@ static const char *proc_ns_get_link(struct dentry *dentry, error =nd_jump_link (&ns_path); out: +up_read (&task->signal->exec_update_lock); +out_put_task:put_task_struct (task);return ERR_PTR (error); }
@@ -80,11 +86,17 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflif (!task)return res; + res =down_read_killable (&task->signal->exec_update_lock); +if (res) + goto out_put_task; +if (ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { res =ns_get_name (name,sizeof (name), task, ns_ops);if (res >=0 ) res =readlink_copy (buffer, buflen, name); } +up_read (&task->signal->exec_update_lock); +out_put_task:put_task_struct (task);return res; }
Signature · 1 line
2.53.0