aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ptrace.h1
-rw-r--r--kernel/ptrace.c29
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 @@
48#define PTRACE_SETREGSET 0x4205 48#define PTRACE_SETREGSET 0x4205
49 49
50#define PTRACE_SEIZE 0x4206 50#define PTRACE_SEIZE 0x4206
51#define PTRACE_INTERRUPT 0x4207
51 52
52/* flags in @data for PTRACE_SEIZE */ 53/* flags in @data for PTRACE_SEIZE */
53#define PTRACE_SEIZE_DEVEL 0x80000000 /* temp flag for development */ 54#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,
658int ptrace_request(struct task_struct *child, long request, 658int ptrace_request(struct task_struct *child, long request,
659 unsigned long addr, unsigned long data) 659 unsigned long addr, unsigned long data)
660{ 660{
661 bool seized = child->ptrace & PT_SEIZED;
661 int ret = -EIO; 662 int ret = -EIO;
662 siginfo_t siginfo; 663 siginfo_t siginfo;
663 void __user *datavp = (void __user *) data; 664 void __user *datavp = (void __user *) data;
664 unsigned long __user *datalp = datavp; 665 unsigned long __user *datalp = datavp;
666 unsigned long flags;
665 667
666 switch (request) { 668 switch (request) {
667 case PTRACE_PEEKTEXT: 669 case PTRACE_PEEKTEXT:
@@ -694,6 +696,27 @@ int ptrace_request(struct task_struct *child, long request,
694 ret = ptrace_setsiginfo(child, &siginfo); 696 ret = ptrace_setsiginfo(child, &siginfo);
695 break; 697 break;
696 698
699 case PTRACE_INTERRUPT:
700 /*
701 * Stop tracee without any side-effect on signal or job
702 * control. At least one trap is guaranteed to happen
703 * after this request. If @child is already trapped, the
704 * current trap is not disturbed and another trap will
705 * happen after the current trap is ended with PTRACE_CONT.
706 *
707 * The actual trap might not be PTRACE_EVENT_STOP trap but
708 * the pending condition is cleared regardless.
709 */
710 if (unlikely(!seized || !lock_task_sighand(child, &flags)))
711 break;
712
713 if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP)))
714 signal_wake_up(child, 0);
715
716 unlock_task_sighand(child, &flags);
717 ret = 0;
718 break;
719
697 case PTRACE_DETACH: /* detach a process that was attached. */ 720 case PTRACE_DETACH: /* detach a process that was attached. */
698 ret = ptrace_detach(child, data); 721 ret = ptrace_detach(child, data);
699 break; 722 break;
@@ -819,7 +842,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
819 goto out_put_task_struct; 842 goto out_put_task_struct;
820 } 843 }
821 844
822 ret = ptrace_check_attach(child, request == PTRACE_KILL); 845 ret = ptrace_check_attach(child, request == PTRACE_KILL ||
846 request == PTRACE_INTERRUPT);
823 if (ret < 0) 847 if (ret < 0)
824 goto out_put_task_struct; 848 goto out_put_task_struct;
825 849
@@ -961,7 +985,8 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
961 goto out_put_task_struct; 985 goto out_put_task_struct;
962 } 986 }
963 987
964 ret = ptrace_check_attach(child, request == PTRACE_KILL); 988 ret = ptrace_check_attach(child, request == PTRACE_KILL ||
989 request == PTRACE_INTERRUPT);
965 if (!ret) 990 if (!ret)
966 ret = compat_arch_ptrace(child, request, addr, data); 991 ret = compat_arch_ptrace(child, request, addr, data);
967 992