|
@@ -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,
|
|
int ptrace_request(struct task_struct *child, long request,
|
|
unsigned long addr, unsigned long data)
|
|
unsigned long addr, unsigned long data)
|
|
{
|
|
{
|
|
|
|
+ bool seized = child->ptrace & PT_SEIZED;
|
|
int ret = -EIO;
|
|
int ret = -EIO;
|
|
siginfo_t siginfo;
|
|
siginfo_t siginfo;
|
|
void __user *datavp = (void __user *) data;
|
|
void __user *datavp = (void __user *) data;
|
|
unsigned long __user *datalp = datavp;
|
|
unsigned long __user *datalp = datavp;
|
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
switch (request) {
|
|
switch (request) {
|
|
case PTRACE_PEEKTEXT:
|
|
case PTRACE_PEEKTEXT:
|
|
@@ -694,6 +696,27 @@ int ptrace_request(struct task_struct *child, long request,
|
|
ret = ptrace_setsiginfo(child, &siginfo);
|
|
ret = ptrace_setsiginfo(child, &siginfo);
|
|
break;
|
|
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. */
|
|
case PTRACE_DETACH: /* detach a process that was attached. */
|
|
ret = ptrace_detach(child, data);
|
|
ret = ptrace_detach(child, data);
|
|
break;
|
|
break;
|
|
@@ -819,7 +842,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
|
|
goto out_put_task_struct;
|
|
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)
|
|
if (ret < 0)
|
|
goto out_put_task_struct;
|
|
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;
|
|
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)
|
|
if (!ret)
|
|
ret = compat_arch_ptrace(child, request, addr, data);
|
|
ret = compat_arch_ptrace(child, request, addr, data);
|
|
|
|
|