aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c178
1 files changed, 62 insertions, 116 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 42c317874cfa..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 */
@@ -418,37 +424,33 @@ static int ptrace_setoptions(struct task_struct *child, long data)
418 424
419static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) 425static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
420{ 426{
427 unsigned long flags;
421 int error = -ESRCH; 428 int error = -ESRCH;
422 429
423 read_lock(&tasklist_lock); 430 if (lock_task_sighand(child, &flags)) {
424 if (likely(child->sighand != NULL)) {
425 error = -EINVAL; 431 error = -EINVAL;
426 spin_lock_irq(&child->sighand->siglock);
427 if (likely(child->last_siginfo != NULL)) { 432 if (likely(child->last_siginfo != NULL)) {
428 *info = *child->last_siginfo; 433 *info = *child->last_siginfo;
429 error = 0; 434 error = 0;
430 } 435 }
431 spin_unlock_irq(&child->sighand->siglock); 436 unlock_task_sighand(child, &flags);
432 } 437 }
433 read_unlock(&tasklist_lock);
434 return error; 438 return error;
435} 439}
436 440
437static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) 441static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
438{ 442{
443 unsigned long flags;
439 int error = -ESRCH; 444 int error = -ESRCH;
440 445
441 read_lock(&tasklist_lock); 446 if (lock_task_sighand(child, &flags)) {
442 if (likely(child->sighand != NULL)) {
443 error = -EINVAL; 447 error = -EINVAL;
444 spin_lock_irq(&child->sighand->siglock);
445 if (likely(child->last_siginfo != NULL)) { 448 if (likely(child->last_siginfo != NULL)) {
446 *child->last_siginfo = *info; 449 *child->last_siginfo = *info;
447 error = 0; 450 error = 0;
448 } 451 }
449 spin_unlock_irq(&child->sighand->siglock); 452 unlock_task_sighand(child, &flags);
450 } 453 }
451 read_unlock(&tasklist_lock);
452 return error; 454 return error;
453} 455}
454 456
@@ -575,72 +577,16 @@ int ptrace_request(struct task_struct *child, long request,
575 return ret; 577 return ret;
576} 578}
577 579
578/** 580static struct task_struct *ptrace_get_task_struct(pid_t pid)
579 * ptrace_traceme -- helper for PTRACE_TRACEME
580 *
581 * Performs checks and sets PT_PTRACED.
582 * Should be used by all ptrace implementations for PTRACE_TRACEME.
583 */
584int ptrace_traceme(void)
585{
586 int ret = -EPERM;
587
588 /*
589 * Are we already being traced?
590 */
591repeat:
592 task_lock(current);
593 if (!(current->ptrace & PT_PTRACED)) {
594 /*
595 * See ptrace_attach() comments about the locking here.
596 */
597 unsigned long flags;
598 if (!write_trylock_irqsave(&tasklist_lock, flags)) {
599 task_unlock(current);
600 do {
601 cpu_relax();
602 } while (!write_can_lock(&tasklist_lock));
603 goto repeat;
604 }
605
606 ret = security_ptrace_traceme(current->parent);
607
608 /*
609 * Check PF_EXITING to ensure ->real_parent has not passed
610 * exit_ptrace(). Otherwise we don't report the error but
611 * pretend ->real_parent untraces us right after return.
612 */
613 if (!ret && !(current->real_parent->flags & PF_EXITING)) {
614 current->ptrace |= PT_PTRACED;
615 __ptrace_link(current, current->real_parent);
616 }
617
618 write_unlock_irqrestore(&tasklist_lock, flags);
619 }
620 task_unlock(current);
621 return ret;
622}
623
624/**
625 * ptrace_get_task_struct -- grab a task struct reference for ptrace
626 * @pid: process id to grab a task_struct reference of
627 *
628 * This function is a helper for ptrace implementations. It checks
629 * permissions and then grabs a task struct for use of the actual
630 * ptrace implementation.
631 *
632 * Returns the task_struct for @pid or an ERR_PTR() on failure.
633 */
634struct task_struct *ptrace_get_task_struct(pid_t pid)
635{ 581{
636 struct task_struct *child; 582 struct task_struct *child;
637 583
638 read_lock(&tasklist_lock); 584 rcu_read_lock();
639 child = find_task_by_vpid(pid); 585 child = find_task_by_vpid(pid);
640 if (child) 586 if (child)
641 get_task_struct(child); 587 get_task_struct(child);
588 rcu_read_unlock();
642 589
643 read_unlock(&tasklist_lock);
644 if (!child) 590 if (!child)
645 return ERR_PTR(-ESRCH); 591 return ERR_PTR(-ESRCH);
646 return child; 592 return child;