]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/mach_process.c
xnu-517.9.4.tar.gz
[apple/xnu.git] / bsd / kern / mach_process.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*-
24 * Copyright (c) 1982, 1986, 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 * (c) UNIX System Laboratories, Inc.
27 * All or some portions of this file are derived from material licensed
28 * to the University of California by American Telephone and Telegraph
29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
30 * the permission of UNIX System Laboratories, Inc.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93
61 */
62
63 #include <machine/reg.h>
64 #include <machine/psl.h>
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/proc.h>
69 #include <sys/errno.h>
70 #include <sys/ptrace.h>
71 #include <sys/uio.h>
72 #include <sys/user.h>
73 #include <sys/sysctl.h>
74 #include <sys/wait.h>
75
76 #include <sys/mount.h>
77
78 #include <bsm/audit_kernel.h>
79
80 #include <kern/task.h>
81 #include <kern/thread.h>
82 #include <mach/machine/thread_status.h>
83
84 /* Macros to clear/set/test flags. */
85 #define SET(t, f) (t) |= (f)
86 #define CLR(t, f) (t) &= ~(f)
87 #define ISSET(t, f) ((t) & (f))
88
89 void psignal_lock __P((struct proc *, int, int));
90
91 /*
92 * sys-trace system call.
93 */
94 struct ptrace_args {
95 int req;
96 pid_t pid;
97 caddr_t addr;
98 int data;
99 };
100
101 int
102 ptrace(p, uap, retval)
103 struct proc *p;
104 struct ptrace_args *uap;
105 register_t *retval;
106 {
107 struct proc *t = current_proc(); /* target process */
108 vm_offset_t start_addr, end_addr,
109 kern_addr, offset;
110 vm_size_t size;
111 task_t task;
112 thread_t thread;
113 thread_act_t th_act;
114 struct uthread *ut;
115 int *locr0;
116 int error = 0;
117 #if defined(ppc)
118 struct ppc_thread_state64 statep;
119 #elif defined(i386)
120 struct i386_saved_state statep;
121 #else
122 #error architecture not supported
123 #endif
124 unsigned long state_count;
125 int tr_sigexc = 0;
126
127 AUDIT_ARG(cmd, uap->req);
128 AUDIT_ARG(pid, uap->pid);
129 AUDIT_ARG(addr, uap->addr);
130 AUDIT_ARG(value, uap->data);
131
132 if (uap->req == PT_DENY_ATTACH) {
133 if (ISSET(p->p_flag, P_TRACED)) {
134 exit1(p, W_EXITCODE(ENOTSUP, 0), retval);
135 /* drop funnel before we return */
136 thread_funnel_set(kernel_flock, FALSE);
137 thread_exception_return();
138 /* NOTREACHED */
139 }
140 SET(p->p_flag, P_NOATTACH);
141
142 return(0);
143 }
144
145 if (uap->req == PT_FORCEQUOTA) {
146 if (is_suser()) {
147 SET(t->p_flag, P_FORCEQUOTA);
148 return (0);
149 } else
150 return (EPERM);
151 }
152
153 /*
154 * Intercept and deal with "please trace me" request.
155 */
156 if (uap->req == PT_TRACE_ME) {
157 SET(p->p_flag, P_TRACED);
158 /* Non-attached case, our tracer is our parent. */
159 t->p_oppid = t->p_pptr->p_pid;
160 return(0);
161 }
162 if (uap->req == PT_SIGEXC) {
163 if (ISSET(p->p_flag, P_TRACED)) {
164 SET(p->p_flag, P_SIGEXC);
165 return(0);
166 } else
167 return(EINVAL);
168 }
169
170 /*
171 * Locate victim, and make sure it is traceable.
172 */
173 if ((t = pfind(uap->pid)) == NULL)
174 return (ESRCH);
175
176
177 AUDIT_ARG(process, t);
178
179 /* We do not want ptrace to do anything with kernel, init
180 * and mach_init
181 */
182 if (uap->pid <=2 )
183 return (EPERM);
184
185 task = t->task;
186 if (uap->req == PT_ATTACHEXC) {
187 uap->req = PT_ATTACH;
188 tr_sigexc = 1;
189 }
190 if (uap->req == PT_ATTACH) {
191
192 /*
193 * You can't attach to a process if:
194 * (1) it's the process that's doing the attaching,
195 */
196 if (t->p_pid == p->p_pid)
197 return (EINVAL);
198
199 /*
200 * (2) it's already being traced, or
201 */
202 if (ISSET(t->p_flag, P_TRACED))
203 return (EBUSY);
204
205 /*
206 * (3) it's not owned by you, or is set-id on exec
207 * (unless you're root).
208 */
209 if ((t->p_cred->p_ruid != p->p_cred->p_ruid ||
210 ISSET(t->p_flag, P_SUGID)) &&
211 (error = suser(p->p_ucred, &p->p_acflag)) != 0)
212 return (error);
213
214 if ((p->p_flag & P_TRACED) && isinferior(p, t))
215 return(EPERM);
216
217 if (ISSET(t->p_flag, P_NOATTACH)) {
218 psignal(p, SIGSEGV);
219 return (EBUSY);
220 }
221 SET(t->p_flag, P_TRACED);
222 if (tr_sigexc)
223 SET(t->p_flag, P_SIGEXC);
224
225 t->p_oppid = t->p_pptr->p_pid;
226 if (t->p_pptr != p)
227 proc_reparent(t, p);
228
229 if (get_task_userstop(task) == 0 ) {
230 t->p_xstat = 0;
231 psignal(t, SIGSTOP);
232 } else {
233 t->p_xstat = SIGSTOP;
234 task_resume(task);
235 }
236 return(0);
237 }
238
239 /*
240 * You can't do what you want to the process if:
241 * (1) It's not being traced at all,
242 */
243 if (!ISSET(t->p_flag, P_TRACED))
244 return (EPERM);
245
246 /*
247 * (2) it's not being traced by _you_, or
248 */
249 if (t->p_pptr != p)
250 return (EBUSY);
251
252 /*
253 * (3) it's not currently stopped.
254 */
255 if (t->p_stat != SSTOP)
256 return (EBUSY);
257
258 /*
259 * Mach version of ptrace executes request directly here,
260 * thus simplifying the interaction of ptrace and signals.
261 */
262 switch (uap->req) {
263
264 case PT_DETACH:
265 if (t->p_oppid != t->p_pptr->p_pid) {
266 struct proc *pp;
267
268 pp = pfind(t->p_oppid);
269 proc_reparent(t, pp ? pp : initproc);
270 }
271
272 t->p_oppid = 0;
273 CLR(t->p_flag, P_TRACED);
274 CLR(t->p_flag, P_SIGEXC);
275 goto resume;
276
277 case PT_KILL:
278 /*
279 * Tell child process to kill itself after it
280 * is resumed by adding NSIG to p_cursig. [see issig]
281 */
282 psignal_lock(t, SIGKILL, 0);
283 goto resume;
284
285 case PT_STEP: /* single step the child */
286 case PT_CONTINUE: /* continue the child */
287 th_act = (thread_act_t)get_firstthread(task);
288 if (th_act == THR_ACT_NULL)
289 goto errorLabel;
290 ut = (uthread_t)get_bsdthread_info(th_act);
291 locr0 = ut->uu_ar0;
292 #if defined(i386)
293 state_count = i386_NEW_THREAD_STATE_COUNT;
294 if (thread_getstatus(th_act, i386_NEW_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) {
295 goto errorLabel;
296 }
297 #elif defined(ppc)
298 state_count = PPC_THREAD_STATE64_COUNT;
299 if (thread_getstatus(th_act, PPC_THREAD_STATE64, &statep, &state_count) != KERN_SUCCESS) {
300 goto errorLabel;
301 }
302 #else
303 #error architecture not supported
304 #endif
305 if ((int)uap->addr != 1) {
306 #if defined(i386)
307 locr0[PC] = (int)uap->addr;
308 #elif defined(ppc)
309 #define ALIGNED(addr,size) (((unsigned)(addr)&((size)-1))==0)
310 if (!ALIGNED((int)uap->addr, sizeof(int)))
311 return (ERESTART);
312
313 statep.srr0 = (uint64_t)((uint32_t)uap->addr);
314 state_count = PPC_THREAD_STATE64_COUNT;
315 if (thread_setstatus(th_act, PPC_THREAD_STATE64, &statep, &state_count) != KERN_SUCCESS) {
316 goto errorLabel;
317 }
318 #undef ALIGNED
319 #else
320 #error architecture not implemented!
321 #endif
322 } /* (int)uap->addr != 1 */
323
324 if ((unsigned)uap->data < 0 || (unsigned)uap->data >= NSIG)
325 goto errorLabel;
326
327 if (uap->data != 0) {
328 psignal_lock(t, uap->data, 0);
329 }
330 #if defined(ppc)
331 state_count = PPC_THREAD_STATE64_COUNT;
332 if (thread_getstatus(th_act, PPC_THREAD_STATE64, &statep, &state_count) != KERN_SUCCESS) {
333 goto errorLabel;
334 }
335 #endif
336
337 #define MSR_SE_BIT 21
338
339 if (uap->req == PT_STEP) {
340 #if defined(i386)
341 locr0[PS] |= PSL_T;
342 #elif defined(ppc)
343 statep.srr1 |= MASK(MSR_SE);
344 #else
345 #error architecture not implemented!
346 #endif
347 } /* uap->req == PT_STEP */
348 else { /* PT_CONTINUE - clear trace bit if set */
349 #if defined(i386)
350 locr0[PS] &= ~PSL_T;
351 #elif defined(ppc)
352 statep.srr1 &= ~MASK(MSR_SE);
353 #endif
354 }
355 #if defined (ppc)
356 state_count = PPC_THREAD_STATE64_COUNT;
357 if (thread_setstatus(th_act, PPC_THREAD_STATE64, &statep, &state_count) != KERN_SUCCESS) {
358 goto errorLabel;
359 }
360 #endif
361 resume:
362 t->p_xstat = uap->data;
363 t->p_stat = SRUN;
364 if (t->sigwait) {
365 wakeup((caddr_t)&(t->sigwait));
366 if ((t->p_flag & P_SIGEXC) == 0)
367 task_release(task);
368 }
369 break;
370
371 case PT_THUPDATE: {
372 thread_act_t target_act;
373
374 if ((unsigned)uap->data >= NSIG)
375 goto errorLabel;
376 th_act = (thread_act_t)port_name_to_act((void *)uap->addr);
377 if (th_act == THR_ACT_NULL)
378 return (ESRCH);
379 ut = (uthread_t)get_bsdthread_info(th_act);
380 if (uap->data)
381 ut->uu_siglist |= sigmask(uap->data);
382 t->p_xstat = uap->data;
383 t->p_stat = SRUN;
384 act_deallocate(th_act);
385 return(0);
386 }
387 break;
388 errorLabel:
389 default:
390 return(EINVAL);
391 }
392
393 return(0);
394 }
395