| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
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 | * 3. All advertising materials mentioning features or use of this software | |
| 18 | * must display the following acknowledgement: | |
| 19 | * This product includes software developed by the University of | |
| 20 | * California, Berkeley and its contributors. | |
| 21 | * 4. Neither the name of the University nor the names of its contributors | |
| 22 | * may be used to endorse or promote products derived from this software | |
| 23 | * without specific prior written permission. | |
| 24 | * | |
| 25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 35 | * SUCH DAMAGE. | |
| 36 | * | |
| 37 | * @(#)procfs_ctl.c 8.4 (Berkeley) 6/15/94 | |
| 38 | * | |
| 39 | * From: | |
| 40 | * $FreeBSD: src/sys/miscfs/procfs/procfs_ctl.c,v 1.20.2.2 2002/01/22 17:22:59 nectar Exp $ | |
| f33e8653 | 41 | * $DragonFly: src/sys/vfs/procfs/procfs_ctl.c,v 1.16 2007/03/12 21:08:15 corecode Exp $ |
| 984263bc MD |
42 | */ |
| 43 | ||
| 44 | #include <sys/param.h> | |
| 45 | #include <sys/systm.h> | |
| 46 | #include <sys/proc.h> | |
| 75bda2d9 | 47 | #include <sys/priv.h> |
| 984263bc MD |
48 | #include <sys/vnode.h> |
| 49 | #include <sys/ptrace.h> | |
| 50 | #include <sys/signalvar.h> | |
| 1f2de5d4 | 51 | #include <vfs/procfs/procfs.h> |
| 984263bc | 52 | |
| b5d16701 MD |
53 | #include <sys/signal2.h> |
| 54 | #include <sys/thread2.h> | |
| 55 | #include <sys/mplock2.h> | |
| 94f98873 | 56 | #include <sys/spinlock2.h> |
| b5d16701 | 57 | |
| 984263bc MD |
58 | #include <vm/vm.h> |
| 59 | ||
| 60 | #ifndef FIX_SSTEP | |
| c7e98b2f | 61 | #define FIX_SSTEP(lp) |
| 984263bc MD |
62 | #endif |
| 63 | ||
| 64 | /* | |
| 65 | * True iff process (p) is in trace wait state | |
| 66 | * relative to process (curp) | |
| 67 | */ | |
| 68 | #define TRACE_WAIT_P(curp, p) \ | |
| 164b8401 | 69 | (((p)->p_stat == SSTOP) && \ |
| 984263bc | 70 | (p)->p_pptr == (curp) && \ |
| 4643740a | 71 | ((p)->p_flags & P_TRACED)) |
| 984263bc MD |
72 | |
| 73 | #define PROCFS_CTL_ATTACH 1 | |
| 74 | #define PROCFS_CTL_DETACH 2 | |
| 75 | #define PROCFS_CTL_STEP 3 | |
| 76 | #define PROCFS_CTL_RUN 4 | |
| 77 | #define PROCFS_CTL_WAIT 5 | |
| 78 | ||
| 79 | static vfs_namemap_t ctlnames[] = { | |
| 80 | /* special /proc commands */ | |
| 81 | { "attach", PROCFS_CTL_ATTACH }, | |
| 82 | { "detach", PROCFS_CTL_DETACH }, | |
| 83 | { "step", PROCFS_CTL_STEP }, | |
| 84 | { "run", PROCFS_CTL_RUN }, | |
| 85 | { "wait", PROCFS_CTL_WAIT }, | |
| 86 | { 0 }, | |
| 87 | }; | |
| 88 | ||
| 89 | static vfs_namemap_t signames[] = { | |
| 90 | /* regular signal names */ | |
| 91 | { "hup", SIGHUP }, { "int", SIGINT }, | |
| 92 | { "quit", SIGQUIT }, { "ill", SIGILL }, | |
| 93 | { "trap", SIGTRAP }, { "abrt", SIGABRT }, | |
| 94 | { "iot", SIGIOT }, { "emt", SIGEMT }, | |
| 95 | { "fpe", SIGFPE }, { "kill", SIGKILL }, | |
| 96 | { "bus", SIGBUS }, { "segv", SIGSEGV }, | |
| 97 | { "sys", SIGSYS }, { "pipe", SIGPIPE }, | |
| 98 | { "alrm", SIGALRM }, { "term", SIGTERM }, | |
| 99 | { "urg", SIGURG }, { "stop", SIGSTOP }, | |
| 100 | { "tstp", SIGTSTP }, { "cont", SIGCONT }, | |
| 101 | { "chld", SIGCHLD }, { "ttin", SIGTTIN }, | |
| 102 | { "ttou", SIGTTOU }, { "io", SIGIO }, | |
| 103 | { "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ }, | |
| 104 | { "vtalrm", SIGVTALRM }, { "prof", SIGPROF }, | |
| 105 | { "winch", SIGWINCH }, { "info", SIGINFO }, | |
| 106 | { "usr1", SIGUSR1 }, { "usr2", SIGUSR2 }, | |
| 107 | { 0 }, | |
| 108 | }; | |
| 109 | ||
| c7e98b2f | 110 | static int procfs_control (struct proc *curp, struct lwp *lp, int op); |
| 984263bc MD |
111 | |
| 112 | static int | |
| c7e98b2f | 113 | procfs_control(struct proc *curp, struct lwp *lp, int op) |
| 984263bc | 114 | { |
| c7e98b2f | 115 | struct proc *p = lp->lwp_proc; |
| 984263bc MD |
116 | int error; |
| 117 | ||
| 5686ec5a | 118 | ASSERT_LWKT_TOKEN_HELD(&p->p_token); |
| 98c2b8ac MD |
119 | ASSERT_LWKT_TOKEN_HELD(&proc_token); |
| 120 | ||
| 984263bc | 121 | /* Can't trace a process that's currently exec'ing. */ |
| 4643740a | 122 | if ((p->p_flags & P_INEXEC) != 0) |
| 984263bc MD |
123 | return EAGAIN; |
| 124 | /* | |
| 125 | * Authorization check: rely on normal debugging protection, except | |
| 126 | * allow processes to disengage debugging on a process onto which | |
| 127 | * they have previously attached, but no longer have permission to | |
| 128 | * debug. | |
| 129 | */ | |
| 130 | if (op != PROCFS_CTL_DETACH) { | |
| 131 | if (securelevel > 0 && p->p_pid == 1) | |
| 132 | return (EPERM); | |
| 133 | ||
| 41c20dac | 134 | if (!CHECKIO(curp, p) || p_trespass(curp->p_ucred, p->p_ucred)) |
| 984263bc MD |
135 | return (EPERM); |
| 136 | } | |
| 137 | ||
| 138 | /* | |
| 139 | * Attach - attaches the target process for debugging | |
| 140 | * by the calling process. | |
| 141 | */ | |
| 142 | if (op == PROCFS_CTL_ATTACH) { | |
| 143 | /* check whether already being traced */ | |
| 4643740a | 144 | if (p->p_flags & P_TRACED) |
| 984263bc MD |
145 | return (EBUSY); |
| 146 | ||
| 147 | /* can't trace yourself! */ | |
| 148 | if (p->p_pid == curp->p_pid) | |
| 149 | return (EINVAL); | |
| 150 | ||
| 151 | /* | |
| 152 | * Go ahead and set the trace flag. | |
| 153 | * Save the old parent (it's reset in | |
| 154 | * _DETACH, and also in kern_exit.c:wait4() | |
| 155 | * Reparent the process so that the tracing | |
| 156 | * proc gets to see all the action. | |
| 157 | * Stop the target. | |
| 158 | */ | |
| 4643740a | 159 | p->p_flags |= P_TRACED; |
| 984263bc MD |
160 | faultin(p); |
| 161 | p->p_xstat = 0; /* XXX ? */ | |
| 162 | if (p->p_pptr != curp) { | |
| 163 | p->p_oppid = p->p_pptr->p_pid; | |
| 164 | proc_reparent(p, curp); | |
| 165 | } | |
| f33e8653 | 166 | proc_stop(p); |
| 984263bc MD |
167 | return (0); |
| 168 | } | |
| 169 | ||
| 170 | /* | |
| 171 | * Target process must be stopped, owned by (curp) 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(curp, p)) | |
| 183 | return (EBUSY); | |
| 184 | } | |
| 185 | ||
| 186 | ||
| 187 | #ifdef FIX_SSTEP | |
| 188 | /* | |
| 189 | * do single-step fixup if needed | |
| 190 | */ | |
| c7e98b2f | 191 | FIX_SSTEP(lp); |
| 984263bc MD |
192 | #endif |
| 193 | ||
| 194 | /* | |
| 195 | * Don't deliver any signal by default. | |
| 196 | * To continue with a signal, just send | |
| 197 | * the signal name to the ctl file | |
| 198 | */ | |
| 199 | p->p_xstat = 0; | |
| 200 | ||
| 201 | switch (op) { | |
| 202 | /* | |
| 203 | * Detach. Cleans up the target process, reparent it if possible | |
| 204 | * and set it running once more. | |
| 205 | */ | |
| 206 | case PROCFS_CTL_DETACH: | |
| 207 | /* if not being traced, then this is a painless no-op */ | |
| 4643740a | 208 | if ((p->p_flags & P_TRACED) == 0) |
| 984263bc MD |
209 | return (0); |
| 210 | ||
| 211 | /* not being traced any more */ | |
| 4643740a | 212 | p->p_flags &= ~P_TRACED; |
| 984263bc MD |
213 | |
| 214 | /* remove pending SIGTRAP, else the process will die */ | |
| 94f98873 | 215 | spin_lock(&lp->lwp_spin); |
| aa6c3de6 | 216 | lwp_delsig(lp, SIGTRAP); |
| 94f98873 | 217 | spin_unlock(&lp->lwp_spin); |
| 984263bc MD |
218 | |
| 219 | /* give process back to original parent */ | |
| 220 | if (p->p_oppid != p->p_pptr->p_pid) { | |
| 221 | struct proc *pp; | |
| 222 | ||
| 223 | pp = pfind(p->p_oppid); | |
| 58c2553a | 224 | if (pp) { |
| 984263bc | 225 | proc_reparent(p, pp); |
| 58c2553a MD |
226 | PRELE(pp); |
| 227 | } | |
| 984263bc MD |
228 | } |
| 229 | ||
| 230 | p->p_oppid = 0; | |
| 4643740a MD |
231 | p->p_flags &= ~P_WAITED; /* XXX ? */ |
| 232 | wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */ | |
| 984263bc MD |
233 | |
| 234 | break; | |
| 235 | ||
| 236 | /* | |
| 237 | * Step. Let the target process execute a single instruction. | |
| 238 | */ | |
| 239 | case PROCFS_CTL_STEP: | |
| c7e98b2f SS |
240 | LWPHOLD(lp); |
| 241 | error = procfs_sstep(lp); | |
| 242 | LWPRELE(lp); | |
| 984263bc MD |
243 | if (error) |
| 244 | return (error); | |
| 245 | break; | |
| 246 | ||
| 247 | /* | |
| 248 | * Run. Let the target process continue running until a breakpoint | |
| 249 | * or some other trap. | |
| 250 | */ | |
| 251 | case PROCFS_CTL_RUN: | |
| 252 | break; | |
| 253 | ||
| 254 | /* | |
| 255 | * Wait for the target process to stop. | |
| 256 | * If the target is not being traced then just wait | |
| 257 | * to enter | |
| 258 | */ | |
| 259 | case PROCFS_CTL_WAIT: | |
| 260 | error = 0; | |
| 4643740a | 261 | if (p->p_flags & P_TRACED) { |
| 984263bc | 262 | while (error == 0 && |
| 164b8401 | 263 | p->p_stat != SSTOP && |
| 4643740a | 264 | (p->p_flags & P_TRACED) && |
| 984263bc MD |
265 | (p->p_pptr == curp)) { |
| 266 | error = tsleep((caddr_t) p, | |
| 377d4740 | 267 | PCATCH, "procfsx", 0); |
| 984263bc MD |
268 | } |
| 269 | if (error == 0 && !TRACE_WAIT_P(curp, p)) | |
| 270 | error = EBUSY; | |
| 271 | } else { | |
| 164b8401 | 272 | while (error == 0 && p->p_stat != SSTOP) { |
| 984263bc | 273 | error = tsleep((caddr_t) p, |
| 377d4740 | 274 | PCATCH, "procfs", 0); |
| 984263bc MD |
275 | } |
| 276 | } | |
| 277 | return (error); | |
| 278 | ||
| 279 | default: | |
| 280 | panic("procfs_control"); | |
| 281 | } | |
| 282 | ||
| 344ad853 MD |
283 | /* |
| 284 | * If the process is in a stopped state, make it runnable again. | |
| 4643740a MD |
285 | * Do not set LWP_MP_BREAKTSLEEP - that is, do not break a tsleep |
| 286 | * that might be in progress. | |
| 344ad853 | 287 | */ |
| 164b8401 | 288 | if (p->p_stat == SSTOP) |
| 9a379a4a | 289 | proc_unstop(p); |
| 984263bc MD |
290 | return (0); |
| 291 | } | |
| 292 | ||
| 293 | int | |
| c7e98b2f | 294 | procfs_doctl(struct proc *curp, struct lwp *lp, struct pfsnode *pfs, |
| ac424f9b | 295 | struct uio *uio) |
| 984263bc | 296 | { |
| c7e98b2f | 297 | struct proc *p = lp->lwp_proc; |
| 984263bc MD |
298 | int xlen; |
| 299 | int error; | |
| 300 | char msg[PROCFS_CTLLEN+1]; | |
| 301 | vfs_namemap_t *nm; | |
| 302 | ||
| 5686ec5a | 303 | ASSERT_LWKT_TOKEN_HELD(&p->p_token); |
| 98c2b8ac MD |
304 | ASSERT_LWKT_TOKEN_HELD(&proc_token); |
| 305 | ||
| 984263bc MD |
306 | if (uio->uio_rw != UIO_WRITE) |
| 307 | return (EOPNOTSUPP); | |
| 308 | ||
| 309 | xlen = PROCFS_CTLLEN; | |
| 310 | error = vfs_getuserstr(uio, msg, &xlen); | |
| 311 | if (error) | |
| 312 | return (error); | |
| 313 | ||
| 314 | /* | |
| 315 | * Map signal names into signal generation | |
| 316 | * or debug control. Unknown commands and/or signals | |
| 317 | * return EOPNOTSUPP. | |
| 318 | * | |
| 319 | * Sending a signal while the process is being debugged | |
| 320 | * also has the side effect of letting the target continue | |
| 321 | * to run. There is no way to single-step a signal delivery. | |
| 322 | */ | |
| 323 | error = EOPNOTSUPP; | |
| 324 | ||
| 325 | nm = vfs_findname(ctlnames, msg, xlen); | |
| 326 | if (nm) { | |
| c7e98b2f | 327 | error = procfs_control(curp, lp, nm->nm_val); |
| 984263bc MD |
328 | } else { |
| 329 | nm = vfs_findname(signames, msg, xlen); | |
| 330 | if (nm) { | |
| 331 | if (TRACE_WAIT_P(curp, p)) { | |
| 332 | p->p_xstat = nm->nm_val; | |
| 333 | #ifdef FIX_SSTEP | |
| c7e98b2f | 334 | FIX_SSTEP(lp); |
| 984263bc | 335 | #endif |
| 344ad853 MD |
336 | /* |
| 337 | * Make the process runnable but do not | |
| 338 | * break its tsleep. | |
| 339 | */ | |
| 9a379a4a | 340 | proc_unstop(p); |
| 984263bc | 341 | } else { |
| 84204577 | 342 | ksignal(p, nm->nm_val); |
| 984263bc MD |
343 | } |
| 344 | error = 0; | |
| 345 | } | |
| 346 | } | |
| 347 | ||
| 348 | return (error); | |
| 349 | } |