diff options
| -rw-r--r-- | include/linux/ptrace.h | 1 | ||||
| -rw-r--r-- | kernel/ptrace.c | 29 | 
2 files changed, 28 insertions, 2 deletions
| diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 67ad3f152329..ad754d1e0b13 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -48,6 +48,7 @@  #define PTRACE_SETREGSET	0x4205  #define PTRACE_SEIZE		0x4206 +#define PTRACE_INTERRUPT	0x4207  /* flags in @data for PTRACE_SEIZE */  #define PTRACE_SEIZE_DEVEL	0x80000000 /* temp flag for development */ diff --git a/kernel/ptrace.c b/kernel/ptrace.c index dcf9f974198c..6852c0f4a916 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -658,10 +658,12 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type,  int ptrace_request(struct task_struct *child, long request,  		   unsigned long addr, unsigned long data)  { +	bool seized = child->ptrace & PT_SEIZED;  	int ret = -EIO;  	siginfo_t siginfo;  	void __user *datavp = (void __user *) data;  	unsigned long __user *datalp = datavp; +	unsigned long flags;  	switch (request) {  	case PTRACE_PEEKTEXT: @@ -694,6 +696,27 @@ int ptrace_request(struct task_struct *child, long request,  			ret = ptrace_setsiginfo(child, &siginfo);  		break; +	case PTRACE_INTERRUPT: +		/* +		 * Stop tracee without any side-effect on signal or job +		 * control.  At least one trap is guaranteed to happen +		 * after this request.  If @child is already trapped, the +		 * current trap is not disturbed and another trap will +		 * happen after the current trap is ended with PTRACE_CONT. +		 * +		 * The actual trap might not be PTRACE_EVENT_STOP trap but +		 * the pending condition is cleared regardless. +		 */ +		if (unlikely(!seized || !lock_task_sighand(child, &flags))) +			break; + +		if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) +			signal_wake_up(child, 0); + +		unlock_task_sighand(child, &flags); +		ret = 0; +		break; +  	case PTRACE_DETACH:	 /* detach a process that was attached. */  		ret = ptrace_detach(child, data);  		break; @@ -819,7 +842,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,  		goto out_put_task_struct;  	} -	ret = ptrace_check_attach(child, request == PTRACE_KILL); +	ret = ptrace_check_attach(child, request == PTRACE_KILL || +				  request == PTRACE_INTERRUPT);  	if (ret < 0)  		goto out_put_task_struct; @@ -961,7 +985,8 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,  		goto out_put_task_struct;  	} -	ret = ptrace_check_attach(child, request == PTRACE_KILL); +	ret = ptrace_check_attach(child, request == PTRACE_KILL || +				  request == PTRACE_INTERRUPT);  	if (!ret)  		ret = compat_arch_ptrace(child, request, addr, data); | 
