diff options
-rw-r--r-- | include/linux/ptrace.h | 2 | ||||
-rw-r--r-- | kernel/ptrace.c | 24 |
2 files changed, 20 insertions, 6 deletions
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 9178d5cc0b01..e93ef1a54fc7 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -105,7 +105,7 @@ extern long arch_ptrace(struct task_struct *child, long request, | |||
105 | extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); | 105 | extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); |
106 | extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); | 106 | extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); |
107 | extern void ptrace_disable(struct task_struct *); | 107 | extern void ptrace_disable(struct task_struct *); |
108 | extern int ptrace_check_attach(struct task_struct *task, int kill); | 108 | extern int ptrace_check_attach(struct task_struct *task, bool ignore_state); |
109 | extern int ptrace_request(struct task_struct *child, long request, | 109 | extern int ptrace_request(struct task_struct *child, long request, |
110 | unsigned long addr, unsigned long data); | 110 | unsigned long addr, unsigned long data); |
111 | extern void ptrace_notify(int exit_code); | 111 | extern void ptrace_notify(int exit_code); |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 134f34cb142b..eb191116edf7 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -97,10 +97,24 @@ void __ptrace_unlink(struct task_struct *child) | |||
97 | spin_unlock(&child->sighand->siglock); | 97 | spin_unlock(&child->sighand->siglock); |
98 | } | 98 | } |
99 | 99 | ||
100 | /* | 100 | /** |
101 | * Check that we have indeed attached to the thing.. | 101 | * ptrace_check_attach - check whether ptracee is ready for ptrace operation |
102 | * @child: ptracee to check for | ||
103 | * @ignore_state: don't check whether @child is currently %TASK_TRACED | ||
104 | * | ||
105 | * Check whether @child is being ptraced by %current and ready for further | ||
106 | * ptrace operations. If @ignore_state is %false, @child also should be in | ||
107 | * %TASK_TRACED state and on return the child is guaranteed to be traced | ||
108 | * and not executing. If @ignore_state is %true, @child can be in any | ||
109 | * state. | ||
110 | * | ||
111 | * CONTEXT: | ||
112 | * Grabs and releases tasklist_lock and @child->sighand->siglock. | ||
113 | * | ||
114 | * RETURNS: | ||
115 | * 0 on success, -ESRCH if %child is not ready. | ||
102 | */ | 116 | */ |
103 | int ptrace_check_attach(struct task_struct *child, int kill) | 117 | int ptrace_check_attach(struct task_struct *child, bool ignore_state) |
104 | { | 118 | { |
105 | int ret = -ESRCH; | 119 | int ret = -ESRCH; |
106 | 120 | ||
@@ -119,13 +133,13 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
119 | */ | 133 | */ |
120 | spin_lock_irq(&child->sighand->siglock); | 134 | spin_lock_irq(&child->sighand->siglock); |
121 | WARN_ON_ONCE(task_is_stopped(child)); | 135 | WARN_ON_ONCE(task_is_stopped(child)); |
122 | if (task_is_traced(child) || kill) | 136 | if (task_is_traced(child) || ignore_state) |
123 | ret = 0; | 137 | ret = 0; |
124 | spin_unlock_irq(&child->sighand->siglock); | 138 | spin_unlock_irq(&child->sighand->siglock); |
125 | } | 139 | } |
126 | read_unlock(&tasklist_lock); | 140 | read_unlock(&tasklist_lock); |
127 | 141 | ||
128 | if (!ret && !kill) | 142 | if (!ret && !ignore_state) |
129 | ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH; | 143 | ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH; |
130 | 144 | ||
131 | /* All systems go.. */ | 145 | /* All systems go.. */ |