Пример #1
0
int
procfs_dofpregs(struct proc *curp, struct lwp *lp, struct pfsnode *pfs,
		struct uio *uio)
{
	struct proc *p = lp->lwp_proc;
	int error;
	struct fpreg r;

	/* Can't trace a process that's currently exec'ing. */ 
	if ((p->p_flags & P_INEXEC) != 0)
		return EAGAIN;
	if (!CHECKIO(curp, p) || p_trespass(curp->p_ucred, p->p_ucred))
		return EPERM;

	LWPHOLD(lp);
	error = procfs_read_fpregs(lp, &r);
	if (error == 0)
		error = uiomove_frombuf(&r, sizeof(r), uio);
	if (error == 0 && uio->uio_rw == UIO_WRITE) {
		if (lp->lwp_stat != LSSTOP)
			error = EBUSY;
		else
			error = procfs_write_fpregs(lp, &r);
	}
	LWPRELE(lp);
	uio->uio_offset = 0;

	return (error);
}
Пример #2
0
/*
 * set things up for doing i/o on
 * the pfsnode (vp).  (vp) is locked
 * on entry, and should be left locked
 * on exit.
 *
 * for procfs we don't need to do anything
 * in particular for i/o.  all that is done
 * is to support exclusive open on process
 * memory images.
 */
static int
linprocfs_open(struct vop_open_args *ap)
{
	struct pfsnode *pfs = VTOPFS(ap->a_vp);
	struct proc *p2;

	p2 = PFIND(pfs->pfs_pid);
	if (p2 == NULL)
		return (ENOENT);
	if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred))
		return (ENOENT);

	switch (pfs->pfs_type) {
	case Pmem:
		if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
		    ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
			return (EBUSY);

		if (p_trespass(ap->a_cred, p2->p_ucred))
			return (EPERM);

		if (ap->a_mode & FWRITE)
			pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);

		break;
	default:
		break;
	}

	return (vop_stdopen(ap));
}
Пример #3
0
/*
 * Copy data in and out of the target process.
 * We do this by mapping the process's page into
 * the kernel and then doing a uiomove direct
 * from the kernel address space.
 *
 * lp->lwp_proc->p_token is held on entry.
 */
int
procfs_domem(struct proc *curp, struct lwp *lp, struct pfsnode *pfs,
	     struct uio *uio)
{
	struct proc *p = lp->lwp_proc;
	int error;

	if (uio->uio_resid == 0)
		return (0);

	if ((p->p_flags & P_INEXEC) != 0) {
		/*
		 * Can't trace a process that's currently exec'ing.
		 */
		error = EAGAIN;
	} else if (!CHECKIO(curp, p) || p_trespass(curp->p_ucred, p->p_ucred)) {
		/*
		 * Can't trace processes outside our jail
		 */
		error = EPERM;
	} else {
		error = procfs_rwmem(curp, p, uio);
	}
	return(error);
}
Пример #4
0
/*
 * set things up for doing i/o on
 * the pfsnode (vp).  (vp) is locked
 * on entry, and should be left locked
 * on exit.
 *
 * for procfs we don't need to do anything
 * in particular for i/o.  all that is done
 * is to support exclusive open on process
 * memory images.
 *
 * procfs_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred,
 *	       struct file *a_fp)
 */
static int
procfs_open(struct vop_open_args *ap)
{
	struct pfsnode *pfs = VTOPFS(ap->a_vp);
	struct proc *p1, *p2;
	int error;

	p2 = pfs_pfind(pfs->pfs_pid);
	if (p2 == NULL)
		return (ENOENT);
	if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred)) {
		error = ENOENT;
		goto done;
	}

	switch (pfs->pfs_type) {
	case Pmem:
		if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
		    ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) {
			error = EBUSY;
			goto done;
		}

		p1 = curproc;
		KKASSERT(p1);
		/* Can't trace a process that's currently exec'ing. */ 
		if ((p2->p_flags & P_INEXEC) != 0) {
			error = EAGAIN;
			goto done;
		}
		if (!CHECKIO(p1, p2) || p_trespass(ap->a_cred, p2->p_ucred)) {
			error = EPERM;
			goto done;
		}

		if (ap->a_mode & FWRITE)
			pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);

		break;

	default:
		break;
	}
	error = vop_stdopen(ap);
