diff options
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 206 |
1 files changed, 138 insertions, 68 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index f34d798ef4a2..2df115790cd9 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/syscalls.h> | 22 | #include <linux/syscalls.h> |
23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <linux/regset.h> | 24 | #include <linux/regset.h> |
25 | #include <linux/hw_breakpoint.h> | ||
25 | 26 | ||
26 | 27 | ||
27 | /* | 28 | /* |
@@ -37,35 +38,33 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) | |||
37 | child->parent = new_parent; | 38 | child->parent = new_parent; |
38 | } | 39 | } |
39 | 40 | ||
40 | /* | 41 | /** |
41 | * Turn a tracing stop into a normal stop now, since with no tracer there | 42 | * __ptrace_unlink - unlink ptracee and restore its execution state |
42 | * would be no way to wake it up with SIGCONT or SIGKILL. If there was a | 43 | * @child: ptracee to be unlinked |
43 | * signal sent that would resume the child, but didn't because it was in | ||
44 | * TASK_TRACED, resume it now. | ||
45 | * Requires that irqs be disabled. | ||
46 | */ | ||
47 | static void ptrace_untrace(struct task_struct *child) | ||
48 | { | ||
49 | spin_lock(&child->sighand->siglock); | ||
50 | if (task_is_traced(child)) { | ||
51 | /* | ||
52 | * If the group stop is completed or in progress, | ||
53 | * this thread was already counted as stopped. | ||
54 | */ | ||
55 | if (child->signal->flags & SIGNAL_STOP_STOPPED || | ||
56 | child->signal->group_stop_count) | ||
57 | __set_task_state(child, TASK_STOPPED); | ||
58 | else | ||
59 | signal_wake_up(child, 1); | ||
60 | } | ||
61 | spin_unlock(&child->sighand->siglock); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * unptrace a task: move it back to its original parent and | ||
66 | * remove it from the ptrace list. | ||
67 | * | 44 | * |
68 | * Must be called with the tasklist lock write-held. | 45 | * Remove @child from the ptrace list, move it back to the original parent, |
46 | * and restore the execution state so that it conforms to the group stop | ||
47 | * state. | ||
48 | * | ||
49 | * Unlinking can happen via two paths - explicit PTRACE_DETACH or ptracer | ||
50 | * exiting. For PTRACE_DETACH, unless the ptracee has been killed between | ||
51 | * ptrace_check_attach() and here, it's guaranteed to be in TASK_TRACED. | ||
52 | * If the ptracer is exiting, the ptracee can be in any state. | ||
53 | * | ||
54 | * After detach, the ptracee should be in a state which conforms to the | ||
55 | * group stop. If the group is stopped or in the process of stopping, the | ||
56 | * ptracee should be put into TASK_STOPPED; otherwise, it should be woken | ||
57 | * up from TASK_TRACED. | ||
58 | * | ||
59 | * If the ptracee is in TASK_TRACED and needs to be moved to TASK_STOPPED, | ||
60 | * it goes through TRACED -> RUNNING -> STOPPED transition which is similar | ||
61 | * to but in the opposite direction of what happens while attaching to a | ||
62 | * stopped task. However, in this direction, the intermediate RUNNING | ||
63 | * state is not hidden even from the current ptracer and if it immediately | ||
64 | * re-attaches and performs a WNOHANG wait(2), it may fail. | ||
65 | * | ||
66 | * CONTEXT: | ||
67 | * write_lock_irq(tasklist_lock) | ||
69 | */ | 68 | */ |
70 | void __ptrace_unlink(struct task_struct *child) | 69 | void __ptrace_unlink(struct task_struct *child) |
71 | { | 70 | { |
@@ -75,8 +74,27 @@ void __ptrace_unlink(struct task_struct *child) | |||
75 | child->parent = child->real_parent; | 74 | child->parent = child->real_parent; |
76 | list_del_init(&child->ptrace_entry); | 75 | list_del_init(&child->ptrace_entry); |
77 | 76 | ||
78 | if (task_is_traced(child)) | 77 | spin_lock(&child->sighand->siglock); |
79 | ptrace_untrace(child); | 78 | |
79 | /* | ||
80 | * Reinstate GROUP_STOP_PENDING if group stop is in effect and | ||
81 | * @child isn't dead. | ||
82 | */ | ||
83 | if (!(child->flags & PF_EXITING) && | ||
84 | (child->signal->flags & SIGNAL_STOP_STOPPED || | ||
85 | child->signal->group_stop_count)) | ||
86 | child->group_stop |= GROUP_STOP_PENDING; | ||
87 | |||
88 | /* | ||
89 | * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick | ||
90 | * @child in the butt. Note that @resume should be used iff @child | ||
91 | * is in TASK_TRACED; otherwise, we might unduly disrupt | ||
92 | * TASK_KILLABLE sleeps. | ||
93 | */ | ||
94 | if (child->group_stop & GROUP_STOP_PENDING || task_is_traced(child)) | ||
95 | signal_wake_up(child, task_is_traced(child)); | ||
96 | |||
97 | spin_unlock(&child->sighand->siglock); | ||
80 | } | 98 | } |
81 | 99 | ||
82 | /* | 100 | /* |
@@ -95,16 +113,14 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
95 | */ | 113 | */ |
96 | read_lock(&tasklist_lock); | 114 | read_lock(&tasklist_lock); |
97 | if ((child->ptrace & PT_PTRACED) && child->parent == current) { | 115 | if ((child->ptrace & PT_PTRACED) && child->parent == current) { |
98 | ret = 0; | ||
99 | /* | 116 | /* |
100 | * child->sighand can't be NULL, release_task() | 117 | * child->sighand can't be NULL, release_task() |
101 | * does ptrace_unlink() before __exit_signal(). | 118 | * does ptrace_unlink() before __exit_signal(). |
102 | */ | 119 | */ |
103 | spin_lock_irq(&child->sighand->siglock); | 120 | spin_lock_irq(&child->sighand->siglock); |
104 | if (task_is_stopped(child)) | 121 | WARN_ON_ONCE(task_is_stopped(child)); |
105 | child->state = TASK_TRACED; | 122 | if (task_is_traced(child) || kill) |
106 | else if (!task_is_traced(child) && !kill) | 123 | ret = 0; |
107 | ret = -ESRCH; | ||
108 | spin_unlock_irq(&child->sighand->siglock); | 124 | spin_unlock_irq(&child->sighand->siglock); |
109 | } | 125 | } |
110 | read_unlock(&tasklist_lock); | 126 | read_unlock(&tasklist_lock); |
@@ -134,21 +150,24 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
134 | return 0; | 150 | return 0; |
135 | rcu_read_lock(); | 151 | rcu_read_lock(); |
136 | tcred = __task_cred(task); | 152 | tcred = __task_cred(task); |
137 | if ((cred->uid != tcred->euid || | 153 | if (cred->user->user_ns == tcred->user->user_ns && |
138 | cred->uid != tcred->suid || | 154 | (cred->uid == tcred->euid && |
139 | cred->uid != tcred->uid || | 155 | cred->uid == tcred->suid && |
140 | cred->gid != tcred->egid || | 156 | cred->uid == tcred->uid && |
141 | cred->gid != tcred->sgid || | 157 | cred->gid == tcred->egid && |
142 | cred->gid != tcred->gid) && | 158 | cred->gid == tcred->sgid && |
143 | !capable(CAP_SYS_PTRACE)) { | 159 | cred->gid == tcred->gid)) |
144 | rcu_read_unlock(); | 160 | goto ok; |
145 | return -EPERM; | 161 | if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE)) |
146 | } | 162 | goto ok; |
163 | rcu_read_unlock(); | ||
164 | return -EPERM; | ||
165 | ok: | ||
147 | rcu_read_unlock(); | 166 | rcu_read_unlock(); |
148 | smp_rmb(); | 167 | smp_rmb(); |
149 | if (task->mm) | 168 | if (task->mm) |
150 | dumpable = get_dumpable(task->mm); | 169 | dumpable = get_dumpable(task->mm); |
151 | if (!dumpable && !capable(CAP_SYS_PTRACE)) | 170 | if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE)) |
152 | return -EPERM; | 171 | return -EPERM; |
153 | 172 | ||
154 | return security_ptrace_access_check(task, mode); | 173 | return security_ptrace_access_check(task, mode); |
@@ -163,8 +182,9 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
163 | return !err; | 182 | return !err; |
164 | } | 183 | } |
165 | 184 | ||
166 | int ptrace_attach(struct task_struct *task) | 185 | static int ptrace_attach(struct task_struct *task) |
167 | { | 186 | { |
187 | bool wait_trap = false; | ||
168 | int retval; | 188 | int retval; |
169 | 189 | ||
170 | audit_ptrace(task); | 190 | audit_ptrace(task); |
@@ -181,7 +201,7 @@ int ptrace_attach(struct task_struct *task) | |||
181 | * under ptrace. | 201 | * under ptrace. |
182 | */ | 202 | */ |
183 | retval = -ERESTARTNOINTR; | 203 | retval = -ERESTARTNOINTR; |
184 | if (mutex_lock_interruptible(&task->cred_guard_mutex)) | 204 | if (mutex_lock_interruptible(&task->signal->cred_guard_mutex)) |
185 | goto out; | 205 | goto out; |
186 | 206 | ||
187 | task_lock(task); | 207 | task_lock(task); |
@@ -198,18 +218,48 @@ int ptrace_attach(struct task_struct *task) | |||
198 | goto unlock_tasklist; | 218 | goto unlock_tasklist; |
199 | 219 | ||
200 | task->ptrace = PT_PTRACED; | 220 | task->ptrace = PT_PTRACED; |
201 | if (capable(CAP_SYS_PTRACE)) | 221 | if (task_ns_capable(task, CAP_SYS_PTRACE)) |
202 | task->ptrace |= PT_PTRACE_CAP; | 222 | task->ptrace |= PT_PTRACE_CAP; |
203 | 223 | ||
204 | __ptrace_link(task, current); | 224 | __ptrace_link(task, current); |
205 | send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); | 225 | send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); |
206 | 226 | ||
227 | spin_lock(&task->sighand->siglock); | ||
228 | |||
229 | /* | ||
230 | * If the task is already STOPPED, set GROUP_STOP_PENDING and | ||
231 | * TRAPPING, and kick it so that it transits to TRACED. TRAPPING | ||
232 | * will be cleared if the child completes the transition or any | ||
233 | * event which clears the group stop states happens. We'll wait | ||
234 | * for the transition to complete before returning from this | ||
235 | * function. | ||
236 | * | ||
237 | * This hides STOPPED -> RUNNING -> TRACED transition from the | ||
238 | * attaching thread but a different thread in the same group can | ||
239 | * still observe the transient RUNNING state. IOW, if another | ||
240 | * thread's WNOHANG wait(2) on the stopped tracee races against | ||
241 | * ATTACH, the wait(2) may fail due to the transient RUNNING. | ||
242 | * | ||
243 | * The following task_is_stopped() test is safe as both transitions | ||
244 | * in and out of STOPPED are protected by siglock. | ||
245 | */ | ||
246 | if (task_is_stopped(task)) { | ||
247 | task->group_stop |= GROUP_STOP_PENDING | GROUP_STOP_TRAPPING; | ||
248 | signal_wake_up(task, 1); | ||
249 | wait_trap = true; | ||
250 | } | ||
251 | |||
252 | spin_unlock(&task->sighand->siglock); | ||
253 | |||
207 | retval = 0; | 254 | retval = 0; |
208 | unlock_tasklist: | 255 | unlock_tasklist: |
209 | write_unlock_irq(&tasklist_lock); | 256 | write_unlock_irq(&tasklist_lock); |
210 | unlock_creds: | 257 | unlock_creds: |
211 | mutex_unlock(&task->cred_guard_mutex); | 258 | mutex_unlock(&task->signal->cred_guard_mutex); |
212 | out: | 259 | out: |
260 | if (wait_trap) | ||
261 | wait_event(current->signal->wait_chldexit, | ||
262 | !(task->group_stop & GROUP_STOP_TRAPPING)); | ||
213 | return retval; | 263 | return retval; |
214 | } | 264 | } |
215 | 265 | ||
@@ -219,7 +269,7 @@ out: | |||
219 | * Performs checks and sets PT_PTRACED. | 269 | * Performs checks and sets PT_PTRACED. |
220 | * Should be used by all ptrace implementations for PTRACE_TRACEME. | 270 | * Should be used by all ptrace implementations for PTRACE_TRACEME. |
221 | */ | 271 | */ |
222 | int ptrace_traceme(void) | 272 | static int ptrace_traceme(void) |
223 | { | 273 | { |
224 | int ret = -EPERM; | 274 | int ret = -EPERM; |
225 | 275 | ||
@@ -293,7 +343,7 @@ static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) | |||
293 | return false; | 343 | return false; |
294 | } | 344 | } |
295 | 345 | ||
296 | int ptrace_detach(struct task_struct *child, unsigned int data) | 346 | static int ptrace_detach(struct task_struct *child, unsigned int data) |
297 | { | 347 | { |
298 | bool dead = false; | 348 | bool dead = false; |
299 | 349 | ||
@@ -312,8 +362,6 @@ int ptrace_detach(struct task_struct *child, unsigned int data) | |||
312 | if (child->ptrace) { | 362 | if (child->ptrace) { |
313 | child->exit_code = data; | 363 | child->exit_code = data; |
314 | dead = __ptrace_detach(current, child); | 364 | dead = __ptrace_detach(current, child); |
315 | if (!child->exit_state) | ||
316 | wake_up_process(child); | ||
317 | } | 365 | } |
318 | write_unlock_irq(&tasklist_lock); | 366 | write_unlock_irq(&tasklist_lock); |
319 | 367 | ||
@@ -329,6 +377,8 @@ int ptrace_detach(struct task_struct *child, unsigned int data) | |||
329 | * and reacquire the lock. | 377 | * and reacquire the lock. |
330 | */ | 378 | */ |
331 | void exit_ptrace(struct task_struct *tracer) | 379 | void exit_ptrace(struct task_struct *tracer) |
380 | __releases(&tasklist_lock) | ||
381 | __acquires(&tasklist_lock) | ||
332 | { | 382 | { |
333 | struct task_struct *p, *n; | 383 | struct task_struct *p, *n; |
334 | LIST_HEAD(ptrace_dead); | 384 | LIST_HEAD(ptrace_dead); |
@@ -402,7 +452,7 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds | |||
402 | return copied; | 452 | return copied; |
403 | } | 453 | } |
404 | 454 | ||
405 | static int ptrace_setoptions(struct task_struct *child, long data) | 455 | static int ptrace_setoptions(struct task_struct *child, unsigned long data) |
406 | { | 456 | { |
407 | child->ptrace &= ~PT_TRACE_MASK; | 457 | child->ptrace &= ~PT_TRACE_MASK; |
408 | 458 | ||
@@ -481,7 +531,8 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) | |||
481 | #define is_sysemu_singlestep(request) 0 | 531 | #define is_sysemu_singlestep(request) 0 |
482 | #endif | 532 | #endif |
483 | 533 | ||
484 | static int ptrace_resume(struct task_struct *child, long request, long data) | 534 | static int ptrace_resume(struct task_struct *child, long request, |
535 | unsigned long data) | ||
485 | { | 536 | { |
486 | if (!valid_signal(data)) | 537 | if (!valid_signal(data)) |
487 | return -EIO; | 538 | return -EIO; |
@@ -511,7 +562,7 @@ static int ptrace_resume(struct task_struct *child, long request, long data) | |||
511 | } | 562 | } |
512 | 563 | ||
513 | child->exit_code = data; | 564 | child->exit_code = data; |
514 | wake_up_process(child); | 565 | wake_up_state(child, __TASK_TRACED); |
515 | 566 | ||
516 | return 0; | 567 | return 0; |
517 | } | 568 | } |
@@ -558,10 +609,12 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type, | |||
558 | #endif | 609 | #endif |
559 | 610 | ||
560 | int ptrace_request(struct task_struct *child, long request, | 611 | int ptrace_request(struct task_struct *child, long request, |
561 | long addr, long data) | 612 | unsigned long addr, unsigned long data) |
562 | { | 613 | { |
563 | int ret = -EIO; | 614 | int ret = -EIO; |
564 | siginfo_t siginfo; | 615 | siginfo_t siginfo; |
616 | void __user *datavp = (void __user *) data; | ||
617 | unsigned long __user *datalp = datavp; | ||
565 | 618 | ||
566 | switch (request) { | 619 | switch (request) { |
567 | case PTRACE_PEEKTEXT: | 620 | case PTRACE_PEEKTEXT: |
@@ -578,19 +631,17 @@ int ptrace_request(struct task_struct *child, long request, | |||
578 | ret = ptrace_setoptions(child, data); | 631 | ret = ptrace_setoptions(child, data); |
579 | break; | 632 | break; |
580 | case PTRACE_GETEVENTMSG: | 633 | case PTRACE_GETEVENTMSG: |
581 | ret = put_user(child->ptrace_message, (unsigned long __user *) data); | 634 | ret = put_user(child->ptrace_message, datalp); |
582 | break; | 635 | break; |
583 | 636 | ||
584 | case PTRACE_GETSIGINFO: | 637 | case PTRACE_GETSIGINFO: |
585 | ret = ptrace_getsiginfo(child, &siginfo); | 638 | ret = ptrace_getsiginfo(child, &siginfo); |
586 | if (!ret) | 639 | if (!ret) |
587 | ret = copy_siginfo_to_user((siginfo_t __user *) data, | 640 | ret = copy_siginfo_to_user(datavp, &siginfo); |
588 | &siginfo); | ||
589 | break; | 641 | break; |
590 | 642 | ||
591 | case PTRACE_SETSIGINFO: | 643 | case PTRACE_SETSIGINFO: |
592 | if (copy_from_user(&siginfo, (siginfo_t __user *) data, | 644 | if (copy_from_user(&siginfo, datavp, sizeof siginfo)) |
593 | sizeof siginfo)) | ||
594 | ret = -EFAULT; | 645 | ret = -EFAULT; |
595 | else | 646 | else |
596 | ret = ptrace_setsiginfo(child, &siginfo); | 647 | ret = ptrace_setsiginfo(child, &siginfo); |
@@ -621,7 +672,7 @@ int ptrace_request(struct task_struct *child, long request, | |||
621 | } | 672 | } |
622 | mmput(mm); | 673 | mmput(mm); |
623 | 674 | ||
624 | ret = put_user(tmp, (unsigned long __user *) data); | 675 | ret = put_user(tmp, datalp); |
625 | break; | 676 | break; |
626 | } | 677 | } |
627 | #endif | 678 | #endif |
@@ -650,7 +701,7 @@ int ptrace_request(struct task_struct *child, long request, | |||
650 | case PTRACE_SETREGSET: | 701 | case PTRACE_SETREGSET: |
651 | { | 702 | { |
652 | struct iovec kiov; | 703 | struct iovec kiov; |
653 | struct iovec __user *uiov = (struct iovec __user *) data; | 704 | struct iovec __user *uiov = datavp; |
654 | 705 | ||
655 | if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) | 706 | if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) |
656 | return -EFAULT; | 707 | return -EFAULT; |
@@ -691,7 +742,8 @@ static struct task_struct *ptrace_get_task_struct(pid_t pid) | |||
691 | #define arch_ptrace_attach(child) do { } while (0) | 742 | #define arch_ptrace_attach(child) do { } while (0) |
692 | #endif | 743 | #endif |
693 | 744 | ||
694 | SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data) | 745 | SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, |
746 | unsigned long, data) | ||
695 | { | 747 | { |
696 | struct task_struct *child; | 748 | struct task_struct *child; |
697 | long ret; | 749 | long ret; |
@@ -732,7 +784,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data) | |||
732 | return ret; | 784 | return ret; |
733 | } | 785 | } |
734 | 786 | ||
735 | int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data) | 787 | int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, |
788 | unsigned long data) | ||
736 | { | 789 | { |
737 | unsigned long tmp; | 790 | unsigned long tmp; |
738 | int copied; | 791 | int copied; |
@@ -743,7 +796,8 @@ int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data) | |||
743 | return put_user(tmp, (unsigned long __user *)data); | 796 | return put_user(tmp, (unsigned long __user *)data); |
744 | } | 797 | } |
745 | 798 | ||
746 | int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data) | 799 | int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, |
800 | unsigned long data) | ||
747 | { | 801 | { |
748 | int copied; | 802 | int copied; |
749 | 803 | ||
@@ -870,3 +924,19 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, | |||
870 | return ret; | 924 | return ret; |
871 | } | 925 | } |
872 | #endif /* CONFIG_COMPAT */ | 926 | #endif /* CONFIG_COMPAT */ |
927 | |||
928 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
929 | int ptrace_get_breakpoints(struct task_struct *tsk) | ||
930 | { | ||
931 | if (atomic_inc_not_zero(&tsk->ptrace_bp_refcnt)) | ||
932 | return 0; | ||
933 | |||
934 | return -1; | ||
935 | } | ||
936 | |||
937 | void ptrace_put_breakpoints(struct task_struct *tsk) | ||
938 | { | ||
939 | if (atomic_dec_and_test(&tsk->ptrace_bp_refcnt)) | ||
940 | flush_ptrace_hw_breakpoint(tsk); | ||
941 | } | ||
942 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||