Blame view

kernel/ptrace.c 20.7 KB
1da177e4c   Linus Torvalds   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   Randy.Dunlap   [PATCH] move capa...
9
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
  #include <linux/module.h>
  #include <linux/sched.h>
  #include <linux/errno.h>
  #include <linux/mm.h>
  #include <linux/highmem.h>
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  #include <linux/ptrace.h>
  #include <linux/security.h>
7ed20e1ad   Jesper Juhl   [PATCH] convert t...
18
  #include <linux/signal.h>
a5cb013da   Al Viro   [PATCH] auditing ...
19
  #include <linux/audit.h>
b488893a3   Pavel Emelyanov   pid namespaces: c...
20
  #include <linux/pid_namespace.h>
f17d30a80   Adrian Bunk   kernel/ptrace.c s...
21
  #include <linux/syscalls.h>
3a7097035   Roland McGrath   ptrace: some chec...
22
  #include <linux/uaccess.h>
2225a122a   Suresh Siddha   ptrace: Add suppo...
23
  #include <linux/regset.h>
bf26c0184   Frederic Weisbecker   ptrace: Prepare t...
24
  #include <linux/hw_breakpoint.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25

bf53de907   Markus Metzger   x86, bts: add for...
26
27
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
   * 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   Ingo Molnar   [PATCH] sched: cl...
33
  void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  {
f470021ad   Roland McGrath   ptrace children r...
35
36
  	BUG_ON(!list_empty(&child->ptrace_entry));
  	list_add(&child->ptrace_entry, &new_parent->ptraced);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  	child->parent = new_parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  }
3a7097035   Roland McGrath   ptrace: some chec...
39

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
  /*
   * Turn a tracing stop into a normal stop now, since with no tracer there
   * would be no way to wake it up with SIGCONT or SIGKILL.  If there was a
   * signal sent that would resume the child, but didn't because it was in
   * TASK_TRACED, resume it now.
   * Requires that irqs be disabled.
   */