done:
	pfs_pdone(p2);
	return error;
}
Пример #5
0
/*
 * do an ioctl operation on a pfsnode (vp).
 * (vp) is not locked on entry or exit.
 */
static int
linprocfs_ioctl(struct vop_ioctl_args *ap)
{
	struct pfsnode *pfs = VTOPFS(ap->a_vp);
	struct proc *procp;
	int error;
	int signo;
	struct procfs_status *psp;
	unsigned char flags;

	procp = pfind(pfs->pfs_pid);
	if (procp == NULL) {
		return ENOTTY;
	}

	if (p_trespass(ap->a_cred, procp->p_ucred)) {
		error = EPERM;
		goto done;
	}

	switch (ap->a_command) {
	case PIOCBIS:
	  procp->p_stops |= *(unsigned int*)ap->a_data;
	  break;
	case PIOCBIC:
	  procp->p_stops &= ~*(unsigned int*)ap->a_data;
	  break;
	case PIOCSFL:
	  /*
	   * NFLAGS is "non-suser_xxx flags" -- currently, only
	   * PFS_ISUGID ("ignore set u/g id");
	   */
#define NFLAGS	(PF_ISUGID)
	  flags = (unsigned char)*(unsigned int*)ap->a_data;
	  if (flags & NFLAGS && (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)))
	    goto done;
	  procp->p_pfsflags = flags;
	  break;
	case PIOCGFL:
	  *(unsigned int*)ap->a_data = (unsigned int)procp->p_pfsflags;
	case PIOCSTATUS:
	  psp = (struct procfs_status *)ap->a_data;
	  psp->state = (procp->p_step == 0);
	  psp->flags = procp->p_pfsflags;
	  psp->events = procp->p_stops;
	  if (procp->p_step) {
	    psp->why = procp->p_stype;
	    psp->val = procp->p_xstat;
	  } else {
	    psp->why = psp->val = 0;	/* Not defined values */
	  }
	  break;
	case PIOCWAIT:
	  psp = (struct procfs_status *)ap->a_data;
	  if (procp->p_step == 0) {
	    error = tsleep(&procp->p_stype, PCATCH, "piocwait", 0);
	    if (error)
	      goto done;
	  }
	  psp->state = 1;	/* It stopped */
	  psp->flags = procp->p_pfsflags;
	  psp->events = procp->p_stops;
	  psp->why = procp->p_stype;	/* why it stopped */
	  psp->val = procp->p_xstat;	/* any extra info */
	  break;
	case PIOCCONT:	/* Restart a proc */
	  if (procp->p_step == 0) {
	    error = EINVAL;	/* Can only start a stopped process */
	    goto done;
	  }
	  if ((signo = *(int*)ap->a_data) != 0) {
	    if (signo >= NSIG || signo <= 0) {
	      error = EINVAL;
	      goto done;
	    }
	    ksignal(procp, signo);
	  }
	  procp->p_step = 0;
	  wakeup(&procp->p_step);
	  break;
	default:
	  error = ENOTTY;
	  goto done;
	}
	error = 0;
done:
	if (procp)
		PRELE(procp);
	return error;
}
Пример #6
0
/*
 * do an ioctl operation on a pfsnode (vp).
 * (vp) is not locked on entry or exit.
 */
static int
procfs_ioctl(struct vop_ioctl_args *ap)
{
	struct pfsnode *pfs = VTOPFS(ap->a_vp);
	struct proc *procp;
	struct proc *p;
	int error;
	int signo;
	struct procfs_status *psp;
	unsigned char flags;

	procp = pfs_pfind(pfs->pfs_pid);
	if (procp == NULL)
		return ENOTTY;
	p = curproc;
	if (p == NULL) {
		error = EINVAL;
		goto done;
	}

	/* Can't trace a process that's currently exec'ing. */ 
	if ((procp->p_flags & P_INEXEC) != 0) {
		error = EAGAIN;
		goto done;
	}
	if (!CHECKIO(p, procp) || p_trespass(ap->a_cred, procp->p_ucred)) {
		error = EPERM;
		goto done;
	}

	switch (ap->a_command) {
	case PIOCBIS:
	  spin_lock(&procp->p_spin);
	  procp->p_stops |= *(unsigned int*)ap->a_data;
	  spin_unlock(&procp->p_spin);
	  break;
	case PIOCBIC:
	  spin_lock(&procp->p_spin);
	  procp->p_stops &= ~*(unsigned int*)ap->a_data;
	  spin_unlock(&procp->p_spin);
	  break;
	case PIOCSFL:
	  /*
	   * NFLAGS is "non-suser_xxx flags" -- currently, only
	   * PFS_ISUGID ("ignore set u/g id");
	   */
#define NFLAGS	(PF_ISUGID)
	  flags = (unsigned char)*(unsigned int*)ap->a_data;
	  if (flags & NFLAGS && (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)))
	    goto done;
	  procp->p_pfsflags = flags;
	  break;
	case PIOCGFL:
	  *(unsigned int*)ap->a_data = (unsigned int)procp->p_pfsflags;
	  break;
	case PIOCSTATUS:
	  /*
	   * NOTE: syscall entry deals with stopevents and may run without
	   *	   the MP lock.
	   */
	  psp = (struct procfs_status *)ap->a_data;
	  psp->flags = procp->p_pfsflags;
	  psp->events = procp->p_stops;
	  spin_lock(&procp->p_spin);
	  if (procp->p_step) {
	    psp->state = 0;
	    psp->why = procp->p_stype;
	    psp->val = procp->p_xstat;
	    spin_unlock(&procp->p_spin);
	  } else {
	    psp->state = 1;
	    spin_unlock(&procp->p_spin);
	    psp->why = 0;	/* Not defined values */
	    psp->val = 0;	/* Not defined values */
	  }
	  break;
	case PIOCWAIT:
	  /*
	   * NOTE: syscall entry deals with stopevents and may run without
	   *	   the MP lock.
	   */
	  psp = (struct procfs_status *)ap->a_data;
	  spin_lock(&procp->p_spin);
	  while (procp->p_step == 0) {
	    tsleep_interlock(&procp->p_stype, PCATCH);
	    spin_unlock(&procp->p_spin);
	    if (procp->p_stops == 0) {
		error = EINVAL;
		goto done;
	    }
	    if (procp->p_flags & P_POSTEXIT) {
		error = EINVAL;
		goto done;
	    }
	    if (procp->p_flags & P_INEXEC) {
		error = EAGAIN;
		goto done;
	    }
	    error = tsleep(&procp->p_stype, PCATCH | PINTERLOCKED,
			   "piocwait", 0);
	    if (error)
	      goto done;
	    spin_lock(&procp->p_spin);
	  }
	  spin_unlock(&procp->p_spin);
	  psp->state = 1;	/* It stopped */
	  psp->flags = procp->p_pfsflags;
	  psp->events = procp->p_stops;
	  psp->why = procp->p_stype;	/* why it stopped */
	  psp->val = procp->p_xstat;	/* any extra info */
	  break;
	case PIOCCONT:	/* Restart a proc */
	  /*
	   * NOTE: syscall entry deals with stopevents and may run without
	   *	   the MP lock.  However, the caller is presumably interlocked
	   *	   by having waited.
	   */
	  if (procp->p_step == 0) {
	    error = EINVAL;	/* Can only start a stopped process */
	    goto done;
	  }
	  if ((signo = *(int*)ap->a_data) != 0) {
	    if (signo >= NSIG || signo <= 0) {
	      error = EINVAL;
	      goto done;
	    }
	    ksignal(procp, signo);
	  }
	  procp->p_step = 0;
	  wakeup(&procp->p_step);
	  break;
	default:
	  error = ENOTTY;
	  goto done;
	}
	error = 0;
