1 | /* $NetBSD: procfs_ctl.c,v 1.48 2016/04/04 20:47:57 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1993 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to Berkeley by |
8 | * Jan-Simon Pendry. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. |
21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. |
33 | * |
34 | * @(#)procfs_ctl.c 8.4 (Berkeley) 6/15/94 |
35 | */ |
36 | |
37 | /* |
38 | * Copyright (c) 1993 Jan-Simon Pendry |
39 | * |
40 | * This code is derived from software contributed to Berkeley by |
41 | * Jan-Simon Pendry. |
42 | * |
43 | * Redistribution and use in source and binary forms, with or without |
44 | * modification, are permitted provided that the following conditions |
45 | * are met: |
46 | * 1. Redistributions of source code must retain the above copyright |
47 | * notice, this list of conditions and the following disclaimer. |
48 | * 2. Redistributions in binary form must reproduce the above copyright |
49 | * notice, this list of conditions and the following disclaimer in the |
50 | * documentation and/or other materials provided with the distribution. |
51 | * 3. All advertising materials mentioning features or use of this software |
52 | * must display the following acknowledgement: |
53 | * This product includes software developed by the University of |
54 | * California, Berkeley and its contributors. |
55 | * 4. Neither the name of the University nor the names of its contributors |
56 | * may be used to endorse or promote products derived from this software |
57 | * without specific prior written permission. |
58 | * |
59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
69 | * SUCH DAMAGE. |
70 | * |
71 | * @(#)procfs_ctl.c 8.4 (Berkeley) 6/15/94 |
72 | */ |
73 | |
74 | #include <sys/cdefs.h> |
75 | __KERNEL_RCSID(0, "$NetBSD: procfs_ctl.c,v 1.48 2016/04/04 20:47:57 christos Exp $" ); |
76 | |
77 | #include <sys/param.h> |
78 | #include <sys/systm.h> |
79 | #include <sys/time.h> |
80 | #include <sys/kernel.h> |
81 | #include <sys/proc.h> |
82 | #include <sys/vnode.h> |
83 | #include <sys/ioctl.h> |
84 | #include <sys/tty.h> |
85 | #include <sys/resource.h> |
86 | #include <sys/resourcevar.h> |
87 | #include <sys/signalvar.h> |
88 | #include <sys/kauth.h> |
89 | |
90 | #include <uvm/uvm_extern.h> |
91 | |
92 | #include <miscfs/procfs/procfs.h> |
93 | |
94 | #define PROCFS_CTL_ATTACH 1 |
95 | #define PROCFS_CTL_DETACH 2 |
96 | #define PROCFS_CTL_STEP 3 |
97 | #define PROCFS_CTL_RUN 4 |
98 | #define PROCFS_CTL_WAIT 5 |
99 | |
100 | static const vfs_namemap_t ctlnames[] = { |
101 | /* special /proc commands */ |
102 | { "attach" , PROCFS_CTL_ATTACH }, |
103 | { "detach" , PROCFS_CTL_DETACH }, |
104 | { "step" , PROCFS_CTL_STEP }, |
105 | { "run" , PROCFS_CTL_RUN }, |
106 | { "wait" , PROCFS_CTL_WAIT }, |
107 | { NULL, 0 }, |
108 | }; |
109 | |
110 | static const vfs_namemap_t signames[] = { |
111 | /* regular signal names */ |
112 | { "hup" , SIGHUP }, { "int" , SIGINT }, |
113 | { "quit" , SIGQUIT }, { "ill" , SIGILL }, |
114 | { "trap" , SIGTRAP }, { "abrt" , SIGABRT }, |
115 | { "iot" , SIGIOT }, { "emt" , SIGEMT }, |
116 | { "fpe" , SIGFPE }, { "kill" , SIGKILL }, |
117 | { "bus" , SIGBUS }, { "segv" , SIGSEGV }, |
118 | { "sys" , SIGSYS }, { "pipe" , SIGPIPE }, |
119 | { "alrm" , SIGALRM }, { "term" , SIGTERM }, |
120 | { "urg" , SIGURG }, { "stop" , SIGSTOP }, |
121 | { "tstp" , SIGTSTP }, { "cont" , SIGCONT }, |
122 | { "chld" , SIGCHLD }, { "ttin" , SIGTTIN }, |
123 | { "ttou" , SIGTTOU }, { "io" , SIGIO }, |
124 | { "xcpu" , SIGXCPU }, { "xfsz" , SIGXFSZ }, |
125 | { "vtalrm" , SIGVTALRM }, { "prof" , SIGPROF }, |
126 | { "winch" , SIGWINCH }, { "info" , SIGINFO }, |
127 | { "usr1" , SIGUSR1 }, { "usr2" , SIGUSR2 }, |
128 | { NULL, 0 }, |
129 | }; |
130 | |
131 | static int procfs_control(struct lwp *, struct lwp *, int, int, |
132 | struct pfsnode *); |
133 | |
134 | int |
135 | procfs_control(struct lwp *curl, struct lwp *l, int op, int sig, struct pfsnode *pfs) |
136 | { |
137 | struct proc *curp = curl->l_proc; |
138 | struct proc *p = l->l_proc; |
139 | int error = 0; |
140 | |
141 | mutex_enter(proc_lock); |
142 | mutex_enter(p->p_lock); |
143 | |
144 | switch (op) { |
145 | /* |
146 | * Attach - attaches the target process for debugging |
147 | * by the calling process. |
148 | */ |
149 | case PROCFS_CTL_ATTACH: |
150 | /* |
151 | * You can't attach to a process if: |
152 | * (1) it's the process that's doing the attaching, |
153 | */ |
154 | if (p->p_pid == curp->p_pid) { |
155 | error = EINVAL; |
156 | break; |
157 | } |
158 | |
159 | /* |
160 | * (2) it's already being traced, or |
161 | */ |
162 | if (ISSET(p->p_slflag, PSL_TRACED)) { |
163 | error = EBUSY; |
164 | break; |
165 | } |
166 | |
167 | /* |
168 | * (3) the security model prevents it. |
169 | */ |
170 | if ((error = kauth_authorize_process(curl->l_cred, |
171 | KAUTH_PROCESS_PROCFS, p, pfs, |
172 | KAUTH_ARG(KAUTH_REQ_PROCESS_PROCFS_CTL), NULL)) != 0) |
173 | break; |
174 | |
175 | break; |
176 | |
177 | /* |
178 | * Target process must be stopped, owned by (curp) and |
179 | * be set up for tracing (PSL_TRACED flag set). |
180 | * Allow DETACH to take place at any time for sanity. |
181 | * Allow WAIT any time, of course. |
182 | * |
183 | * Note that the semantics of DETACH are different here |
184 | * from ptrace(2). |
185 | */ |
186 | case PROCFS_CTL_DETACH: |
187 | case PROCFS_CTL_WAIT: |
188 | /* |
189 | * You can't do what you want to the process if: |
190 | * (1) It's not being traced at all, |
191 | */ |
192 | if (!ISSET(p->p_slflag, PSL_TRACED)) { |
193 | error = EPERM; |
194 | break; |
195 | } |
196 | |
197 | /* |
198 | * (2) it's being traced by ptrace(2) (which has |
199 | * different signal delivery semantics), or |
200 | */ |
201 | if (!ISSET(p->p_slflag, PSL_FSTRACE)) { |
202 | error = EBUSY; |
203 | break; |
204 | } |
205 | |
206 | /* |
207 | * (3) it's not being traced by _you_. |
208 | */ |
209 | if (p->p_pptr != curp) |
210 | error = EBUSY; |
211 | |
212 | break; |
213 | |
214 | default: |
215 | /* |
216 | * You can't do what you want to the process if: |
217 | * (1) It's not being traced at all, |
218 | */ |
219 | if (!ISSET(p->p_slflag, PSL_TRACED)) { |
220 | error = EPERM; |
221 | break; |
222 | } |
223 | |
224 | /* |
225 | * (2) it's being traced by ptrace(2) (which has |
226 | * different signal delivery semantics), |
227 | */ |
228 | if (!ISSET(p->p_slflag, PSL_FSTRACE)) { |
229 | error = EBUSY; |
230 | break; |
231 | } |
232 | |
233 | /* |
234 | * (3) it's not being traced by _you_, or |
235 | */ |
236 | if (p->p_pptr != curp) { |
237 | error = EBUSY; |
238 | break; |
239 | } |
240 | |
241 | /* |
242 | * (4) it's not currently stopped. |
243 | */ |
244 | if (p->p_stat != SSTOP || !p->p_waited /* XXXSMP */) |
245 | error = EBUSY; |
246 | |
247 | break; |
248 | } |
249 | |
250 | if (error != 0) { |
251 | mutex_exit(p->p_lock); |
252 | mutex_exit(proc_lock); |
253 | return (error); |
254 | } |
255 | |
256 | /* Do single-step fixup if needed. */ |
257 | FIX_SSTEP(p); |
258 | |
259 | switch (op) { |
260 | case PROCFS_CTL_ATTACH: |
261 | /* |
262 | * Go ahead and set the trace flag. |
263 | * Save the old parent (it's reset in |
264 | * _DETACH, and also in kern_exit.c:wait4() |
265 | * Reparent the process so that the tracing |
266 | * proc gets to see all the action. |
267 | * Stop the target. |
268 | */ |
269 | SET(p->p_slflag, PSL_TRACED|PSL_FSTRACE); |
270 | p->p_opptr = p->p_pptr; |
271 | if (p->p_pptr != curp) { |
272 | if (p->p_pptr->p_lock < p->p_lock) { |
273 | if (!mutex_tryenter(p->p_pptr->p_lock)) { |
274 | mutex_exit(p->p_lock); |
275 | mutex_enter(p->p_pptr->p_lock); |
276 | } |
277 | } else if (p->p_pptr->p_lock > p->p_lock) { |
278 | mutex_enter(p->p_pptr->p_lock); |
279 | } |
280 | p->p_pptr->p_slflag |= PSL_CHTRACED; |
281 | proc_reparent(p, curp); |
282 | if (p->p_pptr->p_lock != p->p_lock) |
283 | mutex_exit(p->p_pptr->p_lock); |
284 | } |
285 | sig = SIGSTOP; |
286 | goto sendsig; |
287 | |
288 | #ifdef PT_STEP |
289 | case PROCFS_CTL_STEP: |
290 | /* |
291 | * Step. Let the target process execute a single instruction. |
292 | */ |
293 | #endif |
294 | case PROCFS_CTL_RUN: |
295 | case PROCFS_CTL_DETACH: |
296 | #ifdef PT_STEP |
297 | /* XXXAD locking? */ |
298 | error = process_sstep(l, op == PROCFS_CTL_STEP); |
299 | if (error) |
300 | break; |
301 | #endif |
302 | |
303 | if (op == PROCFS_CTL_DETACH) { |
304 | /* give process back to original parent */ |
305 | if (p->p_opptr != p->p_pptr) { |
306 | struct proc *pp = p->p_opptr; |
307 | proc_reparent(p, pp ? pp : initproc); |
308 | } |
309 | |
310 | /* not being traced any more */ |
311 | p->p_opptr = NULL; |
312 | CLR(p->p_slflag, PSL_TRACED|PSL_FSTRACE); |
313 | p->p_waited = 0; /* XXXSMP */ |
314 | } |
315 | |
316 | sendsig: |
317 | /* Finally, deliver the requested signal (or none). */ |
318 | lwp_lock(l); |
319 | if (l->l_stat == LSSTOP) { |
320 | p->p_xsig = sig; |
321 | /* setrunnable() will release the lock. */ |
322 | setrunnable(l); |
323 | } else { |
324 | lwp_unlock(l); |
325 | if (sig != 0) { |
326 | mutex_exit(p->p_lock); |
327 | psignal(p, sig); |
328 | mutex_enter(p->p_lock); |
329 | } |
330 | } |
331 | mutex_exit(p->p_lock); |
332 | mutex_exit(proc_lock); |
333 | return (error); |
334 | |
335 | case PROCFS_CTL_WAIT: |
336 | mutex_exit(p->p_lock); |
337 | mutex_exit(proc_lock); |
338 | |
339 | /* |
340 | * Wait for the target process to stop. |
341 | * XXXSMP WTF is this? |
342 | */ |
343 | while (l->l_stat != LSSTOP && P_ZOMBIE(p)) { |
344 | error = tsleep(l, PWAIT|PCATCH, "procfsx" , hz); |
345 | if (error) |
346 | break; |
347 | } |
348 | |
349 | return (error); |
350 | |
351 | default: |
352 | panic("procfs_ctl" ); |
353 | /* NOTREACHED */ |
354 | } |
355 | |
356 | mutex_exit(p->p_lock); |
357 | mutex_exit(proc_lock); |
358 | return (error); |
359 | } |
360 | |
361 | int |
362 | procfs_doctl( |
363 | struct lwp *curl, |
364 | struct lwp *l, |
365 | struct pfsnode *pfs, |
366 | struct uio *uio |
367 | ) |
368 | { |
369 | struct proc *p = l->l_proc; |
370 | char msg[PROCFS_CTLLEN+1]; |
371 | const vfs_namemap_t *nm; |
372 | int error; |
373 | int xlen; |
374 | |
375 | if (uio->uio_rw != UIO_WRITE) |
376 | return (EOPNOTSUPP); |
377 | |
378 | xlen = PROCFS_CTLLEN; |
379 | error = vfs_getuserstr(uio, msg, &xlen); |
380 | if (error) |
381 | return (error); |
382 | |
383 | /* |
384 | * Map signal names into signal generation |
385 | * or debug control. Unknown commands and/or signals |
386 | * return EOPNOTSUPP. |
387 | * |
388 | * Sending a signal while the process is being debugged |
389 | * also has the side effect of letting the target continue |
390 | * to run. There is no way to single-step a signal delivery. |
391 | */ |
392 | error = EOPNOTSUPP; |
393 | |
394 | nm = vfs_findname(ctlnames, msg, xlen); |
395 | if (nm) { |
396 | error = procfs_control(curl, l, nm->nm_val, 0, pfs); |
397 | } else { |
398 | nm = vfs_findname(signames, msg, xlen); |
399 | if (nm) { |
400 | if (ISSET(p->p_slflag, PSL_TRACED) && |
401 | p->p_pptr == p) |
402 | error = procfs_control(curl, l, PROCFS_CTL_RUN, |
403 | nm->nm_val, pfs); |
404 | else { |
405 | psignal(p, nm->nm_val); |
406 | error = 0; |
407 | } |
408 | } |
409 | } |
410 | |
411 | return (error); |
412 | } |
413 | |