Blame view
kernel/ptrace.c
27 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 |
/* * linux/kernel/ptrace.c * * (C) Copyright 1999 Linus Torvalds * * Common interfaces for "ptrace()" which we do not want * to continually duplicate across every architecture. */ |
c59ede7b7 [PATCH] move capa... |
9 |
#include <linux/capability.h> |
9984de1a5 kernel: Map most ... |
10 |
#include <linux/export.h> |
1da177e4c Linux-2.6.12-rc2 |
11 12 13 14 15 |
#include <linux/sched.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/highmem.h> #include <linux/pagemap.h> |
1da177e4c Linux-2.6.12-rc2 |
16 17 |
#include <linux/ptrace.h> #include <linux/security.h> |
7ed20e1ad [PATCH] convert t... |
18 |
#include <linux/signal.h> |
a5cb013da [PATCH] auditing ... |
19 |
#include <linux/audit.h> |
b488893a3 pid namespaces: c... |
20 |
#include <linux/pid_namespace.h> |
f17d30a80 kernel/ptrace.c s... |
21 |
#include <linux/syscalls.h> |
3a7097035 ptrace: some chec... |
22 |
#include <linux/uaccess.h> |
2225a122a ptrace: Add suppo... |
23 |
#include <linux/regset.h> |
bf26c0184 ptrace: Prepare t... |
24 |
#include <linux/hw_breakpoint.h> |
f701e5b73 connector: add an... |
25 |
#include <linux/cn_proc.h> |
1da177e4c Linux-2.6.12-rc2 |
26 |
|
bf53de907 x86, bts: add for... |
27 |
|
62c124ff3 ptrace: use bit_w... |
28 29 30 31 32 |
static int ptrace_trapping_sleep_fn(void *flags) { schedule(); return 0; } |
bf53de907 x86, bts: add for... |
33 |
/* |
1da177e4c Linux-2.6.12-rc2 |
34 35 36 37 38 |
* ptrace a task: make the debugger its new parent and * move it to the ptrace list. * * Must be called with the tasklist lock write-held. */ |
36c8b5868 [PATCH] sched: cl... |
39 |
void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) |
1da177e4c Linux-2.6.12-rc2 |
40 |
{ |
f470021ad ptrace children r... |
41 42 |
BUG_ON(!list_empty(&child->ptrace_entry)); list_add(&child->ptrace_entry, &new_parent->ptraced); |
1da177e4c Linux-2.6.12-rc2 |
43 |
child->parent = new_parent; |
1da177e4c Linux-2.6.12-rc2 |
44 |
} |
3a7097035 ptrace: some chec... |
45 |
|
e3bd058f6 ptrace: Collapse ... |
46 47 48 |
/** * __ptrace_unlink - unlink ptracee and restore its execution state * @child: ptracee to be unlinked |
1da177e4c Linux-2.6.12-rc2 |
49 |
* |
0e9f0a4ab ptrace: Always pu... |
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
* Remove @child from the ptrace list, move it back to the original parent, * and restore the execution state so that it conforms to the group stop * state. * * Unlinking can happen via two paths - explicit PTRACE_DETACH or ptracer * exiting. For PTRACE_DETACH, unless the ptracee has been killed between * ptrace_check_attach() and here, it's guaranteed to be in TASK_TRACED. * If the ptracer is exiting, the ptracee can be in any state. * * After detach, the ptracee should be in a state which conforms to the * group stop. If the group is stopped or in the process of stopping, the * ptracee should be put into TASK_STOPPED; otherwise, it should be woken * up from TASK_TRACED. * * If the ptracee is in TASK_TRACED and needs to be moved to TASK_STOPPED, * it goes through TRACED -> RUNNING -> STOPPED transition which is similar * to but in the opposite direction of what happens while attaching to a * stopped task. However, in this direction, the intermediate RUNNING * state is not hidden even from the current ptracer and if it immediately * re-attaches and performs a WNOHANG wait(2), it may fail. |
e3bd058f6 ptrace: Collapse ... |
70 71 72 |
* * CONTEXT: * write_lock_irq(tasklist_lock) |
1da177e4c Linux-2.6.12-rc2 |
73 |
*/ |
36c8b5868 [PATCH] sched: cl... |
74 |
void __ptrace_unlink(struct task_struct *child) |
1da177e4c Linux-2.6.12-rc2 |
75 |
{ |
5ecfbae09 [PATCH] fix zap_t... |
76 |
BUG_ON(!child->ptrace); |
1da177e4c Linux-2.6.12-rc2 |
77 |
child->ptrace = 0; |
f470021ad ptrace children r... |
78 79 |
child->parent = child->real_parent; list_del_init(&child->ptrace_entry); |
1da177e4c Linux-2.6.12-rc2 |
80 |
|
1da177e4c Linux-2.6.12-rc2 |
81 |
spin_lock(&child->sighand->siglock); |
0e9f0a4ab ptrace: Always pu... |
82 83 |
/* |
73ddff2be job control: intr... |
84 85 86 87 88 89 90 |
* Clear all pending traps and TRAPPING. TRAPPING should be * cleared regardless of JOBCTL_STOP_PENDING. Do it explicitly. */ task_clear_jobctl_pending(child, JOBCTL_TRAP_MASK); task_clear_jobctl_trapping(child); /* |
a8f072c1d job control: rena... |
91 |
* Reinstate JOBCTL_STOP_PENDING if group stop is in effect and |
0e9f0a4ab ptrace: Always pu... |
92 93 94 95 |
* @child isn't dead. */ if (!(child->flags & PF_EXITING) && (child->signal->flags & SIGNAL_STOP_STOPPED || |
8a88951b5 ptrace: ensure JO... |
96 |
child->signal->group_stop_count)) { |
a8f072c1d job control: rena... |
97 |
child->jobctl |= JOBCTL_STOP_PENDING; |
0e9f0a4ab ptrace: Always pu... |
98 |
|
8a88951b5 ptrace: ensure JO... |
99 100 101 102 103 104 105 106 107 108 |
/* * This is only possible if this thread was cloned by the * traced task running in the stopped group, set the signal * for the future reports. * FIXME: we should change ptrace_init_task() to handle this * case. */ if (!(child->jobctl & JOBCTL_STOP_SIGMASK)) child->jobctl |= SIGSTOP; } |
0e9f0a4ab ptrace: Always pu... |
109 110 111 112 113 114 |
/* * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick * @child in the butt. Note that @resume should be used iff @child * is in TASK_TRACED; otherwise, we might unduly disrupt * TASK_KILLABLE sleeps. */ |
a8f072c1d job control: rena... |
115 |
if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) |
0e9f0a4ab ptrace: Always pu... |
116 |
signal_wake_up(child, task_is_traced(child)); |
1da177e4c Linux-2.6.12-rc2 |
117 |
spin_unlock(&child->sighand->siglock); |
1da177e4c Linux-2.6.12-rc2 |
118 |
} |
755e276b3 ptrace: ptrace_ch... |
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
/** * ptrace_check_attach - check whether ptracee is ready for ptrace operation * @child: ptracee to check for * @ignore_state: don't check whether @child is currently %TASK_TRACED * * Check whether @child is being ptraced by %current and ready for further * ptrace operations. If @ignore_state is %false, @child also should be in * %TASK_TRACED state and on return the child is guaranteed to be traced * and not executing. If @ignore_state is %true, @child can be in any * state. * * CONTEXT: * Grabs and releases tasklist_lock and @child->sighand->siglock. * * RETURNS: * 0 on success, -ESRCH if %child is not ready. |
1da177e4c Linux-2.6.12-rc2 |
135 |
*/ |
755e276b3 ptrace: ptrace_ch... |
136 |
int ptrace_check_attach(struct task_struct *child, bool ignore_state) |
1da177e4c Linux-2.6.12-rc2 |
137 138 139 140 141 142 143 144 145 146 147 |
{ int ret = -ESRCH; /* * We take the read lock around doing both checks to close a * possible race where someone else was tracing our child and * detached between these two checks. After this locked check, * we are sure that this is our traced child and that can only * be changed by us so it's not changing right after this. */ read_lock(&tasklist_lock); |
c0c0b649d ptrace_check_atta... |
148 |
if ((child->ptrace & PT_PTRACED) && child->parent == current) { |
c0c0b649d ptrace_check_atta... |
149 150 151 152 |
/* * child->sighand can't be NULL, release_task() * does ptrace_unlink() before __exit_signal(). */ |
1da177e4c Linux-2.6.12-rc2 |
153 |
spin_lock_irq(&child->sighand->siglock); |
321fb5619 ptrace: ptrace_ch... |
154 |
WARN_ON_ONCE(task_is_stopped(child)); |
544b2c91a ptrace: implement... |
155 156 |
if (ignore_state || (task_is_traced(child) && !(child->jobctl & JOBCTL_LISTENING))) |
321fb5619 ptrace: ptrace_ch... |
157 |
ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
158 159 160 |
spin_unlock_irq(&child->sighand->siglock); } read_unlock(&tasklist_lock); |
755e276b3 ptrace: ptrace_ch... |
161 |
if (!ret && !ignore_state) |
85ba2d862 tracehook: wait_t... |
162 |
ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH; |
1da177e4c Linux-2.6.12-rc2 |
163 164 165 166 |
/* All systems go.. */ return ret; } |
69f594a38 ptrace: do not au... |
167 168 169 170 171 172 173 |
static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) { if (mode & PTRACE_MODE_NOAUDIT) return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); else return has_ns_capability(current, ns, CAP_SYS_PTRACE); } |
006ebb40d Security: split p... |
174 |
int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
ab8d11beb [PATCH] remove du... |
175 |
{ |
c69e8d9c0 CRED: Use RCU to ... |
176 |
const struct cred *cred = current_cred(), *tcred; |
b6dff3ec5 CRED: Separate ta... |
177 |
|
df26c40e5 [PATCH] proc: Cle... |
178 179 180 181 182 183 184 185 186 187 188 189 |
/* May we inspect the given task? * This check is used both for attaching with ptrace * and for allowing access to sensitive information in /proc. * * ptrace_attach denies several cases that /proc allows * because setting up the necessary parent/child relationship * or halting the specified task is impossible. */ int dumpable = 0; /* Don't let security modules deny introspection */ if (task == current) return 0; |
c69e8d9c0 CRED: Use RCU to ... |
190 191 |
rcu_read_lock(); tcred = __task_cred(task); |
8409cca70 userns: allow ptr... |
192 193 194 195 196 197 198 199 |
if (cred->user->user_ns == tcred->user->user_ns && (cred->uid == tcred->euid && cred->uid == tcred->suid && cred->uid == tcred->uid && cred->gid == tcred->egid && cred->gid == tcred->sgid && cred->gid == tcred->gid)) goto ok; |
69f594a38 ptrace: do not au... |
200 |
if (ptrace_has_cap(tcred->user->user_ns, mode)) |
8409cca70 userns: allow ptr... |
201 202 203 204 |
goto ok; rcu_read_unlock(); return -EPERM; ok: |
c69e8d9c0 CRED: Use RCU to ... |
205 |
rcu_read_unlock(); |
ab8d11beb [PATCH] remove du... |
206 |
smp_rmb(); |
df26c40e5 [PATCH] proc: Cle... |
207 |
if (task->mm) |
6c5d52382 coredump masking:... |
208 |
dumpable = get_dumpable(task->mm); |
69f594a38 ptrace: do not au... |
209 |
if (!dumpable && !ptrace_has_cap(task_user_ns(task), mode)) |
ab8d11beb [PATCH] remove du... |
210 |
return -EPERM; |
9e48858f7 security: rename ... |
211 |
return security_ptrace_access_check(task, mode); |
ab8d11beb [PATCH] remove du... |
212 |
} |
006ebb40d Security: split p... |
213 |
bool ptrace_may_access(struct task_struct *task, unsigned int mode) |
ab8d11beb [PATCH] remove du... |
214 215 216 |
{ int err; task_lock(task); |
006ebb40d Security: split p... |
217 |
err = __ptrace_may_access(task, mode); |
ab8d11beb [PATCH] remove du... |
218 |
task_unlock(task); |
3a7097035 ptrace: some chec... |
219 |
return !err; |
ab8d11beb [PATCH] remove du... |
220 |
} |
3544d72a0 ptrace: implement... |
221 222 |
static int ptrace_attach(struct task_struct *task, long request, unsigned long flags) |
1da177e4c Linux-2.6.12-rc2 |
223 |
{ |
3544d72a0 ptrace: implement... |
224 |
bool seize = (request == PTRACE_SEIZE); |
1da177e4c Linux-2.6.12-rc2 |
225 |
int retval; |
f5b40e363 Fix ptrace_attach... |
226 |
|
3544d72a0 ptrace: implement... |
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
/* * SEIZE will enable new ptrace behaviors which will be implemented * gradually. SEIZE_DEVEL is used to prevent applications * expecting full SEIZE behaviors trapping on kernel commits which * are still in the process of implementing them. * * Only test programs for new ptrace behaviors being implemented * should set SEIZE_DEVEL. If unset, SEIZE will fail with -EIO. * * Once SEIZE behaviors are completely implemented, this flag and * the following test will be removed. */ retval = -EIO; if (seize && !(flags & PTRACE_SEIZE_DEVEL)) goto out; |
a5cb013da [PATCH] auditing ... |
242 |
audit_ptrace(task); |
1da177e4c Linux-2.6.12-rc2 |
243 |
retval = -EPERM; |
b79b7ba93 ptrace: ptrace_at... |
244 245 |
if (unlikely(task->flags & PF_KTHREAD)) goto out; |
bac0abd61 Isolate some expl... |
246 |
if (same_thread_group(task, current)) |
f5b40e363 Fix ptrace_attach... |
247 |
goto out; |
f2f0b00ad ptrace: cleanup c... |
248 249 |
/* * Protect exec's credential calculations against our interference; |
5e751e992 CRED: Rename cred... |
250 251 |
* interference; SUID, SGID and LSM creds get determined differently * under ptrace. |
d84f4f992 CRED: Inaugurate ... |
252 |
*/ |
793285fca cred_guard_mutex:... |
253 |
retval = -ERESTARTNOINTR; |
9b1bf12d5 signals: move cre... |
254 |
if (mutex_lock_interruptible(&task->signal->cred_guard_mutex)) |
d84f4f992 CRED: Inaugurate ... |
255 |
goto out; |
f5b40e363 Fix ptrace_attach... |
256 |
|
4b105cbba ptrace: do not us... |
257 |
task_lock(task); |
006ebb40d Security: split p... |
258 |
retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); |
4b105cbba ptrace: do not us... |
259 |
task_unlock(task); |
1da177e4c Linux-2.6.12-rc2 |
260 |
if (retval) |
4b105cbba ptrace: do not us... |
261 |
goto unlock_creds; |
1da177e4c Linux-2.6.12-rc2 |
262 |
|
4b105cbba ptrace: do not us... |
263 |
write_lock_irq(&tasklist_lock); |
b79b7ba93 ptrace: ptrace_at... |
264 265 |
retval = -EPERM; if (unlikely(task->exit_state)) |
4b105cbba ptrace: do not us... |
266 |
goto unlock_tasklist; |
f2f0b00ad ptrace: cleanup c... |
267 |
if (task->ptrace) |
4b105cbba ptrace: do not us... |
268 |
goto unlock_tasklist; |
b79b7ba93 ptrace: ptrace_at... |
269 |
|
f2f0b00ad ptrace: cleanup c... |
270 |
task->ptrace = PT_PTRACED; |
3544d72a0 ptrace: implement... |
271 272 |
if (seize) task->ptrace |= PT_SEIZED; |
f1c84dae0 capabilities: rem... |
273 |
if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE)) |
1da177e4c Linux-2.6.12-rc2 |
274 |
task->ptrace |= PT_PTRACE_CAP; |
1da177e4c Linux-2.6.12-rc2 |
275 |
|
1da177e4c Linux-2.6.12-rc2 |
276 |
__ptrace_link(task, current); |
3544d72a0 ptrace: implement... |
277 278 279 280 |
/* SEIZE doesn't trap tracee on attach */ if (!seize) send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); |
b79b7ba93 ptrace: ptrace_at... |
281 |
|
d79fdd6d9 ptrace: Clean tra... |
282 283 284 |
spin_lock(&task->sighand->siglock); /* |
73ddff2be job control: intr... |
285 |
* If the task is already STOPPED, set JOBCTL_TRAP_STOP and |
d79fdd6d9 ptrace: Clean tra... |
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
* TRAPPING, and kick it so that it transits to TRACED. TRAPPING * will be cleared if the child completes the transition or any * event which clears the group stop states happens. We'll wait * for the transition to complete before returning from this * function. * * This hides STOPPED -> RUNNING -> TRACED transition from the * attaching thread but a different thread in the same group can * still observe the transient RUNNING state. IOW, if another * thread's WNOHANG wait(2) on the stopped tracee races against * ATTACH, the wait(2) may fail due to the transient RUNNING. * * The following task_is_stopped() test is safe as both transitions * in and out of STOPPED are protected by siglock. */ |
7dd3db54e job control: intr... |
301 |
if (task_is_stopped(task) && |
73ddff2be job control: intr... |
302 |
task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) |
d79fdd6d9 ptrace: Clean tra... |
303 |
signal_wake_up(task, 1); |
d79fdd6d9 ptrace: Clean tra... |
304 305 |
spin_unlock(&task->sighand->siglock); |
b79b7ba93 ptrace: ptrace_at... |
306 |
retval = 0; |
4b105cbba ptrace: do not us... |
307 308 309 |
unlock_tasklist: write_unlock_irq(&tasklist_lock); unlock_creds: |
9b1bf12d5 signals: move cre... |
310 |
mutex_unlock(&task->signal->cred_guard_mutex); |
f5b40e363 Fix ptrace_attach... |
311 |
out: |
f701e5b73 connector: add an... |
312 |
if (!retval) { |
62c124ff3 ptrace: use bit_w... |
313 314 |
wait_on_bit(&task->jobctl, JOBCTL_TRAPPING_BIT, ptrace_trapping_sleep_fn, TASK_UNINTERRUPTIBLE); |
f701e5b73 connector: add an... |
315 316 |
proc_ptrace_connector(task, PTRACE_ATTACH); } |
1da177e4c Linux-2.6.12-rc2 |
317 318 |
return retval; } |
f2f0b00ad ptrace: cleanup c... |
319 320 321 322 323 324 |
/** * ptrace_traceme -- helper for PTRACE_TRACEME * * Performs checks and sets PT_PTRACED. * Should be used by all ptrace implementations for PTRACE_TRACEME. */ |
e3e89cc53 Mark ptrace_{trac... |
325 |
static int ptrace_traceme(void) |
f2f0b00ad ptrace: cleanup c... |
326 327 |
{ int ret = -EPERM; |
4b105cbba ptrace: do not us... |
328 329 |
write_lock_irq(&tasklist_lock); /* Are we already being traced? */ |
f2f0b00ad ptrace: cleanup c... |
330 |
if (!current->ptrace) { |
f2f0b00ad ptrace: cleanup c... |
331 |
ret = security_ptrace_traceme(current->parent); |
f2f0b00ad ptrace: cleanup c... |
332 333 334 335 336 337 338 339 340 |
/* * Check PF_EXITING to ensure ->real_parent has not passed * exit_ptrace(). Otherwise we don't report the error but * pretend ->real_parent untraces us right after return. */ if (!ret && !(current->real_parent->flags & PF_EXITING)) { current->ptrace = PT_PTRACED; __ptrace_link(current, current->real_parent); } |
f2f0b00ad ptrace: cleanup c... |
341 |
} |
4b105cbba ptrace: do not us... |
342 |
write_unlock_irq(&tasklist_lock); |
f2f0b00ad ptrace: cleanup c... |
343 344 |
return ret; } |
39c626ae4 forget_original_p... |
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
/* * Called with irqs disabled, returns true if childs should reap themselves. */ static int ignoring_children(struct sighand_struct *sigh) { int ret; spin_lock(&sigh->siglock); ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) || (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT); spin_unlock(&sigh->siglock); return ret; } /* * Called with tasklist_lock held for writing. * Unlink a traced task, and clean it up if it was a traced zombie. * Return true if it needs to be reaped with release_task(). * (We can't call release_task() here because we already hold tasklist_lock.) * * If it's a zombie, our attachedness prevented normal parent notification * or self-reaping. Do notification now if it would have happened earlier. * If it should reap itself, return true. * |
a7f0765ed ptrace: __ptrace_... |
368 369 370 371 |
* If it's our own child, there is no notification to do. But if our normal * children self-reap, then this child was prevented by ptrace and we must * reap it now, in that case we must also wake up sub-threads sleeping in * do_wait(). |
39c626ae4 forget_original_p... |
372 373 374 |
*/ static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) { |
9843a1e97 __ptrace_detach: ... |
375 |
bool dead; |
39c626ae4 forget_original_p... |
376 |
__ptrace_unlink(p); |
9843a1e97 __ptrace_detach: ... |
377 378 379 380 381 382 383 384 385 386 |
if (p->exit_state != EXIT_ZOMBIE) return false; dead = !thread_group_leader(p); if (!dead && thread_group_empty(p)) { if (!same_thread_group(p->real_parent, tracer)) dead = do_notify_parent(p, p->exit_signal); else if (ignoring_children(tracer->sighand)) { __wake_up_parent(p, tracer); |
9843a1e97 __ptrace_detach: ... |
387 |
dead = true; |
39c626ae4 forget_original_p... |
388 389 |
} } |
9843a1e97 __ptrace_detach: ... |
390 391 392 393 |
/* Mark it as in the process of being reaped. */ if (dead) p->exit_state = EXIT_DEAD; return dead; |
39c626ae4 forget_original_p... |
394 |
} |
e3e89cc53 Mark ptrace_{trac... |
395 |
static int ptrace_detach(struct task_struct *child, unsigned int data) |
1da177e4c Linux-2.6.12-rc2 |
396 |
{ |
39c626ae4 forget_original_p... |
397 |
bool dead = false; |
4576145c1 ptrace: fix possi... |
398 |
|
7ed20e1ad [PATCH] convert t... |
399 |
if (!valid_signal(data)) |
5ecfbae09 [PATCH] fix zap_t... |
400 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
401 402 403 |
/* Architecture-specific hardware disable .. */ ptrace_disable(child); |
7d9414329 Fix spurious sysc... |
404 |
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
1da177e4c Linux-2.6.12-rc2 |
405 |
|
95c3eb76d ptrace: kill __pt... |
406 |
write_lock_irq(&tasklist_lock); |
39c626ae4 forget_original_p... |
407 408 409 410 |
/* * This child can be already killed. Make sure de_thread() or * our sub-thread doing do_wait() didn't do release_task() yet. */ |
95c3eb76d ptrace: kill __pt... |
411 412 |
if (child->ptrace) { child->exit_code = data; |
4576145c1 ptrace: fix possi... |
413 |
dead = __ptrace_detach(current, child); |
95c3eb76d ptrace: kill __pt... |
414 |
} |
1da177e4c Linux-2.6.12-rc2 |
415 |
write_unlock_irq(&tasklist_lock); |
f701e5b73 connector: add an... |
416 |
proc_ptrace_connector(child, PTRACE_DETACH); |
4576145c1 ptrace: fix possi... |
417 418 |
if (unlikely(dead)) release_task(child); |
1da177e4c Linux-2.6.12-rc2 |
419 420 |
return 0; } |
39c626ae4 forget_original_p... |
421 |
/* |
c7e49c148 ptrace: optimize ... |
422 423 424 |
* Detach all tasks we were using ptrace on. Called with tasklist held * for writing, and returns with it held too. But note it can release * and reacquire the lock. |
39c626ae4 forget_original_p... |
425 426 |
*/ void exit_ptrace(struct task_struct *tracer) |
c4b5ed250 ptrace: annotate ... |
427 428 |
__releases(&tasklist_lock) __acquires(&tasklist_lock) |
39c626ae4 forget_original_p... |
429 430 431 |
{ struct task_struct *p, *n; LIST_HEAD(ptrace_dead); |
c7e49c148 ptrace: optimize ... |
432 433 |
if (likely(list_empty(&tracer->ptraced))) return; |
39c626ae4 forget_original_p... |
434 435 436 437 |
list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) { if (__ptrace_detach(tracer, p)) list_add(&p->ptrace_entry, &ptrace_dead); } |
39c626ae4 forget_original_p... |
438 |
|
c7e49c148 ptrace: optimize ... |
439 |
write_unlock_irq(&tasklist_lock); |
39c626ae4 forget_original_p... |
440 441 442 443 444 445 |
BUG_ON(!list_empty(&tracer->ptraced)); list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) { list_del_init(&p->ptrace_entry); release_task(p); } |
c7e49c148 ptrace: optimize ... |
446 447 |
write_lock_irq(&tasklist_lock); |
39c626ae4 forget_original_p... |
448 |
} |
1da177e4c Linux-2.6.12-rc2 |
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) { int copied = 0; while (len > 0) { char buf[128]; int this_len, retval; this_len = (len > sizeof(buf)) ? sizeof(buf) : len; retval = access_process_vm(tsk, src, buf, this_len, 0); if (!retval) { if (copied) break; return -EIO; } if (copy_to_user(dst, buf, retval)) return -EFAULT; copied += retval; src += retval; dst += retval; |
3a7097035 ptrace: some chec... |
469 |
len -= retval; |
1da177e4c Linux-2.6.12-rc2 |
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
} return copied; } int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len) { int copied = 0; while (len > 0) { char buf[128]; int this_len, retval; this_len = (len > sizeof(buf)) ? sizeof(buf) : len; if (copy_from_user(buf, src, this_len)) return -EFAULT; retval = access_process_vm(tsk, dst, buf, this_len, 1); if (!retval) { if (copied) break; return -EIO; } copied += retval; src += retval; dst += retval; |
3a7097035 ptrace: some chec... |
494 |
len -= retval; |
1da177e4c Linux-2.6.12-rc2 |
495 496 497 |
} return copied; } |
4abf98696 ptrace: change si... |
498 |
static int ptrace_setoptions(struct task_struct *child, unsigned long data) |
1da177e4c Linux-2.6.12-rc2 |
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
{ child->ptrace &= ~PT_TRACE_MASK; if (data & PTRACE_O_TRACESYSGOOD) child->ptrace |= PT_TRACESYSGOOD; if (data & PTRACE_O_TRACEFORK) child->ptrace |= PT_TRACE_FORK; if (data & PTRACE_O_TRACEVFORK) child->ptrace |= PT_TRACE_VFORK; if (data & PTRACE_O_TRACECLONE) child->ptrace |= PT_TRACE_CLONE; if (data & PTRACE_O_TRACEEXEC) child->ptrace |= PT_TRACE_EXEC; if (data & PTRACE_O_TRACEVFORKDONE) child->ptrace |= PT_TRACE_VFORK_DONE; if (data & PTRACE_O_TRACEEXIT) child->ptrace |= PT_TRACE_EXIT; return (data & ~PTRACE_O_MASK) ? -EINVAL : 0; } |
e16b27816 ptrace: compat_pt... |
525 |
static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) |
1da177e4c Linux-2.6.12-rc2 |
526 |
{ |
e49612544 ptrace: don't tak... |
527 |
unsigned long flags; |
1da177e4c Linux-2.6.12-rc2 |
528 |
int error = -ESRCH; |
e49612544 ptrace: don't tak... |
529 |
if (lock_task_sighand(child, &flags)) { |
1da177e4c Linux-2.6.12-rc2 |
530 |
error = -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
531 |
if (likely(child->last_siginfo != NULL)) { |
e16b27816 ptrace: compat_pt... |
532 |
*info = *child->last_siginfo; |
1da177e4c Linux-2.6.12-rc2 |
533 534 |
error = 0; } |
e49612544 ptrace: don't tak... |
535 |
unlock_task_sighand(child, &flags); |
1da177e4c Linux-2.6.12-rc2 |
536 |
} |
1da177e4c Linux-2.6.12-rc2 |
537 538 |
return error; } |
e16b27816 ptrace: compat_pt... |
539 |
static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) |
1da177e4c Linux-2.6.12-rc2 |
540 |
{ |
e49612544 ptrace: don't tak... |
541 |
unsigned long flags; |
1da177e4c Linux-2.6.12-rc2 |
542 |
int error = -ESRCH; |
e49612544 ptrace: don't tak... |
543 |
if (lock_task_sighand(child, &flags)) { |
1da177e4c Linux-2.6.12-rc2 |
544 |
error = -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
545 |
if (likely(child->last_siginfo != NULL)) { |
e16b27816 ptrace: compat_pt... |
546 |
*child->last_siginfo = *info; |
1da177e4c Linux-2.6.12-rc2 |
547 548 |
error = 0; } |
e49612544 ptrace: don't tak... |
549 |
unlock_task_sighand(child, &flags); |
1da177e4c Linux-2.6.12-rc2 |
550 |
} |
1da177e4c Linux-2.6.12-rc2 |
551 552 |
return error; } |
36df29d79 ptrace: generic r... |
553 554 555 556 557 558 |
#ifdef PTRACE_SINGLESTEP #define is_singlestep(request) ((request) == PTRACE_SINGLESTEP) #else #define is_singlestep(request) 0 #endif |
5b88abbf7 ptrace: generic P... |
559 560 561 562 563 |
#ifdef PTRACE_SINGLEBLOCK #define is_singleblock(request) ((request) == PTRACE_SINGLEBLOCK) #else #define is_singleblock(request) 0 #endif |
36df29d79 ptrace: generic r... |
564 565 566 567 568 |
#ifdef PTRACE_SYSEMU #define is_sysemu_singlestep(request) ((request) == PTRACE_SYSEMU_SINGLESTEP) #else #define is_sysemu_singlestep(request) 0 #endif |
4abf98696 ptrace: change si... |
569 570 |
static int ptrace_resume(struct task_struct *child, long request, unsigned long data) |
36df29d79 ptrace: generic r... |
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
{ if (!valid_signal(data)) return -EIO; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); #ifdef TIF_SYSCALL_EMU if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) set_tsk_thread_flag(child, TIF_SYSCALL_EMU); else clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); #endif |
5b88abbf7 ptrace: generic P... |
586 587 588 589 590 |
if (is_singleblock(request)) { if (unlikely(!arch_has_block_step())) return -EIO; user_enable_block_step(child); } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { |
36df29d79 ptrace: generic r... |
591 592 593 |
if (unlikely(!arch_has_single_step())) return -EIO; user_enable_single_step(child); |
3a7097035 ptrace: some chec... |
594 |
} else { |
36df29d79 ptrace: generic r... |
595 |
user_disable_single_step(child); |
3a7097035 ptrace: some chec... |
596 |
} |
36df29d79 ptrace: generic r... |
597 598 |
child->exit_code = data; |
0666fb51b ptrace: ptrace_re... |
599 |
wake_up_state(child, __TASK_TRACED); |
36df29d79 ptrace: generic r... |
600 601 602 |
return 0; } |
2225a122a ptrace: Add suppo... |
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK static const struct user_regset * find_regset(const struct user_regset_view *view, unsigned int type) { const struct user_regset *regset; int n; for (n = 0; n < view->n; ++n) { regset = view->regsets + n; if (regset->core_note_type == type) return regset; } return NULL; } static int ptrace_regset(struct task_struct *task, int req, unsigned int type, struct iovec *kiov) { const struct user_regset_view *view = task_user_regset_view(task); const struct user_regset *regset = find_regset(view, type); int regset_no; if (!regset || (kiov->iov_len % regset->size) != 0) |
c6a0dd7ec ptrace: Fix ptrac... |
628 |
return -EINVAL; |
2225a122a ptrace: Add suppo... |
629 630 631 632 633 634 635 636 637 638 639 640 641 642 |
regset_no = regset - view->regsets; kiov->iov_len = min(kiov->iov_len, (__kernel_size_t) (regset->n * regset->size)); if (req == PTRACE_GETREGSET) return copy_regset_to_user(task, view, regset_no, 0, kiov->iov_len, kiov->iov_base); else return copy_regset_from_user(task, view, regset_no, 0, kiov->iov_len, kiov->iov_base); } #endif |
1da177e4c Linux-2.6.12-rc2 |
643 |
int ptrace_request(struct task_struct *child, long request, |
4abf98696 ptrace: change si... |
644 |
unsigned long addr, unsigned long data) |
1da177e4c Linux-2.6.12-rc2 |
645 |
{ |
fca26f260 ptrace: implement... |
646 |
bool seized = child->ptrace & PT_SEIZED; |
1da177e4c Linux-2.6.12-rc2 |
647 |
int ret = -EIO; |
544b2c91a ptrace: implement... |
648 |
siginfo_t siginfo, *si; |
9fed81dc4 ptrace: cleanup p... |
649 650 |
void __user *datavp = (void __user *) data; unsigned long __user *datalp = datavp; |
fca26f260 ptrace: implement... |
651 |
unsigned long flags; |
1da177e4c Linux-2.6.12-rc2 |
652 653 |
switch (request) { |
16c3e389e x86: ptrace_reque... |
654 655 656 657 658 659 |
case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: return generic_ptrace_peekdata(child, addr, data); case PTRACE_POKETEXT: case PTRACE_POKEDATA: return generic_ptrace_pokedata(child, addr, data); |
1da177e4c Linux-2.6.12-rc2 |
660 661 662 663 664 665 666 |
#ifdef PTRACE_OLDSETOPTIONS case PTRACE_OLDSETOPTIONS: #endif case PTRACE_SETOPTIONS: ret = ptrace_setoptions(child, data); break; case PTRACE_GETEVENTMSG: |
9fed81dc4 ptrace: cleanup p... |
667 |
ret = put_user(child->ptrace_message, datalp); |
1da177e4c Linux-2.6.12-rc2 |
668 |
break; |
e16b27816 ptrace: compat_pt... |
669 |
|
1da177e4c Linux-2.6.12-rc2 |
670 |
case PTRACE_GETSIGINFO: |
e16b27816 ptrace: compat_pt... |
671 672 |
ret = ptrace_getsiginfo(child, &siginfo); if (!ret) |
9fed81dc4 ptrace: cleanup p... |
673 |
ret = copy_siginfo_to_user(datavp, &siginfo); |
1da177e4c Linux-2.6.12-rc2 |
674 |
break; |
e16b27816 ptrace: compat_pt... |
675 |
|
1da177e4c Linux-2.6.12-rc2 |
676 |
case PTRACE_SETSIGINFO: |
9fed81dc4 ptrace: cleanup p... |
677 |
if (copy_from_user(&siginfo, datavp, sizeof siginfo)) |
e16b27816 ptrace: compat_pt... |
678 679 680 |
ret = -EFAULT; else ret = ptrace_setsiginfo(child, &siginfo); |
1da177e4c Linux-2.6.12-rc2 |
681 |
break; |
e16b27816 ptrace: compat_pt... |
682 |
|
fca26f260 ptrace: implement... |
683 684 685 686 687 688 689 690 691 692 693 694 695 |
case PTRACE_INTERRUPT: /* * Stop tracee without any side-effect on signal or job * control. At least one trap is guaranteed to happen * after this request. If @child is already trapped, the * current trap is not disturbed and another trap will * happen after the current trap is ended with PTRACE_CONT. * * The actual trap might not be PTRACE_EVENT_STOP trap but * the pending condition is cleared regardless. */ if (unlikely(!seized || !lock_task_sighand(child, &flags))) break; |
544b2c91a ptrace: implement... |
696 697 698 699 700 701 |
/* * INTERRUPT doesn't disturb existing trap sans one * exception. If ptracer issued LISTEN for the current * STOP, this INTERRUPT should clear LISTEN and re-trap * tracee into STOP. */ |
fca26f260 ptrace: implement... |
702 |
if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) |
544b2c91a ptrace: implement... |
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 |
signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); unlock_task_sighand(child, &flags); ret = 0; break; case PTRACE_LISTEN: /* * Listen for events. Tracee must be in STOP. It's not * resumed per-se but is not considered to be in TRACED by * wait(2) or ptrace(2). If an async event (e.g. group * stop state change) happens, tracee will enter STOP trap * again. Alternatively, ptracer can issue INTERRUPT to * finish listening and re-trap tracee into STOP. */ if (unlikely(!seized || !lock_task_sighand(child, &flags))) break; si = child->last_siginfo; |
f9d81f61c ptrace: PTRACE_LI... |
722 723 724 725 726 727 728 729 730 731 |
if (likely(si && (si->si_code >> 8) == PTRACE_EVENT_STOP)) { child->jobctl |= JOBCTL_LISTENING; /* * If NOTIFY is set, it means event happened between * start of this trap and now. Trigger re-trap. */ if (child->jobctl & JOBCTL_TRAP_NOTIFY) signal_wake_up(child, true); ret = 0; } |
fca26f260 ptrace: implement... |
732 |
unlock_task_sighand(child, &flags); |
fca26f260 ptrace: implement... |
733 |
break; |
1bcf54829 Consolidate PTRAC... |
734 735 736 |
case PTRACE_DETACH: /* detach a process that was attached. */ ret = ptrace_detach(child, data); break; |
36df29d79 ptrace: generic r... |
737 |
|
9c1a12592 ptrace: unify FDP... |
738 739 |
#ifdef CONFIG_BINFMT_ELF_FDPIC case PTRACE_GETFDPIC: { |
e0129ef91 ptrace: PTRACE_GE... |
740 |
struct mm_struct *mm = get_task_mm(child); |
9c1a12592 ptrace: unify FDP... |
741 |
unsigned long tmp = 0; |
e0129ef91 ptrace: PTRACE_GE... |
742 743 744 |
ret = -ESRCH; if (!mm) break; |
9c1a12592 ptrace: unify FDP... |
745 746 |
switch (addr) { case PTRACE_GETFDPIC_EXEC: |
e0129ef91 ptrace: PTRACE_GE... |
747 |
tmp = mm->context.exec_fdpic_loadmap; |
9c1a12592 ptrace: unify FDP... |
748 749 |
break; case PTRACE_GETFDPIC_INTERP: |
e0129ef91 ptrace: PTRACE_GE... |
750 |
tmp = mm->context.interp_fdpic_loadmap; |
9c1a12592 ptrace: unify FDP... |
751 752 753 754 |
break; default: break; } |
e0129ef91 ptrace: PTRACE_GE... |
755 |
mmput(mm); |
9c1a12592 ptrace: unify FDP... |
756 |
|
9fed81dc4 ptrace: cleanup p... |
757 |
ret = put_user(tmp, datalp); |
9c1a12592 ptrace: unify FDP... |
758 759 760 |
break; } #endif |
36df29d79 ptrace: generic r... |
761 762 763 |
#ifdef PTRACE_SINGLESTEP case PTRACE_SINGLESTEP: #endif |
5b88abbf7 ptrace: generic P... |
764 765 766 |
#ifdef PTRACE_SINGLEBLOCK case PTRACE_SINGLEBLOCK: #endif |
36df29d79 ptrace: generic r... |
767 768 769 770 771 772 773 774 775 776 777 778 |
#ifdef PTRACE_SYSEMU case PTRACE_SYSEMU: case PTRACE_SYSEMU_SINGLESTEP: #endif case PTRACE_SYSCALL: case PTRACE_CONT: return ptrace_resume(child, request, data); case PTRACE_KILL: if (child->exit_state) /* already dead */ return 0; return ptrace_resume(child, request, SIGKILL); |
2225a122a ptrace: Add suppo... |
779 780 781 782 783 |
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK case PTRACE_GETREGSET: case PTRACE_SETREGSET: { struct iovec kiov; |
9fed81dc4 ptrace: cleanup p... |
784 |
struct iovec __user *uiov = datavp; |
2225a122a ptrace: Add suppo... |
785 786 787 788 789 790 791 792 793 794 795 796 797 798 |
if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) return -EFAULT; if (__get_user(kiov.iov_base, &uiov->iov_base) || __get_user(kiov.iov_len, &uiov->iov_len)) return -EFAULT; ret = ptrace_regset(child, request, addr, &kiov); if (!ret) ret = __put_user(kiov.iov_len, &uiov->iov_len); break; } #endif |
1da177e4c Linux-2.6.12-rc2 |
799 800 801 802 803 804 |
default: break; } return ret; } |
481bed454 [PATCH] consolida... |
805 |
|
8053bdd5c ptrace_get_task_s... |
806 |
static struct task_struct *ptrace_get_task_struct(pid_t pid) |
6b9c7ed84 [PATCH] use ptrac... |
807 808 |
{ struct task_struct *child; |
481bed454 [PATCH] consolida... |
809 |
|
8053bdd5c ptrace_get_task_s... |
810 |
rcu_read_lock(); |
228ebcbe6 Uninline find_tas... |
811 |
child = find_task_by_vpid(pid); |
481bed454 [PATCH] consolida... |
812 813 |
if (child) get_task_struct(child); |
8053bdd5c ptrace_get_task_s... |
814 |
rcu_read_unlock(); |
f400e198b [PATCH] pidspace:... |
815 |
|
481bed454 [PATCH] consolida... |
816 |
if (!child) |
6b9c7ed84 [PATCH] use ptrac... |
817 818 |
return ERR_PTR(-ESRCH); return child; |
481bed454 [PATCH] consolida... |
819 |
} |
0ac155591 m32r: convert to ... |
820 821 822 |
#ifndef arch_ptrace_attach #define arch_ptrace_attach(child) do { } while (0) #endif |
4abf98696 ptrace: change si... |
823 824 |
SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, unsigned long, data) |
481bed454 [PATCH] consolida... |
825 826 827 |
{ struct task_struct *child; long ret; |
6b9c7ed84 [PATCH] use ptrac... |
828 829 |
if (request == PTRACE_TRACEME) { ret = ptrace_traceme(); |
6ea6dd93c ptrace: Call arch... |
830 831 |
if (!ret) arch_ptrace_attach(current); |
481bed454 [PATCH] consolida... |
832 |
goto out; |
6b9c7ed84 [PATCH] use ptrac... |
833 834 835 836 837 838 839 |
} child = ptrace_get_task_struct(pid); if (IS_ERR(child)) { ret = PTR_ERR(child); goto out; } |
481bed454 [PATCH] consolida... |
840 |
|
3544d72a0 ptrace: implement... |
841 842 |
if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { ret = ptrace_attach(child, request, data); |
0ac155591 m32r: convert to ... |
843 844 845 846 847 848 |
/* * Some architectures need to do book-keeping after * a ptrace attach. */ if (!ret) arch_ptrace_attach(child); |
005f18dfd [PATCH] fix task_... |
849 |
goto out_put_task_struct; |
481bed454 [PATCH] consolida... |
850 |
} |
fca26f260 ptrace: implement... |
851 852 |
ret = ptrace_check_attach(child, request == PTRACE_KILL || request == PTRACE_INTERRUPT); |
481bed454 [PATCH] consolida... |
853 854 855 856 |
if (ret < 0) goto out_put_task_struct; ret = arch_ptrace(child, request, addr, data); |
481bed454 [PATCH] consolida... |
857 858 859 860 |
out_put_task_struct: put_task_struct(child); out: |
481bed454 [PATCH] consolida... |
861 862 |
return ret; } |
766473231 PTRACE_PEEKDATA c... |
863 |
|
4abf98696 ptrace: change si... |
864 865 |
int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, unsigned long data) |
766473231 PTRACE_PEEKDATA c... |
866 867 868 869 870 871 872 873 874 |
{ unsigned long tmp; int copied; copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; return put_user(tmp, (unsigned long __user *)data); } |
f284ce726 PTRACE_POKEDATA c... |
875 |
|
4abf98696 ptrace: change si... |
876 877 |
int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, unsigned long data) |
f284ce726 PTRACE_POKEDATA c... |
878 879 880 881 882 883 |
{ int copied; copied = access_process_vm(tsk, addr, &data, sizeof(data), 1); return (copied == sizeof(data)) ? 0 : -EIO; } |
032d82d90 x86: compat_ptrac... |
884 |
|
96b8936a9 remove __ARCH_WAN... |
885 |
#if defined CONFIG_COMPAT |
032d82d90 x86: compat_ptrac... |
886 887 888 889 890 891 892 |
#include <linux/compat.h> int compat_ptrace_request(struct task_struct *child, compat_long_t request, compat_ulong_t addr, compat_ulong_t data) { compat_ulong_t __user *datap = compat_ptr(data); compat_ulong_t word; |
e16b27816 ptrace: compat_pt... |
893 |
siginfo_t siginfo; |
032d82d90 x86: compat_ptrac... |
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 |
int ret; switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: ret = access_process_vm(child, addr, &word, sizeof(word), 0); if (ret != sizeof(word)) ret = -EIO; else ret = put_user(word, datap); break; case PTRACE_POKETEXT: case PTRACE_POKEDATA: ret = access_process_vm(child, addr, &data, sizeof(data), 1); ret = (ret != sizeof(data) ? -EIO : 0); break; case PTRACE_GETEVENTMSG: ret = put_user((compat_ulong_t) child->ptrace_message, datap); break; |
e16b27816 ptrace: compat_pt... |
915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 |
case PTRACE_GETSIGINFO: ret = ptrace_getsiginfo(child, &siginfo); if (!ret) ret = copy_siginfo_to_user32( (struct compat_siginfo __user *) datap, &siginfo); break; case PTRACE_SETSIGINFO: memset(&siginfo, 0, sizeof siginfo); if (copy_siginfo_from_user32( &siginfo, (struct compat_siginfo __user *) datap)) ret = -EFAULT; else ret = ptrace_setsiginfo(child, &siginfo); break; |
2225a122a ptrace: Add suppo... |
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 |
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK case PTRACE_GETREGSET: case PTRACE_SETREGSET: { struct iovec kiov; struct compat_iovec __user *uiov = (struct compat_iovec __user *) datap; compat_uptr_t ptr; compat_size_t len; if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) return -EFAULT; if (__get_user(ptr, &uiov->iov_base) || __get_user(len, &uiov->iov_len)) return -EFAULT; kiov.iov_base = compat_ptr(ptr); kiov.iov_len = len; ret = ptrace_regset(child, request, addr, &kiov); if (!ret) ret = __put_user(kiov.iov_len, &uiov->iov_len); break; } #endif |
e16b27816 ptrace: compat_pt... |
957 |
|
032d82d90 x86: compat_ptrac... |
958 959 960 961 962 963 |
default: ret = ptrace_request(child, request, addr, data); } return ret; } |
c269f1961 x86: compat_sys_p... |
964 |
|
c269f1961 x86: compat_sys_p... |
965 966 967 968 969 |
asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, compat_long_t addr, compat_long_t data) { struct task_struct *child; long ret; |
c269f1961 x86: compat_sys_p... |
970 971 972 973 974 975 976 977 978 979 |
if (request == PTRACE_TRACEME) { ret = ptrace_traceme(); goto out; } child = ptrace_get_task_struct(pid); if (IS_ERR(child)) { ret = PTR_ERR(child); goto out; } |
3544d72a0 ptrace: implement... |
980 981 |
if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { ret = ptrace_attach(child, request, data); |
c269f1961 x86: compat_sys_p... |
982 983 984 985 986 987 988 989 |
/* * Some architectures need to do book-keeping after * a ptrace attach. */ if (!ret) arch_ptrace_attach(child); goto out_put_task_struct; } |
fca26f260 ptrace: implement... |
990 991 |
ret = ptrace_check_attach(child, request == PTRACE_KILL || request == PTRACE_INTERRUPT); |
c269f1961 x86: compat_sys_p... |
992 993 994 995 996 997 |
if (!ret) ret = compat_arch_ptrace(child, request, addr, data); out_put_task_struct: put_task_struct(child); out: |
c269f1961 x86: compat_sys_p... |
998 999 |
return ret; } |
96b8936a9 remove __ARCH_WAN... |
1000 |
#endif /* CONFIG_COMPAT */ |
bf26c0184 ptrace: Prepare t... |
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 |
#ifdef CONFIG_HAVE_HW_BREAKPOINT int ptrace_get_breakpoints(struct task_struct *tsk) { if (atomic_inc_not_zero(&tsk->ptrace_bp_refcnt)) return 0; return -1; } void ptrace_put_breakpoints(struct task_struct *tsk) { if (atomic_dec_and_test(&tsk->ptrace_bp_refcnt)) flush_ptrace_hw_breakpoint(tsk); } #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |