root/miscfs/procfs/procfs_ctl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. procfs_control
  2. procfs_doctl

    1 /*      $OpenBSD: procfs_ctl.c,v 1.21 2007/06/18 08:30:07 jasper Exp $  */
    2 /*      $NetBSD: procfs_ctl.c,v 1.14 1996/02/09 22:40:48 christos Exp $ */
    3 
    4 /*
    5  * Copyright (c) 1993 Jan-Simon Pendry
    6  * Copyright (c) 1993
    7  *      The Regents of the University of California.  All rights reserved.
    8  *
    9  * This code is derived from software contributed to Berkeley by
   10  * Jan-Simon Pendry.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)procfs_ctl.c        8.4 (Berkeley) 6/15/94
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/time.h>
   42 #include <sys/kernel.h>
   43 #include <sys/proc.h>
   44 #include <sys/vnode.h>
   45 #include <sys/ioctl.h>
   46 #include <sys/tty.h>
   47 #include <sys/resource.h>
   48 #include <sys/resourcevar.h>
   49 #include <sys/signalvar.h>
   50 #include <sys/ptrace.h>
   51 #include <sys/sched.h>
   52 #include <miscfs/procfs/procfs.h>
   53 
   54 /*
   55  * True iff process (p) is in trace wait state
   56  * relative to process (curp)
   57  */
   58 #define TRACE_WAIT_P(curp, p) \
   59         ((p)->p_stat == SSTOP && \
   60          (p)->p_pptr == (curp) && \
   61          ISSET((p)->p_flag, P_TRACED))
   62 
   63 #ifdef PTRACE
   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 
   71 static const vfs_namemap_t ctlnames[] = {
   72         /* special /proc commands */
   73         { "attach",     PROCFS_CTL_ATTACH },
   74         { "detach",     PROCFS_CTL_DETACH },
   75         { "step",       PROCFS_CTL_STEP },
   76         { "run",        PROCFS_CTL_RUN },
   77         { "wait",       PROCFS_CTL_WAIT },
   78         { 0 },
   79 };
   80 
   81 #endif
   82 
   83 static const vfs_namemap_t signames[] = {
   84         /* regular signal names */
   85         { "hup",        SIGHUP },       { "int",        SIGINT },
   86         { "quit",       SIGQUIT },      { "ill",        SIGILL },
   87         { "trap",       SIGTRAP },      { "abrt",       SIGABRT },
   88         { "iot",        SIGIOT },       { "emt",        SIGEMT },
   89         { "fpe",        SIGFPE },       { "kill",       SIGKILL },
   90         { "bus",        SIGBUS },       { "segv",       SIGSEGV },
   91         { "sys",        SIGSYS },       { "pipe",       SIGPIPE },
   92         { "alrm",       SIGALRM },      { "term",       SIGTERM },
   93         { "urg",        SIGURG },       { "stop",       SIGSTOP },
   94         { "tstp",       SIGTSTP },      { "cont",       SIGCONT },
   95         { "chld",       SIGCHLD },      { "ttin",       SIGTTIN },
   96         { "ttou",       SIGTTOU },      { "io",         SIGIO },
   97         { "xcpu",       SIGXCPU },      { "xfsz",       SIGXFSZ },
   98         { "vtalrm",     SIGVTALRM },    { "prof",       SIGPROF },
   99         { "winch",      SIGWINCH },     { "info",       SIGINFO },
  100         { "usr1",       SIGUSR1 },      { "usr2",       SIGUSR2 },
  101         { 0 },
  102 };
  103 
  104 #ifdef PTRACE
  105 static int procfs_control(struct proc *, struct proc *, int);
  106 
  107 static int
  108 procfs_control(struct proc *curp, struct proc *p, int op)
  109 /* *curp being the tracer, and *p the traced */
  110 {
  111         int error;
  112         int s;
  113 
  114         /*
  115          * Attach - attaches the target process for debugging
  116          * by the calling process.
  117          */
  118         if (op == PROCFS_CTL_ATTACH) {
  119                 /* Can't trace yourself! */
  120                 if (p->p_pid == curp->p_pid)
  121                         return (EINVAL);
  122 
  123                 /* Check whether already being traced. */
  124                 if (ISSET(p->p_flag, P_TRACED))
  125                         return (EBUSY);
  126 
  127                 if ((error = process_checkioperm(curp, p)) != 0)
  128                         return (error);
  129 
  130                 /*
  131                  * Go ahead and set the trace flag.
  132                  * Save the old parent (it's reset in
  133                  *   _DETACH, and also in kern_exit.c:wait4()
  134                  * Reparent the process so that the tracing
  135                  *   proc gets to see all the action.
  136                  * Stop the target.
  137                  */
  138                 atomic_setbits_int(&p->p_flag, P_TRACED);
  139                 p->p_xstat = 0;         /* XXX ? */
  140                 if (p->p_pptr != curp) {
  141                         p->p_oppid = p->p_pptr->p_pid;
  142                         proc_reparent(p, curp);
  143                 }
  144                 psignal(p, SIGSTOP);
  145                 return (0);
  146         }
  147 
  148         /*
  149          * Target process must be stopped, owned by (curp) and
  150          * be set up for tracing (P_TRACED flag set).
  151          * Allow DETACH to take place at any time for sanity.
  152          * Allow WAIT any time, of course.
  153          */
  154         switch (op) {
  155         case PROCFS_CTL_DETACH:
  156         case PROCFS_CTL_WAIT:
  157                 break;
  158 
  159         default:
  160                 if (!TRACE_WAIT_P(curp, p))
  161                         return (EBUSY);
  162         }
  163 
  164         /*
  165          * do single-step fixup if needed
  166          */
  167         FIX_SSTEP(p);
  168 
  169         /*
  170          * Don't deliver any signal by default.
  171          * To continue with a signal, just send
  172          * the signal name to the ctl file
  173          */
  174         p->p_xstat = 0;
  175 
  176         switch (op) {
  177         /*
  178          * Detach.  Cleans up the target process, reparent it if possible
  179          * and set it running once more.
  180          */
  181         case PROCFS_CTL_DETACH:
  182                 /* if not being traced, then this is a painless no-op */
  183                 if (!ISSET(p->p_flag, P_TRACED))
  184                         return (0);
  185 
  186                 /* not being traced any more */
  187                 atomic_clearbits_int(&p->p_flag, P_TRACED);
  188 
  189                 /* give process back to original parent */
  190                 if (p->p_oppid != p->p_pptr->p_pid) {
  191                         struct proc *pp;
  192 
  193                         pp = pfind(p->p_oppid);
  194                         if (pp)
  195                                 proc_reparent(p, pp);
  196                 }
  197 
  198                 p->p_oppid = 0;
  199                 atomic_clearbits_int(&p->p_flag, P_WAITED);
  200                 wakeup(curp);   /* XXX for CTL_WAIT below ? */
  201 
  202                 break;
  203 
  204         /*
  205          * Step.  Let the target process execute a single instruction.
  206          */
  207         case PROCFS_CTL_STEP:
  208 #ifdef PT_STEP
  209                 error = process_sstep(p, 1);
  210                 if (error)
  211                         return (error);
  212                 break;
  213 #else
  214                 return (EOPNOTSUPP);
  215 #endif
  216 
  217         /*
  218          * Run.  Let the target process continue running until a breakpoint
  219          * or some other trap.
  220          */
  221         case PROCFS_CTL_RUN:
  222                 break;
  223 
  224         /*
  225          * Wait for the target process to stop.
  226          * If the target is not being traced then just wait
  227          * to enter
  228          */
  229         case PROCFS_CTL_WAIT:
  230                 error = 0;
  231                 if (ISSET(p->p_flag, P_TRACED)) {
  232                         while (error == 0 &&
  233                                         (p->p_stat != SSTOP) &&
  234                                         ISSET(p->p_flag, P_TRACED) &&
  235                                         (p->p_pptr == curp)) {
  236                                 error = tsleep(p, PWAIT|PCATCH, "procfsx", 0);
  237                         }
  238                         if (error == 0 && !TRACE_WAIT_P(curp, p))
  239                                 error = EBUSY;
  240                 } else {
  241                         while (error == 0 && p->p_stat != SSTOP) {
  242                                 error = tsleep(p, PWAIT|PCATCH, "procfs", 0);
  243                         }
  244                 }
  245                 return (error);
  246 
  247 #ifdef DIAGNOSTIC
  248         default:
  249                 panic("procfs_control");
  250 #endif
  251         }
  252 
  253         SCHED_LOCK(s);
  254         if (p->p_stat == SSTOP)
  255                 setrunnable(p);
  256         SCHED_UNLOCK(s);
  257         return (0);
  258 }
  259 #endif
  260 
  261 int
  262 procfs_doctl(struct proc *curp, struct proc *p, struct pfsnode *pfs, struct uio *uio)
  263 {
  264         int xlen;
  265         int error;
  266         char msg[PROCFS_CTLLEN+1];
  267         const vfs_namemap_t *nm;
  268         int s;
  269 
  270         if (uio->uio_rw != UIO_WRITE)
  271                 return (EOPNOTSUPP);
  272 
  273         xlen = PROCFS_CTLLEN;
  274         error = vfs_getuserstr(uio, msg, &xlen);
  275         if (error)
  276                 return (error);
  277 
  278         /*
  279          * Map signal names into signal generation
  280          * or debug control.  Unknown commands and/or signals
  281          * return EOPNOTSUPP.
  282          *
  283          * Sending a signal while the process is being debugged
  284          * also has the side effect of letting the target continue
  285          * to run.  There is no way to single-step a signal delivery.
  286          */
  287         error = EOPNOTSUPP;
  288 
  289 #ifdef PTRACE
  290         nm = vfs_findname(ctlnames, msg, xlen);
  291         if (nm) {
  292                 error = procfs_control(curp, p, nm->nm_val);
  293         } else
  294 #endif
  295         {
  296                 nm = vfs_findname(signames, msg, xlen);
  297                 if (nm) {
  298                         if (TRACE_WAIT_P(curp, p)) {
  299                                 p->p_xstat = nm->nm_val;
  300                                 FIX_SSTEP(p);
  301                                 SCHED_LOCK(s);
  302                                 setrunnable(p);
  303                                 SCHED_UNLOCK(s);
  304                         } else {
  305                                 psignal(p, nm->nm_val);
  306                         }
  307                         error = 0;
  308                 }
  309         }
  310 
  311         return (error);
  312 }

/* [<][>][^][v][top][bottom][index][help] */