aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c180
1 files changed, 64 insertions, 116 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 0692ab5a0d67..61c78b2c07ba 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -25,16 +25,6 @@
25 25
26 26
27/* 27/*
28 * Initialize a new task whose father had been ptraced.
29 *
30 * Called from copy_process().
31 */
32void ptrace_fork(struct task_struct *child, unsigned long clone_flags)
33{
34 arch_ptrace_fork(child, clone_flags);
35}
36
37/*
38 * ptrace a task: make the debugger its new parent and 28 * ptrace a task: make the debugger its new parent and
39 * move it to the ptrace list. 29 * move it to the ptrace list.
40 * 30 *
@@ -177,66 +167,82 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
177int ptrace_attach(struct task_struct *task) 167int ptrace_attach(struct task_struct *task)
178{ 168{
179 int retval; 169 int retval;
180 unsigned long flags;
181 170
182 audit_ptrace(task); 171 audit_ptrace(task);
183 172
184 retval = -EPERM; 173 retval = -EPERM;
174 if (unlikely(task->flags & PF_KTHREAD))
175 goto out;
185 if (same_thread_group(task, current)) 176 if (same_thread_group(task, current))
186 goto out; 177 goto out;
187 178
188 /* Protect exec's credential calculations against our interference; 179 /*
189 * SUID, SGID and LSM creds get determined differently under ptrace. 180 * Protect exec's credential calculations against our interference;
181 * interference; SUID, SGID and LSM creds get determined differently
182 * under ptrace.
190 */ 183 */
191 retval = mutex_lock_interruptible(&task->cred_exec_mutex); 184 retval = mutex_lock_interruptible(&task->cred_guard_mutex);
192 if (retval < 0) 185 if (retval < 0)
193 goto out; 186 goto out;
194 187
195 retval = -EPERM;
196repeat:
197 /*
198 * Nasty, nasty.
199 *
200 * We want to hold both the task-lock and the
201 * tasklist_lock for writing at the same time.
202 * But that's against the rules (tasklist_lock
203 * is taken for reading by interrupts on other
204 * cpu's that may have task_lock).
205 */
206 task_lock(task); 188 task_lock(task);
207 if (!write_trylock_irqsave(&tasklist_lock, flags)) {
208 task_unlock(task);
209 do {
210 cpu_relax();
211 } while (!write_can_lock(&tasklist_lock));
212 goto repeat;
213 }
214
215 if (!task->mm)
216 goto bad;
217 /* the same process cannot be attached many times */
218 if (task->ptrace & PT_PTRACED)
219 goto bad;
220 retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); 189 retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH);
190 task_unlock(task);
221 if (retval) 191 if (retval)
222 goto bad; 192 goto unlock_creds;
193
194 write_lock_irq(&tasklist_lock);
195 retval = -EPERM;
196 if (unlikely(task->exit_state))
197 goto unlock_tasklist;
198 if (task->ptrace)
199 goto unlock_tasklist;
223 200
224 /* Go */ 201 task->ptrace = PT_PTRACED;
225 task->ptrace |= PT_PTRACED;
226 if (capable(CAP_SYS_PTRACE)) 202 if (capable(CAP_SYS_PTRACE))
227 task->ptrace |= PT_PTRACE_CAP; 203 task->ptrace |= PT_PTRACE_CAP;
228 204
229 __ptrace_link(task, current); 205 __ptrace_link(task, current);
230
231 send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); 206 send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
232bad: 207
233 write_unlock_irqrestore(&tasklist_lock, flags); 208 retval = 0;
234 task_unlock(task); 209unlock_tasklist:
235 mutex_unlock(&task->cred_exec_mutex); 210 write_unlock_irq(&tasklist_lock);
211unlock_creds:
212 mutex_unlock(&task->cred_guard_mutex);
236out: 213out:
237 return retval; 214 return retval;
238} 215}
239 216
217/**
218 * ptrace_traceme -- helper for PTRACE_TRACEME
219 *
220 * Performs checks and sets PT_PTRACED.
221 * Should be used by all ptrace implementations for PTRACE_TRACEME.
222 */
223int ptrace_traceme(void)
224{
225 int ret = -EPERM;
226
227 write_lock_irq(&tasklist_lock);
228 /* Are we already being traced? */
229 if (!current->ptrace) {
230 ret = security_ptrace_traceme(current->parent);
231 /*
232 * Check PF_EXITING to ensure ->real_parent has not passed
233 * exit_ptrace(). Otherwise we don't report the error but
234 * pretend ->real_parent untraces us right after return.
235 */
236 if (!ret && !(current->real_parent->flags & PF_EXITING)) {
237 current->ptrace = PT_PTRACED;
238 __ptrace_link(current, current->real_parent);
239 }
240 }
241 write_unlock_irq(&tasklist_lock);
242
243 return ret;
244}
245
240/* 246/*
241 * Called with irqs disabled, returns true if childs should reap themselves. 247 * Called with irqs disabled, returns true if childs should reap themselves.
242 */ 248 */
@@ -304,6 +310,8 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
304 if (child->ptrace) { 310 if (child->ptrace) {
305 child->exit_code = data; 311 child->exit_code = data;
306 dead = __ptrace_detach(current, child); 312 dead = __ptrace_detach(current, child);
313 if (!child->exit_state)
314 wake_up_process(child);
307 } 315 }
308 write_unlock_irq(&tasklist_lock); 316 write_unlock_irq(&tasklist_lock);
309 317
@@ -416,37 +424,33 @@ static int ptrace_setoptions(struct task_struct *child, long data)
416 424
417static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) 425static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
418{ 426{
427 unsigned long flags;
419 int error = -ESRCH; 428 int error = -ESRCH;
420 429
421 read_lock(&tasklist_lock); 430 if (lock_task_sighand(child, &flags)) {
422 if (likely(child->sighand != NULL)) {
423 error = -EINVAL; 431 error = -EINVAL;
424 spin_lock_irq(&child->sighand->siglock);
425 if (likely(child->last_siginfo != NULL)) { 432 if (likely(child->last_siginfo != NULL)) {
426 *info = *child->last_siginfo; 433 *info = *child->last_siginfo;
427 error = 0; 434 error = 0;
428 } 435 }
429 spin_unlock_irq(&child->sighand->siglock); 436 unlock_task_sighand(child, &flags);
430 } 437 }
431 read_unlock(&tasklist_lock);
432 return error; 438 return error;
433} 439}
434 440
435static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) 441static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
436{ 442{
443 unsigned long flags;
437 int error = -ESRCH; 444 int error = -ESRCH;
438 445
439 read_lock(&tasklist_lock); 446 if (lock_task_sighand(child, &flags)) {
440 if (likely(child->sighand != NULL)) {
441 error = -EINVAL; 447 error = -EINVAL;
442 spin_lock_irq(&child->sighand->siglock);
443 if (likely(child->last_siginfo != NULL)) { 448 if (likely(child->last_siginfo != NULL)) {
444 *child->last_siginfo = *info; 449 *child->last_siginfo = *info;
445 error = 0; 450 error = 0;
446 } 451 }
447 spin_unlock_irq(&child->sighand->siglock); 452 unlock_task_sighand(child, &flags);
448 } 453 }
449 read_unlock(&tasklist_lock);
450 return error; 454 return error;
451} 455}
452 456
@@ -573,72 +577,16 @@ int ptrace_request(struct task_struct *child, long request,
573 return ret; 577 return ret;
574} 578}
575 579
576/** 580static struct task_struct *ptrace_get_task_struct(pid_t pid)
577 * ptrace_traceme -- helper for PTRACE_TRACEME
578 *
579 * Performs checks and sets PT_PTRACED.
580 * Should be used by all ptrace implementations for PTRACE_TRACEME.
581 */
582int ptrace_traceme(void)
583{
584 int ret = -EPERM;
585
586 /*
587 * Are we already being traced?
588 */
589repeat:
590 task_lock(current);
591 if (!(current->ptrace & PT_PTRACED)) {
592 /*
593 * See ptrace_attach() comments about the locking here.
594 */
595 unsigned long flags;
596 if (!write_trylock_irqsave(&tasklist_lock, flags)) {
597 task_unlock(current);
598 do {
599 cpu_relax();
600 } while (!write_can_lock(&tasklist_lock));
601 goto repeat;
602 }
603
604 ret = security_ptrace_traceme(current->parent);
605
606 /*
607 * Check PF_EXITING to ensure ->real_parent has not passed
608 * exit_ptrace(). Otherwise we don't report the error but
609 * pretend ->real_parent untraces us right after return.
610 */
611 if (!ret && !(current->real_parent->flags & PF_EXITING)) {
612 current->ptrace |= PT_PTRACED;
613 __ptrace_link(current, current->real_parent);
614 }
615
616 write_unlock_irqrestore(&tasklist_lock, flags);
617 }
618 task_unlock(current);
619 return ret;
620}
621
622/**
623 * ptrace_get_task_struct -- grab a task struct reference for ptrace
624 * @pid: process id to grab a task_struct reference of
625 *
626 * This function is a helper for ptrace implementations. It checks
627 * permissions and then grabs a task struct for use of the actual
628 * ptrace implementation.
629 *
630 * Returns the task_struct for @pid or an ERR_PTR() on failure.
631 */
632struct task_struct *ptrace_get_task_struct(pid_t pid)
633{ 581{
634 struct task_struct *child; 582 struct task_struct *child;
635 583
636 read_lock(&tasklist_lock); 584 rcu_read_lock();
637 child = find_task_by_vpid(pid); 585 child = find_task_by_vpid(pid);
638 if (child) 586 if (child)
639 get_task_struct(child); 587 get_task_struct(child);
588 rcu_read_unlock();
640 589
641 read_unlock(&tasklist_lock);
642 if (!child) 590 if (!child)
643 return ERR_PTR(-ESRCH); 591 return ERR_PTR(-ESRCH);
644 return child; 592 return child;