130 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From: Oleg Nesterov <oleg@redhat.com>
 | |
| 
 | |
| [PATCH] signals: check ->group_stop_count after tracehook_get_signal()
 | |
| 
 | |
| Move the call to do_signal_stop() down, after tracehook call.
 | |
| This makes ->group_stop_count condition visible to tracers before
 | |
| do_signal_stop() will participate in this group-stop.
 | |
| 
 | |
| Currently the patch has no effect, tracehook_get_signal() always
 | |
| returns 0.
 | |
| 
 | |
| Signed-off-by: Oleg Nesterov <oleg@redhat.com>
 | |
| Signed-off-by: Roland McGrath <roland@redhat.com>
 | |
| ---
 | |
|  include/linux/ptrace.h    |    1 +
 | |
|  include/linux/sched.h     |    1 +
 | |
|  include/linux/tracehook.h |   10 +++++-----
 | |
|  kernel/ptrace.c           |    2 +-
 | |
|  kernel/signal.c           |    4 ++--
 | |
|  5 files changed, 10 insertions(+), 8 deletions(-)
 | |
| 
 | |
| diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
 | |
| index 4272521..a85fb41 100644  
 | |
| --- a/include/linux/ptrace.h
 | |
| +++ b/include/linux/ptrace.h
 | |
| @@ -105,6 +105,7 @@ extern int ptrace_traceme(void);
 | |
|  extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
 | |
|  extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
 | |
|  extern int ptrace_attach(struct task_struct *tsk);
 | |
| +extern bool __ptrace_detach(struct task_struct *tracer, struct task_struct *tracee);
 | |
|  extern int ptrace_detach(struct task_struct *, unsigned int);
 | |
|  extern void ptrace_disable(struct task_struct *);
 | |
|  extern int ptrace_check_attach(struct task_struct *task, int kill);
 | |
| diff --git a/include/linux/sched.h b/include/linux/sched.h
 | |
| index ce160d6..5e7cc95 100644  
 | |
| --- a/include/linux/sched.h
 | |
| +++ b/include/linux/sched.h
 | |
| @@ -2030,6 +2030,7 @@ extern int kill_pgrp(struct pid *pid, in
 | |
|  extern int kill_pid(struct pid *pid, int sig, int priv);
 | |
|  extern int kill_proc_info(int, struct siginfo *, pid_t);
 | |
|  extern int do_notify_parent(struct task_struct *, int);
 | |
| +extern void do_notify_parent_cldstop(struct task_struct *, int);
 | |
|  extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent);
 | |
|  extern void force_sig(int, struct task_struct *);
 | |
|  extern int send_sig(int, struct task_struct *, int);
 | |
| diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
 | |
| index 10db010..c78b2f4 100644  
 | |
| --- a/include/linux/tracehook.h
 | |
| +++ b/include/linux/tracehook.h
 | |
| @@ -134,7 +134,7 @@ static inline __must_check int tracehook
 | |
|   */
 | |
|  static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
 | |
|  {
 | |
| -	if (step) {
 | |
| +	if (step && (task_ptrace(current) & PT_PTRACED)) {
 | |
|  		siginfo_t info;
 | |
|  		user_single_step_siginfo(current, regs, &info);
 | |
|  		force_sig_info(SIGTRAP, &info, current);
 | |
| @@ -156,7 +156,7 @@ static inline int tracehook_unsafe_exec(
 | |
|  {
 | |
|  	int unsafe = 0;
 | |
|  	int ptrace = task_ptrace(task);
 | |
| -	if (ptrace & PT_PTRACED) {
 | |
| +	if (ptrace) {
 | |
|  		if (ptrace & PT_PTRACE_CAP)
 | |
|  			unsafe |= LSM_UNSAFE_PTRACE_CAP;
 | |
|  		else
 | |
| @@ -178,7 +178,7 @@ static inline int tracehook_unsafe_exec(
 | |
|   */
 | |
|  static inline struct task_struct *tracehook_tracer_task(struct task_struct *tsk)
 | |
|  {
 | |
| -	if (task_ptrace(tsk) & PT_PTRACED)
 | |
| +	if (task_ptrace(tsk))
 | |
|  		return rcu_dereference(tsk->parent);
 | |
|  	return NULL;
 | |
|  }
 | |
| @@ -386,7 +386,7 @@ static inline void tracehook_signal_hand
 | |
|  					    const struct k_sigaction *ka,
 | |
|  					    struct pt_regs *regs, int stepping)
 | |
|  {
 | |
| -	if (stepping)
 | |
| +	if (stepping && (task_ptrace(current) & PT_PTRACED))
 | |
|  		ptrace_notify(SIGTRAP);
 | |
|  }
 | |
|  
 | |
| @@ -492,7 +492,7 @@ static inline int tracehook_get_signal(s
 | |
|   */
 | |
|  static inline int tracehook_notify_jctl(int notify, int why)
 | |
|  {
 | |
| -	return notify ?: (current->ptrace & PT_PTRACED) ? why : 0;
 | |
| +	return notify ?: task_ptrace(current) ? why : 0;
 | |
|  }
 | |
|  
 | |
|  /**
 | |
| diff --git a/kernel/ptrace.c b/kernel/ptrace.c
 | |
| index f34d798..8049cb5 100644  
 | |
| --- a/kernel/ptrace.c
 | |
| +++ b/kernel/ptrace.c
 | |
| @@ -270,7 +270,7 @@ static int ignoring_children(struct sigh
 | |
|   * reap it now, in that case we must also wake up sub-threads sleeping in
 | |
|   * do_wait().
 | |
|   */
 | |
| -static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
 | |
| +bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
 | |
|  {
 | |
|  	__ptrace_unlink(p);
 | |
|  
 | |
| diff --git a/kernel/signal.c b/kernel/signal.c
 | |
| index bded651..6d13d9f 100644  
 | |
| --- a/kernel/signal.c
 | |
| +++ b/kernel/signal.c
 | |
| @@ -1521,7 +1521,7 @@ int do_notify_parent(struct task_struct 
 | |
|  	return ret;
 | |
|  }
 | |
|  
 | |
| -static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
 | |
| +void do_notify_parent_cldstop(struct task_struct *tsk, int why)
 | |
|  {
 | |
|  	struct siginfo info;
 | |
|  	unsigned long flags;
 | |
| @@ -1791,7 +1791,7 @@ static int do_signal_stop(int signr)
 | |
|  static int ptrace_signal(int signr, siginfo_t *info,
 | |
|  			 struct pt_regs *regs, void *cookie)
 | |
|  {
 | |
| -	if (!task_ptrace(current))
 | |
| +	if (!(task_ptrace(current) & PT_PTRACED))
 | |
|  		return signr;
 | |
|  
 | |
|  	ptrace_signal_deliver(regs, cookie);
 |