1/*-
2 * Copyright (c) 1993 Jan-Simon Pendry
3 * Copyright (c) 1993
4 *	The Regents of the University of California.  All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	@(#)procfs_ctl.c	8.4 (Berkeley) 6/15/94
34 *
35 * From:
36 *	$Id: procfs_ctl.c,v 1.51 2003/12/07 17:40:00 des Exp $
37 * $FreeBSD$
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/lock.h>
43#include <sys/mutex.h>
44#include <sys/proc.h>
45#include <sys/ptrace.h>
46#include <sys/sbuf.h>
47#include <sys/signalvar.h>
48#include <sys/sx.h>
49#include <sys/uio.h>
50
51#include <fs/pseudofs/pseudofs.h>
52#include <fs/procfs/procfs.h>
53
54#include <vm/vm.h>
55
56/*
57 * True iff process (p) is in trace wait state
58 * relative to process (curp)
59 */
60#define TRACE_WAIT_P(curp, p) \
61	 (P_SHOULDSTOP(p) && \
62	 (p)->p_pptr == (curp) && \
63	 ((p)->p_flag & P_TRACED))
64
65#define PROCFS_CTL_ATTACH	1
66#define PROCFS_CTL_DETACH	2
67#define PROCFS_CTL_STEP		3
68#define PROCFS_CTL_RUN		4
69#define PROCFS_CTL_WAIT		5
70
71struct namemap {
72	const char *nm_name;
73	int nm_val;
74};
75
76static struct namemap ctlnames[] = {
77	/* special /proc commands */
78	{ "attach",	PROCFS_CTL_ATTACH },
79	{ "detach",	PROCFS_CTL_DETACH },
80	{ "step",	PROCFS_CTL_STEP },
81	{ "run",	PROCFS_CTL_RUN },
82	{ "wait",	PROCFS_CTL_WAIT },
83	{ 0 },
84};
85
86static struct namemap signames[] = {
87	/* regular signal names */
88	{ "hup",	SIGHUP },	{ "int",	SIGINT },
89	{ "quit",	SIGQUIT },	{ "ill",	SIGILL },
90	{ "trap",	SIGTRAP },	{ "abrt",	SIGABRT },
91	{ "iot",	SIGIOT },	{ "emt",	SIGEMT },
92	{ "fpe",	SIGFPE },	{ "kill",	SIGKILL },
93	{ "bus",	SIGBUS },	{ "segv",	SIGSEGV },
94	{ "sys",	SIGSYS },	{ "pipe",	SIGPIPE },
95	{ "alrm",	SIGALRM },	{ "term",	SIGTERM },
96	{ "urg",	SIGURG },	{ "stop",	SIGSTOP },
97	{ "tstp",	SIGTSTP },	{ "cont",	SIGCONT },
98	{ "chld",	SIGCHLD },	{ "ttin",	SIGTTIN },
99	{ "ttou",	SIGTTOU },	{ "io",		SIGIO },
100	{ "xcpu",	SIGXCPU },	{ "xfsz",	SIGXFSZ },
101	{ "vtalrm",	SIGVTALRM },	{ "prof",	SIGPROF },
102	{ "winch",	SIGWINCH },	{ "info",	SIGINFO },
103	{ "usr1",	SIGUSR1 },	{ "usr2",	SIGUSR2 },
104	{ 0 },
105};
106
107static int	procfs_control(struct thread *td, struct proc *p, int op);
108
109static int
110procfs_control(struct thread *td, struct proc *p, int op)
111{
112	int error = 0;
113	struct thread *temp;
114
115	/*
116	 * Attach - attaches the target process for debugging
117	 * by the calling process.
118	 */
119	if (op == PROCFS_CTL_ATTACH) {
120		sx_xlock(&proctree_lock);
121		PROC_LOCK(p);
122		if ((error = p_candebug(td, p)) != 0)
123			goto out;
124		if (p->p_flag & P_TRACED) {
125			error = EBUSY;
126			goto out;
127		}
128
129		/* Can't trace yourself! */
130		if (p->p_pid == td->td_proc->p_pid) {
131			error = EINVAL;
132			goto out;
133		}
134
135		/*
136		 * Go ahead and set the trace flag.
137		 * Save the old parent (it's reset in
138		 *   _DETACH, and also in kern_exit.c:wait4()
139		 * Reparent the process so that the tracing
140		 *   proc gets to see all the action.
141		 * Stop the target.
142		 */
143		p->p_flag |= P_TRACED;
144		faultin(p);
145		p->p_xstat = 0;		/* XXX ? */
146		if (p->p_pptr != td->td_proc) {
147			p->p_oppid = p->p_pptr->p_pid;
148			proc_reparent(p, td->td_proc);
149		}
150		kern_psignal(p, SIGSTOP);
151out:
152		PROC_UNLOCK(p);
153		sx_xunlock(&proctree_lock);
154		return (error);
155	}
156
157	/*
158	 * Authorization check: rely on normal debugging protection, except
159	 * allow processes to disengage debugging on a process onto which
160	 * they have previously attached, but no longer have permission to
161	 * debug.
162	 */
163	PROC_LOCK(p);
164	if (op != PROCFS_CTL_DETACH &&
165	    ((error = p_candebug(td, p)))) {
166		PROC_UNLOCK(p);
167		return (error);
168	}
169
170	/*
171	 * Target process must be stopped, owned by (td) and
172	 * be set up for tracing (P_TRACED flag set).
173	 * Allow DETACH to take place at any time for sanity.
174	 * Allow WAIT any time, of course.
175	 */
176	switch (op) {
177	case PROCFS_CTL_DETACH:
178	case PROCFS_CTL_WAIT:
179		break;
180
181	default:
182		if (!TRACE_WAIT_P(td->td_proc, p)) {
183			PROC_UNLOCK(p);
184			return (EBUSY);
185		}
186	}
187
188
189#ifdef FIX_SSTEP
190	/*
191	 * do single-step fixup if needed
192	 */
193	FIX_SSTEP(FIRST_THREAD_IN_PROC(p));
194#endif
195
196	/*
197	 * Don't deliver any signal by default.
198	 * To continue with a signal, just send
199	 * the signal name to the ctl file
200	 */
201	p->p_xstat = 0;
202
203	switch (op) {
204	/*
205	 * Detach.  Cleans up the target process, reparent it if possible
206	 * and set it running once more.
207	 */
208	case PROCFS_CTL_DETACH:
209		/* if not being traced, then this is a painless no-op */
210		if ((p->p_flag & P_TRACED) == 0) {
211			PROC_UNLOCK(p);
212			return (0);
213		}
214
215		/* not being traced any more */
216		p->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
217
218		/* remove pending SIGTRAP, else the process will die */
219		sigqueue_delete_proc(p, SIGTRAP);
220		FOREACH_THREAD_IN_PROC(p, temp)
221			temp->td_dbgflags &= ~TDB_SUSPEND;
222		PROC_UNLOCK(p);
223
224		/* give process back to original parent */
225		sx_xlock(&proctree_lock);
226		if (p->p_oppid != p->p_pptr->p_pid) {
227			struct proc *pp;
228
229			pp = pfind(p->p_oppid);
230			PROC_LOCK(p);
231			if (pp) {
232				PROC_UNLOCK(pp);
233				proc_reparent(p, pp);
234			}
235		} else
236			PROC_LOCK(p);
237		p->p_oppid = 0;
238		p->p_flag &= ~P_WAITED;	/* XXX ? */
239		sx_xunlock(&proctree_lock);
240
241		wakeup(td->td_proc);	/* XXX for CTL_WAIT below ? */
242
243		break;
244
245	/*
246	 * Step.  Let the target process execute a single instruction.
247	 * What does it mean to single step a threaded program?
248	 */
249	case PROCFS_CTL_STEP:
250		error = proc_sstep(FIRST_THREAD_IN_PROC(p));
251		if (error) {
252			PROC_UNLOCK(p);
253			return (error);
254		}
255		break;
256
257	/*
258	 * Run.  Let the target process continue running until a breakpoint
259	 * or some other trap.
260	 */
261	case PROCFS_CTL_RUN:
262		p->p_flag &= ~P_STOPPED_SIG;	/* this uses SIGSTOP */
263		break;
264
265	/*
266	 * Wait for the target process to stop.
267	 * If the target is not being traced then just wait
268	 * to enter
269	 */
270	case PROCFS_CTL_WAIT:
271		if (p->p_flag & P_TRACED) {
272			while (error == 0 &&
273					(P_SHOULDSTOP(p)) &&
274					(p->p_flag & P_TRACED) &&
275					(p->p_pptr == td->td_proc))
276				error = msleep(p, &p->p_mtx,
277						PWAIT|PCATCH, "procfsx", 0);
278			if (error == 0 && !TRACE_WAIT_P(td->td_proc, p))
279				error = EBUSY;
280		} else {
281			while (error == 0 && P_SHOULDSTOP(p))
282				error = msleep(p, &p->p_mtx,
283						PWAIT|PCATCH, "procfs", 0);
284		}
285		PROC_UNLOCK(p);
286		return (error);
287	default:
288		panic("procfs_control");
289	}
290
291	PROC_SLOCK(p);
292	thread_unsuspend(p); /* If it can run, let it do so. */
293	PROC_SUNLOCK(p);
294	PROC_UNLOCK(p);
295	return (0);
296}
297
298static struct namemap *
299findname(struct namemap *nm, char *buf, int buflen)
300{
301
302	for (; nm->nm_name; nm++)
303		if (bcmp(buf, nm->nm_name, buflen+1) == 0)
304			return (nm);
305
306	return (0);
307}
308
309int
310procfs_doprocctl(PFS_FILL_ARGS)
311{
312	int error;
313	struct namemap *nm;
314
315	if (uio == NULL || uio->uio_rw != UIO_WRITE)
316		return (EOPNOTSUPP);
317
318	/*
319	 * Map signal names into signal generation
320	 * or debug control.  Unknown commands and/or signals
321	 * return EOPNOTSUPP.
322	 *
323	 * Sending a signal while the process is being debugged
324	 * also has the side effect of letting the target continue
325	 * to run.  There is no way to single-step a signal delivery.
326	 */
327	error = EOPNOTSUPP;
328
329	sbuf_trim(sb);
330	sbuf_finish(sb);
331	nm = findname(ctlnames, sbuf_data(sb), sbuf_len(sb));
332	if (nm) {
333		printf("procfs: got a %s command\n", sbuf_data(sb));
334		error = procfs_control(td, p, nm->nm_val);
335	} else {
336		nm = findname(signames, sbuf_data(sb), sbuf_len(sb));
337		if (nm) {
338			printf("procfs: got a sig%s\n", sbuf_data(sb));
339			PROC_LOCK(p);
340
341			if (TRACE_WAIT_P(td->td_proc, p)) {
342				p->p_xstat = nm->nm_val;
343#ifdef FIX_SSTEP
344				FIX_SSTEP(FIRST_THREAD_IN_PROC(p));
345#endif
346				p->p_flag &= ~P_STOPPED_SIG;
347				PROC_SLOCK(p);
348				thread_unsuspend(p);
349				PROC_SUNLOCK(p);
350			} else
351				kern_psignal(p, nm->nm_val);
352			PROC_UNLOCK(p);
353			error = 0;
354		}
355	}
356
357	return (error);
358}
359