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