b747c8c10   Adrian Bunk   make ptrace_untra...
47
  static void ptrace_untrace(struct task_struct *child)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
  {
  	spin_lock(&child->sighand->siglock);
6618a3e27   Matthew Wilcox   ptrace: Use task_...
50
  	if (task_is_traced(child)) {
1ee118448   Oleg Nesterov   ptrace_untrace: f...
51
52
53
54
55
56
  		/*
  		 * If the group stop is completed or in progress,
  		 * this thread was already counted as stopped.
  		 */
  		if (child->signal->flags & SIGNAL_STOP_STOPPED ||
  		    child->signal->group_stop_count)
d9ae90ac4   Oleg Nesterov   use __set_task_st...
57
  			__set_task_state(child, TASK_STOPPED);
1ee118448   Oleg Nesterov   ptrace_untrace: f...
58
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  			signal_wake_up(child, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
67
68
69
  	}
  	spin_unlock(&child->sighand->siglock);
  }
  
  /*
   * unptrace a task: move it back to its original parent and
   * remove it from the ptrace list.
   *
   * Must be called with the tasklist lock write-held.
   */
36c8b5868   Ingo Molnar   [PATCH] sched: cl...
70
  void __ptrace_unlink(struct task_struct *child)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  {
5ecfbae09   Oleg Nesterov   [PATCH] fix zap_t...
72
  	BUG_ON(!child->ptrace);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
  	child->ptrace = 0;
f470021ad   Roland McGrath   ptrace children r...
74
75
  	child->parent = child->real_parent;
  	list_del_init(&child->ptrace_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

6618a3e27   Matthew Wilcox   ptrace: Use task_...
77
  	if (task_is_traced(child))
e57a50598   Roland McGrath   [PATCH] fix non-l...
78
  		ptrace_untrace(child);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  }
  
  /*
   * Check that we have indeed attached to the thing..
   */
  int ptrace_check_attach(struct task_struct *child, int kill)
  {
  	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   Oleg Nesterov   ptrace_check_atta...
96
  	if ((child->ptrace & PT_PTRACED) && child->parent == current) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  		ret = 0;
c0c0b649d   Oleg Nesterov   ptrace_check_atta...
98
99
100
101
  		/*
  		 * child->sighand can't be NULL, release_task()
  		 * does ptrace_unlink() before __exit_signal().
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  		spin_lock_irq(&child->sighand->siglock);
d9ae90ac4   Oleg Nesterov   use __set_task_st...
103
  		if (task_is_stopped(child))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  			child->state = TASK_TRACED;
d9ae90ac4   Oleg Nesterov   use __set_task_st...
105
  		else if (!task_is_traced(child) && !kill)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  			ret = -ESRCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
  		spin_unlock_irq(&child->sighand->siglock);
  	}
  	read_unlock(&tasklist_lock);
d9ae90ac4   Oleg Nesterov   use __set_task_st...
110
  	if (!ret && !kill)
85ba2d862   Roland McGrath   tracehook: wait_t...
111
  		ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
  
  	/* All systems go.. */
  	return ret;
  }
006ebb40d   Stephen Smalley   Security: split p...
116
  int __ptrace_may_access(struct task_struct *task, unsigned int mode)
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
117
  {
c69e8d9c0   David Howells   CRED: Use RCU to ...
118
  	const struct cred *cred = current_cred(), *tcred;
b6dff3ec5   David Howells   CRED: Separate ta...
119

df26c40e5   Eric W. Biederman   [PATCH] proc: Cle...
120
121
122
123
124
125
126
127
128
129
130
131
  	/* 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   David Howells   CRED: Use RCU to ...
132
133
  	rcu_read_lock();
  	tcred = __task_cred(task);
8409cca70   Serge E. Hallyn   userns: allow ptr...
134
135
136
137
138
139
140
141
142
143
144
145
146
  	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;
  	if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE))
  		goto ok;
  	rcu_read_unlock();
  	return -EPERM;
  ok:
c69e8d9c0   David Howells   CRED: Use RCU to ...
147
  	rcu_read_unlock();
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
148
  	smp_rmb();
df26c40e5   Eric W. Biederman   [PATCH] proc: Cle...
149
  	if (task->mm)
6c5d52382   Kawai, Hidehiro   coredump masking:...
150
  		dumpable = get_dumpable(task->mm);
8409cca70   Serge E. Hallyn   userns: allow ptr...
151
  	if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE))
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
152
  		return -EPERM;
9e48858f7   Ingo Molnar   security: rename ...
153
  	return security_ptrace_access_check(task, mode);
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
154
  }
006ebb40d   Stephen Smalley   Security: split p...
155
  bool ptrace_may_access(struct task_struct *task, unsigned int mode)
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
156
157
158
  {
  	int err;
  	task_lock(task);
006ebb40d   Stephen Smalley   Security: split p...
159
  	err = __ptrace_may_access(task, mode);
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
160
  	task_unlock(task);
3a7097035   Roland McGrath   ptrace: some chec...
161
  	return !err;
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
162
  }
e3e89cc53   Linus Torvalds   Mark ptrace_{trac...
163
  static int ptrace_attach(struct task_struct *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
  {
  	int retval;
f5b40e363   Linus Torvalds   Fix ptrace_attach...
166

a5cb013da   Al Viro   [PATCH] auditing ...
167
  	audit_ptrace(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  	retval = -EPERM;
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
169
170
  	if (unlikely(task->flags & PF_KTHREAD))
  		goto out;
bac0abd61   Pavel Emelyanov   Isolate some expl...
171
  	if (same_thread_group(task, current))
f5b40e363   Linus Torvalds   Fix ptrace_attach...
172
  		goto out;
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
173
174
  	/*
  	 * Protect exec's credential calculations against our interference;
5e751e992   David Howells   CRED: Rename cred...
175
176
  	 * interference; SUID, SGID and LSM creds get determined differently
  	 * under ptrace.
d84f4f992   David Howells   CRED: Inaugurate ...
177
  	 */
793285fca   Oleg Nesterov   cred_guard_mutex:...
178
  	retval = -ERESTARTNOINTR;
9b1bf12d5   KOSAKI Motohiro   signals: move cre...
179
  	if (mutex_lock_interruptible(&task->signal->cred_guard_mutex))
d84f4f992   David Howells   CRED: Inaugurate ...
180
  		goto out;
f5b40e363   Linus Torvalds   Fix ptrace_attach...
181

4b105cbba   Oleg Nesterov   ptrace: do not us...
182
  	task_lock(task);
006ebb40d   Stephen Smalley   Security: split p...
183
  	retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH);
4b105cbba   Oleg Nesterov   ptrace: do not us...
184
  	task_unlock(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  	if (retval)
4b105cbba   Oleg Nesterov   ptrace: do not us...
186
  		goto unlock_creds;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187

4b105cbba   Oleg Nesterov   ptrace: do not us...
188
  	write_lock_irq(&tasklist_lock);
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
189
190
  	retval = -EPERM;
  	if (unlikely(task->exit_state))
4b105cbba   Oleg Nesterov   ptrace: do not us...
191
  		goto unlock_tasklist;
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
192
  	if (task->ptrace)
4b105cbba   Oleg Nesterov   ptrace: do not us...
193
  		goto unlock_tasklist;
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
194

f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
195
  	task->ptrace = PT_PTRACED;
8409cca70   Serge E. Hallyn   userns: allow ptr...
196
  	if (task_ns_capable(task, CAP_SYS_PTRACE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  		task->ptrace |= PT_PTRACE_CAP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  	__ptrace_link(task, current);
33e9fc7d0   Oleg Nesterov   ptrace: ptrace_at...
200
  	send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
201
202
  
  	retval = 0;
4b105cbba   Oleg Nesterov   ptrace: do not us...
203
204
205
  unlock_tasklist:
  	write_unlock_irq(&tasklist_lock);
  unlock_creds:
9b1bf12d5   KOSAKI Motohiro   signals: move cre...
206
  	mutex_unlock(&task->signal->cred_guard_mutex);
f5b40e363   Linus Torvalds   Fix ptrace_attach...
207
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  	return retval;
  }
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
210
211
212
213
214
215
  /**
   * ptrace_traceme  --  helper for PTRACE_TRACEME
   *
   * Performs checks and sets PT_PTRACED.
   * Should be used by all ptrace implementations for PTRACE_TRACEME.
   */
e3e89cc53   Linus Torvalds   Mark ptrace_{trac...
216
  static int ptrace_traceme(void)
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
217
218
  {
  	int ret = -EPERM;
4b105cbba   Oleg Nesterov   ptrace: do not us...
219
220
  	write_lock_irq(&tasklist_lock);
  	/* Are we already being traced? */
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
221
  	if (!current->ptrace) {
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
222
  		ret = security_ptrace_traceme(current->parent);
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
223
224
225
226
227
228
229
230
231
  		/*
  		 * 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   Oleg Nesterov   ptrace: cleanup c...
232
  	}
4b105cbba   Oleg Nesterov   ptrace: do not us...
233
  	write_unlock_irq(&tasklist_lock);
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
234
235
  	return ret;
  }
39c626ae4   Oleg Nesterov   forget_original_p...
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  /*
   * 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   Oleg Nesterov   ptrace: __ptrace_...
259
260
261
262
   * 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   Oleg Nesterov   forget_original_p...
263
264
265
266
267
268
269
270
271
   */
  static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
  {
  	__ptrace_unlink(p);
  
  	if (p->exit_state == EXIT_ZOMBIE) {
  		if (!task_detached(p) && thread_group_empty(p)) {
  			if (!same_thread_group(p->real_parent, tracer))
  				do_notify_parent(p, p->exit_signal);
a7f0765ed   Oleg Nesterov   ptrace: __ptrace_...
272
273
  			else if (ignoring_children(tracer->sighand)) {
  				__wake_up_parent(p, tracer);
39c626ae4   Oleg Nesterov   forget_original_p...
274
  				p->exit_signal = -1;
a7f0765ed   Oleg Nesterov   ptrace: __ptrace_...
275
  			}
39c626ae4   Oleg Nesterov   forget_original_p...
276
277
278
279
280
281
282
283
284
285
  		}
  		if (task_detached(p)) {
  			/* Mark it as in the process of being reaped. */
  			p->exit_state = EXIT_DEAD;
  			return true;
  		}
  	}
  
  	return false;
  }
e3e89cc53   Linus Torvalds   Mark ptrace_{trac...
286
  static int ptrace_detach(struct task_struct *child, unsigned int data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  {
39c626ae4   Oleg Nesterov   forget_original_p...
288
  	bool dead = false;
4576145c1   Oleg Nesterov   ptrace: fix possi...
289

7ed20e1ad   Jesper Juhl   [PATCH] convert t...
290
  	if (!valid_signal(data))
5ecfbae09   Oleg Nesterov   [PATCH] fix zap_t...
291
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
  
  	/* Architecture-specific hardware disable .. */
  	ptrace_disable(child);
7d9414329   Roland McGrath   Fix spurious sysc...
295
  	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296

95c3eb76d   Oleg Nesterov   ptrace: kill __pt...
297
  	write_lock_irq(&tasklist_lock);
39c626ae4   Oleg Nesterov   forget_original_p...
298
299
300
301
  	/*
  	 * This child can be already killed. Make sure de_thread() or
  	 * our sub-thread doing do_wait() didn't do release_task() yet.
  	 */
95c3eb76d   Oleg Nesterov   ptrace: kill __pt...
302
303
  	if (child->ptrace) {
  		child->exit_code = data;
4576145c1   Oleg Nesterov   ptrace: fix possi...
304
  		dead = __ptrace_detach(current, child);
edaba2c53   Oleg Nesterov   ptrace: revert "p...
305
  		if (!child->exit_state)
01e05e9a9   Tejun Heo   ptrace: use safer...
306
  			wake_up_state(child, TASK_TRACED | TASK_STOPPED);
95c3eb76d   Oleg Nesterov   ptrace: kill __pt...
307
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  	write_unlock_irq(&tasklist_lock);
4576145c1   Oleg Nesterov   ptrace: fix possi...
309
310
  	if (unlikely(dead))
  		release_task(child);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
  	return 0;
  }
39c626ae4   Oleg Nesterov   forget_original_p...
313
  /*
c7e49c148   Oleg Nesterov   ptrace: optimize ...
314
315
316
   * 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   Oleg Nesterov   forget_original_p...
317
318
   */
  void exit_ptrace(struct task_struct *tracer)
c4b5ed250   Namhyung Kim   ptrace: annotate ...
319
320
  	__releases(&tasklist_lock)
  	__acquires(&tasklist_lock)
39c626ae4   Oleg Nesterov   forget_original_p...
321
322
323
  {
  	struct task_struct *p, *n;
  	LIST_HEAD(ptrace_dead);
c7e49c148   Oleg Nesterov   ptrace: optimize ...
324
325
  	if (likely(list_empty(&tracer->ptraced)))
  		return;
39c626ae4   Oleg Nesterov   forget_original_p...
326
327
328
329
  	list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
  		if (__ptrace_detach(tracer, p))
  			list_add(&p->ptrace_entry, &ptrace_dead);
  	}
39c626ae4   Oleg Nesterov   forget_original_p...
330

c7e49c148   Oleg Nesterov   ptrace: optimize ...
331
  	write_unlock_irq(&tasklist_lock);
39c626ae4   Oleg Nesterov   forget_original_p...
332
333
334
335
336
337
  	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   Oleg Nesterov   ptrace: optimize ...
338
339
  
  	write_lock_irq(&tasklist_lock);
39c626ae4   Oleg Nesterov   forget_original_p...
340
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  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   Roland McGrath   ptrace: some chec...
361
  		len -= retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  	}
  	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   Roland McGrath   ptrace: some chec...
386
  		len -= retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
  	}
  	return copied;
  }
4abf98696   Namhyung Kim   ptrace: change si...
390
  static int ptrace_setoptions(struct task_struct *child, unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  {
  	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   Roland McGrath   ptrace: compat_pt...
417
  static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  {
e49612544   Oleg Nesterov   ptrace: don't tak...
419
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  	int error = -ESRCH;
e49612544   Oleg Nesterov   ptrace: don't tak...
421
  	if (lock_task_sighand(child, &flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  		error = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  		if (likely(child->last_siginfo != NULL)) {
e16b27816   Roland McGrath   ptrace: compat_pt...
424
  			*info = *child->last_siginfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  			error = 0;
  		}
e49612544   Oleg Nesterov   ptrace: don't tak...
427
  		unlock_task_sighand(child, &flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
  	return error;
  }
e16b27816   Roland McGrath   ptrace: compat_pt...
431
  static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  {
e49612544   Oleg Nesterov   ptrace: don't tak...
433
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
  	int error = -ESRCH;
e49612544   Oleg Nesterov   ptrace: don't tak...
435
  	if (lock_task_sighand(child, &flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  		error = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  		if (likely(child->last_siginfo != NULL)) {
e16b27816   Roland McGrath   ptrace: compat_pt...
438
  			*child->last_siginfo = *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  			error = 0;
  		}
e49612544   Oleg Nesterov   ptrace: don't tak...
441
  		unlock_task_sighand(child, &flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
  	return error;
  }
36df29d79   Roland McGrath   ptrace: generic r...
445
446
447
448
449
450
  
  #ifdef PTRACE_SINGLESTEP
  #define is_singlestep(request)		((request) == PTRACE_SINGLESTEP)
  #else
  #define is_singlestep(request)		0
  #endif
5b88abbf7   Roland McGrath   ptrace: generic P...
451
452
453
454
455
  #ifdef PTRACE_SINGLEBLOCK
  #define is_singleblock(request)		((request) == PTRACE_SINGLEBLOCK)
  #else
  #define is_singleblock(request)		0
  #endif
36df29d79   Roland McGrath   ptrace: generic r...
456
457
458
459
460
  #ifdef PTRACE_SYSEMU
  #define is_sysemu_singlestep(request)	((request) == PTRACE_SYSEMU_SINGLESTEP)
  #else
  #define is_sysemu_singlestep(request)	0
  #endif
4abf98696   Namhyung Kim   ptrace: change si...
461
462
  static int ptrace_resume(struct task_struct *child, long request,
  			 unsigned long data)
36df29d79   Roland McGrath   ptrace: generic r...
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  {
  	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   Roland McGrath   ptrace: generic P...
478
479
480
481
482
  	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   Roland McGrath   ptrace: generic r...
483
484
485
  		if (unlikely(!arch_has_single_step()))
  			return -EIO;
  		user_enable_single_step(child);
3a7097035   Roland McGrath   ptrace: some chec...
486
  	} else {
36df29d79   Roland McGrath   ptrace: generic r...
487
  		user_disable_single_step(child);
3a7097035   Roland McGrath   ptrace: some chec...
488
  	}
36df29d79   Roland McGrath   ptrace: generic r...
489
490
491
492
493
494
  
  	child->exit_code = data;
  	wake_up_process(child);
  
  	return 0;
  }
2225a122a   Suresh Siddha   ptrace: Add suppo...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  #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   Suresh Siddha   ptrace: Fix ptrac...
520
  		return -EINVAL;
2225a122a   Suresh Siddha   ptrace: Add suppo...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
  
  	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   Linus Torvalds   Linux-2.6.12-rc2
535
  int ptrace_request(struct task_struct *child, long request,
4abf98696   Namhyung Kim   ptrace: change si...
536
  		   unsigned long addr, unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
  {
  	int ret = -EIO;
e16b27816   Roland McGrath   ptrace: compat_pt...
539
  	siginfo_t siginfo;
9fed81dc4   Namhyung Kim   ptrace: cleanup p...
540
541
  	void __user *datavp = (void __user *) data;
  	unsigned long __user *datalp = datavp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  
  	switch (request) {
16c3e389e   Roland McGrath   x86: ptrace_reque...
544
545
546
547
548
549
  	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   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
555
556
  #ifdef PTRACE_OLDSETOPTIONS
  	case PTRACE_OLDSETOPTIONS:
  #endif
  	case PTRACE_SETOPTIONS:
  		ret = ptrace_setoptions(child, data);
  		break;
  	case PTRACE_GETEVENTMSG:
9fed81dc4   Namhyung Kim   ptrace: cleanup p...
557
  		ret = put_user(child->ptrace_message, datalp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  		break;
e16b27816   Roland McGrath   ptrace: compat_pt...
559

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  	case PTRACE_GETSIGINFO:
e16b27816   Roland McGrath   ptrace: compat_pt...
561
562
  		ret = ptrace_getsiginfo(child, &siginfo);
  		if (!ret)
9fed81dc4   Namhyung Kim   ptrace: cleanup p...
563
  			ret = copy_siginfo_to_user(datavp, &siginfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
  		break;
e16b27816   Roland McGrath   ptrace: compat_pt...
565

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  	case PTRACE_SETSIGINFO:
9fed81dc4   Namhyung Kim   ptrace: cleanup p...
567
  		if (copy_from_user(&siginfo, datavp, sizeof siginfo))
e16b27816   Roland McGrath   ptrace: compat_pt...
568
569
570
  			ret = -EFAULT;
  		else
  			ret = ptrace_setsiginfo(child, &siginfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  		break;
e16b27816   Roland McGrath   ptrace: compat_pt...
572

1bcf54829   Alexey Dobriyan   Consolidate PTRAC...
573
574
575
  	case PTRACE_DETACH:	 /* detach a process that was attached. */
  		ret = ptrace_detach(child, data);
  		break;
36df29d79   Roland McGrath   ptrace: generic r...
576

9c1a12592   Mike Frysinger   ptrace: unify FDP...
577
578
  #ifdef CONFIG_BINFMT_ELF_FDPIC
  	case PTRACE_GETFDPIC: {
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
579
  		struct mm_struct *mm = get_task_mm(child);
9c1a12592   Mike Frysinger   ptrace: unify FDP...
580
  		unsigned long tmp = 0;
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
581
582
583
  		ret = -ESRCH;
  		if (!mm)
  			break;
9c1a12592   Mike Frysinger   ptrace: unify FDP...
584
585
  		switch (addr) {
  		case PTRACE_GETFDPIC_EXEC:
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
586
  			tmp = mm->context.exec_fdpic_loadmap;
9c1a12592   Mike Frysinger   ptrace: unify FDP...
587
588
  			break;
  		case PTRACE_GETFDPIC_INTERP:
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
589
  			tmp = mm->context.interp_fdpic_loadmap;
9c1a12592   Mike Frysinger   ptrace: unify FDP...
590
591
592
593
  			break;
  		default:
  			break;
  		}
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
594
  		mmput(mm);
9c1a12592   Mike Frysinger   ptrace: unify FDP...
595

9fed81dc4   Namhyung Kim   ptrace: cleanup p...
596
  		ret = put_user(tmp, datalp);
9c1a12592   Mike Frysinger   ptrace: unify FDP...
597
598
599
  		break;
  	}
  #endif
36df29d79   Roland McGrath   ptrace: generic r...
600
601
602
  #ifdef PTRACE_SINGLESTEP
  	case PTRACE_SINGLESTEP:
  #endif
5b88abbf7   Roland McGrath   ptrace: generic P...
603
604
605
  #ifdef PTRACE_SINGLEBLOCK
  	case PTRACE_SINGLEBLOCK:
  #endif
36df29d79   Roland McGrath   ptrace: generic r...
606
607
608
609
610
611
612
613
614
615
616
617
  #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   Suresh Siddha   ptrace: Add suppo...
618
619
620
621
622
  #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
  	case PTRACE_GETREGSET:
  	case PTRACE_SETREGSET:
  	{
  		struct iovec kiov;
9fed81dc4   Namhyung Kim   ptrace: cleanup p...
623
  		struct iovec __user *uiov = datavp;
2225a122a   Suresh Siddha   ptrace: Add suppo...
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  
  		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   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
642
643
  	default:
  		break;
  	}
  
  	return ret;
  }
481bed454   Christoph Hellwig   [PATCH] consolida...
644

8053bdd5c   Oleg Nesterov   ptrace_get_task_s...
645
  static struct task_struct *ptrace_get_task_struct(pid_t pid)
6b9c7ed84   Christoph Hellwig   [PATCH] use ptrac...
646
647
  {
  	struct task_struct *child;
481bed454   Christoph Hellwig   [PATCH] consolida...
648

8053bdd5c   Oleg Nesterov   ptrace_get_task_s...
649
  	rcu_read_lock();
228ebcbe6   Pavel Emelyanov   Uninline find_tas...
650
  	child = find_task_by_vpid(pid);
481bed454   Christoph Hellwig   [PATCH] consolida...
651
652
  	if (child)
  		get_task_struct(child);
8053bdd5c   Oleg Nesterov   ptrace_get_task_s...
653
  	rcu_read_unlock();
f400e198b   Sukadev Bhattiprolu   [PATCH] pidspace:...
654

481bed454   Christoph Hellwig   [PATCH] consolida...
655
  	if (!child)
6b9c7ed84   Christoph Hellwig   [PATCH] use ptrac...
656
657
  		return ERR_PTR(-ESRCH);
  	return child;
481bed454   Christoph Hellwig   [PATCH] consolida...
658
  }
0ac155591   Christoph Hellwig   m32r: convert to ...
659
660
661
  #ifndef arch_ptrace_attach
  #define arch_ptrace_attach(child)	do { } while (0)
  #endif
4abf98696   Namhyung Kim   ptrace: change si...
662
663
  SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
  		unsigned long, data)
481bed454   Christoph Hellwig   [PATCH] consolida...
664
665
666
  {
  	struct task_struct *child;
  	long ret;
6b9c7ed84   Christoph Hellwig   [PATCH] use ptrac...
667
668
  	if (request == PTRACE_TRACEME) {
  		ret = ptrace_traceme();
6ea6dd93c   Haavard Skinnemoen   ptrace: Call arch...
669
670
  		if (!ret)
  			arch_ptrace_attach(current);
481bed454   Christoph Hellwig   [PATCH] consolida...
671
  		goto out;
6b9c7ed84   Christoph Hellwig   [PATCH] use ptrac...
672
673
674
675
676
677
678
  	}
  
  	child = ptrace_get_task_struct(pid);
  	if (IS_ERR(child)) {
  		ret = PTR_ERR(child);
  		goto out;
  	}
481bed454   Christoph Hellwig   [PATCH] consolida...
679
680
681
  
  	if (request == PTRACE_ATTACH) {
  		ret = ptrace_attach(child);
0ac155591   Christoph Hellwig   m32r: convert to ...
682
683
684
685
686
687
  		/*
  		 * Some architectures need to do book-keeping after
  		 * a ptrace attach.
  		 */
  		if (!ret)
  			arch_ptrace_attach(child);
005f18dfd   Christoph Hellwig   [PATCH] fix task_...
688
  		goto out_put_task_struct;
481bed454   Christoph Hellwig   [PATCH] consolida...
689
690
691
692
693
694
695
  	}
  
  	ret = ptrace_check_attach(child, request == PTRACE_KILL);
  	if (ret < 0)
  		goto out_put_task_struct;
  
  	ret = arch_ptrace(child, request, addr, data);
481bed454   Christoph Hellwig   [PATCH] consolida...
696
697
698
699
  
   out_put_task_struct:
  	put_task_struct(child);
   out:
481bed454   Christoph Hellwig   [PATCH] consolida...
700
701
  	return ret;
  }
766473231   Alexey Dobriyan   PTRACE_PEEKDATA c...
702

4abf98696   Namhyung Kim   ptrace: change si...
703
704
  int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr,
  			    unsigned long data)
766473231   Alexey Dobriyan   PTRACE_PEEKDATA c...
705
706
707
708
709
710
711
712
713
  {
  	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   Alexey Dobriyan   PTRACE_POKEDATA c...
714

4abf98696   Namhyung Kim   ptrace: change si...
715
716
  int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,
  			    unsigned long data)
f284ce726   Alexey Dobriyan   PTRACE_POKEDATA c...
717
718
719
720
721
722
  {
  	int copied;
  
  	copied = access_process_vm(tsk, addr, &data, sizeof(data), 1);
  	return (copied == sizeof(data)) ? 0 : -EIO;
  }
032d82d90   Roland McGrath   x86: compat_ptrac...
723

96b8936a9   Christoph Hellwig   remove __ARCH_WAN...
724
  #if defined CONFIG_COMPAT
032d82d90   Roland McGrath   x86: compat_ptrac...
725
726
727
728
729
730
731
  #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   Roland McGrath   ptrace: compat_pt...
732
  	siginfo_t siginfo;
032d82d90   Roland McGrath   x86: compat_ptrac...
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
  	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   Roland McGrath   ptrace: compat_pt...
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  	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   Suresh Siddha   ptrace: Add suppo...
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
  #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   Roland McGrath   ptrace: compat_pt...
796

032d82d90   Roland McGrath   x86: compat_ptrac...
797
798
799
800
801
802
  	default:
  		ret = ptrace_request(child, request, addr, data);
  	}
  
  	return ret;
  }
c269f1961   Roland McGrath   x86: compat_sys_p...
803

c269f1961   Roland McGrath   x86: compat_sys_p...
804
805
806
807
808
  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   Roland McGrath   x86: compat_sys_p...
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
  	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;
  	}
  
  	if (request == PTRACE_ATTACH) {
  		ret = ptrace_attach(child);
  		/*
  		 * Some architectures need to do book-keeping after
  		 * a ptrace attach.
  		 */
  		if (!ret)
  			arch_ptrace_attach(child);
  		goto out_put_task_struct;
  	}
  
  	ret = ptrace_check_attach(child, request == PTRACE_KILL);
  	if (!ret)
  		ret = compat_arch_ptrace(child, request, addr, data);
  
   out_put_task_struct:
  	put_task_struct(child);
   out:
c269f1961   Roland McGrath   x86: compat_sys_p...
838
839
  	return ret;
  }
96b8936a9   Christoph Hellwig   remove __ARCH_WAN...
840
  #endif	/* CONFIG_COMPAT */
bf26c0184   Frederic Weisbecker   ptrace: Prepare t...
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  
  #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 */