Blame view

kernel/ptrace.c 36.5 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
  /*
   * 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...
10
  #include <linux/capability.h>
9984de1a5   Paul Gortmaker   kernel: Map most ...
11
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/sched.h>
6e84f3152   Ingo Molnar   sched/headers: Pr...
13
  #include <linux/sched/mm.h>
f7ccbae45   Ingo Molnar   sched/headers: Pr...
14
  #include <linux/sched/coredump.h>
299300258   Ingo Molnar   sched/headers: Pr...
15
  #include <linux/sched/task.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
  #include <linux/errno.h>
  #include <linux/mm.h>
  #include <linux/highmem.h>
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include <linux/ptrace.h>
  #include <linux/security.h>
7ed20e1ad   Jesper Juhl   [PATCH] convert t...
22
  #include <linux/signal.h>
a27bb332c   Kent Overstreet   aio: don't includ...
23
  #include <linux/uio.h>
a5cb013da   Al Viro   [PATCH] auditing ...
24
  #include <linux/audit.h>
b488893a3   Pavel Emelyanov   pid namespaces: c...
25
  #include <linux/pid_namespace.h>
f17d30a80   Adrian Bunk   kernel/ptrace.c s...
26
  #include <linux/syscalls.h>
3a7097035   Roland McGrath   ptrace: some chec...
27
  #include <linux/uaccess.h>
2225a122a   Suresh Siddha   ptrace: Add suppo...
28
  #include <linux/regset.h>
bf26c0184   Frederic Weisbecker   ptrace: Prepare t...
29
  #include <linux/hw_breakpoint.h>
f701e5b73   Vladimir Zapolskiy   connector: add an...
30
  #include <linux/cn_proc.h>
84c751bd4   Andrey Vagin   ptrace: add abili...
31
  #include <linux/compat.h>
fcfc2aa01   Andrei Vagin   ptrace: take into...
32
  #include <linux/sched/signal.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

201766a20   Elvira Khabirova   ptrace: add PTRAC...
34
  #include <asm/syscall.h>	/* for syscall_get_* */
84d77d3f0   Eric W. Biederman   ptrace: Don't all...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  /*
   * Access another process' address space via ptrace.
   * Source/target buffer must be kernel space,
   * Do not walk the page table directly, use get_user_pages
   */
  int ptrace_access_vm(struct task_struct *tsk, unsigned long addr,
  		     void *buf, int len, unsigned int gup_flags)
  {
  	struct mm_struct *mm;
  	int ret;
  
  	mm = get_task_mm(tsk);
  	if (!mm)
  		return 0;
  
  	if (!tsk->ptrace ||
  	    (current != tsk->parent) ||
  	    ((get_dumpable(mm) != SUID_DUMP_USER) &&
  	     !ptracer_capable(tsk, mm->user_ns))) {
  		mmput(mm);
  		return 0;
  	}
  
  	ret = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags);
  	mmput(mm);
  
  	return ret;
  }
bf53de907   Markus Metzger   x86, bts: add for...
63

c70d9d809   Eric W. Biederman   ptrace: Properly ...
64
65
66
67
68
69
70
71
  void __ptrace_link(struct task_struct *child, struct task_struct *new_parent,
  		   const struct cred *ptracer_cred)
  {
  	BUG_ON(!list_empty(&child->ptrace_entry));
  	list_add(&child->ptrace_entry, &new_parent->ptraced);
  	child->parent = new_parent;
  	child->ptracer_cred = get_cred(ptracer_cred);
  }
bf53de907   Markus Metzger   x86, bts: add for...
72
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
   * 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.
   */