done:
	pfs_pdone(procp);
	return 0;
}
Пример #7
0
int
procfs_docmdline(struct proc *curp, struct lwp *lp, struct pfsnode *pfs,
		 struct uio *uio)
{
	struct proc *p = lp->lwp_proc;
	char *ps;
	int error;
	char *buf, *bp;
	struct ps_strings pstr;
	char **ps_argvstr;
	int i;
	size_t bytes_left, done;
	size_t buflen;

	if (uio->uio_rw != UIO_READ)
		return (EOPNOTSUPP);
	
	/*
	 * If we are using the ps/cmdline caching, use that.  Otherwise
	 * revert back to the old way which only implements full cmdline
	 * for the currept process and just p->p_comm for all other
	 * processes.
	 * Note that if the argv is no longer available, we deliberately
	 * don't fall back on p->p_comm or return an error: the authentic
	 * Linux behaviour is to return zero-length in this case.
	 */

	if (p->p_args &&
	    (ps_argsopen || (CHECKIO(curp, p) &&
	     (p->p_flags & P_INEXEC) == 0 &&
	     !p_trespass(curp->p_ucred, p->p_ucred)))
	 ) {
		bp = p->p_args->ar_args;
		buflen = p->p_args->ar_length;
		buf = NULL;
	} else if (p != curp) {
		bp = p->p_comm;
		buflen = MAXCOMLEN;
		buf = NULL;
	} else {
		buflen = 256;
		buf = kmalloc(buflen + 1, M_TEMP, M_WAITOK);
		bp = buf;
		ps = buf;
		error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));

		if (error) {
			kfree(buf, M_TEMP);
			return (error);
		}
		if (pstr.ps_nargvstr < 0) {
			kfree(buf, M_TEMP);
			return (EINVAL);
		}
		if (pstr.ps_nargvstr > ARG_MAX) {
			kfree(buf, M_TEMP);
			return (E2BIG);
		}
		ps_argvstr = kmalloc(pstr.ps_nargvstr * sizeof(char *),
				     M_TEMP, M_WAITOK);
		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
			       pstr.ps_nargvstr * sizeof(char *));
		if (error) {
			kfree(ps_argvstr, M_TEMP);
			kfree(buf, M_TEMP);
			return (error);
		}
		bytes_left = buflen;
		for (i = 0; bytes_left && (i < pstr.ps_nargvstr); i++) {
			error = copyinstr(ps_argvstr[i], ps,
					  bytes_left, &done);
			/* If too long or malformed, just truncate */
			if (error) {
				error = 0;
				break;
			}
			ps += done;
			bytes_left -= done;
		}
		buflen = ps - buf;
		kfree(ps_argvstr, M_TEMP);
	}

	error = uiomove_frombuf(bp, buflen, uio);
	if (buf)
		kfree(buf, M_TEMP);
	return (error);
}
Пример #8
0
static int
procfs_control(struct proc *curp, struct lwp *lp, int op)
{
	struct proc *p = lp->lwp_proc;
	int error;

	ASSERT_LWKT_TOKEN_HELD(&p->p_token);
	ASSERT_LWKT_TOKEN_HELD(&proc_token);

	/* Can't trace a process that's currently exec'ing. */ 
	if ((p->p_flags & P_INEXEC) != 0)
		return EAGAIN;
	/*
	 * Authorization check: rely on normal debugging protection, except
	 * allow processes to disengage debugging on a process onto which
	 * they have previously attached, but no longer have permission to
	 * debug.
	 */
	if (op != PROCFS_CTL_DETACH) {
		if (securelevel > 0 && p->p_pid == 1)
			return (EPERM);

		if (!CHECKIO(curp, p) || p_trespass(curp->p_ucred, p->p_ucred))
			return (EPERM);
	}

	/*
	 * Attach - attaches the target process for debugging
	 * by the calling process.
	 */
	if (op == PROCFS_CTL_ATTACH) {
		/* check whether already being traced */
		if (p->p_flags & P_TRACED)
			return (EBUSY);

		/* can't trace yourself! */
		if (p->p_pid == curp->p_pid)
			return (EINVAL);

		/*
		 * Go ahead and set the trace flag.
		 * Save the old parent (it's reset in
		 *   _DETACH, and also in kern_exit.c:wait4()
		 * Reparent the process so that the tracing
		 *   proc gets to see all the action.
		 * Stop the target.
		 */
		p->p_flags |= P_TRACED;
		faultin(p);
		p->p_xstat = 0;		/* XXX ? */
		if (p->p_pptr != curp) {
			p->p_oppid = p->p_pptr->p_pid;
			proc_reparent(p, curp);
		}
		proc_stop(p);
		return (0);
	}

	/*
	 * Target process must be stopped, owned by (curp) and
	 * be set up for tracing (P_TRACED flag set).
	 * Allow DETACH to take place at any time for sanity.
	 * Allow WAIT any time, of course.
	 */
	switch (op) {
	case PROCFS_CTL_DETACH:
	case PROCFS_CTL_WAIT:
		break;

	default:
		if (!TRACE_WAIT_P(curp, p))
			return (EBUSY);
	}


#ifdef FIX_SSTEP
	/*
	 * do single-step fixup if needed
	 */
	FIX_SSTEP(lp);
#endif

	/*
	 * Don't deliver any signal by default.
	 * To continue with a signal, just send
	 * the signal name to the ctl file
	 */
	p->p_xstat = 0;

	switch (op) {
	/*
	 * Detach.  Cleans up the target process, reparent it if possible
	 * and set it running once more.
	 */
	case PROCFS_CTL_DETACH:
		/* if not being traced, then this is a painless no-op */
		if ((p->p_flags & P_TRACED) == 0)
			return (0);

		/* not being traced any more */
		p->p_flags &= ~P_TRACED;

		/* remove pending SIGTRAP, else the process will die */
		spin_lock(&lp->lwp_spin);
		lwp_delsig(lp, SIGTRAP);
		spin_unlock(&lp->lwp_spin);

		/* give process back to original parent */
		if (p->p_oppid != p->p_pptr->p_pid) {
			struct proc *pp;

			pp = pfs_pfind(p->p_oppid);
			if (pp) {
				proc_reparent(p, pp);
				pfs_pdone(pp);
			}
		}

		p->p_oppid = 0;
		p->p_flags &= ~P_WAITED;	/* XXX ? */
		wakeup((caddr_t) curp);		/* XXX for CTL_WAIT below ? */

		break;

	/*
	 * Step.  Let the target process execute a single instruction.
	 */
	case PROCFS_CTL_STEP:
		LWPHOLD(lp);
		error = procfs_sstep(lp);
		LWPRELE(lp);
		if (error)
			return (error);
		break;

	/*
	 * Run.  Let the target process continue running until a breakpoint
	 * or some other trap.
	 */
	case PROCFS_CTL_RUN:
		break;

	/*
	 * Wait for the target process to stop.
	 * If the target is not being traced then just wait
	 * to enter
	 */
	case PROCFS_CTL_WAIT:
		error = 0;
		if (p->p_flags & P_TRACED) {
			while (error == 0 &&
					p->p_stat != SSTOP &&
					(p->p_flags & P_TRACED) &&
					(p->p_pptr == curp)) {
				error = tsleep((caddr_t) p,
						PCATCH, "procfsx", 0);
			}
			if (error == 0 && !TRACE_WAIT_P(curp, p))
				error = EBUSY;
		} else {
			while (error == 0 && p->p_stat != SSTOP) {
				error = tsleep((caddr_t) p,
						PCATCH, "procfs", 0);
			}
		}
		return (error);

	default:
		panic("procfs_control");
	}

	/*
	 * If the process is in a stopped state, make it runnable again.
	 * Do not set LWP_MP_BREAKTSLEEP - that is, do not break a tsleep
	 * that might be in progress.
	 */
	if (p->p_stat == SSTOP)
		proc_unstop(p);
	return (0);
}