procfs_ctl.c revision 287604
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: stable/10/sys/fs/procfs/procfs_ctl.c 287604 2015-09-09 23:39:30Z jhb $
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		p->p_oppid = p->p_pptr->p_pid;
147		if (p->p_pptr != td->td_proc) {
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_stops = 0;
239		p->p_flag &= ~P_WAITED;	/* XXX ? */
240		sx_xunlock(&proctree_lock);
241
242		wakeup(td->td_proc);	/* XXX for CTL_WAIT below ? */
243
244		break;
245
246	/*
247	 * Step.  Let the target process execute a single instruction.
248	 * What does it mean to single step a threaded program?
249	 */
250	case PROCFS_CTL_STEP:
251		error = proc_sstep(FIRST_THREAD_IN_PROC(p));
252		if (error) {
253			PROC_UNLOCK(p);
254			return (error);
255		}
256		break;
257
258	/*
259	 * Run.  Let the target process continue running until a breakpoint
260	 * or some other trap.
261	 */
262	case PROCFS_CTL_RUN:
263		p->p_flag &= ~P_STOPPED_SIG;	/* this uses SIGSTOP */
264		break;
265
266	/*
267	 * Wait for the target process to stop.
268	 * If the target is not being traced then just wait
269	 * to enter
270	 */
271	case PROCFS_CTL_WAIT:
272		if (p->p_flag & P_TRACED) {
273			while (error == 0 &&
274					(P_SHOULDSTOP(p)) &&
275					(p->p_flag & P_TRACED) &&
276					(p->p_pptr == td->td_proc))
277				error = msleep(p, &p->p_mtx,
278						PWAIT|PCATCH, "procfsx", 0);
279			if (error == 0 && !TRACE_WAIT_P(td->td_proc, p))
280				error = EBUSY;
281		} else {
282			while (error == 0 && P_SHOULDSTOP(p))
283				error = msleep(p, &p->p_mtx,
284						PWAIT|PCATCH, "procfs", 0);
285		}
286		PROC_UNLOCK(p);
287		return (error);
288	default:
289		panic("procfs_control");
290	}
291
292	PROC_SLOCK(p);
293	thread_unsuspend(p); /* If it can run, let it do so. */
294	PROC_SUNLOCK(p);
295	PROC_UNLOCK(p);
296	return (0);
297}
298
299static struct namemap *
300findname(struct namemap *nm, char *buf, int buflen)
301{
302
303	for (; nm->nm_name; nm++)
304		if (bcmp(buf, nm->nm_name, buflen+1) == 0)
305			return (nm);
306
307	return (0);
308}
309
310int
311procfs_doprocctl(PFS_FILL_ARGS)
312{
313	int error;
314	struct namemap *nm;
315
316	if (uio == NULL || uio->uio_rw != UIO_WRITE)
317		return (EOPNOTSUPP);
318
319	/*
320	 * Map signal names into signal generation
321	 * or debug control.  Unknown commands and/or signals
322	 * return EOPNOTSUPP.
323	 *
324	 * Sending a signal while the process is being debugged
325	 * also has the side effect of letting the target continue
326	 * to run.  There is no way to single-step a signal delivery.
327	 */
328	error = EOPNOTSUPP;
329
330	sbuf_trim(sb);
331	sbuf_finish(sb);
332	nm = findname(ctlnames, sbuf_data(sb), sbuf_len(sb));
333	if (nm) {
334		printf("procfs: got a %s command\n", sbuf_data(sb));
335		error = procfs_control(td, p, nm->nm_val);
336	} else {
337		nm = findname(signames, sbuf_data(sb), sbuf_len(sb));
338		if (nm) {
339			printf("procfs: got a sig%s\n", sbuf_data(sb));
340			PROC_LOCK(p);
341
342			if (TRACE_WAIT_P(td->td_proc, p)) {
343				p->p_xstat = nm->nm_val;
344#ifdef FIX_SSTEP
345				FIX_SSTEP(FIRST_THREAD_IN_PROC(p));
346#endif
347				p->p_flag &= ~P_STOPPED_SIG;
348				PROC_SLOCK(p);
349				thread_unsuspend(p);
350				PROC_SUNLOCK(p);
351			} else
352				kern_psignal(p, nm->nm_val);
353			PROC_UNLOCK(p);
354			error = 0;
355		}
356	}
357
358	return (error);
359}
360