c70d9d809   Eric W. Biederman   ptrace: Properly ...
78
  static void ptrace_link(struct task_struct *child, struct task_struct *new_parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  {
6994eefb0   Jann Horn   ptrace: Fix ->ptr...
80
  	__ptrace_link(child, new_parent, current_cred());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  }
3a7097035   Roland McGrath   ptrace: some chec...
82

e3bd058f6   Tejun Heo   ptrace: Collapse ...
83
84
85
  /**
   * __ptrace_unlink - unlink ptracee and restore its execution state
   * @child: ptracee to be unlinked
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
   *
0e9f0a4ab   Tejun Heo   ptrace: Always pu...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
   * 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   Tejun Heo   ptrace: Collapse ...
107
108
109
   *
   * CONTEXT:
   * write_lock_irq(tasklist_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
   */
36c8b5868   Ingo Molnar   [PATCH] sched: cl...
111
  void __ptrace_unlink(struct task_struct *child)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  {
64b875f7a   Eric W. Biederman   ptrace: Capture t...
113
  	const struct cred *old_cred;
5ecfbae09   Oleg Nesterov   [PATCH] fix zap_t...
114
  	BUG_ON(!child->ptrace);
0a5bf409d   Ales Novak   ptrace: clear TIF...
115
  	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
15532fd6f   Sudeep Holla   ptrace: move clea...
116
117
118
  #ifdef TIF_SYSCALL_EMU
  	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
  #endif
0a5bf409d   Ales Novak   ptrace: clear TIF...
119

f470021ad   Roland McGrath   ptrace children r...
120
121
  	child->parent = child->real_parent;
  	list_del_init(&child->ptrace_entry);
64b875f7a   Eric W. Biederman   ptrace: Capture t...
122
123
124
  	old_cred = child->ptracer_cred;
  	child->ptracer_cred = NULL;
  	put_cred(old_cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  	spin_lock(&child->sighand->siglock);
1333ab031   Oleg Nesterov   ptrace: change __...
127
  	child->ptrace = 0;
0e9f0a4ab   Tejun Heo   ptrace: Always pu...
128
  	/*
73ddff2be   Tejun Heo   job control: intr...
129
130
131
132
133
134
135
  	 * 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   Tejun Heo   job control: rena...
136
  	 * Reinstate JOBCTL_STOP_PENDING if group stop is in effect and
0e9f0a4ab   Tejun Heo   ptrace: Always pu...
137
138
139
140
  	 * @child isn't dead.
  	 */
  	if (!(child->flags & PF_EXITING) &&
  	    (child->signal->flags & SIGNAL_STOP_STOPPED ||
8a88951b5   Oleg Nesterov   ptrace: ensure JO...
141
  	     child->signal->group_stop_count)) {
a8f072c1d   Tejun Heo   job control: rena...
142
  		child->jobctl |= JOBCTL_STOP_PENDING;
0e9f0a4ab   Tejun Heo   ptrace: Always pu...
143

8a88951b5   Oleg Nesterov   ptrace: ensure JO...
144
145
146
147
148
149
150
151
152
153
  		/*
  		 * 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   Tejun Heo   ptrace: Always pu...
154
155
156
157
158
159
  	/*
  	 * 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   Tejun Heo   job control: rena...
160
  	if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child))
910ffdb18   Oleg Nesterov   ptrace: introduce...
161
  		ptrace_signal_wake_up(child, true);
0e9f0a4ab   Tejun Heo   ptrace: Always pu...
162

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  	spin_unlock(&child->sighand->siglock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  }
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  /* Ensure that nothing can wake it up, even SIGKILL */
  static bool ptrace_freeze_traced(struct task_struct *task)
  {
  	bool ret = false;
  
  	/* Lockless, nobody but us can set this flag */
  	if (task->jobctl & JOBCTL_LISTENING)
  		return ret;
  
  	spin_lock_irq(&task->sighand->siglock);
  	if (task_is_traced(task) && !__fatal_signal_pending(task)) {
  		task->state = __TASK_TRACED;
  		ret = true;
  	}
  	spin_unlock_irq(&task->sighand->siglock);
  
  	return ret;
  }
  
  static void ptrace_unfreeze_traced(struct task_struct *task)
  {
  	if (task->state != __TASK_TRACED)
  		return;
  
  	WARN_ON(!task->ptrace || task->parent != current);
5402e97af   bsegall@google.com   ptrace: fix PTRAC...
190
191
192
193
  	/*
  	 * PTRACE_LISTEN can allow ptrace_trap_notify to wake us up remotely.
  	 * Recheck state under the lock to close this race.
  	 */
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
194
  	spin_lock_irq(&task->sighand->siglock);
5402e97af   bsegall@google.com   ptrace: fix PTRAC...
195
196
197
198
199
200
  	if (task->state == __TASK_TRACED) {
  		if (__fatal_signal_pending(task))
  			wake_up_state(task, __TASK_TRACED);
  		else
  			task->state = TASK_TRACED;
  	}
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
201
202
  	spin_unlock_irq(&task->sighand->siglock);
  }
755e276b3   Tejun Heo   ptrace: ptrace_ch...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  /**
   * 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   Linus Torvalds   Linux-2.6.12-rc2
219
   */
edea0d03e   Oleg Nesterov   ia64: kill thread...
220
  static int ptrace_check_attach(struct task_struct *child, bool ignore_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
227
228
229
230
231
  {
  	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);
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
232
233
  	if (child->ptrace && child->parent == current) {
  		WARN_ON(child->state == __TASK_TRACED);
c0c0b649d   Oleg Nesterov   ptrace_check_atta...
234
235
236
237
  		/*
  		 * child->sighand can't be NULL, release_task()
  		 * does ptrace_unlink() before __exit_signal().
  		 */
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
238
  		if (ignore_state || ptrace_freeze_traced(child))
321fb5619   Oleg Nesterov   ptrace: ptrace_ch...
239
  			ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  	}
  	read_unlock(&tasklist_lock);
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
242
243
244
245
246
247
248
249
250
251
252
  	if (!ret && !ignore_state) {
  		if (!wait_task_inactive(child, __TASK_TRACED)) {
  			/*
  			 * This can only happen if may_ptrace_stop() fails and
  			 * ptrace_stop() changes ->state back to TASK_RUNNING,
  			 * so we should not worry about leaking __TASK_TRACED.
  			 */
  			WARN_ON(child->state == __TASK_TRACED);
  			ret = -ESRCH;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
  	return ret;
  }
a26a63588   Christian Brauner   ptrace: reintrodu...
256
257
  static bool ptrace_has_cap(const struct cred *cred, struct user_namespace *ns,
  			   unsigned int mode)
69f594a38   Eric Paris   ptrace: do not au...
258
  {
a26a63588   Christian Brauner   ptrace: reintrodu...
259
  	int ret;
69f594a38   Eric Paris   ptrace: do not au...
260
  	if (mode & PTRACE_MODE_NOAUDIT)
a26a63588   Christian Brauner   ptrace: reintrodu...
261
  		ret = security_capable(cred, ns, CAP_SYS_PTRACE, CAP_OPT_NOAUDIT);
69f594a38   Eric Paris   ptrace: do not au...
262
  	else
a26a63588   Christian Brauner   ptrace: reintrodu...
263
264
265
  		ret = security_capable(cred, ns, CAP_SYS_PTRACE, CAP_OPT_NONE);
  
  	return ret == 0;
69f594a38   Eric Paris   ptrace: do not au...
266
  }
9f99798ff   Tetsuo Handa   ptrace: mark __pt...
267
268
  /* Returns 0 on success, -errno on denial. */
  static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
269
  {
c69e8d9c0   David Howells   CRED: Use RCU to ...
270
  	const struct cred *cred = current_cred(), *tcred;
bfedb5892   Eric W. Biederman   mm: Add a user_ns...
271
  	struct mm_struct *mm;
caaee6234   Jann Horn   ptrace: use fsuid...
272
273
274
275
276
277
278
279
  	kuid_t caller_uid;
  	kgid_t caller_gid;
  
  	if (!(mode & PTRACE_MODE_FSCREDS) == !(mode & PTRACE_MODE_REALCREDS)) {
  		WARN(1, "denying ptrace access check without PTRACE_MODE_*CREDS
  ");
  		return -EPERM;
  	}
b6dff3ec5   David Howells   CRED: Separate ta...
280

df26c40e5   Eric W. Biederman   [PATCH] proc: Cle...
281
282
283
284
285
286
287
288
  	/* 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.
  	 */
caaee6234   Jann Horn   ptrace: use fsuid...
289

df26c40e5   Eric W. Biederman   [PATCH] proc: Cle...
290
  	/* Don't let security modules deny introspection */
73af963f9   Mark Grondona   __ptrace_may_acce...
291
  	if (same_thread_group(task, current))
df26c40e5   Eric W. Biederman   [PATCH] proc: Cle...
292
  		return 0;
c69e8d9c0   David Howells   CRED: Use RCU to ...
293
  	rcu_read_lock();
caaee6234   Jann Horn   ptrace: use fsuid...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  	if (mode & PTRACE_MODE_FSCREDS) {
  		caller_uid = cred->fsuid;
  		caller_gid = cred->fsgid;
  	} else {
  		/*
  		 * Using the euid would make more sense here, but something
  		 * in userland might rely on the old behavior, and this
  		 * shouldn't be a security problem since
  		 * PTRACE_MODE_REALCREDS implies that the caller explicitly
  		 * used a syscall that requests access to another process
  		 * (and not a filesystem syscall to procfs).
  		 */
  		caller_uid = cred->uid;
  		caller_gid = cred->gid;
  	}
c69e8d9c0   David Howells   CRED: Use RCU to ...
309
  	tcred = __task_cred(task);
caaee6234   Jann Horn   ptrace: use fsuid...
310
311
312
313
314
315
  	if (uid_eq(caller_uid, tcred->euid) &&
  	    uid_eq(caller_uid, tcred->suid) &&
  	    uid_eq(caller_uid, tcred->uid)  &&
  	    gid_eq(caller_gid, tcred->egid) &&
  	    gid_eq(caller_gid, tcred->sgid) &&
  	    gid_eq(caller_gid, tcred->gid))
8409cca70   Serge E. Hallyn   userns: allow ptr...
316
  		goto ok;
a26a63588   Christian Brauner   ptrace: reintrodu...
317
  	if (ptrace_has_cap(cred, tcred->user_ns, mode))
8409cca70   Serge E. Hallyn   userns: allow ptr...
318
319
320
321
  		goto ok;
  	rcu_read_unlock();
  	return -EPERM;
  ok:
c69e8d9c0   David Howells   CRED: Use RCU to ...
322
  	rcu_read_unlock();
f6581f5b5   Jann Horn   ptrace: restore s...
323
324
325
326
327
328
329
330
331
332
  	/*
  	 * If a task drops privileges and becomes nondumpable (through a syscall
  	 * like setresuid()) while we are trying to access it, we must ensure
  	 * that the dumpability is read after the credentials; otherwise,
  	 * we may be able to attach to a task that we shouldn't be able to
  	 * attach to (as if the task had dropped privileges without becoming
  	 * nondumpable).
  	 * Pairs with a write barrier in commit_creds().
  	 */
  	smp_rmb();
bfedb5892   Eric W. Biederman   mm: Add a user_ns...
333
334
335
  	mm = task->mm;
  	if (mm &&
  	    ((get_dumpable(mm) != SUID_DUMP_USER) &&
a26a63588   Christian Brauner   ptrace: reintrodu...
336
  	     !ptrace_has_cap(cred, mm->user_ns, mode)))
bfedb5892   Eric W. Biederman   mm: Add a user_ns...
337
  	    return -EPERM;
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
338

9e48858f7   Ingo Molnar   security: rename ...
339
  	return security_ptrace_access_check(task, mode);
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
340
  }
006ebb40d   Stephen Smalley   Security: split p...
341
  bool ptrace_may_access(struct task_struct *task, unsigned int mode)
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
342
343
344
  {
  	int err;
  	task_lock(task);
006ebb40d   Stephen Smalley   Security: split p...
345
  	err = __ptrace_may_access(task, mode);
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
346
  	task_unlock(task);
3a7097035   Roland McGrath   ptrace: some chec...
347
  	return !err;
ab8d11beb   Miklos Szeredi   [PATCH] remove du...
348
  }
3544d72a0   Tejun Heo   ptrace: implement...
349
  static int ptrace_attach(struct task_struct *task, long request,
aa9147c98   Denys Vlasenko   ptrace: make PTRA...
350
  			 unsigned long addr,
3544d72a0   Tejun Heo   ptrace: implement...
351
  			 unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  {
3544d72a0   Tejun Heo   ptrace: implement...
353
  	bool seize = (request == PTRACE_SEIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  	int retval;
f5b40e363   Linus Torvalds   Fix ptrace_attach...
355

3544d72a0   Tejun Heo   ptrace: implement...
356
  	retval = -EIO;
aa9147c98   Denys Vlasenko   ptrace: make PTRA...
357
358
359
  	if (seize) {
  		if (addr != 0)
  			goto out;
aa9147c98   Denys Vlasenko   ptrace: make PTRA...
360
361
362
363
364
365
  		if (flags & ~(unsigned long)PTRACE_O_MASK)
  			goto out;
  		flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT);
  	} else {
  		flags = PT_PTRACED;
  	}
3544d72a0   Tejun Heo   ptrace: implement...
366

a5cb013da   Al Viro   [PATCH] auditing ...
367
  	audit_ptrace(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  	retval = -EPERM;
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
369
370
  	if (unlikely(task->flags & PF_KTHREAD))
  		goto out;
bac0abd61   Pavel Emelyanov   Isolate some expl...
371
  	if (same_thread_group(task, current))
f5b40e363   Linus Torvalds   Fix ptrace_attach...
372
  		goto out;
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
373
374
  	/*
  	 * Protect exec's credential calculations against our interference;
86b6c1f30   Denys Vlasenko   ptrace: simplify ...
375
  	 * SUID, SGID and LSM creds get determined differently
5e751e992   David Howells   CRED: Rename cred...
376
  	 * under ptrace.
d84f4f992   David Howells   CRED: Inaugurate ...
377
  	 */
793285fca   Oleg Nesterov   cred_guard_mutex:...
378
  	retval = -ERESTARTNOINTR;
9b1bf12d5   KOSAKI Motohiro   signals: move cre...
379
  	if (mutex_lock_interruptible(&task->signal->cred_guard_mutex))
d84f4f992   David Howells   CRED: Inaugurate ...
380
  		goto out;
f5b40e363   Linus Torvalds   Fix ptrace_attach...
381

4b105cbba   Oleg Nesterov   ptrace: do not us...
382
  	task_lock(task);
caaee6234   Jann Horn   ptrace: use fsuid...
383
  	retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS);
4b105cbba   Oleg Nesterov   ptrace: do not us...
384
  	task_unlock(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  	if (retval)
4b105cbba   Oleg Nesterov   ptrace: do not us...
386
  		goto unlock_creds;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

4b105cbba   Oleg Nesterov   ptrace: do not us...
388
  	write_lock_irq(&tasklist_lock);
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
389
390
  	retval = -EPERM;
  	if (unlikely(task->exit_state))
4b105cbba   Oleg Nesterov   ptrace: do not us...
391
  		goto unlock_tasklist;
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
392
  	if (task->ptrace)
4b105cbba   Oleg Nesterov   ptrace: do not us...
393
  		goto unlock_tasklist;
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
394

3544d72a0   Tejun Heo   ptrace: implement...
395
  	if (seize)
aa9147c98   Denys Vlasenko   ptrace: make PTRA...
396
  		flags |= PT_SEIZED;
aa9147c98   Denys Vlasenko   ptrace: make PTRA...
397
  	task->ptrace = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398

c70d9d809   Eric W. Biederman   ptrace: Properly ...
399
  	ptrace_link(task, current);
3544d72a0   Tejun Heo   ptrace: implement...
400
401
402
  
  	/* SEIZE doesn't trap tracee on attach */
  	if (!seize)
079b22dc9   Eric W. Biederman   signal: Use SEND_...
403
  		send_sig_info(SIGSTOP, SEND_SIG_PRIV, task);
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
404

d79fdd6d9   Tejun Heo   ptrace: Clean tra...
405
406
407
  	spin_lock(&task->sighand->siglock);
  
  	/*
73ddff2be   Tejun Heo   job control: intr...
408
  	 * If the task is already STOPPED, set JOBCTL_TRAP_STOP and
d79fdd6d9   Tejun Heo   ptrace: Clean tra...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  	 * 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   Tejun Heo   job control: intr...
424
  	if (task_is_stopped(task) &&
73ddff2be   Tejun Heo   job control: intr...
425
  	    task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING))
910ffdb18   Oleg Nesterov   ptrace: introduce...
426
  		signal_wake_up_state(task, __TASK_STOPPED);
d79fdd6d9   Tejun Heo   ptrace: Clean tra...
427
428
  
  	spin_unlock(&task->sighand->siglock);
b79b7ba93   Oleg Nesterov   ptrace: ptrace_at...
429
  	retval = 0;
4b105cbba   Oleg Nesterov   ptrace: do not us...
430
431
432
  unlock_tasklist:
  	write_unlock_irq(&tasklist_lock);
  unlock_creds:
9b1bf12d5   KOSAKI Motohiro   signals: move cre...
433
  	mutex_unlock(&task->signal->cred_guard_mutex);
f5b40e363   Linus Torvalds   Fix ptrace_attach...
434
  out:
f701e5b73   Vladimir Zapolskiy   connector: add an...
435
  	if (!retval) {
7c3b00e06   Oleg Nesterov   ptrace: make wait...
436
437
438
439
440
441
442
443
  		/*
  		 * We do not bother to change retval or clear JOBCTL_TRAPPING
  		 * if wait_on_bit() was interrupted by SIGKILL. The tracer will
  		 * not return to user-mode, it will exit and clear this bit in
  		 * __ptrace_unlink() if it wasn't already cleared by the tracee;
  		 * and until then nobody can ptrace this task.
  		 */
  		wait_on_bit(&task->jobctl, JOBCTL_TRAPPING_BIT, TASK_KILLABLE);
f701e5b73   Vladimir Zapolskiy   connector: add an...
444
445
  		proc_ptrace_connector(task, PTRACE_ATTACH);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
  	return retval;
  }
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
448
449
450
451
452
453
  /**
   * 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...
454
  static int ptrace_traceme(void)
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
455
456
  {
  	int ret = -EPERM;
4b105cbba   Oleg Nesterov   ptrace: do not us...
457
458
  	write_lock_irq(&tasklist_lock);
  	/* Are we already being traced? */
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
459
  	if (!current->ptrace) {
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
460
  		ret = security_ptrace_traceme(current->parent);
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
461
462
463
464
465
466
467
  		/*
  		 * 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;
c70d9d809   Eric W. Biederman   ptrace: Properly ...
468
  			ptrace_link(current, current->real_parent);
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
469
  		}
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
470
  	}
4b105cbba   Oleg Nesterov   ptrace: do not us...
471
  	write_unlock_irq(&tasklist_lock);
f2f0b00ad   Oleg Nesterov   ptrace: cleanup c...
472
473
  	return ret;
  }
39c626ae4   Oleg Nesterov   forget_original_p...
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  /*
   * 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_...
497
498
499
500
   * 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...
501
502
503
   */
  static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
  {
9843a1e97   Oleg Nesterov   __ptrace_detach: ...
504
  	bool dead;
39c626ae4   Oleg Nesterov   forget_original_p...
505
  	__ptrace_unlink(p);
9843a1e97   Oleg Nesterov   __ptrace_detach: ...
506
507
508
509
510
511
512
513
514
515
  	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   Oleg Nesterov   __ptrace_detach: ...
516
  			dead = true;
39c626ae4   Oleg Nesterov   forget_original_p...
517
518
  		}
  	}
9843a1e97   Oleg Nesterov   __ptrace_detach: ...
519
520
521
522
  	/* Mark it as in the process of being reaped. */
  	if (dead)
  		p->exit_state = EXIT_DEAD;
  	return dead;
39c626ae4   Oleg Nesterov   forget_original_p...
523
  }
e3e89cc53   Linus Torvalds   Mark ptrace_{trac...
524
  static int ptrace_detach(struct task_struct *child, unsigned int data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  {
7ed20e1ad   Jesper Juhl   [PATCH] convert t...
526
  	if (!valid_signal(data))
5ecfbae09   Oleg Nesterov   [PATCH] fix zap_t...
527
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
  
  	/* Architecture-specific hardware disable .. */
  	ptrace_disable(child);
95c3eb76d   Oleg Nesterov   ptrace: kill __pt...
531
  	write_lock_irq(&tasklist_lock);
39c626ae4   Oleg Nesterov   forget_original_p...
532
  	/*
64a4096c5   Oleg Nesterov   ptrace: ptrace_de...
533
534
  	 * We rely on ptrace_freeze_traced(). It can't be killed and
  	 * untraced by another thread, it can't be a zombie.
39c626ae4   Oleg Nesterov   forget_original_p...
535
  	 */
64a4096c5   Oleg Nesterov   ptrace: ptrace_de...
536
537
538
539
540
541
542
  	WARN_ON(!child->ptrace || child->exit_state);
  	/*
  	 * tasklist_lock avoids the race with wait_task_stopped(), see
  	 * the comment in ptrace_resume().
  	 */
  	child->exit_code = data;
  	__ptrace_detach(current, child);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  	write_unlock_irq(&tasklist_lock);
f701e5b73   Vladimir Zapolskiy   connector: add an...
544
  	proc_ptrace_connector(child, PTRACE_DETACH);
4576145c1   Oleg Nesterov   ptrace: fix possi...
545

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
  	return 0;
  }
39c626ae4   Oleg Nesterov   forget_original_p...
548
  /*
c7e49c148   Oleg Nesterov   ptrace: optimize ...
549
   * Detach all tasks we were using ptrace on. Called with tasklist held
7c8bd2322   Oleg Nesterov   exit: ptrace: shi...
550
   * for writing.
39c626ae4   Oleg Nesterov   forget_original_p...
551
   */
7c8bd2322   Oleg Nesterov   exit: ptrace: shi...
552
  void exit_ptrace(struct task_struct *tracer, struct list_head *dead)
39c626ae4   Oleg Nesterov   forget_original_p...
553
554
  {
  	struct task_struct *p, *n;
c7e49c148   Oleg Nesterov   ptrace: optimize ...
555

39c626ae4   Oleg Nesterov   forget_original_p...
556
  	list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
992fb6e17   Oleg Nesterov   ptrace: introduce...
557
  		if (unlikely(p->ptrace & PT_EXITKILL))
079b22dc9   Eric W. Biederman   signal: Use SEND_...
558
  			send_sig_info(SIGKILL, SEND_SIG_PRIV, p);
992fb6e17   Oleg Nesterov   ptrace: introduce...
559

39c626ae4   Oleg Nesterov   forget_original_p...
560
  		if (__ptrace_detach(tracer, p))
7c8bd2322   Oleg Nesterov   exit: ptrace: shi...
561
  			list_add(&p->ptrace_entry, dead);
39c626ae4   Oleg Nesterov   forget_original_p...
562
563
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
567
568
569
570
571
572
  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;
84d77d3f0   Eric W. Biederman   ptrace: Don't all...
573
  		retval = ptrace_access_vm(tsk, src, buf, this_len, FOLL_FORCE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
579
580
581
582
583
  		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...
584
  		len -= retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  	}
  	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;
84d77d3f0   Eric W. Biederman   ptrace: Don't all...
600
  		retval = ptrace_access_vm(tsk, dst, buf, this_len,
f307ab6dc   Lorenzo Stoakes   mm: replace acces...
601
  				FOLL_FORCE | FOLL_WRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
605
606
607
608
609
  		if (!retval) {
  			if (copied)
  				break;
  			return -EIO;
  		}
  		copied += retval;
  		src += retval;
  		dst += retval;
3a7097035   Roland McGrath   ptrace: some chec...
610
  		len -= retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
  	}
  	return copied;
  }
4abf98696   Namhyung Kim   ptrace: change si...
614
  static int ptrace_setoptions(struct task_struct *child, unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
  {
86b6c1f30   Denys Vlasenko   ptrace: simplify ...
616
  	unsigned flags;
8c5cf9e5c   Denys Vlasenko   ptrace: don't mod...
617
618
  	if (data & ~(unsigned long)PTRACE_O_MASK)
  		return -EINVAL;
13c4a9011   Tycho Andersen   seccomp: add ptra...
619
  	if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) {
97f2645f3   Masahiro Yamada   tree-wide: replac...
620
621
  		if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) ||
  		    !IS_ENABLED(CONFIG_SECCOMP))
13c4a9011   Tycho Andersen   seccomp: add ptra...
622
623
624
625
626
627
628
629
630
  			return -EINVAL;
  
  		if (!capable(CAP_SYS_ADMIN))
  			return -EPERM;
  
  		if (seccomp_mode(&current->seccomp) != SECCOMP_MODE_DISABLED ||
  		    current->ptrace & PT_SUSPEND_SECCOMP)
  			return -EPERM;
  	}
86b6c1f30   Denys Vlasenko   ptrace: simplify ...
631
632
633
634
635
  	/* Avoid intermediate state when all opts are cleared */
  	flags = child->ptrace;
  	flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT);
  	flags |= (data << PT_OPT_FLAG_SHIFT);
  	child->ptrace = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

8c5cf9e5c   Denys Vlasenko   ptrace: don't mod...
637
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
  }
ae7795bc6   Eric W. Biederman   signal: Distingui...
639
  static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  {
e49612544   Oleg Nesterov   ptrace: don't tak...
641
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
  	int error = -ESRCH;
e49612544   Oleg Nesterov   ptrace: don't tak...
643
  	if (lock_task_sighand(child, &flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  		error = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
  		if (likely(child->last_siginfo != NULL)) {
0752d7bf6   Eric W. Biederman   ptrace: Use copy_...
646
  			copy_siginfo(info, child->last_siginfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
  			error = 0;
  		}
e49612544   Oleg Nesterov   ptrace: don't tak...
649
  		unlock_task_sighand(child, &flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
  	return error;
  }
ae7795bc6   Eric W. Biederman   signal: Distingui...
653
  static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  {
e49612544   Oleg Nesterov   ptrace: don't tak...
655
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  	int error = -ESRCH;
e49612544   Oleg Nesterov   ptrace: don't tak...
657
  	if (lock_task_sighand(child, &flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  		error = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  		if (likely(child->last_siginfo != NULL)) {
0752d7bf6   Eric W. Biederman   ptrace: Use copy_...
660
  			copy_siginfo(child->last_siginfo, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
  			error = 0;
  		}
e49612544   Oleg Nesterov   ptrace: don't tak...
663
  		unlock_task_sighand(child, &flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
  	return error;
  }
84c751bd4   Andrey Vagin   ptrace: add abili...
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
  static int ptrace_peek_siginfo(struct task_struct *child,
  				unsigned long addr,
  				unsigned long data)
  {
  	struct ptrace_peeksiginfo_args arg;
  	struct sigpending *pending;
  	struct sigqueue *q;
  	int ret, i;
  
  	ret = copy_from_user(&arg, (void __user *) addr,
  				sizeof(struct ptrace_peeksiginfo_args));
  	if (ret)
  		return -EFAULT;
  
  	if (arg.flags & ~PTRACE_PEEKSIGINFO_SHARED)
  		return -EINVAL; /* unknown flags */
  
  	if (arg.nr < 0)
  		return -EINVAL;
f6e2aa91a   Eric W. Biederman   signal/ptrace: Do...
686
687
688
  	/* Ensure arg.off fits in an unsigned long */
  	if (arg.off > ULONG_MAX)
  		return 0;
84c751bd4   Andrey Vagin   ptrace: add abili...
689
690
691
692
693
694
  	if (arg.flags & PTRACE_PEEKSIGINFO_SHARED)
  		pending = &child->signal->shared_pending;
  	else
  		pending = &child->pending;
  
  	for (i = 0; i < arg.nr; ) {
ae7795bc6   Eric W. Biederman   signal: Distingui...
695
  		kernel_siginfo_t info;
f6e2aa91a   Eric W. Biederman   signal/ptrace: Do...
696
697
  		unsigned long off = arg.off + i;
  		bool found = false;
84c751bd4   Andrey Vagin   ptrace: add abili...
698
699
700
701
  
  		spin_lock_irq(&child->sighand->siglock);
  		list_for_each_entry(q, &pending->list, list) {
  			if (!off--) {
f6e2aa91a   Eric W. Biederman   signal/ptrace: Do...
702
  				found = true;
84c751bd4   Andrey Vagin   ptrace: add abili...
703
704
705
706
707
  				copy_siginfo(&info, &q->info);
  				break;
  			}
  		}
  		spin_unlock_irq(&child->sighand->siglock);
f6e2aa91a   Eric W. Biederman   signal/ptrace: Do...
708
  		if (!found) /* beyond the end of the list */
84c751bd4   Andrey Vagin   ptrace: add abili...
709
710
711
  			break;
  
  #ifdef CONFIG_COMPAT
5c465217a   Andy Lutomirski   ptrace: in PEEK_S...
712
  		if (unlikely(in_compat_syscall())) {
84c751bd4   Andrey Vagin   ptrace: add abili...
713
  			compat_siginfo_t __user *uinfo = compat_ptr(data);
cc731525f   Eric W. Biederman   signal: Remove ke...
714
  			if (copy_siginfo_to_user32(uinfo, &info)) {
706b23bde   Mathieu Desnoyers   Fix: kernel/ptrac...
715
716
717
  				ret = -EFAULT;
  				break;
  			}
84c751bd4   Andrey Vagin   ptrace: add abili...
718
719
720
721
  		} else
  #endif
  		{
  			siginfo_t __user *uinfo = (siginfo_t __user *) data;
cc731525f   Eric W. Biederman   signal: Remove ke...
722
  			if (copy_siginfo_to_user(uinfo, &info)) {
706b23bde   Mathieu Desnoyers   Fix: kernel/ptrac...
723
724
725
  				ret = -EFAULT;
  				break;
  			}
84c751bd4   Andrey Vagin   ptrace: add abili...
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
  		}
  
  		data += sizeof(siginfo_t);
  		i++;
  
  		if (signal_pending(current))
  			break;
  
  		cond_resched();
  	}
  
  	if (i > 0)
  		return i;
  
  	return ret;
  }
36df29d79   Roland McGrath   ptrace: generic r...
742
743
744
745
746
747
  
  #ifdef PTRACE_SINGLESTEP
  #define is_singlestep(request)		((request) == PTRACE_SINGLESTEP)
  #else
  #define is_singlestep(request)		0
  #endif
5b88abbf7   Roland McGrath   ptrace: generic P...
748
749
750
751
752
  #ifdef PTRACE_SINGLEBLOCK
  #define is_singleblock(request)		((request) == PTRACE_SINGLEBLOCK)
  #else
  #define is_singleblock(request)		0
  #endif
36df29d79   Roland McGrath   ptrace: generic r...
753
754
755
756
757
  #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...
758
759
  static int ptrace_resume(struct task_struct *child, long request,
  			 unsigned long data)
36df29d79   Roland McGrath   ptrace: generic r...
760
  {
b72c18699   Oleg Nesterov   ptrace: fix race ...
761
  	bool need_siglock;
36df29d79   Roland McGrath   ptrace: generic r...
762
763
764
765
766
767
768
769
770
771
772
773
774
775
  	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...
776
777
778
779
780
  	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...
781
782
783
  		if (unlikely(!arch_has_single_step()))
  			return -EIO;
  		user_enable_single_step(child);
3a7097035   Roland McGrath   ptrace: some chec...
784
  	} else {
36df29d79   Roland McGrath   ptrace: generic r...
785
  		user_disable_single_step(child);
3a7097035   Roland McGrath   ptrace: some chec...
786
  	}
36df29d79   Roland McGrath   ptrace: generic r...
787

b72c18699   Oleg Nesterov   ptrace: fix race ...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  	/*
  	 * Change ->exit_code and ->state under siglock to avoid the race
  	 * with wait_task_stopped() in between; a non-zero ->exit_code will
  	 * wrongly look like another report from tracee.
  	 *
  	 * Note that we need siglock even if ->exit_code == data and/or this
  	 * status was not reported yet, the new status must not be cleared by
  	 * wait_task_stopped() after resume.
  	 *
  	 * If data == 0 we do not care if wait_task_stopped() reports the old
  	 * status and clears the code too; this can't race with the tracee, it
  	 * takes siglock after resume.
  	 */
  	need_siglock = data && !thread_group_empty(current);
  	if (need_siglock)
  		spin_lock_irq(&child->sighand->siglock);
36df29d79   Roland McGrath   ptrace: generic r...
804
  	child->exit_code = data;
0666fb51b   Oleg Nesterov   ptrace: ptrace_re...
805
  	wake_up_state(child, __TASK_TRACED);
b72c18699   Oleg Nesterov   ptrace: fix race ...
806
807
  	if (need_siglock)
  		spin_unlock_irq(&child->sighand->siglock);
36df29d79   Roland McGrath   ptrace: generic r...
808
809
810
  
  	return 0;
  }
2225a122a   Suresh Siddha   ptrace: Add suppo...
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
  #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...
836
  		return -EINVAL;
2225a122a   Suresh Siddha   ptrace: Add suppo...
837
838
839
840
841
842
843
844
845
846
847
848
  
  	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);
  }
e8440c145   Josh Stone   uprobes: Add expo...
849
850
851
852
853
854
  /*
   * This is declared in linux/regset.h and defined in machine-dependent
   * code.  We put the export here, near the primary machine-neutral use,
   * to ensure no machine forgets it.
   */
  EXPORT_SYMBOL_GPL(task_user_regset_view);
201766a20   Elvira Khabirova   ptrace: add PTRAC...
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  
  static unsigned long
  ptrace_get_syscall_info_entry(struct task_struct *child, struct pt_regs *regs,
  			      struct ptrace_syscall_info *info)
  {
  	unsigned long args[ARRAY_SIZE(info->entry.args)];
  	int i;
  
  	info->op = PTRACE_SYSCALL_INFO_ENTRY;
  	info->entry.nr = syscall_get_nr(child, regs);
  	syscall_get_arguments(child, regs, args);
  	for (i = 0; i < ARRAY_SIZE(args); i++)
  		info->entry.args[i] = args[i];
  
  	/* args is the last field in struct ptrace_syscall_info.entry */
  	return offsetofend(struct ptrace_syscall_info, entry.args);
  }
  
  static unsigned long
  ptrace_get_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs,
  				struct ptrace_syscall_info *info)
  {
  	/*
  	 * As struct ptrace_syscall_info.entry is currently a subset
  	 * of struct ptrace_syscall_info.seccomp, it makes sense to
  	 * initialize that subset using ptrace_get_syscall_info_entry().
  	 * This can be reconsidered in the future if these structures
  	 * diverge significantly enough.
  	 */
  	ptrace_get_syscall_info_entry(child, regs, info);
  	info->op = PTRACE_SYSCALL_INFO_SECCOMP;
  	info->seccomp.ret_data = child->ptrace_message;
  
  	/* ret_data is the last field in struct ptrace_syscall_info.seccomp */
  	return offsetofend(struct ptrace_syscall_info, seccomp.ret_data);
  }
  
  static unsigned long
  ptrace_get_syscall_info_exit(struct task_struct *child, struct pt_regs *regs,
  			     struct ptrace_syscall_info *info)
  {
  	info->op = PTRACE_SYSCALL_INFO_EXIT;
  	info->exit.rval = syscall_get_error(child, regs);
  	info->exit.is_error = !!info->exit.rval;
  	if (!info->exit.is_error)
  		info->exit.rval = syscall_get_return_value(child, regs);
  
  	/* is_error is the last field in struct ptrace_syscall_info.exit */
  	return offsetofend(struct ptrace_syscall_info, exit.is_error);
  }
  
  static int
  ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size,
  			void __user *datavp)
  {
  	struct pt_regs *regs = task_pt_regs(child);
  	struct ptrace_syscall_info info = {
  		.op = PTRACE_SYSCALL_INFO_NONE,
  		.arch = syscall_get_arch(child),
  		.instruction_pointer = instruction_pointer(regs),
  		.stack_pointer = user_stack_pointer(regs),
  	};
  	unsigned long actual_size = offsetof(struct ptrace_syscall_info, entry);
  	unsigned long write_size;
  
  	/*
  	 * This does not need lock_task_sighand() to access
  	 * child->last_siginfo because ptrace_freeze_traced()
  	 * called earlier by ptrace_check_attach() ensures that
  	 * the tracee cannot go away and clear its last_siginfo.
  	 */
  	switch (child->last_siginfo ? child->last_siginfo->si_code : 0) {
  	case SIGTRAP | 0x80:
  		switch (child->ptrace_message) {
  		case PTRACE_EVENTMSG_SYSCALL_ENTRY:
  			actual_size = ptrace_get_syscall_info_entry(child, regs,
  								    &info);
  			break;
  		case PTRACE_EVENTMSG_SYSCALL_EXIT:
  			actual_size = ptrace_get_syscall_info_exit(child, regs,
  								   &info);
  			break;
  		}
  		break;
  	case SIGTRAP | (PTRACE_EVENT_SECCOMP << 8):
  		actual_size = ptrace_get_syscall_info_seccomp(child, regs,
  							      &info);
  		break;
  	}
  
  	write_size = min(actual_size, user_size);
  	return copy_to_user(datavp, &info, write_size) ? -EFAULT : actual_size;
  }
  #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */
2225a122a   Suresh Siddha   ptrace: Add suppo...
949

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  int ptrace_request(struct task_struct *child, long request,
4abf98696   Namhyung Kim   ptrace: change si...
951
  		   unsigned long addr, unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
  {
fca26f260   Tejun Heo   ptrace: implement...
953
  	bool seized = child->ptrace & PT_SEIZED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
  	int ret = -EIO;
ae7795bc6   Eric W. Biederman   signal: Distingui...
955
  	kernel_siginfo_t siginfo, *si;
9fed81dc4   Namhyung Kim   ptrace: cleanup p...
956
957
  	void __user *datavp = (void __user *) data;
  	unsigned long __user *datalp = datavp;
fca26f260   Tejun Heo   ptrace: implement...
958
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
  
  	switch (request) {
16c3e389e   Roland McGrath   x86: ptrace_reque...
961
962
963
964
965
966
  	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
967
968
969
970
971
972
973
  #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...
974
  		ret = put_user(child->ptrace_message, datalp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
  		break;
e16b27816   Roland McGrath   ptrace: compat_pt...
976

84c751bd4   Andrey Vagin   ptrace: add abili...
977
978
979
  	case PTRACE_PEEKSIGINFO:
  		ret = ptrace_peek_siginfo(child, addr, data);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
  	case PTRACE_GETSIGINFO:
e16b27816   Roland McGrath   ptrace: compat_pt...
981
982
  		ret = ptrace_getsiginfo(child, &siginfo);
  		if (!ret)
9fed81dc4   Namhyung Kim   ptrace: cleanup p...
983
  			ret = copy_siginfo_to_user(datavp, &siginfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
  		break;
e16b27816   Roland McGrath   ptrace: compat_pt...
985

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
  	case PTRACE_SETSIGINFO:
4cd2e0e70   Eric W. Biederman   signal: Introduce...
987
988
  		ret = copy_siginfo_from_user(&siginfo, datavp);
  		if (!ret)
e16b27816   Roland McGrath   ptrace: compat_pt...
989
  			ret = ptrace_setsiginfo(child, &siginfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  		break;
e16b27816   Roland McGrath   ptrace: compat_pt...
991

fcfc2aa01   Andrei Vagin   ptrace: take into...
992
993
  	case PTRACE_GETSIGMASK: {
  		sigset_t *mask;
29000caec   Andrey Vagin   ptrace: add abili...
994
995
996
997
  		if (addr != sizeof(sigset_t)) {
  			ret = -EINVAL;
  			break;
  		}
fcfc2aa01   Andrei Vagin   ptrace: take into...
998
999
1000
1001
1002
1003
  		if (test_tsk_restore_sigmask(child))
  			mask = &child->saved_sigmask;
  		else
  			mask = &child->blocked;
  
  		if (copy_to_user(datavp, mask, sizeof(sigset_t)))
29000caec   Andrey Vagin   ptrace: add abili...
1004
1005
1006
1007
1008
  			ret = -EFAULT;
  		else
  			ret = 0;
  
  		break;
fcfc2aa01   Andrei Vagin   ptrace: take into...
1009
  	}
29000caec   Andrey Vagin   ptrace: add abili...
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
  
  	case PTRACE_SETSIGMASK: {
  		sigset_t new_set;
  
  		if (addr != sizeof(sigset_t)) {
  			ret = -EINVAL;
  			break;
  		}
  
  		if (copy_from_user(&new_set, datavp, sizeof(sigset_t))) {
  			ret = -EFAULT;
  			break;
  		}
  
  		sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
  
  		/*
  		 * Every thread does recalc_sigpending() after resume, so
  		 * retarget_shared_pending() and recalc_sigpending() are not
  		 * called here.
  		 */
  		spin_lock_irq(&child->sighand->siglock);
  		child->blocked = new_set;
  		spin_unlock_irq(&child->sighand->siglock);
fcfc2aa01   Andrei Vagin   ptrace: take into...
1034
  		clear_tsk_restore_sigmask(child);
29000caec   Andrey Vagin   ptrace: add abili...
1035
1036
1037
  		ret = 0;
  		break;
  	}
fca26f260   Tejun Heo   ptrace: implement...
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
  	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   Tejun Heo   ptrace: implement...
1051
1052
1053
1054
1055
1056
  		/*
  		 * 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   Tejun Heo   ptrace: implement...
1057
  		if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP)))
910ffdb18   Oleg Nesterov   ptrace: introduce...
1058
  			ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
544b2c91a   Tejun Heo   ptrace: implement...
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
  
  		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   Oleg Nesterov   ptrace: PTRACE_LI...
1077
1078
1079
1080
1081
1082
1083
  		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)
910ffdb18   Oleg Nesterov   ptrace: introduce...
1084
  				ptrace_signal_wake_up(child, true);
f9d81f61c   Oleg Nesterov   ptrace: PTRACE_LI...
1085
1086
  			ret = 0;
  		}
fca26f260   Tejun Heo   ptrace: implement...
1087
  		unlock_task_sighand(child, &flags);
fca26f260   Tejun Heo   ptrace: implement...
1088
  		break;
1bcf54829   Alexey Dobriyan   Consolidate PTRAC...
1089
1090
1091
  	case PTRACE_DETACH:	 /* detach a process that was attached. */
  		ret = ptrace_detach(child, data);
  		break;
36df29d79   Roland McGrath   ptrace: generic r...
1092

9c1a12592   Mike Frysinger   ptrace: unify FDP...
1093
1094
  #ifdef CONFIG_BINFMT_ELF_FDPIC
  	case PTRACE_GETFDPIC: {
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
1095
  		struct mm_struct *mm = get_task_mm(child);
9c1a12592   Mike Frysinger   ptrace: unify FDP...
1096
  		unsigned long tmp = 0;
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
1097
1098
1099
  		ret = -ESRCH;
  		if (!mm)
  			break;
9c1a12592   Mike Frysinger   ptrace: unify FDP...
1100
1101
  		switch (addr) {
  		case PTRACE_GETFDPIC_EXEC:
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
1102
  			tmp = mm->context.exec_fdpic_loadmap;
9c1a12592   Mike Frysinger   ptrace: unify FDP...
1103
1104
  			break;
  		case PTRACE_GETFDPIC_INTERP:
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
1105
  			tmp = mm->context.interp_fdpic_loadmap;
9c1a12592   Mike Frysinger   ptrace: unify FDP...
1106
1107
1108
1109
  			break;
  		default:
  			break;
  		}
e0129ef91   Oleg Nesterov   ptrace: PTRACE_GE...
1110
  		mmput(mm);
9c1a12592   Mike Frysinger   ptrace: unify FDP...
1111

9fed81dc4   Namhyung Kim   ptrace: cleanup p...
1112
  		ret = put_user(tmp, datalp);
9c1a12592   Mike Frysinger   ptrace: unify FDP...
1113
1114
1115
  		break;
  	}
  #endif
36df29d79   Roland McGrath   ptrace: generic r...
1116
1117
1118
  #ifdef PTRACE_SINGLESTEP
  	case PTRACE_SINGLESTEP:
  #endif
5b88abbf7   Roland McGrath   ptrace: generic P...
1119
1120
1121
  #ifdef PTRACE_SINGLEBLOCK
  	case PTRACE_SINGLEBLOCK:
  #endif
36df29d79   Roland McGrath   ptrace: generic r...
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
  #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...
1134
1135
  #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
  	case PTRACE_GETREGSET:
29000caec   Andrey Vagin   ptrace: add abili...
1136
  	case PTRACE_SETREGSET: {
2225a122a   Suresh Siddha   ptrace: Add suppo...
1137
  		struct iovec kiov;
9fed81dc4   Namhyung Kim   ptrace: cleanup p...
1138
  		struct iovec __user *uiov = datavp;
2225a122a   Suresh Siddha   ptrace: Add suppo...
1139

96d4f267e   Linus Torvalds   Remove 'type' arg...
1140
  		if (!access_ok(uiov, sizeof(*uiov)))
2225a122a   Suresh Siddha   ptrace: Add suppo...
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
  			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;
  	}
201766a20   Elvira Khabirova   ptrace: add PTRAC...
1152
1153
1154
1155
  
  	case PTRACE_GET_SYSCALL_INFO:
  		ret = ptrace_get_syscall_info(child, addr, datavp);
  		break;
2225a122a   Suresh Siddha   ptrace: Add suppo...
1156
  #endif
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1157
1158
1159
1160
  
  	case PTRACE_SECCOMP_GET_FILTER:
  		ret = seccomp_get_filter(child, addr, datavp);
  		break;
26500475a   Tycho Andersen   ptrace, seccomp: ...
1161
1162
1163
  	case PTRACE_SECCOMP_GET_METADATA:
  		ret = seccomp_get_metadata(child, addr, datavp);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
1166
1167
1168
1169
  	default:
  		break;
  	}
  
  	return ret;
  }
481bed454   Christoph Hellwig   [PATCH] consolida...
1170

0ac155591   Christoph Hellwig   m32r: convert to ...
1171
1172
1173
  #ifndef arch_ptrace_attach
  #define arch_ptrace_attach(child)	do { } while (0)
  #endif
4abf98696   Namhyung Kim   ptrace: change si...
1174
1175
  SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
  		unsigned long, data)
481bed454   Christoph Hellwig   [PATCH] consolida...
1176
1177
1178
  {
  	struct task_struct *child;
  	long ret;
6b9c7ed84   Christoph Hellwig   [PATCH] use ptrac...
1179
1180
  	if (request == PTRACE_TRACEME) {
  		ret = ptrace_traceme();
6ea6dd93c   Haavard Skinnemoen   ptrace: Call arch...
1181
1182
  		if (!ret)
  			arch_ptrace_attach(current);
481bed454   Christoph Hellwig   [PATCH] consolida...
1183
  		goto out;
6b9c7ed84   Christoph Hellwig   [PATCH] use ptrac...
1184
  	}
2ee082608   Mike Rapoport   pids: introduce f...
1185
1186
1187
  	child = find_get_task_by_vpid(pid);
  	if (!child) {
  		ret = -ESRCH;
6b9c7ed84   Christoph Hellwig   [PATCH] use ptrac...
1188
1189
  		goto out;
  	}
481bed454   Christoph Hellwig   [PATCH] consolida...
1190

3544d72a0   Tejun Heo   ptrace: implement...
1191
  	if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
aa9147c98   Denys Vlasenko   ptrace: make PTRA...
1192
  		ret = ptrace_attach(child, request, addr, data);
0ac155591   Christoph Hellwig   m32r: convert to ...
1193
1194
1195
1196
1197
1198
  		/*
  		 * Some architectures need to do book-keeping after
  		 * a ptrace attach.
  		 */
  		if (!ret)
  			arch_ptrace_attach(child);
005f18dfd   Christoph Hellwig   [PATCH] fix task_...
1199
  		goto out_put_task_struct;
481bed454   Christoph Hellwig   [PATCH] consolida...
1200
  	}
fca26f260   Tejun Heo   ptrace: implement...
1201
1202
  	ret = ptrace_check_attach(child, request == PTRACE_KILL ||
  				  request == PTRACE_INTERRUPT);
481bed454   Christoph Hellwig   [PATCH] consolida...
1203
1204
1205
1206
  	if (ret < 0)
  		goto out_put_task_struct;
  
  	ret = arch_ptrace(child, request, addr, data);
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
1207
1208
  	if (ret || request != PTRACE_DETACH)
  		ptrace_unfreeze_traced(child);
481bed454   Christoph Hellwig   [PATCH] consolida...
1209
1210
1211
1212
  
   out_put_task_struct:
  	put_task_struct(child);
   out:
481bed454   Christoph Hellwig   [PATCH] consolida...
1213
1214
  	return ret;
  }
766473231   Alexey Dobriyan   PTRACE_PEEKDATA c...
1215

4abf98696   Namhyung Kim   ptrace: change si...
1216
1217
  int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr,
  			    unsigned long data)
766473231   Alexey Dobriyan   PTRACE_PEEKDATA c...
1218
1219
1220
  {
  	unsigned long tmp;
  	int copied;
84d77d3f0   Eric W. Biederman   ptrace: Don't all...
1221
  	copied = ptrace_access_vm(tsk, addr, &tmp, sizeof(tmp), FOLL_FORCE);
766473231   Alexey Dobriyan   PTRACE_PEEKDATA c...
1222
1223
1224
1225
  	if (copied != sizeof(tmp))
  		return -EIO;
  	return put_user(tmp, (unsigned long __user *)data);
  }
f284ce726   Alexey Dobriyan   PTRACE_POKEDATA c...
1226

4abf98696   Namhyung Kim   ptrace: change si...
1227
1228
  int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,
  			    unsigned long data)
f284ce726   Alexey Dobriyan   PTRACE_POKEDATA c...
1229
1230
  {
  	int copied;
84d77d3f0   Eric W. Biederman   ptrace: Don't all...
1231
  	copied = ptrace_access_vm(tsk, addr, &data, sizeof(data),
f307ab6dc   Lorenzo Stoakes   mm: replace acces...
1232
  			FOLL_FORCE | FOLL_WRITE);
f284ce726   Alexey Dobriyan   PTRACE_POKEDATA c...
1233
1234
  	return (copied == sizeof(data)) ? 0 : -EIO;
  }
032d82d90   Roland McGrath   x86: compat_ptrac...
1235

96b8936a9   Christoph Hellwig   remove __ARCH_WAN...
1236
  #if defined CONFIG_COMPAT
032d82d90   Roland McGrath   x86: compat_ptrac...
1237
1238
1239
1240
1241
1242
  
  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;
ae7795bc6   Eric W. Biederman   signal: Distingui...
1243
  	kernel_siginfo_t siginfo;
032d82d90   Roland McGrath   x86: compat_ptrac...
1244
1245
1246
1247
1248
  	int ret;
  
  	switch (request) {
  	case PTRACE_PEEKTEXT:
  	case PTRACE_PEEKDATA:
84d77d3f0   Eric W. Biederman   ptrace: Don't all...
1249
  		ret = ptrace_access_vm(child, addr, &word, sizeof(word),
f307ab6dc   Lorenzo Stoakes   mm: replace acces...
1250
  				FOLL_FORCE);
032d82d90   Roland McGrath   x86: compat_ptrac...
1251
1252
1253
1254
1255
1256
1257
1258
  		if (ret != sizeof(word))
  			ret = -EIO;
  		else
  			ret = put_user(word, datap);
  		break;
  
  	case PTRACE_POKETEXT:
  	case PTRACE_POKEDATA:
84d77d3f0   Eric W. Biederman   ptrace: Don't all...
1259
  		ret = ptrace_access_vm(child, addr, &data, sizeof(data),
f307ab6dc   Lorenzo Stoakes   mm: replace acces...
1260
  				FOLL_FORCE | FOLL_WRITE);
032d82d90   Roland McGrath   x86: compat_ptrac...
1261
1262
1263
1264
1265
1266
  		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...
1267
1268
1269
1270
1271
1272
1273
1274
1275
  	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:
4cd2e0e70   Eric W. Biederman   signal: Introduce...
1276
1277
1278
  		ret = copy_siginfo_from_user32(
  			&siginfo, (struct compat_siginfo __user *) datap);
  		if (!ret)
e16b27816   Roland McGrath   ptrace: compat_pt...
1279
1280
  			ret = ptrace_setsiginfo(child, &siginfo);
  		break;
2225a122a   Suresh Siddha   ptrace: Add suppo...
1281
1282
1283
1284
1285
1286
1287
1288
1289
  #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;
96d4f267e   Linus Torvalds   Remove 'type' arg...
1290
  		if (!access_ok(uiov, sizeof(*uiov)))
2225a122a   Suresh Siddha   ptrace: Add suppo...
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
  			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...
1306

032d82d90   Roland McGrath   x86: compat_ptrac...
1307
1308
1309
1310
1311
1312
  	default:
  		ret = ptrace_request(child, request, addr, data);
  	}
  
  	return ret;
  }
c269f1961   Roland McGrath   x86: compat_sys_p...
1313

62a6fa976   Heiko Carstens   kernel/compat: co...
1314
1315
  COMPAT_SYSCALL_DEFINE4(ptrace, compat_long_t, request, compat_long_t, pid,
  		       compat_long_t, addr, compat_long_t, data)
c269f1961   Roland McGrath   x86: compat_sys_p...
1316
1317
1318
  {
  	struct task_struct *child;
  	long ret;
c269f1961   Roland McGrath   x86: compat_sys_p...
1319
1320
1321
1322
  	if (request == PTRACE_TRACEME) {
  		ret = ptrace_traceme();
  		goto out;
  	}
2ee082608   Mike Rapoport   pids: introduce f...
1323
1324
1325
  	child = find_get_task_by_vpid(pid);
  	if (!child) {
  		ret = -ESRCH;
c269f1961   Roland McGrath   x86: compat_sys_p...
1326
1327
  		goto out;
  	}
3544d72a0   Tejun Heo   ptrace: implement...
1328
  	if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
aa9147c98   Denys Vlasenko   ptrace: make PTRA...
1329
  		ret = ptrace_attach(child, request, addr, data);
c269f1961   Roland McGrath   x86: compat_sys_p...
1330
1331
1332
1333
1334
1335
1336
1337
  		/*
  		 * Some architectures need to do book-keeping after
  		 * a ptrace attach.
  		 */
  		if (!ret)
  			arch_ptrace_attach(child);
  		goto out_put_task_struct;
  	}
fca26f260   Tejun Heo   ptrace: implement...
1338
1339
  	ret = ptrace_check_attach(child, request == PTRACE_KILL ||
  				  request == PTRACE_INTERRUPT);
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
1340
  	if (!ret) {
c269f1961   Roland McGrath   x86: compat_sys_p...
1341
  		ret = compat_arch_ptrace(child, request, addr, data);
9899d11f6   Oleg Nesterov   ptrace: ensure ar...
1342
1343
1344
  		if (ret || request != PTRACE_DETACH)
  			ptrace_unfreeze_traced(child);
  	}
c269f1961   Roland McGrath   x86: compat_sys_p...
1345
1346
1347
1348
  
   out_put_task_struct:
  	put_task_struct(child);
   out:
c269f1961   Roland McGrath   x86: compat_sys_p...
1349
1350
  	return ret;
  }
96b8936a9   Christoph Hellwig   remove __ARCH_WAN...
1351
  #endif	/* CONFIG_COMPAT */