xref: /onnv-gate/usr/src/uts/common/fs/proc/prcontrol.c (revision 11940:98e0550abcac)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53768Ssl108498  * Common Development and Distribution License (the "License").
63768Ssl108498  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21390Sraf 
220Sstevel@tonic-gate /*
23*11940SRoger.Faulkner@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/uio.h>
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/cmn_err.h>
310Sstevel@tonic-gate #include <sys/cred.h>
320Sstevel@tonic-gate #include <sys/policy.h>
330Sstevel@tonic-gate #include <sys/debug.h>
340Sstevel@tonic-gate #include <sys/errno.h>
350Sstevel@tonic-gate #include <sys/file.h>
360Sstevel@tonic-gate #include <sys/inline.h>
370Sstevel@tonic-gate #include <sys/kmem.h>
380Sstevel@tonic-gate #include <sys/proc.h>
39*11940SRoger.Faulkner@Sun.COM #include <sys/brand.h>
400Sstevel@tonic-gate #include <sys/regset.h>
410Sstevel@tonic-gate #include <sys/sysmacros.h>
420Sstevel@tonic-gate #include <sys/systm.h>
430Sstevel@tonic-gate #include <sys/vfs.h>
440Sstevel@tonic-gate #include <sys/vnode.h>
450Sstevel@tonic-gate #include <sys/signal.h>
460Sstevel@tonic-gate #include <sys/auxv.h>
470Sstevel@tonic-gate #include <sys/user.h>
480Sstevel@tonic-gate #include <sys/class.h>
490Sstevel@tonic-gate #include <sys/fault.h>
500Sstevel@tonic-gate #include <sys/syscall.h>
510Sstevel@tonic-gate #include <sys/procfs.h>
520Sstevel@tonic-gate #include <sys/zone.h>
530Sstevel@tonic-gate #include <sys/copyops.h>
540Sstevel@tonic-gate #include <sys/schedctl.h>
550Sstevel@tonic-gate #include <vm/as.h>
560Sstevel@tonic-gate #include <vm/seg.h>
570Sstevel@tonic-gate #include <fs/proc/prdata.h>
580Sstevel@tonic-gate #include <sys/contract/process_impl.h>
590Sstevel@tonic-gate 
600Sstevel@tonic-gate static	void	pr_settrace(proc_t *, sigset_t *);
610Sstevel@tonic-gate static	int	pr_setfpregs(prnode_t *, prfpregset_t *);
620Sstevel@tonic-gate #if defined(__sparc)
630Sstevel@tonic-gate static	int	pr_setxregs(prnode_t *, prxregset_t *);
640Sstevel@tonic-gate static	int	pr_setasrs(prnode_t *, asrset_t);
650Sstevel@tonic-gate #endif
660Sstevel@tonic-gate static	int	pr_setvaddr(prnode_t *, caddr_t);
670Sstevel@tonic-gate static	int	pr_clearsig(prnode_t *);
680Sstevel@tonic-gate static	int	pr_clearflt(prnode_t *);
690Sstevel@tonic-gate static	int	pr_watch(prnode_t *, prwatch_t *, int *);
700Sstevel@tonic-gate static	int	pr_agent(prnode_t *, prgregset_t, int *);
710Sstevel@tonic-gate static	int	pr_rdwr(proc_t *, enum uio_rw, priovec_t *);
720Sstevel@tonic-gate static	int	pr_scred(proc_t *, prcred_t *, cred_t *, boolean_t);
730Sstevel@tonic-gate static	int	pr_spriv(proc_t *, prpriv_t *, cred_t *);
740Sstevel@tonic-gate static	int	pr_szoneid(proc_t *, zoneid_t, cred_t *);
750Sstevel@tonic-gate static	void	pauselwps(proc_t *);
760Sstevel@tonic-gate static	void	unpauselwps(proc_t *);
770Sstevel@tonic-gate 
780Sstevel@tonic-gate typedef union {
790Sstevel@tonic-gate 	long		sig;		/* PCKILL, PCUNKILL */
800Sstevel@tonic-gate 	long		nice;		/* PCNICE */
810Sstevel@tonic-gate 	long		timeo;		/* PCTWSTOP */
820Sstevel@tonic-gate 	ulong_t		flags;		/* PCRUN, PCSET, PCUNSET */
830Sstevel@tonic-gate 	caddr_t		vaddr;		/* PCSVADDR */
840Sstevel@tonic-gate 	siginfo_t	siginfo;	/* PCSSIG */
850Sstevel@tonic-gate 	sigset_t	sigset;		/* PCSTRACE, PCSHOLD */
860Sstevel@tonic-gate 	fltset_t	fltset;		/* PCSFAULT */
870Sstevel@tonic-gate 	sysset_t	sysset;		/* PCSENTRY, PCSEXIT */
880Sstevel@tonic-gate 	prgregset_t	prgregset;	/* PCSREG, PCAGENT */
890Sstevel@tonic-gate 	prfpregset_t	prfpregset;	/* PCSFPREG */
900Sstevel@tonic-gate #if defined(__sparc)
910Sstevel@tonic-gate 	prxregset_t	prxregset;	/* PCSXREG */
920Sstevel@tonic-gate 	asrset_t	asrset;		/* PCSASRS */
930Sstevel@tonic-gate #endif
940Sstevel@tonic-gate 	prwatch_t	prwatch;	/* PCWATCH */
950Sstevel@tonic-gate 	priovec_t	priovec;	/* PCREAD, PCWRITE */
960Sstevel@tonic-gate 	prcred_t	prcred;		/* PCSCRED */
970Sstevel@tonic-gate 	prpriv_t	prpriv;		/* PCSPRIV */
980Sstevel@tonic-gate 	long		przoneid;	/* PCSZONE */
990Sstevel@tonic-gate } arg_t;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate static	int	pr_control(long, arg_t *, prnode_t *, cred_t *);
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate static size_t
ctlsize(long cmd,size_t resid,arg_t * argp)1040Sstevel@tonic-gate ctlsize(long cmd, size_t resid, arg_t *argp)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate 	size_t size = sizeof (long);
1070Sstevel@tonic-gate 	size_t rnd;
1080Sstevel@tonic-gate 	int ngrp;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	switch (cmd) {
1110Sstevel@tonic-gate 	case PCNULL:
1120Sstevel@tonic-gate 	case PCSTOP:
1130Sstevel@tonic-gate 	case PCDSTOP:
1140Sstevel@tonic-gate 	case PCWSTOP:
1150Sstevel@tonic-gate 	case PCCSIG:
1160Sstevel@tonic-gate 	case PCCFAULT:
1170Sstevel@tonic-gate 		break;
1180Sstevel@tonic-gate 	case PCSSIG:
1190Sstevel@tonic-gate 		size += sizeof (siginfo_t);
1200Sstevel@tonic-gate 		break;
1210Sstevel@tonic-gate 	case PCTWSTOP:
1220Sstevel@tonic-gate 		size += sizeof (long);
1230Sstevel@tonic-gate 		break;
1240Sstevel@tonic-gate 	case PCKILL:
1250Sstevel@tonic-gate 	case PCUNKILL:
1260Sstevel@tonic-gate 	case PCNICE:
1270Sstevel@tonic-gate 		size += sizeof (long);
1280Sstevel@tonic-gate 		break;
1290Sstevel@tonic-gate 	case PCRUN:
1300Sstevel@tonic-gate 	case PCSET:
1310Sstevel@tonic-gate 	case PCUNSET:
1320Sstevel@tonic-gate 		size += sizeof (ulong_t);
1330Sstevel@tonic-gate 		break;
1340Sstevel@tonic-gate 	case PCSVADDR:
1350Sstevel@tonic-gate 		size += sizeof (caddr_t);
1360Sstevel@tonic-gate 		break;
1370Sstevel@tonic-gate 	case PCSTRACE:
1380Sstevel@tonic-gate 	case PCSHOLD:
1390Sstevel@tonic-gate 		size += sizeof (sigset_t);
1400Sstevel@tonic-gate 		break;
1410Sstevel@tonic-gate 	case PCSFAULT:
1420Sstevel@tonic-gate 		size += sizeof (fltset_t);
1430Sstevel@tonic-gate 		break;
1440Sstevel@tonic-gate 	case PCSENTRY:
1450Sstevel@tonic-gate 	case PCSEXIT:
1460Sstevel@tonic-gate 		size += sizeof (sysset_t);
1470Sstevel@tonic-gate 		break;
1480Sstevel@tonic-gate 	case PCSREG:
1490Sstevel@tonic-gate 	case PCAGENT:
1500Sstevel@tonic-gate 		size += sizeof (prgregset_t);
1510Sstevel@tonic-gate 		break;
1520Sstevel@tonic-gate 	case PCSFPREG:
1530Sstevel@tonic-gate 		size += sizeof (prfpregset_t);
1540Sstevel@tonic-gate 		break;
1550Sstevel@tonic-gate #if defined(__sparc)
1560Sstevel@tonic-gate 	case PCSXREG:
1570Sstevel@tonic-gate 		size += sizeof (prxregset_t);
1580Sstevel@tonic-gate 		break;
1590Sstevel@tonic-gate 	case PCSASRS:
1600Sstevel@tonic-gate 		size += sizeof (asrset_t);
1610Sstevel@tonic-gate 		break;
1620Sstevel@tonic-gate #endif
1630Sstevel@tonic-gate 	case PCWATCH:
1640Sstevel@tonic-gate 		size += sizeof (prwatch_t);
1650Sstevel@tonic-gate 		break;
1660Sstevel@tonic-gate 	case PCREAD:
1670Sstevel@tonic-gate 	case PCWRITE:
1680Sstevel@tonic-gate 		size += sizeof (priovec_t);
1690Sstevel@tonic-gate 		break;
1700Sstevel@tonic-gate 	case PCSCRED:
1710Sstevel@tonic-gate 		size += sizeof (prcred_t);
1720Sstevel@tonic-gate 		break;
1730Sstevel@tonic-gate 	case PCSCREDX:
1740Sstevel@tonic-gate 		/*
1750Sstevel@tonic-gate 		 * We cannot derefence the pr_ngroups fields if it
1760Sstevel@tonic-gate 		 * we don't have enough data.
1770Sstevel@tonic-gate 		 */
1780Sstevel@tonic-gate 		if (resid < size + sizeof (prcred_t) - sizeof (gid_t))
1790Sstevel@tonic-gate 			return (0);
1800Sstevel@tonic-gate 		ngrp = argp->prcred.pr_ngroups;
1810Sstevel@tonic-gate 		if (ngrp < 0 || ngrp > ngroups_max)
1820Sstevel@tonic-gate 			return (0);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 		/* The result can be smaller than sizeof (prcred_t) */
1850Sstevel@tonic-gate 		size += sizeof (prcred_t) - sizeof (gid_t);
1860Sstevel@tonic-gate 		size += ngrp * sizeof (gid_t);
1870Sstevel@tonic-gate 		break;
1880Sstevel@tonic-gate 	case PCSPRIV:
1890Sstevel@tonic-gate 		if (resid >= size + sizeof (prpriv_t))
1900Sstevel@tonic-gate 			size += priv_prgetprivsize(&argp->prpriv);
1910Sstevel@tonic-gate 		else
1920Sstevel@tonic-gate 			return (0);
1930Sstevel@tonic-gate 		break;
1940Sstevel@tonic-gate 	case PCSZONE:
1950Sstevel@tonic-gate 		size += sizeof (long);
1960Sstevel@tonic-gate 		break;
1970Sstevel@tonic-gate 	default:
1989319SSuhasini.Peddada@Sun.COM 		return (0);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/* Round up to a multiple of long, unless exact amount written */
2020Sstevel@tonic-gate 	if (size < resid) {
2030Sstevel@tonic-gate 		rnd = size & (sizeof (long) - 1);
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 		if (rnd != 0)
2060Sstevel@tonic-gate 			size += sizeof (long) - rnd;
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	if (size > resid)
2100Sstevel@tonic-gate 		return (0);
2110Sstevel@tonic-gate 	return (size);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate  * Control operations (lots).
2160Sstevel@tonic-gate  */
2170Sstevel@tonic-gate int
prwritectl(vnode_t * vp,uio_t * uiop,cred_t * cr)2180Sstevel@tonic-gate prwritectl(vnode_t *vp, uio_t *uiop, cred_t *cr)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate #define	MY_BUFFER_SIZE \
2210Sstevel@tonic-gate 		100 > 1 + sizeof (arg_t) / sizeof (long) ? \
2220Sstevel@tonic-gate 		100 : 1 + sizeof (arg_t) / sizeof (long)
2230Sstevel@tonic-gate 	long buf[MY_BUFFER_SIZE];
2240Sstevel@tonic-gate 	long *bufp;
2250Sstevel@tonic-gate 	size_t resid = 0;
2260Sstevel@tonic-gate 	size_t size;
2270Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
2280Sstevel@tonic-gate 	int error;
2290Sstevel@tonic-gate 	int locked = 0;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	while (uiop->uio_resid) {
2320Sstevel@tonic-gate 		/*
2330Sstevel@tonic-gate 		 * Read several commands in one gulp.
2340Sstevel@tonic-gate 		 */
2350Sstevel@tonic-gate 		bufp = buf;
2360Sstevel@tonic-gate 		if (resid) {	/* move incomplete command to front of buffer */
2370Sstevel@tonic-gate 			long *tail;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 			if (resid >= sizeof (buf))
2400Sstevel@tonic-gate 				break;
2410Sstevel@tonic-gate 			tail = (long *)((char *)buf + sizeof (buf) - resid);
2420Sstevel@tonic-gate 			do {
2430Sstevel@tonic-gate 				*bufp++ = *tail++;
2440Sstevel@tonic-gate 			} while ((resid -= sizeof (long)) != 0);
2450Sstevel@tonic-gate 		}
2460Sstevel@tonic-gate 		resid = sizeof (buf) - ((char *)bufp - (char *)buf);
2470Sstevel@tonic-gate 		if (resid > uiop->uio_resid)
2480Sstevel@tonic-gate 			resid = uiop->uio_resid;
2490Sstevel@tonic-gate 		if (error = uiomove((caddr_t)bufp, resid, UIO_WRITE, uiop))
2500Sstevel@tonic-gate 			return (error);
2510Sstevel@tonic-gate 		resid += (char *)bufp - (char *)buf;
2520Sstevel@tonic-gate 		bufp = buf;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		do {		/* loop over commands in buffer */
2550Sstevel@tonic-gate 			long cmd = bufp[0];
2560Sstevel@tonic-gate 			arg_t *argp = (arg_t *)&bufp[1];
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 			size = ctlsize(cmd, resid, argp);
2599319SSuhasini.Peddada@Sun.COM 			if (size == 0)	/* incomplete or invalid command */
2609275SSuhasini.Peddada@Sun.COM 				break;
2610Sstevel@tonic-gate 			/*
2620Sstevel@tonic-gate 			 * Perform the specified control operation.
2630Sstevel@tonic-gate 			 */
2640Sstevel@tonic-gate 			if (!locked) {
2650Sstevel@tonic-gate 				if ((error = prlock(pnp, ZNO)) != 0)
2660Sstevel@tonic-gate 					return (error);
2670Sstevel@tonic-gate 				locked = 1;
2680Sstevel@tonic-gate 			}
2690Sstevel@tonic-gate 			if (error = pr_control(cmd, argp, pnp, cr)) {
2700Sstevel@tonic-gate 				if (error == -1)	/* -1 is timeout */
2710Sstevel@tonic-gate 					locked = 0;
2720Sstevel@tonic-gate 				else
2730Sstevel@tonic-gate 					return (error);
2740Sstevel@tonic-gate 			}
2750Sstevel@tonic-gate 			bufp = (long *)((char *)bufp + size);
2760Sstevel@tonic-gate 		} while ((resid -= size) != 0);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 		if (locked) {
2790Sstevel@tonic-gate 			prunlock(pnp);
2800Sstevel@tonic-gate 			locked = 0;
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 	return (resid? EINVAL : 0);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate static int
pr_control(long cmd,arg_t * argp,prnode_t * pnp,cred_t * cr)2870Sstevel@tonic-gate pr_control(long cmd, arg_t *argp, prnode_t *pnp, cred_t *cr)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	prcommon_t *pcp;
2900Sstevel@tonic-gate 	proc_t *p;
2910Sstevel@tonic-gate 	int unlocked;
2920Sstevel@tonic-gate 	int error = 0;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (cmd == PCNULL)
2950Sstevel@tonic-gate 		return (0);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	pcp = pnp->pr_common;
2980Sstevel@tonic-gate 	p = pcp->prc_proc;
2990Sstevel@tonic-gate 	ASSERT(p != NULL);
3000Sstevel@tonic-gate 
30111173SJonathan.Adams@Sun.COM 	/* System processes defy control. */
30211173SJonathan.Adams@Sun.COM 	if (p->p_flag & SSYS) {
30311173SJonathan.Adams@Sun.COM 		prunlock(pnp);
30411173SJonathan.Adams@Sun.COM 		return (EBUSY);
30511173SJonathan.Adams@Sun.COM 	}
30611173SJonathan.Adams@Sun.COM 
3070Sstevel@tonic-gate 	switch (cmd) {
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	default:
3100Sstevel@tonic-gate 		error = EINVAL;
3110Sstevel@tonic-gate 		break;
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	case PCSTOP:	/* direct process or lwp to stop and wait for stop */
3140Sstevel@tonic-gate 	case PCDSTOP:	/* direct process or lwp to stop, don't wait */
3150Sstevel@tonic-gate 	case PCWSTOP:	/* wait for process or lwp to stop */
3160Sstevel@tonic-gate 	case PCTWSTOP:	/* wait for process or lwp to stop, with timeout */
3175771Sjp151216 		{
3185771Sjp151216 			time_t timeo;
3190Sstevel@tonic-gate 
3205771Sjp151216 			/*
3215771Sjp151216 			 * Can't apply to a system process.
3225771Sjp151216 			 */
32311173SJonathan.Adams@Sun.COM 			if (p->p_as == &kas) {
3245771Sjp151216 				error = EBUSY;
3255771Sjp151216 				break;
3265771Sjp151216 			}
3270Sstevel@tonic-gate 
3285771Sjp151216 			if (cmd == PCSTOP || cmd == PCDSTOP)
3295771Sjp151216 				pr_stop(pnp);
3300Sstevel@tonic-gate 
3315771Sjp151216 			if (cmd == PCDSTOP)
3325771Sjp151216 				break;
3330Sstevel@tonic-gate 
3345771Sjp151216 			/*
3355771Sjp151216 			 * If an lwp is waiting for itself or its process,
3365771Sjp151216 			 * don't wait. The stopped lwp would never see the
3375771Sjp151216 			 * fact that it is stopped.
3385771Sjp151216 			 */
3395771Sjp151216 			if ((pcp->prc_flags & PRC_LWP)?
3405771Sjp151216 			    (pcp->prc_thread == curthread) : (p == curproc)) {
3415771Sjp151216 				if (cmd == PCWSTOP || cmd == PCTWSTOP)
3425771Sjp151216 					error = EBUSY;
3435771Sjp151216 				break;
3445771Sjp151216 			}
3450Sstevel@tonic-gate 
3466247Sraf 			timeo = (cmd == PCTWSTOP)? (time_t)argp->timeo : 0;
3476247Sraf 			if ((error = pr_wait_stop(pnp, timeo)) != 0)
3486247Sraf 				return (error);
3490Sstevel@tonic-gate 
3506247Sraf 			break;
3515771Sjp151216 		}
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	case PCRUN:	/* make lwp or process runnable */
3540Sstevel@tonic-gate 		error = pr_setrun(pnp, argp->flags);
3550Sstevel@tonic-gate 		break;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	case PCSTRACE:	/* set signal trace mask */
3580Sstevel@tonic-gate 		pr_settrace(p,  &argp->sigset);
3590Sstevel@tonic-gate 		break;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	case PCSSIG:	/* set current signal */
3620Sstevel@tonic-gate 		error = pr_setsig(pnp, &argp->siginfo);
3630Sstevel@tonic-gate 		if (argp->siginfo.si_signo == SIGKILL && error == 0) {
3640Sstevel@tonic-gate 			prunlock(pnp);
3650Sstevel@tonic-gate 			pr_wait_die(pnp);
3660Sstevel@tonic-gate 			return (-1);
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 		break;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	case PCKILL:	/* send signal */
3710Sstevel@tonic-gate 		error = pr_kill(pnp, (int)argp->sig, cr);
3720Sstevel@tonic-gate 		if (error == 0 && argp->sig == SIGKILL) {
3730Sstevel@tonic-gate 			prunlock(pnp);
3740Sstevel@tonic-gate 			pr_wait_die(pnp);
3750Sstevel@tonic-gate 			return (-1);
3760Sstevel@tonic-gate 		}
3770Sstevel@tonic-gate 		break;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	case PCUNKILL:	/* delete a pending signal */
3800Sstevel@tonic-gate 		error = pr_unkill(pnp, (int)argp->sig);
3810Sstevel@tonic-gate 		break;
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	case PCNICE:	/* set nice priority */
3840Sstevel@tonic-gate 		error = pr_nice(p, (int)argp->nice, cr);
3850Sstevel@tonic-gate 		break;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	case PCSENTRY:	/* set syscall entry bit mask */
3880Sstevel@tonic-gate 	case PCSEXIT:	/* set syscall exit bit mask */
3890Sstevel@tonic-gate 		pr_setentryexit(p, &argp->sysset, cmd == PCSENTRY);
3900Sstevel@tonic-gate 		break;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	case PCSET:	/* set process flags */
3930Sstevel@tonic-gate 		error = pr_set(p, argp->flags);
3940Sstevel@tonic-gate 		break;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	case PCUNSET:	/* unset process flags */
3970Sstevel@tonic-gate 		error = pr_unset(p, argp->flags);
3980Sstevel@tonic-gate 		break;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	case PCSREG:	/* set general registers */
4015771Sjp151216 		{
4025771Sjp151216 			kthread_t *t = pr_thread(pnp);
4030Sstevel@tonic-gate 
4045771Sjp151216 			if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
4055771Sjp151216 				thread_unlock(t);
4065771Sjp151216 				error = EBUSY;
4075771Sjp151216 			} else {
4085771Sjp151216 				thread_unlock(t);
4095771Sjp151216 				mutex_exit(&p->p_lock);
4105771Sjp151216 				prsetprregs(ttolwp(t), argp->prgregset, 0);
4115771Sjp151216 				mutex_enter(&p->p_lock);
4125771Sjp151216 			}
4135771Sjp151216 			break;
4140Sstevel@tonic-gate 		}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	case PCSFPREG:	/* set floating-point registers */
4170Sstevel@tonic-gate 		error = pr_setfpregs(pnp, &argp->prfpregset);
4180Sstevel@tonic-gate 		break;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	case PCSXREG:	/* set extra registers */
4210Sstevel@tonic-gate #if defined(__sparc)
4220Sstevel@tonic-gate 		error = pr_setxregs(pnp, &argp->prxregset);
4230Sstevel@tonic-gate #else
4240Sstevel@tonic-gate 		error = EINVAL;
4250Sstevel@tonic-gate #endif
4260Sstevel@tonic-gate 		break;
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate #if defined(__sparc)
4290Sstevel@tonic-gate 	case PCSASRS:	/* set ancillary state registers */
4300Sstevel@tonic-gate 		error = pr_setasrs(pnp, argp->asrset);
4310Sstevel@tonic-gate 		break;
4320Sstevel@tonic-gate #endif
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	case PCSVADDR:	/* set virtual address at which to resume */
4350Sstevel@tonic-gate 		error = pr_setvaddr(pnp, argp->vaddr);
4360Sstevel@tonic-gate 		break;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	case PCSHOLD:	/* set signal-hold mask */
4390Sstevel@tonic-gate 		pr_sethold(pnp, &argp->sigset);
4400Sstevel@tonic-gate 		break;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	case PCSFAULT:	/* set mask of traced faults */
4430Sstevel@tonic-gate 		pr_setfault(p, &argp->fltset);
4440Sstevel@tonic-gate 		break;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	case PCCSIG:	/* clear current signal */
4470Sstevel@tonic-gate 		error = pr_clearsig(pnp);
4480Sstevel@tonic-gate 		break;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	case PCCFAULT:	/* clear current fault */
4510Sstevel@tonic-gate 		error = pr_clearflt(pnp);
4520Sstevel@tonic-gate 		break;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	case PCWATCH:	/* set or clear watched areas */
4550Sstevel@tonic-gate 		error = pr_watch(pnp, &argp->prwatch, &unlocked);
4560Sstevel@tonic-gate 		if (error && unlocked)
4570Sstevel@tonic-gate 			return (error);
4580Sstevel@tonic-gate 		break;
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	case PCAGENT:	/* create the /proc agent lwp in the target process */
4610Sstevel@tonic-gate 		error = pr_agent(pnp, argp->prgregset, &unlocked);
4620Sstevel@tonic-gate 		if (error && unlocked)
4630Sstevel@tonic-gate 			return (error);
4640Sstevel@tonic-gate 		break;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	case PCREAD:	/* read from the address space */
4670Sstevel@tonic-gate 		error = pr_rdwr(p, UIO_READ, &argp->priovec);
4680Sstevel@tonic-gate 		break;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	case PCWRITE:	/* write to the address space */
4710Sstevel@tonic-gate 		error = pr_rdwr(p, UIO_WRITE, &argp->priovec);
4720Sstevel@tonic-gate 		break;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	case PCSCRED:	/* set the process credentials */
4750Sstevel@tonic-gate 	case PCSCREDX:
4760Sstevel@tonic-gate 		error = pr_scred(p, &argp->prcred, cr, cmd == PCSCREDX);
4770Sstevel@tonic-gate 		break;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	case PCSPRIV:	/* set the process privileges */
4800Sstevel@tonic-gate 		error = pr_spriv(p, &argp->prpriv, cr);
4810Sstevel@tonic-gate 		break;
4820Sstevel@tonic-gate 	case PCSZONE:	/* set the process's zoneid credentials */
4830Sstevel@tonic-gate 		error = pr_szoneid(p, (zoneid_t)argp->przoneid, cr);
4840Sstevel@tonic-gate 		break;
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	if (error)
4880Sstevel@tonic-gate 		prunlock(pnp);
4890Sstevel@tonic-gate 	return (error);
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate typedef union {
4950Sstevel@tonic-gate 	int32_t		sig;		/* PCKILL, PCUNKILL */
4960Sstevel@tonic-gate 	int32_t		nice;		/* PCNICE */
4970Sstevel@tonic-gate 	int32_t		timeo;		/* PCTWSTOP */
4980Sstevel@tonic-gate 	uint32_t	flags;		/* PCRUN, PCSET, PCUNSET */
4990Sstevel@tonic-gate 	caddr32_t	vaddr;		/* PCSVADDR */
5000Sstevel@tonic-gate 	siginfo32_t	siginfo;	/* PCSSIG */
5010Sstevel@tonic-gate 	sigset_t	sigset;		/* PCSTRACE, PCSHOLD */
5020Sstevel@tonic-gate 	fltset_t	fltset;		/* PCSFAULT */
5030Sstevel@tonic-gate 	sysset_t	sysset;		/* PCSENTRY, PCSEXIT */
5040Sstevel@tonic-gate 	prgregset32_t	prgregset;	/* PCSREG, PCAGENT */
5050Sstevel@tonic-gate 	prfpregset32_t	prfpregset;	/* PCSFPREG */
5060Sstevel@tonic-gate #if defined(__sparc)
5070Sstevel@tonic-gate 	prxregset_t	prxregset;	/* PCSXREG */
5080Sstevel@tonic-gate #endif
5090Sstevel@tonic-gate 	prwatch32_t	prwatch;	/* PCWATCH */
5100Sstevel@tonic-gate 	priovec32_t	priovec;	/* PCREAD, PCWRITE */
5110Sstevel@tonic-gate 	prcred32_t	prcred;		/* PCSCRED */
5120Sstevel@tonic-gate 	prpriv_t	prpriv;		/* PCSPRIV */
5130Sstevel@tonic-gate 	int32_t		przoneid;	/* PCSZONE */
5140Sstevel@tonic-gate } arg32_t;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate static	int	pr_control32(int32_t, arg32_t *, prnode_t *, cred_t *);
5170Sstevel@tonic-gate static	int	pr_setfpregs32(prnode_t *, prfpregset32_t *);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate /*
5200Sstevel@tonic-gate  * Note that while ctlsize32() can use argp, it must do so only in a way
5210Sstevel@tonic-gate  * that assumes 32-bit rather than 64-bit alignment as argp is a pointer
5220Sstevel@tonic-gate  * to an array of 32-bit values and only 32-bit alignment is ensured.
5230Sstevel@tonic-gate  */
5240Sstevel@tonic-gate static size_t
ctlsize32(int32_t cmd,size_t resid,arg32_t * argp)5250Sstevel@tonic-gate ctlsize32(int32_t cmd, size_t resid, arg32_t *argp)
5260Sstevel@tonic-gate {
5270Sstevel@tonic-gate 	size_t size = sizeof (int32_t);
5280Sstevel@tonic-gate 	size_t rnd;
5290Sstevel@tonic-gate 	int ngrp;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	switch (cmd) {
5320Sstevel@tonic-gate 	case PCNULL:
5330Sstevel@tonic-gate 	case PCSTOP:
5340Sstevel@tonic-gate 	case PCDSTOP:
5350Sstevel@tonic-gate 	case PCWSTOP:
5360Sstevel@tonic-gate 	case PCCSIG:
5370Sstevel@tonic-gate 	case PCCFAULT:
5380Sstevel@tonic-gate 		break;
5390Sstevel@tonic-gate 	case PCSSIG:
5400Sstevel@tonic-gate 		size += sizeof (siginfo32_t);
5410Sstevel@tonic-gate 		break;
5420Sstevel@tonic-gate 	case PCTWSTOP:
5430Sstevel@tonic-gate 		size += sizeof (int32_t);
5440Sstevel@tonic-gate 		break;
5450Sstevel@tonic-gate 	case PCKILL:
5460Sstevel@tonic-gate 	case PCUNKILL:
5470Sstevel@tonic-gate 	case PCNICE:
5480Sstevel@tonic-gate 		size += sizeof (int32_t);
5490Sstevel@tonic-gate 		break;
5500Sstevel@tonic-gate 	case PCRUN:
5510Sstevel@tonic-gate 	case PCSET:
5520Sstevel@tonic-gate 	case PCUNSET:
5530Sstevel@tonic-gate 		size += sizeof (uint32_t);
5540Sstevel@tonic-gate 		break;
5550Sstevel@tonic-gate 	case PCSVADDR:
5560Sstevel@tonic-gate 		size += sizeof (caddr32_t);
5570Sstevel@tonic-gate 		break;
5580Sstevel@tonic-gate 	case PCSTRACE:
5590Sstevel@tonic-gate 	case PCSHOLD:
5600Sstevel@tonic-gate 		size += sizeof (sigset_t);
5610Sstevel@tonic-gate 		break;
5620Sstevel@tonic-gate 	case PCSFAULT:
5630Sstevel@tonic-gate 		size += sizeof (fltset_t);
5640Sstevel@tonic-gate 		break;
5650Sstevel@tonic-gate 	case PCSENTRY:
5660Sstevel@tonic-gate 	case PCSEXIT:
5670Sstevel@tonic-gate 		size += sizeof (sysset_t);
5680Sstevel@tonic-gate 		break;
5690Sstevel@tonic-gate 	case PCSREG:
5700Sstevel@tonic-gate 	case PCAGENT:
5710Sstevel@tonic-gate 		size += sizeof (prgregset32_t);
5720Sstevel@tonic-gate 		break;
5730Sstevel@tonic-gate 	case PCSFPREG:
5740Sstevel@tonic-gate 		size += sizeof (prfpregset32_t);
5750Sstevel@tonic-gate 		break;
5760Sstevel@tonic-gate #if defined(__sparc)
5770Sstevel@tonic-gate 	case PCSXREG:
5780Sstevel@tonic-gate 		size += sizeof (prxregset_t);
5790Sstevel@tonic-gate 		break;
5800Sstevel@tonic-gate #endif
5810Sstevel@tonic-gate 	case PCWATCH:
5820Sstevel@tonic-gate 		size += sizeof (prwatch32_t);
5830Sstevel@tonic-gate 		break;
5840Sstevel@tonic-gate 	case PCREAD:
5850Sstevel@tonic-gate 	case PCWRITE:
5860Sstevel@tonic-gate 		size += sizeof (priovec32_t);
5870Sstevel@tonic-gate 		break;
5880Sstevel@tonic-gate 	case PCSCRED:
5890Sstevel@tonic-gate 		size += sizeof (prcred32_t);
5900Sstevel@tonic-gate 		break;
5910Sstevel@tonic-gate 	case PCSCREDX:
5920Sstevel@tonic-gate 		/*
5930Sstevel@tonic-gate 		 * We cannot derefence the pr_ngroups fields if it
5940Sstevel@tonic-gate 		 * we don't have enough data.
5950Sstevel@tonic-gate 		 */
5960Sstevel@tonic-gate 		if (resid < size + sizeof (prcred32_t) - sizeof (gid32_t))
5970Sstevel@tonic-gate 			return (0);
5980Sstevel@tonic-gate 		ngrp = argp->prcred.pr_ngroups;
5990Sstevel@tonic-gate 		if (ngrp < 0 || ngrp > ngroups_max)
6000Sstevel@tonic-gate 			return (0);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 		/* The result can be smaller than sizeof (prcred32_t) */
6030Sstevel@tonic-gate 		size += sizeof (prcred32_t) - sizeof (gid32_t);
6040Sstevel@tonic-gate 		size += ngrp * sizeof (gid32_t);
6050Sstevel@tonic-gate 		break;
6060Sstevel@tonic-gate 	case PCSPRIV:
6070Sstevel@tonic-gate 		if (resid >= size + sizeof (prpriv_t))
6080Sstevel@tonic-gate 			size += priv_prgetprivsize(&argp->prpriv);
6090Sstevel@tonic-gate 		else
6100Sstevel@tonic-gate 			return (0);
6110Sstevel@tonic-gate 		break;
6120Sstevel@tonic-gate 	case PCSZONE:
6130Sstevel@tonic-gate 		size += sizeof (int32_t);
6140Sstevel@tonic-gate 		break;
6150Sstevel@tonic-gate 	default:
6160Sstevel@tonic-gate 		return (0);
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	/* Round up to a multiple of int32_t */
6200Sstevel@tonic-gate 	rnd = size & (sizeof (int32_t) - 1);
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	if (rnd != 0)
6230Sstevel@tonic-gate 		size += sizeof (int32_t) - rnd;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	if (size > resid)
6260Sstevel@tonic-gate 		return (0);
6270Sstevel@tonic-gate 	return (size);
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate /*
6310Sstevel@tonic-gate  * Control operations (lots).
6320Sstevel@tonic-gate  */
6330Sstevel@tonic-gate int
prwritectl32(struct vnode * vp,struct uio * uiop,cred_t * cr)6340Sstevel@tonic-gate prwritectl32(struct vnode *vp, struct uio *uiop, cred_t *cr)
6350Sstevel@tonic-gate {
6360Sstevel@tonic-gate #define	MY_BUFFER_SIZE32 \
6370Sstevel@tonic-gate 		100 > 1 + sizeof (arg32_t) / sizeof (int32_t) ? \
6380Sstevel@tonic-gate 		100 : 1 + sizeof (arg32_t) / sizeof (int32_t)
6390Sstevel@tonic-gate 	int32_t buf[MY_BUFFER_SIZE32];
6400Sstevel@tonic-gate 	int32_t *bufp;
6410Sstevel@tonic-gate 	arg32_t arg;
6420Sstevel@tonic-gate 	size_t resid = 0;
6430Sstevel@tonic-gate 	size_t size;
6440Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
6450Sstevel@tonic-gate 	int error;
6460Sstevel@tonic-gate 	int locked = 0;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	while (uiop->uio_resid) {
6490Sstevel@tonic-gate 		/*
6500Sstevel@tonic-gate 		 * Read several commands in one gulp.
6510Sstevel@tonic-gate 		 */
6520Sstevel@tonic-gate 		bufp = buf;
6530Sstevel@tonic-gate 		if (resid) {	/* move incomplete command to front of buffer */
6540Sstevel@tonic-gate 			int32_t *tail;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 			if (resid >= sizeof (buf))
6570Sstevel@tonic-gate 				break;
6580Sstevel@tonic-gate 			tail = (int32_t *)((char *)buf + sizeof (buf) - resid);
6590Sstevel@tonic-gate 			do {
6600Sstevel@tonic-gate 				*bufp++ = *tail++;
6610Sstevel@tonic-gate 			} while ((resid -= sizeof (int32_t)) != 0);
6620Sstevel@tonic-gate 		}
6630Sstevel@tonic-gate 		resid = sizeof (buf) - ((char *)bufp - (char *)buf);
6640Sstevel@tonic-gate 		if (resid > uiop->uio_resid)
6650Sstevel@tonic-gate 			resid = uiop->uio_resid;
6660Sstevel@tonic-gate 		if (error = uiomove((caddr_t)bufp, resid, UIO_WRITE, uiop))
6670Sstevel@tonic-gate 			return (error);
6680Sstevel@tonic-gate 		resid += (char *)bufp - (char *)buf;
6690Sstevel@tonic-gate 		bufp = buf;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		do {		/* loop over commands in buffer */
6720Sstevel@tonic-gate 			int32_t cmd = bufp[0];
6730Sstevel@tonic-gate 			arg32_t *argp = (arg32_t *)&bufp[1];
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 			size = ctlsize32(cmd, resid, argp);
6769319SSuhasini.Peddada@Sun.COM 			if (size == 0)	/* incomplete or invalid command */
6779275SSuhasini.Peddada@Sun.COM 				break;
6780Sstevel@tonic-gate 			/*
6790Sstevel@tonic-gate 			 * Perform the specified control operation.
6800Sstevel@tonic-gate 			 */
6810Sstevel@tonic-gate 			if (!locked) {
6820Sstevel@tonic-gate 				if ((error = prlock(pnp, ZNO)) != 0)
6830Sstevel@tonic-gate 					return (error);
6840Sstevel@tonic-gate 				locked = 1;
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 			/*
6880Sstevel@tonic-gate 			 * Since some members of the arg32_t union contain
6890Sstevel@tonic-gate 			 * 64-bit values (which must be 64-bit aligned), we
6900Sstevel@tonic-gate 			 * can't simply pass a pointer to the structure as
6910Sstevel@tonic-gate 			 * it may be unaligned. Note that we do pass the
6920Sstevel@tonic-gate 			 * potentially unaligned structure to ctlsize32()
6930Sstevel@tonic-gate 			 * above, but that uses it a way that makes no
6940Sstevel@tonic-gate 			 * assumptions about alignment.
6950Sstevel@tonic-gate 			 */
6960Sstevel@tonic-gate 			ASSERT(size - sizeof (cmd) <= sizeof (arg));
6970Sstevel@tonic-gate 			bcopy(argp, &arg, size - sizeof (cmd));
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 			if (error = pr_control32(cmd, &arg, pnp, cr)) {
7000Sstevel@tonic-gate 				if (error == -1)	/* -1 is timeout */
7010Sstevel@tonic-gate 					locked = 0;
7020Sstevel@tonic-gate 				else
7030Sstevel@tonic-gate 					return (error);
7040Sstevel@tonic-gate 			}
7050Sstevel@tonic-gate 			bufp = (int32_t *)((char *)bufp + size);
7060Sstevel@tonic-gate 		} while ((resid -= size) != 0);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 		if (locked) {
7090Sstevel@tonic-gate 			prunlock(pnp);
7100Sstevel@tonic-gate 			locked = 0;
7110Sstevel@tonic-gate 		}
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 	return (resid? EINVAL : 0);
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate static int
pr_control32(int32_t cmd,arg32_t * argp,prnode_t * pnp,cred_t * cr)7170Sstevel@tonic-gate pr_control32(int32_t cmd, arg32_t *argp, prnode_t *pnp, cred_t *cr)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	prcommon_t *pcp;
7200Sstevel@tonic-gate 	proc_t *p;
7210Sstevel@tonic-gate 	int unlocked;
7220Sstevel@tonic-gate 	int error = 0;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	if (cmd == PCNULL)
7250Sstevel@tonic-gate 		return (0);
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	pcp = pnp->pr_common;
7280Sstevel@tonic-gate 	p = pcp->prc_proc;
7290Sstevel@tonic-gate 	ASSERT(p != NULL);
7300Sstevel@tonic-gate 
73111173SJonathan.Adams@Sun.COM 	if (p->p_flag & SSYS) {
73211173SJonathan.Adams@Sun.COM 		prunlock(pnp);
73311173SJonathan.Adams@Sun.COM 		return (EBUSY);
73411173SJonathan.Adams@Sun.COM 	}
73511173SJonathan.Adams@Sun.COM 
7360Sstevel@tonic-gate 	switch (cmd) {
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	default:
7390Sstevel@tonic-gate 		error = EINVAL;
7400Sstevel@tonic-gate 		break;
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	case PCSTOP:	/* direct process or lwp to stop and wait for stop */
7430Sstevel@tonic-gate 	case PCDSTOP:	/* direct process or lwp to stop, don't wait */
7440Sstevel@tonic-gate 	case PCWSTOP:	/* wait for process or lwp to stop */
7450Sstevel@tonic-gate 	case PCTWSTOP:	/* wait for process or lwp to stop, with timeout */
7465771Sjp151216 		{
7475771Sjp151216 			time_t timeo;
7485771Sjp151216 
7495771Sjp151216 			/*
7505771Sjp151216 			 * Can't apply to a system process.
7515771Sjp151216 			 */
75211173SJonathan.Adams@Sun.COM 			if (p->p_as == &kas) {
7535771Sjp151216 				error = EBUSY;
7545771Sjp151216 				break;
7555771Sjp151216 			}
7565771Sjp151216 
7575771Sjp151216 			if (cmd == PCSTOP || cmd == PCDSTOP)
7585771Sjp151216 				pr_stop(pnp);
7595771Sjp151216 
7605771Sjp151216 			if (cmd == PCDSTOP)
7615771Sjp151216 				break;
7620Sstevel@tonic-gate 
7635771Sjp151216 			/*
7645771Sjp151216 			 * If an lwp is waiting for itself or its process,
7655771Sjp151216 			 * don't wait. The lwp will never see the fact that
7665771Sjp151216 			 * itself is stopped.
7675771Sjp151216 			 */
7685771Sjp151216 			if ((pcp->prc_flags & PRC_LWP)?
7695771Sjp151216 			    (pcp->prc_thread == curthread) : (p == curproc)) {
7705771Sjp151216 				if (cmd == PCWSTOP || cmd == PCTWSTOP)
7715771Sjp151216 					error = EBUSY;
7725771Sjp151216 				break;
7735771Sjp151216 			}
7745771Sjp151216 
7755771Sjp151216 			timeo = (cmd == PCTWSTOP)? (time_t)argp->timeo : 0;
7765771Sjp151216 			if ((error = pr_wait_stop(pnp, timeo)) != 0)
7775771Sjp151216 				return (error);
7785771Sjp151216 
7790Sstevel@tonic-gate 			break;
7800Sstevel@tonic-gate 		}
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	case PCRUN:	/* make lwp or process runnable */
7830Sstevel@tonic-gate 		error = pr_setrun(pnp, (ulong_t)argp->flags);
7840Sstevel@tonic-gate 		break;
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	case PCSTRACE:	/* set signal trace mask */
7870Sstevel@tonic-gate 		pr_settrace(p,  &argp->sigset);
7880Sstevel@tonic-gate 		break;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	case PCSSIG:	/* set current signal */
7910Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
7920Sstevel@tonic-gate 			error = EOVERFLOW;
7930Sstevel@tonic-gate 		else {
7940Sstevel@tonic-gate 			int sig = (int)argp->siginfo.si_signo;
7950Sstevel@tonic-gate 			siginfo_t siginfo;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
7980Sstevel@tonic-gate 			siginfo_32tok(&argp->siginfo, (k_siginfo_t *)&siginfo);
7990Sstevel@tonic-gate 			error = pr_setsig(pnp, &siginfo);
8000Sstevel@tonic-gate 			if (sig == SIGKILL && error == 0) {
8010Sstevel@tonic-gate 				prunlock(pnp);
8020Sstevel@tonic-gate 				pr_wait_die(pnp);
8030Sstevel@tonic-gate 				return (-1);
8040Sstevel@tonic-gate 			}
8050Sstevel@tonic-gate 		}
8060Sstevel@tonic-gate 		break;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	case PCKILL:	/* send signal */
8090Sstevel@tonic-gate 		error = pr_kill(pnp, (int)argp->sig, cr);
8100Sstevel@tonic-gate 		if (error == 0 && argp->sig == SIGKILL) {
8110Sstevel@tonic-gate 			prunlock(pnp);
8120Sstevel@tonic-gate 			pr_wait_die(pnp);
8130Sstevel@tonic-gate 			return (-1);
8140Sstevel@tonic-gate 		}
8150Sstevel@tonic-gate 		break;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	case PCUNKILL:	/* delete a pending signal */
8180Sstevel@tonic-gate 		error = pr_unkill(pnp, (int)argp->sig);
8190Sstevel@tonic-gate 		break;
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	case PCNICE:	/* set nice priority */
8220Sstevel@tonic-gate 		error = pr_nice(p, (int)argp->nice, cr);
8230Sstevel@tonic-gate 		break;
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	case PCSENTRY:	/* set syscall entry bit mask */
8260Sstevel@tonic-gate 	case PCSEXIT:	/* set syscall exit bit mask */
8270Sstevel@tonic-gate 		pr_setentryexit(p, &argp->sysset, cmd == PCSENTRY);
8280Sstevel@tonic-gate 		break;
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	case PCSET:	/* set process flags */
8310Sstevel@tonic-gate 		error = pr_set(p, (long)argp->flags);
8320Sstevel@tonic-gate 		break;
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	case PCUNSET:	/* unset process flags */
8350Sstevel@tonic-gate 		error = pr_unset(p, (long)argp->flags);
8360Sstevel@tonic-gate 		break;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	case PCSREG:	/* set general registers */
8390Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
8400Sstevel@tonic-gate 			error = EOVERFLOW;
8410Sstevel@tonic-gate 		else {
8420Sstevel@tonic-gate 			kthread_t *t = pr_thread(pnp);
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 			if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
8450Sstevel@tonic-gate 				thread_unlock(t);
8460Sstevel@tonic-gate 				error = EBUSY;
8470Sstevel@tonic-gate 			} else {
8480Sstevel@tonic-gate 				prgregset_t prgregset;
8490Sstevel@tonic-gate 				klwp_t *lwp = ttolwp(t);
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 				thread_unlock(t);
8520Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
8530Sstevel@tonic-gate 				prgregset_32ton(lwp, argp->prgregset,
8545771Sjp151216 				    prgregset);
8550Sstevel@tonic-gate 				prsetprregs(lwp, prgregset, 0);
8560Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
8570Sstevel@tonic-gate 			}
8580Sstevel@tonic-gate 		}
8590Sstevel@tonic-gate 		break;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	case PCSFPREG:	/* set floating-point registers */
8620Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
8630Sstevel@tonic-gate 			error = EOVERFLOW;
8640Sstevel@tonic-gate 		else
8650Sstevel@tonic-gate 			error = pr_setfpregs32(pnp, &argp->prfpregset);
8660Sstevel@tonic-gate 		break;
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	case PCSXREG:	/* set extra registers */
8690Sstevel@tonic-gate #if defined(__sparc)
8700Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
8710Sstevel@tonic-gate 			error = EOVERFLOW;
8720Sstevel@tonic-gate 		else
8730Sstevel@tonic-gate 			error = pr_setxregs(pnp, &argp->prxregset);
8740Sstevel@tonic-gate #else
8750Sstevel@tonic-gate 		error = EINVAL;
8760Sstevel@tonic-gate #endif
8770Sstevel@tonic-gate 		break;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	case PCSVADDR:	/* set virtual address at which to resume */
8800Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
8810Sstevel@tonic-gate 			error = EOVERFLOW;
8820Sstevel@tonic-gate 		else
8830Sstevel@tonic-gate 			error = pr_setvaddr(pnp,
8840Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)argp->vaddr);
8850Sstevel@tonic-gate 		break;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	case PCSHOLD:	/* set signal-hold mask */
8880Sstevel@tonic-gate 		pr_sethold(pnp, &argp->sigset);
8890Sstevel@tonic-gate 		break;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	case PCSFAULT:	/* set mask of traced faults */
8920Sstevel@tonic-gate 		pr_setfault(p, &argp->fltset);
8930Sstevel@tonic-gate 		break;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	case PCCSIG:	/* clear current signal */
8960Sstevel@tonic-gate 		error = pr_clearsig(pnp);
8970Sstevel@tonic-gate 		break;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	case PCCFAULT:	/* clear current fault */
9000Sstevel@tonic-gate 		error = pr_clearflt(pnp);
9010Sstevel@tonic-gate 		break;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	case PCWATCH:	/* set or clear watched areas */
9040Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
9050Sstevel@tonic-gate 			error = EOVERFLOW;
9060Sstevel@tonic-gate 		else {
9070Sstevel@tonic-gate 			prwatch_t prwatch;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 			prwatch.pr_vaddr = argp->prwatch.pr_vaddr;
9100Sstevel@tonic-gate 			prwatch.pr_size = argp->prwatch.pr_size;
9110Sstevel@tonic-gate 			prwatch.pr_wflags = argp->prwatch.pr_wflags;
9120Sstevel@tonic-gate 			prwatch.pr_pad = argp->prwatch.pr_pad;
9130Sstevel@tonic-gate 			error = pr_watch(pnp, &prwatch, &unlocked);
9140Sstevel@tonic-gate 			if (error && unlocked)
9150Sstevel@tonic-gate 				return (error);
9160Sstevel@tonic-gate 		}
9170Sstevel@tonic-gate 		break;
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	case PCAGENT:	/* create the /proc agent lwp in the target process */
9200Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
9210Sstevel@tonic-gate 			error = EOVERFLOW;
9220Sstevel@tonic-gate 		else {
9230Sstevel@tonic-gate 			prgregset_t prgregset;
9240Sstevel@tonic-gate 			kthread_t *t = pr_thread(pnp);
9250Sstevel@tonic-gate 			klwp_t *lwp = ttolwp(t);
9260Sstevel@tonic-gate 			thread_unlock(t);
9270Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
9280Sstevel@tonic-gate 			prgregset_32ton(lwp, argp->prgregset, prgregset);
9290Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
9300Sstevel@tonic-gate 			error = pr_agent(pnp, prgregset, &unlocked);
9310Sstevel@tonic-gate 			if (error && unlocked)
9320Sstevel@tonic-gate 				return (error);
9330Sstevel@tonic-gate 		}
9340Sstevel@tonic-gate 		break;
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	case PCREAD:	/* read from the address space */
9370Sstevel@tonic-gate 	case PCWRITE:	/* write to the address space */
9380Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
9390Sstevel@tonic-gate 			error = EOVERFLOW;
9400Sstevel@tonic-gate 		else {
9410Sstevel@tonic-gate 			enum uio_rw rw = (cmd == PCREAD)? UIO_READ : UIO_WRITE;
9420Sstevel@tonic-gate 			priovec_t priovec;
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 			priovec.pio_base =
9450Sstevel@tonic-gate 			    (void *)(uintptr_t)argp->priovec.pio_base;
9460Sstevel@tonic-gate 			priovec.pio_len = (size_t)argp->priovec.pio_len;
9470Sstevel@tonic-gate 			priovec.pio_offset = (off_t)
9485771Sjp151216 			    (uint32_t)argp->priovec.pio_offset;
9490Sstevel@tonic-gate 			error = pr_rdwr(p, rw, &priovec);
9500Sstevel@tonic-gate 		}
9510Sstevel@tonic-gate 		break;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	case PCSCRED:	/* set the process credentials */
9540Sstevel@tonic-gate 	case PCSCREDX:
9555771Sjp151216 		{
9565771Sjp151216 			/*
9575771Sjp151216 			 * All the fields in these structures are exactly the
9585771Sjp151216 			 * same and so the structures are compatible.  In case
9595771Sjp151216 			 * this ever changes, we catch this with the ASSERT
9605771Sjp151216 			 * below.
9615771Sjp151216 			 */
9625771Sjp151216 			prcred_t *prcred = (prcred_t *)&argp->prcred;
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate #ifndef __lint
9655771Sjp151216 			ASSERT(sizeof (prcred_t) == sizeof (prcred32_t));
9660Sstevel@tonic-gate #endif
9670Sstevel@tonic-gate 
9685771Sjp151216 			error = pr_scred(p, prcred, cr, cmd == PCSCREDX);
9695771Sjp151216 			break;
9705771Sjp151216 		}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	case PCSPRIV:	/* set the process privileges */
9736247Sraf 		error = pr_spriv(p, &argp->prpriv, cr);
9746247Sraf 		break;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	case PCSZONE:	/* set the process's zoneid */
9775771Sjp151216 		error = pr_szoneid(p, (zoneid_t)argp->przoneid, cr);
9785771Sjp151216 		break;
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	if (error)
9820Sstevel@tonic-gate 		prunlock(pnp);
9830Sstevel@tonic-gate 	return (error);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate /*
9890Sstevel@tonic-gate  * Return the specific or chosen thread/lwp for a control operation.
9900Sstevel@tonic-gate  * Returns with the thread locked via thread_lock(t).
9910Sstevel@tonic-gate  */
9920Sstevel@tonic-gate kthread_t *
pr_thread(prnode_t * pnp)9930Sstevel@tonic-gate pr_thread(prnode_t *pnp)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
9960Sstevel@tonic-gate 	kthread_t *t;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {
9990Sstevel@tonic-gate 		t = pcp->prc_thread;
10000Sstevel@tonic-gate 		ASSERT(t != NULL);
10010Sstevel@tonic-gate 		thread_lock(t);
10020Sstevel@tonic-gate 	} else {
10030Sstevel@tonic-gate 		proc_t *p = pcp->prc_proc;
10040Sstevel@tonic-gate 		t = prchoose(p);	/* returns locked thread */
10050Sstevel@tonic-gate 		ASSERT(t != NULL);
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	return (t);
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate /*
10120Sstevel@tonic-gate  * Direct the process or lwp to stop.
10130Sstevel@tonic-gate  */
10140Sstevel@tonic-gate void
pr_stop(prnode_t * pnp)10150Sstevel@tonic-gate pr_stop(prnode_t *pnp)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
10180Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
10190Sstevel@tonic-gate 	kthread_t *t;
10200Sstevel@tonic-gate 	vnode_t *vp;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	/*
10230Sstevel@tonic-gate 	 * If already stopped, do nothing; otherwise flag
10240Sstevel@tonic-gate 	 * it to be stopped the next time it tries to run.
10250Sstevel@tonic-gate 	 * If sleeping at interruptible priority, set it
10260Sstevel@tonic-gate 	 * running so it will stop within cv_wait_sig().
10270Sstevel@tonic-gate 	 *
10280Sstevel@tonic-gate 	 * Take care to cooperate with jobcontrol: if an lwp
10290Sstevel@tonic-gate 	 * is stopped due to the default action of a jobcontrol
10300Sstevel@tonic-gate 	 * stop signal, flag it to be stopped the next time it
10310Sstevel@tonic-gate 	 * starts due to a SIGCONT signal.
10320Sstevel@tonic-gate 	 */
10330Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP)
10340Sstevel@tonic-gate 		t = pcp->prc_thread;
10350Sstevel@tonic-gate 	else
10360Sstevel@tonic-gate 		t = p->p_tlist;
10370Sstevel@tonic-gate 	ASSERT(t != NULL);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	do {
10400Sstevel@tonic-gate 		int notify;
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 		notify = 0;
10430Sstevel@tonic-gate 		thread_lock(t);
10440Sstevel@tonic-gate 		if (!ISTOPPED(t)) {
10450Sstevel@tonic-gate 			t->t_proc_flag |= TP_PRSTOP;
10460Sstevel@tonic-gate 			t->t_sig_check = 1;	/* do ISSIG */
10470Sstevel@tonic-gate 		}
10483792Sakolb 
10493792Sakolb 		/* Move the thread from wait queue to run queue */
10503792Sakolb 		if (ISWAITING(t))
10513792Sakolb 			setrun_locked(t);
10523792Sakolb 
10533792Sakolb 		if (ISWAKEABLE(t)) {
10540Sstevel@tonic-gate 			if (t->t_wchan0 == NULL)
10550Sstevel@tonic-gate 				setrun_locked(t);
10560Sstevel@tonic-gate 			else if (!VSTOPPED(t)) {
10570Sstevel@tonic-gate 				/*
10580Sstevel@tonic-gate 				 * Mark it virtually stopped.
10590Sstevel@tonic-gate 				 */
10600Sstevel@tonic-gate 				t->t_proc_flag |= TP_PRVSTOP;
10610Sstevel@tonic-gate 				notify = 1;
10620Sstevel@tonic-gate 			}
10630Sstevel@tonic-gate 		}
10640Sstevel@tonic-gate 		/*
10650Sstevel@tonic-gate 		 * force the thread into the kernel
10660Sstevel@tonic-gate 		 * if it is not already there.
10670Sstevel@tonic-gate 		 */
10680Sstevel@tonic-gate 		prpokethread(t);
10690Sstevel@tonic-gate 		thread_unlock(t);
10700Sstevel@tonic-gate 		if (notify &&
10710Sstevel@tonic-gate 		    (vp = p->p_lwpdir[t->t_dslot].ld_entry->le_trace) != NULL)
10720Sstevel@tonic-gate 			prnotify(vp);
10730Sstevel@tonic-gate 		if (pcp->prc_flags & PRC_LWP)
10740Sstevel@tonic-gate 			break;
10750Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	/*
10780Sstevel@tonic-gate 	 * We do this just in case the thread we asked
10790Sstevel@tonic-gate 	 * to stop is in holdlwps() (called from cfork()).
10800Sstevel@tonic-gate 	 */
10810Sstevel@tonic-gate 	cv_broadcast(&p->p_holdlwps);
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate /*
10850Sstevel@tonic-gate  * Sleep until the lwp stops, but cooperate with
10860Sstevel@tonic-gate  * jobcontrol:  Don't wake up if the lwp is stopped
10870Sstevel@tonic-gate  * due to the default action of a jobcontrol stop signal.
10880Sstevel@tonic-gate  * If this is the process file descriptor, sleep
10890Sstevel@tonic-gate  * until all of the process's lwps stop.
10900Sstevel@tonic-gate  */
10910Sstevel@tonic-gate int
pr_wait_stop(prnode_t * pnp,time_t timeo)10920Sstevel@tonic-gate pr_wait_stop(prnode_t *pnp, time_t timeo)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
10950Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
10960Sstevel@tonic-gate 	timestruc_t rqtime;
10970Sstevel@tonic-gate 	timestruc_t *rqtp = NULL;
10984123Sdm120769 	int timecheck = 0;
10990Sstevel@tonic-gate 	kthread_t *t;
11000Sstevel@tonic-gate 	int error;
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	if (timeo > 0) {	/* millisecond timeout */
11030Sstevel@tonic-gate 		/*
11040Sstevel@tonic-gate 		 * Determine the precise future time of the requested timeout.
11050Sstevel@tonic-gate 		 */
11060Sstevel@tonic-gate 		timestruc_t now;
11070Sstevel@tonic-gate 
11084123Sdm120769 		timecheck = timechanged;
11090Sstevel@tonic-gate 		gethrestime(&now);
11100Sstevel@tonic-gate 		rqtp = &rqtime;
11110Sstevel@tonic-gate 		rqtp->tv_sec = timeo / MILLISEC;
11120Sstevel@tonic-gate 		rqtp->tv_nsec = (timeo % MILLISEC) * MICROSEC;
11130Sstevel@tonic-gate 		timespecadd(rqtp, &now);
11140Sstevel@tonic-gate 	}
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {	/* lwp file descriptor */
11170Sstevel@tonic-gate 		t = pcp->prc_thread;
11180Sstevel@tonic-gate 		ASSERT(t != NULL);
11190Sstevel@tonic-gate 		thread_lock(t);
11200Sstevel@tonic-gate 		while (!ISTOPPED(t) && !VSTOPPED(t)) {
11210Sstevel@tonic-gate 			thread_unlock(t);
11220Sstevel@tonic-gate 			mutex_enter(&pcp->prc_mutex);
11230Sstevel@tonic-gate 			prunlock(pnp);
11244123Sdm120769 			error = pr_wait(pcp, rqtp, timecheck);
11250Sstevel@tonic-gate 			if (error)	/* -1 is timeout */
11260Sstevel@tonic-gate 				return (error);
11270Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0)
11280Sstevel@tonic-gate 				return (error);
11290Sstevel@tonic-gate 			ASSERT(p == pcp->prc_proc);
11300Sstevel@tonic-gate 			ASSERT(t == pcp->prc_thread);
11310Sstevel@tonic-gate 			thread_lock(t);
11320Sstevel@tonic-gate 		}
11330Sstevel@tonic-gate 		thread_unlock(t);
11340Sstevel@tonic-gate 	} else {			/* process file descriptor */
11350Sstevel@tonic-gate 		t = prchoose(p);	/* returns locked thread */
11360Sstevel@tonic-gate 		ASSERT(t != NULL);
11370Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&p->p_lock));
11380Sstevel@tonic-gate 		while ((!ISTOPPED(t) && !VSTOPPED(t) && !SUSPENDED(t)) ||
11390Sstevel@tonic-gate 		    (p->p_flag & SEXITLWPS)) {
11400Sstevel@tonic-gate 			thread_unlock(t);
11410Sstevel@tonic-gate 			mutex_enter(&pcp->prc_mutex);
11420Sstevel@tonic-gate 			prunlock(pnp);
11434123Sdm120769 			error = pr_wait(pcp, rqtp, timecheck);
11440Sstevel@tonic-gate 			if (error)	/* -1 is timeout */
11450Sstevel@tonic-gate 				return (error);
11460Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0)
11470Sstevel@tonic-gate 				return (error);
11480Sstevel@tonic-gate 			ASSERT(p == pcp->prc_proc);
11490Sstevel@tonic-gate 			t = prchoose(p);	/* returns locked t */
11500Sstevel@tonic-gate 			ASSERT(t != NULL);
11510Sstevel@tonic-gate 		}
11520Sstevel@tonic-gate 		thread_unlock(t);
11530Sstevel@tonic-gate 	}
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	ASSERT(!(pcp->prc_flags & PRC_DESTROY) && p->p_stat != SZOMB &&
11560Sstevel@tonic-gate 	    t != NULL && t->t_state != TS_ZOMB);
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	return (0);
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate int
pr_setrun(prnode_t * pnp,ulong_t flags)11620Sstevel@tonic-gate pr_setrun(prnode_t *pnp, ulong_t flags)
11630Sstevel@tonic-gate {
11640Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
11650Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
11660Sstevel@tonic-gate 	kthread_t *t;
11670Sstevel@tonic-gate 	klwp_t *lwp;
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	/*
11700Sstevel@tonic-gate 	 * Cannot set an lwp running if it is not stopped.
11710Sstevel@tonic-gate 	 * Also, no lwp other than the /proc agent lwp can
11720Sstevel@tonic-gate 	 * be set running so long as the /proc agent lwp exists.
11730Sstevel@tonic-gate 	 */
11740Sstevel@tonic-gate 	t = pr_thread(pnp);	/* returns locked thread */
11750Sstevel@tonic-gate 	if ((!ISTOPPED(t) && !VSTOPPED(t) &&
11760Sstevel@tonic-gate 	    !(t->t_proc_flag & TP_PRSTOP)) ||
11770Sstevel@tonic-gate 	    (p->p_agenttp != NULL &&
11780Sstevel@tonic-gate 	    (t != p->p_agenttp || !(pcp->prc_flags & PRC_LWP)))) {
11790Sstevel@tonic-gate 		thread_unlock(t);
11800Sstevel@tonic-gate 		return (EBUSY);
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 	thread_unlock(t);
11830Sstevel@tonic-gate 	if (flags & ~(PRCSIG|PRCFAULT|PRSTEP|PRSTOP|PRSABORT))
11840Sstevel@tonic-gate 		return (EINVAL);
11850Sstevel@tonic-gate 	lwp = ttolwp(t);
11860Sstevel@tonic-gate 	if ((flags & PRCSIG) && lwp->lwp_cursig != SIGKILL) {
11870Sstevel@tonic-gate 		/*
11880Sstevel@tonic-gate 		 * Discard current siginfo_t, if any.
11890Sstevel@tonic-gate 		 */
11900Sstevel@tonic-gate 		lwp->lwp_cursig = 0;
11910Sstevel@tonic-gate 		lwp->lwp_extsig = 0;
11920Sstevel@tonic-gate 		if (lwp->lwp_curinfo) {
11930Sstevel@tonic-gate 			siginfofree(lwp->lwp_curinfo);
11940Sstevel@tonic-gate 			lwp->lwp_curinfo = NULL;
11950Sstevel@tonic-gate 		}
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate 	if (flags & PRCFAULT)
11980Sstevel@tonic-gate 		lwp->lwp_curflt = 0;
11990Sstevel@tonic-gate 	/*
12000Sstevel@tonic-gate 	 * We can't hold p->p_lock when we touch the lwp's registers.
12010Sstevel@tonic-gate 	 * It may be swapped out and we will get a page fault.
12020Sstevel@tonic-gate 	 */
12030Sstevel@tonic-gate 	if (flags & PRSTEP) {
12040Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
12050Sstevel@tonic-gate 		prstep(lwp, 0);
12060Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
12070Sstevel@tonic-gate 	}
12080Sstevel@tonic-gate 	if (flags & PRSTOP) {
12090Sstevel@tonic-gate 		t->t_proc_flag |= TP_PRSTOP;
12100Sstevel@tonic-gate 		t->t_sig_check = 1;	/* do ISSIG */
12110Sstevel@tonic-gate 	}
12120Sstevel@tonic-gate 	if (flags & PRSABORT)
12130Sstevel@tonic-gate 		lwp->lwp_sysabort = 1;
12140Sstevel@tonic-gate 	thread_lock(t);
12150Sstevel@tonic-gate 	if ((pcp->prc_flags & PRC_LWP) || (flags & (PRSTEP|PRSTOP))) {
12160Sstevel@tonic-gate 		/*
12170Sstevel@tonic-gate 		 * Here, we are dealing with a single lwp.
12180Sstevel@tonic-gate 		 */
12190Sstevel@tonic-gate 		if (ISTOPPED(t)) {
12200Sstevel@tonic-gate 			t->t_schedflag |= TS_PSTART;
12210Sstevel@tonic-gate 			t->t_dtrace_stop = 0;
12220Sstevel@tonic-gate 			setrun_locked(t);
12230Sstevel@tonic-gate 		} else if (flags & PRSABORT) {
12240Sstevel@tonic-gate 			t->t_proc_flag &=
12250Sstevel@tonic-gate 			    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
12260Sstevel@tonic-gate 			setrun_locked(t);
12270Sstevel@tonic-gate 		} else if (!(flags & PRSTOP)) {
12280Sstevel@tonic-gate 			t->t_proc_flag &=
12290Sstevel@tonic-gate 			    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
12300Sstevel@tonic-gate 		}
12310Sstevel@tonic-gate 		thread_unlock(t);
12320Sstevel@tonic-gate 	} else {
12330Sstevel@tonic-gate 		/*
12340Sstevel@tonic-gate 		 * Here, we are dealing with the whole process.
12350Sstevel@tonic-gate 		 */
12360Sstevel@tonic-gate 		if (ISTOPPED(t)) {
12370Sstevel@tonic-gate 			/*
12380Sstevel@tonic-gate 			 * The representative lwp is stopped on an event
12390Sstevel@tonic-gate 			 * of interest.  We demote it to PR_REQUESTED and
12400Sstevel@tonic-gate 			 * choose another representative lwp.  If the new
12410Sstevel@tonic-gate 			 * representative lwp is not stopped on an event of
12420Sstevel@tonic-gate 			 * interest (other than PR_REQUESTED), we set the
12430Sstevel@tonic-gate 			 * whole process running, else we leave the process
12440Sstevel@tonic-gate 			 * stopped showing the next event of interest.
12450Sstevel@tonic-gate 			 */
12460Sstevel@tonic-gate 			kthread_t *tx = NULL;
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 			if (!(flags & PRSABORT) &&
12490Sstevel@tonic-gate 			    t->t_whystop == PR_SYSENTRY &&
12500Sstevel@tonic-gate 			    t->t_whatstop == SYS_lwp_exit)
12510Sstevel@tonic-gate 				tx = t;		/* remember the exiting lwp */
12520Sstevel@tonic-gate 			t->t_whystop = PR_REQUESTED;
12530Sstevel@tonic-gate 			t->t_whatstop = 0;
12540Sstevel@tonic-gate 			thread_unlock(t);
12550Sstevel@tonic-gate 			t = prchoose(p);	/* returns locked t */
12560Sstevel@tonic-gate 			ASSERT(ISTOPPED(t) || VSTOPPED(t));
12570Sstevel@tonic-gate 			if (VSTOPPED(t) ||
12580Sstevel@tonic-gate 			    t->t_whystop == PR_REQUESTED) {
12590Sstevel@tonic-gate 				thread_unlock(t);
12600Sstevel@tonic-gate 				allsetrun(p);
12610Sstevel@tonic-gate 			} else {
12620Sstevel@tonic-gate 				thread_unlock(t);
12630Sstevel@tonic-gate 				/*
12640Sstevel@tonic-gate 				 * As a special case, if the old representative
12650Sstevel@tonic-gate 				 * lwp was stopped on entry to _lwp_exit()
12660Sstevel@tonic-gate 				 * (and we are not aborting the system call),
12670Sstevel@tonic-gate 				 * we set the old representative lwp running.
12680Sstevel@tonic-gate 				 * We do this so that the next process stop
12690Sstevel@tonic-gate 				 * will find the exiting lwp gone.
12700Sstevel@tonic-gate 				 */
12710Sstevel@tonic-gate 				if (tx != NULL) {
12720Sstevel@tonic-gate 					thread_lock(tx);
12730Sstevel@tonic-gate 					tx->t_schedflag |= TS_PSTART;
12740Sstevel@tonic-gate 					t->t_dtrace_stop = 0;
12750Sstevel@tonic-gate 					setrun_locked(tx);
12760Sstevel@tonic-gate 					thread_unlock(tx);
12770Sstevel@tonic-gate 				}
12780Sstevel@tonic-gate 			}
12790Sstevel@tonic-gate 		} else {
12800Sstevel@tonic-gate 			/*
12810Sstevel@tonic-gate 			 * No event of interest; set all of the lwps running.
12820Sstevel@tonic-gate 			 */
12830Sstevel@tonic-gate 			if (flags & PRSABORT) {
12840Sstevel@tonic-gate 				t->t_proc_flag &=
12850Sstevel@tonic-gate 				    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
12860Sstevel@tonic-gate 				setrun_locked(t);
12870Sstevel@tonic-gate 			}
12880Sstevel@tonic-gate 			thread_unlock(t);
12890Sstevel@tonic-gate 			allsetrun(p);
12900Sstevel@tonic-gate 		}
12910Sstevel@tonic-gate 	}
12920Sstevel@tonic-gate 	return (0);
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate /*
12960Sstevel@tonic-gate  * Wait until process/lwp stops or until timer expires.
12970Sstevel@tonic-gate  * Return EINTR for an interruption, -1 for timeout, else 0.
12980Sstevel@tonic-gate  */
12990Sstevel@tonic-gate int
pr_wait(prcommon_t * pcp,timestruc_t * ts,int timecheck)13000Sstevel@tonic-gate pr_wait(prcommon_t *pcp,	/* prcommon referring to process/lwp */
13014123Sdm120769 	timestruc_t *ts,	/* absolute time of timeout, if any */
13024123Sdm120769 	int timecheck)
13030Sstevel@tonic-gate {
13040Sstevel@tonic-gate 	int rval;
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pcp->prc_mutex));
13074123Sdm120769 	rval = cv_waituntil_sig(&pcp->prc_wait, &pcp->prc_mutex, ts, timecheck);
13080Sstevel@tonic-gate 	mutex_exit(&pcp->prc_mutex);
13090Sstevel@tonic-gate 	switch (rval) {
13100Sstevel@tonic-gate 	case 0:
13110Sstevel@tonic-gate 		return (EINTR);
13120Sstevel@tonic-gate 	case -1:
13130Sstevel@tonic-gate 		return (-1);
13140Sstevel@tonic-gate 	default:
13150Sstevel@tonic-gate 		return (0);
13160Sstevel@tonic-gate 	}
13170Sstevel@tonic-gate }
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate /*
13200Sstevel@tonic-gate  * Make all threads in the process runnable.
13210Sstevel@tonic-gate  */
13220Sstevel@tonic-gate void
allsetrun(proc_t * p)13230Sstevel@tonic-gate allsetrun(proc_t *p)
13240Sstevel@tonic-gate {
13250Sstevel@tonic-gate 	kthread_t *t;
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
13300Sstevel@tonic-gate 		do {
13310Sstevel@tonic-gate 			thread_lock(t);
13320Sstevel@tonic-gate 			ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
13330Sstevel@tonic-gate 			t->t_proc_flag &= ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
13340Sstevel@tonic-gate 			if (ISTOPPED(t)) {
13350Sstevel@tonic-gate 				t->t_schedflag |= TS_PSTART;
13360Sstevel@tonic-gate 				t->t_dtrace_stop = 0;
13370Sstevel@tonic-gate 				setrun_locked(t);
13380Sstevel@tonic-gate 			}
13390Sstevel@tonic-gate 			thread_unlock(t);
13400Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
13410Sstevel@tonic-gate 	}
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate  * Wait for the process to die.
13460Sstevel@tonic-gate  * We do this after sending SIGKILL because we know it will
13470Sstevel@tonic-gate  * die soon and we want subsequent operations to return ENOENT.
13480Sstevel@tonic-gate  */
13490Sstevel@tonic-gate void
pr_wait_die(prnode_t * pnp)13500Sstevel@tonic-gate pr_wait_die(prnode_t *pnp)
13510Sstevel@tonic-gate {
13520Sstevel@tonic-gate 	proc_t *p;
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	mutex_enter(&pidlock);
13550Sstevel@tonic-gate 	while ((p = pnp->pr_common->prc_proc) != NULL && p->p_stat != SZOMB) {
13560Sstevel@tonic-gate 		if (!cv_wait_sig(&p->p_srwchan_cv, &pidlock))
13570Sstevel@tonic-gate 			break;
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 	mutex_exit(&pidlock);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate static void
pr_settrace(proc_t * p,sigset_t * sp)13630Sstevel@tonic-gate pr_settrace(proc_t *p, sigset_t *sp)
13640Sstevel@tonic-gate {
13650Sstevel@tonic-gate 	prdelset(sp, SIGKILL);
13660Sstevel@tonic-gate 	prassignset(&p->p_sigmask, sp);
13670Sstevel@tonic-gate 	if (!sigisempty(&p->p_sigmask))
13680Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
13690Sstevel@tonic-gate 	else if (prisempty(&p->p_fltmask)) {
13700Sstevel@tonic-gate 		user_t *up = PTOU(p);
13710Sstevel@tonic-gate 		if (up->u_systrap == 0)
13720Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
13730Sstevel@tonic-gate 	}
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate int
pr_setsig(prnode_t * pnp,siginfo_t * sip)13770Sstevel@tonic-gate pr_setsig(prnode_t *pnp, siginfo_t *sip)
13780Sstevel@tonic-gate {
1379*11940SRoger.Faulkner@Sun.COM 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
13800Sstevel@tonic-gate 	int sig = sip->si_signo;
13810Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
13820Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
13830Sstevel@tonic-gate 	kthread_t *t;
13840Sstevel@tonic-gate 	klwp_t *lwp;
13850Sstevel@tonic-gate 	int error = 0;
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	t = pr_thread(pnp);	/* returns locked thread */
13880Sstevel@tonic-gate 	thread_unlock(t);
13890Sstevel@tonic-gate 	lwp = ttolwp(t);
1390*11940SRoger.Faulkner@Sun.COM 	if (sig < 0 || sig >= nsig)
13910Sstevel@tonic-gate 		/* Zero allowed here */
13920Sstevel@tonic-gate 		error = EINVAL;
13930Sstevel@tonic-gate 	else if (lwp->lwp_cursig == SIGKILL)
13940Sstevel@tonic-gate 		/* "can't happen", but just in case */
13950Sstevel@tonic-gate 		error = EBUSY;
13960Sstevel@tonic-gate 	else if ((lwp->lwp_cursig = (uchar_t)sig) == 0) {
13970Sstevel@tonic-gate 		lwp->lwp_extsig = 0;
13980Sstevel@tonic-gate 		/*
13990Sstevel@tonic-gate 		 * Discard current siginfo_t, if any.
14000Sstevel@tonic-gate 		 */
14010Sstevel@tonic-gate 		if (lwp->lwp_curinfo) {
14020Sstevel@tonic-gate 			siginfofree(lwp->lwp_curinfo);
14030Sstevel@tonic-gate 			lwp->lwp_curinfo = NULL;
14040Sstevel@tonic-gate 		}
14050Sstevel@tonic-gate 	} else {
14060Sstevel@tonic-gate 		kthread_t *tx;
14070Sstevel@tonic-gate 		sigqueue_t *sqp;
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 		/* drop p_lock to do kmem_alloc(KM_SLEEP) */
14100Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
14110Sstevel@tonic-gate 		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
14120Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 		if (lwp->lwp_curinfo == NULL)
14150Sstevel@tonic-gate 			lwp->lwp_curinfo = sqp;
14160Sstevel@tonic-gate 		else
14170Sstevel@tonic-gate 			kmem_free(sqp, sizeof (sigqueue_t));
14180Sstevel@tonic-gate 		/*
14190Sstevel@tonic-gate 		 * Copy contents of info to current siginfo_t.
14200Sstevel@tonic-gate 		 */
14210Sstevel@tonic-gate 		bcopy(sip, &lwp->lwp_curinfo->sq_info,
14220Sstevel@tonic-gate 		    sizeof (lwp->lwp_curinfo->sq_info));
14230Sstevel@tonic-gate 		/*
14240Sstevel@tonic-gate 		 * Prevent contents published by si_zoneid-unaware /proc
14250Sstevel@tonic-gate 		 * consumers from being incorrectly filtered.  Because
14260Sstevel@tonic-gate 		 * an uninitialized si_zoneid is the same as
14270Sstevel@tonic-gate 		 * GLOBAL_ZONEID, this means that you can't pr_setsig a
14280Sstevel@tonic-gate 		 * process in a non-global zone with a siginfo which
14290Sstevel@tonic-gate 		 * appears to come from the global zone.
14300Sstevel@tonic-gate 		 */
14310Sstevel@tonic-gate 		if (SI_FROMUSER(sip) && sip->si_zoneid == 0)
14320Sstevel@tonic-gate 			lwp->lwp_curinfo->sq_info.si_zoneid =
14330Sstevel@tonic-gate 			    p->p_zone->zone_id;
14340Sstevel@tonic-gate 		/*
14350Sstevel@tonic-gate 		 * Side-effects for SIGKILL and jobcontrol signals.
14360Sstevel@tonic-gate 		 */
14370Sstevel@tonic-gate 		if (sig == SIGKILL) {
14380Sstevel@tonic-gate 			p->p_flag |= SKILLED;
14390Sstevel@tonic-gate 			p->p_flag &= ~SEXTKILLED;
14400Sstevel@tonic-gate 		} else if (sig == SIGCONT) {
14410Sstevel@tonic-gate 			p->p_flag |= SSCONT;
14420Sstevel@tonic-gate 			sigdelq(p, NULL, SIGSTOP);
14430Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTSTP);
14440Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTTOU);
14450Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTTIN);
14460Sstevel@tonic-gate 			sigdiffset(&p->p_sig, &stopdefault);
14470Sstevel@tonic-gate 			sigdiffset(&p->p_extsig, &stopdefault);
14480Sstevel@tonic-gate 			if ((tx = p->p_tlist) != NULL) {
14490Sstevel@tonic-gate 				do {
14500Sstevel@tonic-gate 					sigdelq(p, tx, SIGSTOP);
14510Sstevel@tonic-gate 					sigdelq(p, tx, SIGTSTP);
14520Sstevel@tonic-gate 					sigdelq(p, tx, SIGTTOU);
14530Sstevel@tonic-gate 					sigdelq(p, tx, SIGTTIN);
14540Sstevel@tonic-gate 					sigdiffset(&tx->t_sig, &stopdefault);
14550Sstevel@tonic-gate 					sigdiffset(&tx->t_extsig, &stopdefault);
14560Sstevel@tonic-gate 				} while ((tx = tx->t_forw) != p->p_tlist);
14570Sstevel@tonic-gate 			}
14580Sstevel@tonic-gate 		} else if (sigismember(&stopdefault, sig)) {
14590Sstevel@tonic-gate 			if (PTOU(p)->u_signal[sig-1] == SIG_DFL &&
14600Sstevel@tonic-gate 			    (sig == SIGSTOP || !p->p_pgidp->pid_pgorphaned))
14610Sstevel@tonic-gate 				p->p_flag &= ~SSCONT;
14620Sstevel@tonic-gate 			sigdelq(p, NULL, SIGCONT);
14630Sstevel@tonic-gate 			sigdelset(&p->p_sig, SIGCONT);
14640Sstevel@tonic-gate 			sigdelset(&p->p_extsig, SIGCONT);
14650Sstevel@tonic-gate 			if ((tx = p->p_tlist) != NULL) {
14660Sstevel@tonic-gate 				do {
14670Sstevel@tonic-gate 					sigdelq(p, tx, SIGCONT);
14680Sstevel@tonic-gate 					sigdelset(&tx->t_sig, SIGCONT);
14690Sstevel@tonic-gate 					sigdelset(&tx->t_extsig, SIGCONT);
14700Sstevel@tonic-gate 				} while ((tx = tx->t_forw) != p->p_tlist);
14710Sstevel@tonic-gate 			}
14720Sstevel@tonic-gate 		}
14730Sstevel@tonic-gate 		thread_lock(t);
14743792Sakolb 		if (ISWAKEABLE(t) || ISWAITING(t)) {
14755331Samw 			/* Set signaled sleeping/waiting lwp running */
14760Sstevel@tonic-gate 			setrun_locked(t);
14770Sstevel@tonic-gate 		} else if (t->t_state == TS_STOPPED && sig == SIGKILL) {
14780Sstevel@tonic-gate 			/* If SIGKILL, set stopped lwp running */
14790Sstevel@tonic-gate 			p->p_stopsig = 0;
14800Sstevel@tonic-gate 			t->t_schedflag |= TS_XSTART | TS_PSTART;
14810Sstevel@tonic-gate 			t->t_dtrace_stop = 0;
14820Sstevel@tonic-gate 			setrun_locked(t);
14830Sstevel@tonic-gate 		}
14840Sstevel@tonic-gate 		t->t_sig_check = 1;	/* so ISSIG will be done */
14850Sstevel@tonic-gate 		thread_unlock(t);
14860Sstevel@tonic-gate 		/*
14870Sstevel@tonic-gate 		 * More jobcontrol side-effects.
14880Sstevel@tonic-gate 		 */
14890Sstevel@tonic-gate 		if (sig == SIGCONT && (tx = p->p_tlist) != NULL) {
14900Sstevel@tonic-gate 			p->p_stopsig = 0;
14910Sstevel@tonic-gate 			do {
14920Sstevel@tonic-gate 				thread_lock(tx);
14930Sstevel@tonic-gate 				if (tx->t_state == TS_STOPPED &&
14940Sstevel@tonic-gate 				    tx->t_whystop == PR_JOBCONTROL) {
14950Sstevel@tonic-gate 					tx->t_schedflag |= TS_XSTART;
14960Sstevel@tonic-gate 					setrun_locked(tx);
14970Sstevel@tonic-gate 				}
14980Sstevel@tonic-gate 				thread_unlock(tx);
14990Sstevel@tonic-gate 			} while ((tx = tx->t_forw) != p->p_tlist);
15000Sstevel@tonic-gate 		}
15010Sstevel@tonic-gate 	}
15020Sstevel@tonic-gate 	return (error);
15030Sstevel@tonic-gate }
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate int
pr_kill(prnode_t * pnp,int sig,cred_t * cr)15060Sstevel@tonic-gate pr_kill(prnode_t *pnp, int sig, cred_t *cr)
15070Sstevel@tonic-gate {
1508*11940SRoger.Faulkner@Sun.COM 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
15090Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
15100Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
15110Sstevel@tonic-gate 	k_siginfo_t info;
15120Sstevel@tonic-gate 
1513*11940SRoger.Faulkner@Sun.COM 	if (sig <= 0 || sig >= nsig)
15140Sstevel@tonic-gate 		return (EINVAL);
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	bzero(&info, sizeof (info));
15170Sstevel@tonic-gate 	info.si_signo = sig;
15180Sstevel@tonic-gate 	info.si_code = SI_USER;
15190Sstevel@tonic-gate 	info.si_pid = curproc->p_pid;
15200Sstevel@tonic-gate 	info.si_ctid = PRCTID(curproc);
15210Sstevel@tonic-gate 	info.si_zoneid = getzoneid();
15220Sstevel@tonic-gate 	info.si_uid = crgetruid(cr);
15230Sstevel@tonic-gate 	sigaddq(p, (pcp->prc_flags & PRC_LWP)?
15240Sstevel@tonic-gate 	    pcp->prc_thread : NULL, &info, KM_NOSLEEP);
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	return (0);
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate int
pr_unkill(prnode_t * pnp,int sig)15300Sstevel@tonic-gate pr_unkill(prnode_t *pnp, int sig)
15310Sstevel@tonic-gate {
1532*11940SRoger.Faulkner@Sun.COM 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
15330Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
15340Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
15350Sstevel@tonic-gate 	sigqueue_t *infop = NULL;
15360Sstevel@tonic-gate 
1537*11940SRoger.Faulkner@Sun.COM 	if (sig <= 0 || sig >= nsig || sig == SIGKILL)
15380Sstevel@tonic-gate 		return (EINVAL);
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP)
15410Sstevel@tonic-gate 		sigdeq(p, pcp->prc_thread, sig, &infop);
15420Sstevel@tonic-gate 	else
15430Sstevel@tonic-gate 		sigdeq(p, NULL, sig, &infop);
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	if (infop)
15460Sstevel@tonic-gate 		siginfofree(infop);
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	return (0);
15490Sstevel@tonic-gate }
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate int
pr_nice(proc_t * p,int nice,cred_t * cr)15520Sstevel@tonic-gate pr_nice(proc_t *p, int nice, cred_t *cr)
15530Sstevel@tonic-gate {
15540Sstevel@tonic-gate 	kthread_t *t;
15550Sstevel@tonic-gate 	int err;
15560Sstevel@tonic-gate 	int error = 0;
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	t = p->p_tlist;
15590Sstevel@tonic-gate 	do {
15600Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
15610Sstevel@tonic-gate 		err = CL_DONICE(t, cr, nice, (int *)NULL);
15626247Sraf 		schedctl_set_cidpri(t);
15630Sstevel@tonic-gate 		if (error == 0)
15640Sstevel@tonic-gate 			error = err;
15650Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 	return (error);
15680Sstevel@tonic-gate }
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate void
pr_setentryexit(proc_t * p,sysset_t * sysset,int entry)15710Sstevel@tonic-gate pr_setentryexit(proc_t *p, sysset_t *sysset, int entry)
15720Sstevel@tonic-gate {
15730Sstevel@tonic-gate 	user_t *up = PTOU(p);
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	if (entry) {
15760Sstevel@tonic-gate 		prassignset(&up->u_entrymask, sysset);
15770Sstevel@tonic-gate 	} else {
15780Sstevel@tonic-gate 		prassignset(&up->u_exitmask, sysset);
15790Sstevel@tonic-gate 	}
15800Sstevel@tonic-gate 	if (!prisempty(&up->u_entrymask) ||
15810Sstevel@tonic-gate 	    !prisempty(&up->u_exitmask)) {
15820Sstevel@tonic-gate 		up->u_systrap = 1;
15830Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
15840Sstevel@tonic-gate 		set_proc_sys(p);	/* set pre and post-sys flags */
15850Sstevel@tonic-gate 	} else {
15860Sstevel@tonic-gate 		up->u_systrap = 0;
15870Sstevel@tonic-gate 		if (sigisempty(&p->p_sigmask) &&
15880Sstevel@tonic-gate 		    prisempty(&p->p_fltmask))
15890Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
15900Sstevel@tonic-gate 	}
15910Sstevel@tonic-gate }
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate #define	ALLFLAGS	\
15940Sstevel@tonic-gate 	(PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_MSACCT|PR_MSFORK|PR_PTRACE)
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate int
pr_set(proc_t * p,long flags)15970Sstevel@tonic-gate pr_set(proc_t *p, long flags)
15980Sstevel@tonic-gate {
15990Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
16000Sstevel@tonic-gate 		return (EBUSY);
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	if (flags & ~ALLFLAGS)
16030Sstevel@tonic-gate 		return (EINVAL);
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	if (flags & PR_FORK)
16060Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_FORK;
16070Sstevel@tonic-gate 	if (flags & PR_RLC)
16080Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_RUNLCL;
16090Sstevel@tonic-gate 	if (flags & PR_KLC)
16100Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_KILLCL;
16110Sstevel@tonic-gate 	if (flags & PR_ASYNC)
16120Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_ASYNC;
16130Sstevel@tonic-gate 	if (flags & PR_BPTADJ)
16140Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_BPTADJ;
16150Sstevel@tonic-gate 	if (flags & PR_MSACCT)
16160Sstevel@tonic-gate 		if ((p->p_flag & SMSACCT) == 0)
16170Sstevel@tonic-gate 			estimate_msacct(p->p_tlist, gethrtime());
16180Sstevel@tonic-gate 	if (flags & PR_MSFORK)
16190Sstevel@tonic-gate 		p->p_flag |= SMSFORK;
16200Sstevel@tonic-gate 	if (flags & PR_PTRACE) {
16210Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_PTRACE;
16220Sstevel@tonic-gate 		/* ptraced process must die if parent dead */
16230Sstevel@tonic-gate 		if (p->p_ppid == 1)
16240Sstevel@tonic-gate 			sigtoproc(p, NULL, SIGKILL);
16250Sstevel@tonic-gate 	}
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	return (0);
16280Sstevel@tonic-gate }
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate int
pr_unset(proc_t * p,long flags)16310Sstevel@tonic-gate pr_unset(proc_t *p, long flags)
16320Sstevel@tonic-gate {
16330Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
16340Sstevel@tonic-gate 		return (EBUSY);
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	if (flags & ~ALLFLAGS)
16370Sstevel@tonic-gate 		return (EINVAL);
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	if (flags & PR_FORK)
16400Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_FORK;
16410Sstevel@tonic-gate 	if (flags & PR_RLC)
16420Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_RUNLCL;
16430Sstevel@tonic-gate 	if (flags & PR_KLC)
16440Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_KILLCL;
16450Sstevel@tonic-gate 	if (flags & PR_ASYNC)
16460Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_ASYNC;
16470Sstevel@tonic-gate 	if (flags & PR_BPTADJ)
16480Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_BPTADJ;
16490Sstevel@tonic-gate 	if (flags & PR_MSACCT)
16500Sstevel@tonic-gate 		disable_msacct(p);
16510Sstevel@tonic-gate 	if (flags & PR_MSFORK)
16520Sstevel@tonic-gate 		p->p_flag &= ~SMSFORK;
16530Sstevel@tonic-gate 	if (flags & PR_PTRACE)
16540Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_PTRACE;
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	return (0);
16570Sstevel@tonic-gate }
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate static int
pr_setfpregs(prnode_t * pnp,prfpregset_t * prfpregset)16600Sstevel@tonic-gate pr_setfpregs(prnode_t *pnp, prfpregset_t *prfpregset)
16610Sstevel@tonic-gate {
16620Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
16630Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
16660Sstevel@tonic-gate 		thread_unlock(t);
16670Sstevel@tonic-gate 		return (EBUSY);
16680Sstevel@tonic-gate 	}
16690Sstevel@tonic-gate 	if (!prhasfp()) {
16700Sstevel@tonic-gate 		thread_unlock(t);
16710Sstevel@tonic-gate 		return (EINVAL);	/* No FP support */
16720Sstevel@tonic-gate 	}
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
16750Sstevel@tonic-gate 	thread_unlock(t);
16760Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
16770Sstevel@tonic-gate 	prsetprfpregs(ttolwp(t), prfpregset);
16780Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 	return (0);
16810Sstevel@tonic-gate }
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
16840Sstevel@tonic-gate static int
pr_setfpregs32(prnode_t * pnp,prfpregset32_t * prfpregset)16850Sstevel@tonic-gate pr_setfpregs32(prnode_t *pnp, prfpregset32_t *prfpregset)
16860Sstevel@tonic-gate {
16870Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
16880Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
16910Sstevel@tonic-gate 		thread_unlock(t);
16920Sstevel@tonic-gate 		return (EBUSY);
16930Sstevel@tonic-gate 	}
16940Sstevel@tonic-gate 	if (!prhasfp()) {
16950Sstevel@tonic-gate 		thread_unlock(t);
16960Sstevel@tonic-gate 		return (EINVAL);	/* No FP support */
16970Sstevel@tonic-gate 	}
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
17000Sstevel@tonic-gate 	thread_unlock(t);
17010Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17020Sstevel@tonic-gate 	prsetprfpregs32(ttolwp(t), prfpregset);
17030Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	return (0);
17060Sstevel@tonic-gate }
17070Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate #if defined(__sparc)
17100Sstevel@tonic-gate /* ARGSUSED */
17110Sstevel@tonic-gate static int
pr_setxregs(prnode_t * pnp,prxregset_t * prxregset)17120Sstevel@tonic-gate pr_setxregs(prnode_t *pnp, prxregset_t *prxregset)
17130Sstevel@tonic-gate {
17140Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
17150Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
17180Sstevel@tonic-gate 		thread_unlock(t);
17190Sstevel@tonic-gate 		return (EBUSY);
17200Sstevel@tonic-gate 	}
17210Sstevel@tonic-gate 	thread_unlock(t);
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	if (!prhasx(p))
17240Sstevel@tonic-gate 		return (EINVAL);	/* No extra register support */
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
17270Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17280Sstevel@tonic-gate 	prsetprxregs(ttolwp(t), (caddr_t)prxregset);
17290Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	return (0);
17320Sstevel@tonic-gate }
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate static int
pr_setasrs(prnode_t * pnp,asrset_t asrset)17350Sstevel@tonic-gate pr_setasrs(prnode_t *pnp, asrset_t asrset)
17360Sstevel@tonic-gate {
17370Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
17380Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
17410Sstevel@tonic-gate 		thread_unlock(t);
17420Sstevel@tonic-gate 		return (EBUSY);
17430Sstevel@tonic-gate 	}
17440Sstevel@tonic-gate 	thread_unlock(t);
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
17470Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17480Sstevel@tonic-gate 	prsetasregs(ttolwp(t), asrset);
17490Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 	return (0);
17520Sstevel@tonic-gate }
17530Sstevel@tonic-gate #endif
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate static int
pr_setvaddr(prnode_t * pnp,caddr_t vaddr)17560Sstevel@tonic-gate pr_setvaddr(prnode_t *pnp, caddr_t vaddr)
17570Sstevel@tonic-gate {
17580Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
17590Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
17620Sstevel@tonic-gate 		thread_unlock(t);
17630Sstevel@tonic-gate 		return (EBUSY);
17640Sstevel@tonic-gate 	}
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
17670Sstevel@tonic-gate 	thread_unlock(t);
17680Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17690Sstevel@tonic-gate 	prsvaddr(ttolwp(t), vaddr);
17700Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 	return (0);
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate void
pr_sethold(prnode_t * pnp,sigset_t * sp)17760Sstevel@tonic-gate pr_sethold(prnode_t *pnp, sigset_t *sp)
17770Sstevel@tonic-gate {
17780Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
17790Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	schedctl_finish_sigblock(t);
17820Sstevel@tonic-gate 	sigutok(sp, &t->t_hold);
17833792Sakolb 	if (ISWAKEABLE(t) &&
17840Sstevel@tonic-gate 	    (fsig(&p->p_sig, t) || fsig(&t->t_sig, t)))
17850Sstevel@tonic-gate 		setrun_locked(t);
17860Sstevel@tonic-gate 	t->t_sig_check = 1;	/* so thread will see new holdmask */
17870Sstevel@tonic-gate 	thread_unlock(t);
17880Sstevel@tonic-gate }
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate void
pr_setfault(proc_t * p,fltset_t * fltp)17910Sstevel@tonic-gate pr_setfault(proc_t *p, fltset_t *fltp)
17920Sstevel@tonic-gate {
17930Sstevel@tonic-gate 	prassignset(&p->p_fltmask, fltp);
17940Sstevel@tonic-gate 	if (!prisempty(&p->p_fltmask))
17950Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
17960Sstevel@tonic-gate 	else if (sigisempty(&p->p_sigmask)) {
17970Sstevel@tonic-gate 		user_t *up = PTOU(p);
17980Sstevel@tonic-gate 		if (up->u_systrap == 0)
17990Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
18000Sstevel@tonic-gate 	}
18010Sstevel@tonic-gate }
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate static int
pr_clearsig(prnode_t * pnp)18040Sstevel@tonic-gate pr_clearsig(prnode_t *pnp)
18050Sstevel@tonic-gate {
18060Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
18070Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	thread_unlock(t);
18100Sstevel@tonic-gate 	if (lwp->lwp_cursig == SIGKILL)
18110Sstevel@tonic-gate 		return (EBUSY);
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 	/*
18140Sstevel@tonic-gate 	 * Discard current siginfo_t, if any.
18150Sstevel@tonic-gate 	 */
18160Sstevel@tonic-gate 	lwp->lwp_cursig = 0;
18170Sstevel@tonic-gate 	lwp->lwp_extsig = 0;
18180Sstevel@tonic-gate 	if (lwp->lwp_curinfo) {
18190Sstevel@tonic-gate 		siginfofree(lwp->lwp_curinfo);
18200Sstevel@tonic-gate 		lwp->lwp_curinfo = NULL;
18210Sstevel@tonic-gate 	}
18220Sstevel@tonic-gate 
18230Sstevel@tonic-gate 	return (0);
18240Sstevel@tonic-gate }
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate static int
pr_clearflt(prnode_t * pnp)18270Sstevel@tonic-gate pr_clearflt(prnode_t *pnp)
18280Sstevel@tonic-gate {
18290Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 	thread_unlock(t);
18320Sstevel@tonic-gate 	ttolwp(t)->lwp_curflt = 0;
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 	return (0);
18350Sstevel@tonic-gate }
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate static int
pr_watch(prnode_t * pnp,prwatch_t * pwp,int * unlocked)18380Sstevel@tonic-gate pr_watch(prnode_t *pnp, prwatch_t *pwp, int *unlocked)
18390Sstevel@tonic-gate {
18400Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
18410Sstevel@tonic-gate 	struct as *as = p->p_as;
18420Sstevel@tonic-gate 	uintptr_t vaddr = pwp->pr_vaddr;
18430Sstevel@tonic-gate 	size_t size = pwp->pr_size;
18440Sstevel@tonic-gate 	int wflags = pwp->pr_wflags;
18450Sstevel@tonic-gate 	ulong_t newpage = 0;
18460Sstevel@tonic-gate 	struct watched_area *pwa;
18470Sstevel@tonic-gate 	int error;
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	*unlocked = 0;
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	/*
18520Sstevel@tonic-gate 	 * Can't apply to a system process.
18530Sstevel@tonic-gate 	 */
18540Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
18550Sstevel@tonic-gate 		return (EBUSY);
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	/*
18580Sstevel@tonic-gate 	 * Verify that the address range does not wrap
18590Sstevel@tonic-gate 	 * and that only the proper flags were specified.
18600Sstevel@tonic-gate 	 */
18610Sstevel@tonic-gate 	if ((wflags & ~WA_TRAPAFTER) == 0)
18620Sstevel@tonic-gate 		size = 0;
18630Sstevel@tonic-gate 	if (vaddr + size < vaddr ||
18640Sstevel@tonic-gate 	    (wflags & ~(WA_READ|WA_WRITE|WA_EXEC|WA_TRAPAFTER)) != 0 ||
18650Sstevel@tonic-gate 	    ((wflags & ~WA_TRAPAFTER) != 0 && size == 0))
18660Sstevel@tonic-gate 		return (EINVAL);
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	/*
18690Sstevel@tonic-gate 	 * Don't let the address range go above as->a_userlimit.
18700Sstevel@tonic-gate 	 * There is no error here, just a limitation.
18710Sstevel@tonic-gate 	 */
18720Sstevel@tonic-gate 	if (vaddr >= (uintptr_t)as->a_userlimit)
18730Sstevel@tonic-gate 		return (0);
18740Sstevel@tonic-gate 	if (vaddr + size > (uintptr_t)as->a_userlimit)
18750Sstevel@tonic-gate 		size = (uintptr_t)as->a_userlimit - vaddr;
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 	/*
18780Sstevel@tonic-gate 	 * Compute maximum number of pages this will add.
18790Sstevel@tonic-gate 	 */
18800Sstevel@tonic-gate 	if ((wflags & ~WA_TRAPAFTER) != 0) {
18810Sstevel@tonic-gate 		ulong_t pagespan = (vaddr + size) - (vaddr & PAGEMASK);
18820Sstevel@tonic-gate 		newpage = btopr(pagespan);
18830Sstevel@tonic-gate 		if (newpage > 2 * prnwatch)
18840Sstevel@tonic-gate 			return (E2BIG);
18850Sstevel@tonic-gate 	}
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	/*
18880Sstevel@tonic-gate 	 * Force the process to be fully stopped.
18890Sstevel@tonic-gate 	 */
18900Sstevel@tonic-gate 	if (p == curproc) {
18910Sstevel@tonic-gate 		prunlock(pnp);
18920Sstevel@tonic-gate 		while (holdwatch() != 0)
18930Sstevel@tonic-gate 			continue;
18940Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) != 0) {
18950Sstevel@tonic-gate 			continuelwps(p);
18960Sstevel@tonic-gate 			*unlocked = 1;
18970Sstevel@tonic-gate 			return (error);
18980Sstevel@tonic-gate 		}
18990Sstevel@tonic-gate 	} else {
19000Sstevel@tonic-gate 		pauselwps(p);
19010Sstevel@tonic-gate 		while (pr_allstopped(p, 0) > 0) {
19020Sstevel@tonic-gate 			/*
19030Sstevel@tonic-gate 			 * This cv/mutex pair is persistent even
19040Sstevel@tonic-gate 			 * if the process disappears after we
19050Sstevel@tonic-gate 			 * unmark it and drop p->p_lock.
19060Sstevel@tonic-gate 			 */
19070Sstevel@tonic-gate 			kcondvar_t *cv = &pr_pid_cv[p->p_slot];
19080Sstevel@tonic-gate 			kmutex_t *mp = &p->p_lock;
19090Sstevel@tonic-gate 
19100Sstevel@tonic-gate 			prunmark(p);
19110Sstevel@tonic-gate 			(void) cv_wait(cv, mp);
19120Sstevel@tonic-gate 			mutex_exit(mp);
19130Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0) {
19140Sstevel@tonic-gate 				/*
19150Sstevel@tonic-gate 				 * Unpause the process if it exists.
19160Sstevel@tonic-gate 				 */
19170Sstevel@tonic-gate 				p = pr_p_lock(pnp);
19180Sstevel@tonic-gate 				mutex_exit(&pr_pidlock);
19190Sstevel@tonic-gate 				if (p != NULL) {
19200Sstevel@tonic-gate 					unpauselwps(p);
19210Sstevel@tonic-gate 					prunlock(pnp);
19220Sstevel@tonic-gate 				}
19230Sstevel@tonic-gate 				*unlocked = 1;
19240Sstevel@tonic-gate 				return (error);
19250Sstevel@tonic-gate 			}
19260Sstevel@tonic-gate 		}
19270Sstevel@tonic-gate 	}
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	/*
19300Sstevel@tonic-gate 	 * Drop p->p_lock in order to perform the rest of this.
19310Sstevel@tonic-gate 	 * The process is still locked with the P_PR_LOCK flag.
19320Sstevel@tonic-gate 	 */
19330Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	pwa = kmem_alloc(sizeof (struct watched_area), KM_SLEEP);
19360Sstevel@tonic-gate 	pwa->wa_vaddr = (caddr_t)vaddr;
19370Sstevel@tonic-gate 	pwa->wa_eaddr = (caddr_t)vaddr + size;
19380Sstevel@tonic-gate 	pwa->wa_flags = (ulong_t)wflags;
19390Sstevel@tonic-gate 
19406247Sraf 	error = ((pwa->wa_flags & ~WA_TRAPAFTER) == 0)?
19415771Sjp151216 	    clear_watched_area(p, pwa) : set_watched_area(p, pwa);
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	if (p == curproc) {
19440Sstevel@tonic-gate 		setallwatch();
19450Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
19460Sstevel@tonic-gate 		continuelwps(p);
19470Sstevel@tonic-gate 	} else {
19480Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
19490Sstevel@tonic-gate 		unpauselwps(p);
19500Sstevel@tonic-gate 	}
19510Sstevel@tonic-gate 
19520Sstevel@tonic-gate 	return (error);
19530Sstevel@tonic-gate }
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate /* jobcontrol stopped, but with a /proc directed stop in effect */
19560Sstevel@tonic-gate #define	JDSTOPPED(t)	\
19570Sstevel@tonic-gate 	((t)->t_state == TS_STOPPED && \
19580Sstevel@tonic-gate 	(t)->t_whystop == PR_JOBCONTROL && \
19590Sstevel@tonic-gate 	((t)->t_proc_flag & TP_PRSTOP))
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate /*
19620Sstevel@tonic-gate  * pr_agent() creates the agent lwp. If the process is exiting while
19630Sstevel@tonic-gate  * we are creating an agent lwp, then exitlwps() waits until the
19640Sstevel@tonic-gate  * agent has been created using prbarrier().
19650Sstevel@tonic-gate  */
19660Sstevel@tonic-gate static int
pr_agent(prnode_t * pnp,prgregset_t prgregset,int * unlocked)19670Sstevel@tonic-gate pr_agent(prnode_t *pnp, prgregset_t prgregset, int *unlocked)
19680Sstevel@tonic-gate {
19690Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
19700Sstevel@tonic-gate 	prcommon_t *pcp;
19710Sstevel@tonic-gate 	kthread_t *t;
19720Sstevel@tonic-gate 	kthread_t *ct;
19730Sstevel@tonic-gate 	klwp_t *clwp;
19740Sstevel@tonic-gate 	k_sigset_t smask;
19750Sstevel@tonic-gate 	int cid;
19760Sstevel@tonic-gate 	void *bufp = NULL;
19770Sstevel@tonic-gate 	int error;
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate 	*unlocked = 0;
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate 	/*
19820Sstevel@tonic-gate 	 * Cannot create the /proc agent lwp if :-
19830Sstevel@tonic-gate 	 * - the process is not fully stopped or directed to stop.
19840Sstevel@tonic-gate 	 * - there is an agent lwp already.
1985390Sraf 	 * - the process has been killed.
1986390Sraf 	 * - the process is exiting.
19870Sstevel@tonic-gate 	 * - it's a vfork(2) parent.
19880Sstevel@tonic-gate 	 */
19890Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
19900Sstevel@tonic-gate 	ASSERT(t != NULL);
19910Sstevel@tonic-gate 
1992390Sraf 	if ((!ISTOPPED(t) && !VSTOPPED(t) && !SUSPENDED(t) && !JDSTOPPED(t)) ||
1993390Sraf 	    p->p_agenttp != NULL ||
1994390Sraf 	    (p->p_flag & (SKILLED | SEXITING | SVFWAIT))) {
19950Sstevel@tonic-gate 		thread_unlock(t);
19960Sstevel@tonic-gate 		return (EBUSY);
19970Sstevel@tonic-gate 	}
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate 	thread_unlock(t);
20000Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
20010Sstevel@tonic-gate 
20020Sstevel@tonic-gate 	sigfillset(&smask);
20030Sstevel@tonic-gate 	sigdiffset(&smask, &cantmask);
20040Sstevel@tonic-gate 	clwp = lwp_create(lwp_rtt, NULL, 0, p, TS_STOPPED,
20050Sstevel@tonic-gate 	    t->t_pri, &smask, NOCLASS, 0);
20060Sstevel@tonic-gate 	if (clwp == NULL) {
20070Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
20080Sstevel@tonic-gate 		return (ENOMEM);
20090Sstevel@tonic-gate 	}
20100Sstevel@tonic-gate 	prsetprregs(clwp, prgregset, 1);
20110Sstevel@tonic-gate retry:
20120Sstevel@tonic-gate 	cid = t->t_cid;
20130Sstevel@tonic-gate 	(void) CL_ALLOC(&bufp, cid, KM_SLEEP);
20140Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
20150Sstevel@tonic-gate 	if (cid != t->t_cid) {
20160Sstevel@tonic-gate 		/*
20170Sstevel@tonic-gate 		 * Someone just changed this thread's scheduling class,
20180Sstevel@tonic-gate 		 * so try pre-allocating the buffer again.  Hopefully we
20190Sstevel@tonic-gate 		 * don't hit this often.
20200Sstevel@tonic-gate 		 */
20210Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
20220Sstevel@tonic-gate 		CL_FREE(cid, bufp);
20230Sstevel@tonic-gate 		goto retry;
20240Sstevel@tonic-gate 	}
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate 	clwp->lwp_ap = clwp->lwp_arg;
20270Sstevel@tonic-gate 	clwp->lwp_eosys = NORMALRETURN;
20280Sstevel@tonic-gate 	ct = lwptot(clwp);
20290Sstevel@tonic-gate 	ct->t_clfuncs = t->t_clfuncs;
20300Sstevel@tonic-gate 	CL_FORK(t, ct, bufp);
20310Sstevel@tonic-gate 	ct->t_cid = t->t_cid;
20320Sstevel@tonic-gate 	ct->t_proc_flag |= TP_PRSTOP;
20330Sstevel@tonic-gate 	/*
20340Sstevel@tonic-gate 	 * Setting t_sysnum to zero causes post_syscall()
20350Sstevel@tonic-gate 	 * to bypass all syscall checks and go directly to
20360Sstevel@tonic-gate 	 *	if (issig()) psig();
20370Sstevel@tonic-gate 	 * so that the agent lwp will stop in issig_forreal()
20380Sstevel@tonic-gate 	 * showing PR_REQUESTED.
20390Sstevel@tonic-gate 	 */
20400Sstevel@tonic-gate 	ct->t_sysnum = 0;
20410Sstevel@tonic-gate 	ct->t_post_sys = 1;
20420Sstevel@tonic-gate 	ct->t_sig_check = 1;
20430Sstevel@tonic-gate 	p->p_agenttp = ct;
20440Sstevel@tonic-gate 	ct->t_proc_flag &= ~TP_HOLDLWP;
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	pcp = pnp->pr_pcommon;
20470Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 	lwp_create_done(ct);
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 	/*
20520Sstevel@tonic-gate 	 * Don't return until the agent is stopped on PR_REQUESTED.
20530Sstevel@tonic-gate 	 */
20540Sstevel@tonic-gate 
20550Sstevel@tonic-gate 	for (;;) {
20560Sstevel@tonic-gate 		prunlock(pnp);
20570Sstevel@tonic-gate 		*unlocked = 1;
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate 		/*
20600Sstevel@tonic-gate 		 * Wait for the agent to stop and notify us.
20610Sstevel@tonic-gate 		 * If we've been interrupted, return that information.
20620Sstevel@tonic-gate 		 */
20634123Sdm120769 		error = pr_wait(pcp, NULL, 0);
20640Sstevel@tonic-gate 		if (error == EINTR) {
20650Sstevel@tonic-gate 			error = 0;
20660Sstevel@tonic-gate 			break;
20670Sstevel@tonic-gate 		}
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 		/*
20700Sstevel@tonic-gate 		 * Confirm that the agent LWP has stopped.
20710Sstevel@tonic-gate 		 */
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) != 0)
20740Sstevel@tonic-gate 			break;
20750Sstevel@tonic-gate 		*unlocked = 0;
20760Sstevel@tonic-gate 
20770Sstevel@tonic-gate 		/*
20780Sstevel@tonic-gate 		 * Since we dropped the lock on the process, the agent
20790Sstevel@tonic-gate 		 * may have disappeared or changed. Grab the current
20800Sstevel@tonic-gate 		 * agent and check fail if it has disappeared.
20810Sstevel@tonic-gate 		 */
20820Sstevel@tonic-gate 		if ((ct = p->p_agenttp) == NULL) {
20830Sstevel@tonic-gate 			error = ENOENT;
20840Sstevel@tonic-gate 			break;
20850Sstevel@tonic-gate 		}
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
20880Sstevel@tonic-gate 		thread_lock(ct);
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 		if (ISTOPPED(ct)) {
20910Sstevel@tonic-gate 			thread_unlock(ct);
20920Sstevel@tonic-gate 			mutex_exit(&pcp->prc_mutex);
20930Sstevel@tonic-gate 			break;
20940Sstevel@tonic-gate 		}
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 		thread_unlock(ct);
20970Sstevel@tonic-gate 	}
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 	return (error ? error : -1);
21000Sstevel@tonic-gate }
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate static int
pr_rdwr(proc_t * p,enum uio_rw rw,priovec_t * pio)21030Sstevel@tonic-gate pr_rdwr(proc_t *p, enum uio_rw rw, priovec_t *pio)
21040Sstevel@tonic-gate {
21050Sstevel@tonic-gate 	caddr_t base = (caddr_t)pio->pio_base;
21060Sstevel@tonic-gate 	size_t cnt = pio->pio_len;
21070Sstevel@tonic-gate 	uintptr_t offset = (uintptr_t)pio->pio_offset;
21080Sstevel@tonic-gate 	struct uio auio;
21090Sstevel@tonic-gate 	struct iovec aiov;
21100Sstevel@tonic-gate 	int error = 0;
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
21130Sstevel@tonic-gate 		error = EIO;
21140Sstevel@tonic-gate 	else if ((base + cnt) < base || (offset + cnt) < offset)
21150Sstevel@tonic-gate 		error = EINVAL;
21160Sstevel@tonic-gate 	else if (cnt != 0) {
21170Sstevel@tonic-gate 		aiov.iov_base = base;
21180Sstevel@tonic-gate 		aiov.iov_len = cnt;
21190Sstevel@tonic-gate 
21200Sstevel@tonic-gate 		auio.uio_loffset = offset;
21210Sstevel@tonic-gate 		auio.uio_iov = &aiov;
21220Sstevel@tonic-gate 		auio.uio_iovcnt = 1;
21230Sstevel@tonic-gate 		auio.uio_resid = cnt;
21240Sstevel@tonic-gate 		auio.uio_segflg = UIO_USERSPACE;
21250Sstevel@tonic-gate 		auio.uio_llimit = (longlong_t)MAXOFFSET_T;
21260Sstevel@tonic-gate 		auio.uio_fmode = FREAD|FWRITE;
21270Sstevel@tonic-gate 		auio.uio_extflg = UIO_COPY_DEFAULT;
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
21300Sstevel@tonic-gate 		error = prusrio(p, rw, &auio, 0);
21310Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 		/*
21340Sstevel@tonic-gate 		 * We have no way to return the i/o count,
21350Sstevel@tonic-gate 		 * like read() or write() would do, so we
21360Sstevel@tonic-gate 		 * return an error if the i/o was truncated.
21370Sstevel@tonic-gate 		 */
21380Sstevel@tonic-gate 		if (auio.uio_resid != 0 && error == 0)
21390Sstevel@tonic-gate 			error = EIO;
21400Sstevel@tonic-gate 	}
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate 	return (error);
21430Sstevel@tonic-gate }
21440Sstevel@tonic-gate 
21450Sstevel@tonic-gate static int
pr_scred(proc_t * p,prcred_t * prcred,cred_t * cr,boolean_t dogrps)21460Sstevel@tonic-gate pr_scred(proc_t *p, prcred_t *prcred, cred_t *cr, boolean_t dogrps)
21470Sstevel@tonic-gate {
21480Sstevel@tonic-gate 	kthread_t *t;
21490Sstevel@tonic-gate 	cred_t *oldcred;
21500Sstevel@tonic-gate 	cred_t *newcred;
21510Sstevel@tonic-gate 	uid_t oldruid;
21520Sstevel@tonic-gate 	int error;
21535771Sjp151216 	zone_t *zone = crgetzone(cr);
21540Sstevel@tonic-gate 
21555771Sjp151216 	if (!VALID_UID(prcred->pr_euid, zone) ||
21565771Sjp151216 	    !VALID_UID(prcred->pr_ruid, zone) ||
21575771Sjp151216 	    !VALID_UID(prcred->pr_suid, zone) ||
21585771Sjp151216 	    !VALID_GID(prcred->pr_egid, zone) ||
21595771Sjp151216 	    !VALID_GID(prcred->pr_rgid, zone) ||
21605771Sjp151216 	    !VALID_GID(prcred->pr_sgid, zone))
21610Sstevel@tonic-gate 		return (EINVAL);
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	if (dogrps) {
21640Sstevel@tonic-gate 		int ngrp = prcred->pr_ngroups;
21650Sstevel@tonic-gate 		int i;
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 		if (ngrp < 0 || ngrp > ngroups_max)
21680Sstevel@tonic-gate 			return (EINVAL);
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 		for (i = 0; i < ngrp; i++) {
21715771Sjp151216 			if (!VALID_GID(prcred->pr_groups[i], zone))
21720Sstevel@tonic-gate 				return (EINVAL);
21730Sstevel@tonic-gate 		}
21740Sstevel@tonic-gate 	}
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 	error = secpolicy_allow_setid(cr, prcred->pr_euid, B_FALSE);
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 	if (error == 0 && prcred->pr_ruid != prcred->pr_euid)
21790Sstevel@tonic-gate 		error = secpolicy_allow_setid(cr, prcred->pr_ruid, B_FALSE);
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate 	if (error == 0 && prcred->pr_suid != prcred->pr_euid &&
21820Sstevel@tonic-gate 	    prcred->pr_suid != prcred->pr_ruid)
21830Sstevel@tonic-gate 		error = secpolicy_allow_setid(cr, prcred->pr_suid, B_FALSE);
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	if (error)
21860Sstevel@tonic-gate 		return (error);
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate 	/* hold old cred so it doesn't disappear while we dup it */
21910Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
21920Sstevel@tonic-gate 	crhold(oldcred = p->p_cred);
21930Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
21940Sstevel@tonic-gate 	newcred = crdup(oldcred);
21950Sstevel@tonic-gate 	oldruid = crgetruid(oldcred);
21960Sstevel@tonic-gate 	crfree(oldcred);
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate 	/* Error checking done above */
21990Sstevel@tonic-gate 	(void) crsetresuid(newcred, prcred->pr_ruid, prcred->pr_euid,
22005771Sjp151216 	    prcred->pr_suid);
22010Sstevel@tonic-gate 	(void) crsetresgid(newcred, prcred->pr_rgid, prcred->pr_egid,
22025771Sjp151216 	    prcred->pr_sgid);
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 	if (dogrps) {
22050Sstevel@tonic-gate 		(void) crsetgroups(newcred, prcred->pr_ngroups,
22060Sstevel@tonic-gate 		    prcred->pr_groups);
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate 	}
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
22110Sstevel@tonic-gate 	oldcred = p->p_cred;
22120Sstevel@tonic-gate 	p->p_cred = newcred;
22130Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22140Sstevel@tonic-gate 	crfree(oldcred);
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	/*
22170Sstevel@tonic-gate 	 * Keep count of processes per uid consistent.
22180Sstevel@tonic-gate 	 */
22190Sstevel@tonic-gate 	if (oldruid != prcred->pr_ruid) {
22200Sstevel@tonic-gate 		zoneid_t zoneid = crgetzoneid(newcred);
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 		mutex_enter(&pidlock);
22230Sstevel@tonic-gate 		upcount_dec(oldruid, zoneid);
22240Sstevel@tonic-gate 		upcount_inc(prcred->pr_ruid, zoneid);
22250Sstevel@tonic-gate 		mutex_exit(&pidlock);
22260Sstevel@tonic-gate 	}
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate 	/*
22290Sstevel@tonic-gate 	 * Broadcast the cred change to the threads.
22300Sstevel@tonic-gate 	 */
22310Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
22320Sstevel@tonic-gate 	t = p->p_tlist;
22330Sstevel@tonic-gate 	do {
22340Sstevel@tonic-gate 		t->t_pre_sys = 1; /* so syscall will get new cred */
22350Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 	return (0);
22380Sstevel@tonic-gate }
22390Sstevel@tonic-gate 
22400Sstevel@tonic-gate /*
22410Sstevel@tonic-gate  * Change process credentials to specified zone.  Used to temporarily
22420Sstevel@tonic-gate  * set a process to run in the global zone; only transitions between
22430Sstevel@tonic-gate  * the process's actual zone and the global zone are allowed.
22440Sstevel@tonic-gate  */
22450Sstevel@tonic-gate static int
pr_szoneid(proc_t * p,zoneid_t zoneid,cred_t * cr)22460Sstevel@tonic-gate pr_szoneid(proc_t *p, zoneid_t zoneid, cred_t *cr)
22470Sstevel@tonic-gate {
22480Sstevel@tonic-gate 	kthread_t *t;
22490Sstevel@tonic-gate 	cred_t *oldcred;
22500Sstevel@tonic-gate 	cred_t *newcred;
22510Sstevel@tonic-gate 	zone_t *zptr;
22523768Ssl108498 	zoneid_t oldzoneid;
22530Sstevel@tonic-gate 
22540Sstevel@tonic-gate 	if (secpolicy_zone_config(cr) != 0)
22550Sstevel@tonic-gate 		return (EPERM);
22560Sstevel@tonic-gate 	if (zoneid != GLOBAL_ZONEID && zoneid != p->p_zone->zone_id)
22570Sstevel@tonic-gate 		return (EINVAL);
22580Sstevel@tonic-gate 	if ((zptr = zone_find_by_id(zoneid)) == NULL)
22590Sstevel@tonic-gate 		return (EINVAL);
22600Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
22610Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
22623768Ssl108498 	oldcred = p->p_cred;
22633768Ssl108498 	crhold(oldcred);
22640Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22650Sstevel@tonic-gate 	newcred = crdup(oldcred);
22663768Ssl108498 	oldzoneid = crgetzoneid(oldcred);
22670Sstevel@tonic-gate 	crfree(oldcred);
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 	crsetzone(newcred, zptr);
22700Sstevel@tonic-gate 	zone_rele(zptr);
22710Sstevel@tonic-gate 
22720Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
22730Sstevel@tonic-gate 	oldcred = p->p_cred;
22740Sstevel@tonic-gate 	p->p_cred = newcred;
22750Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22760Sstevel@tonic-gate 	crfree(oldcred);
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 	/*
22793768Ssl108498 	 * The target process is changing zones (according to its cred), so
22803768Ssl108498 	 * update the per-zone upcounts, which are based on process creds.
22813768Ssl108498 	 */
22823768Ssl108498 	if (oldzoneid != zoneid) {
22833768Ssl108498 		uid_t ruid = crgetruid(newcred);
22843768Ssl108498 
22853768Ssl108498 		mutex_enter(&pidlock);
22863768Ssl108498 		upcount_dec(ruid, oldzoneid);
22873768Ssl108498 		upcount_inc(ruid, zoneid);
22883768Ssl108498 		mutex_exit(&pidlock);
22893768Ssl108498 	}
22903768Ssl108498 	/*
22910Sstevel@tonic-gate 	 * Broadcast the cred change to the threads.
22920Sstevel@tonic-gate 	 */
22930Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
22940Sstevel@tonic-gate 	t = p->p_tlist;
22950Sstevel@tonic-gate 	do {
22960Sstevel@tonic-gate 		t->t_pre_sys = 1;	/* so syscall will get new cred */
22970Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 	return (0);
23000Sstevel@tonic-gate }
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate static int
pr_spriv(proc_t * p,prpriv_t * prpriv,cred_t * cr)23030Sstevel@tonic-gate pr_spriv(proc_t *p, prpriv_t *prpriv, cred_t *cr)
23040Sstevel@tonic-gate {
23050Sstevel@tonic-gate 	kthread_t *t;
23060Sstevel@tonic-gate 	int err;
23070Sstevel@tonic-gate 
23080Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 	if ((err = priv_pr_spriv(p, prpriv, cr)) == 0) {
23110Sstevel@tonic-gate 		/*
23120Sstevel@tonic-gate 		 * Broadcast the cred change to the threads.
23130Sstevel@tonic-gate 		 */
23140Sstevel@tonic-gate 		t = p->p_tlist;
23150Sstevel@tonic-gate 		do {
23160Sstevel@tonic-gate 			t->t_pre_sys = 1; /* so syscall will get new cred */
23170Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
23180Sstevel@tonic-gate 	}
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	return (err);
23210Sstevel@tonic-gate }
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate /*
23240Sstevel@tonic-gate  * Return -1 if the process is the parent of a vfork(1) whose child has yet to
23250Sstevel@tonic-gate  * terminate or perform an exec(2).
23260Sstevel@tonic-gate  *
23270Sstevel@tonic-gate  * Returns 0 if the process is fully stopped except for the current thread (if
23280Sstevel@tonic-gate  * we are operating on our own process), 1 otherwise.
23290Sstevel@tonic-gate  *
23300Sstevel@tonic-gate  * If the watchstop flag is set, then we ignore threads with TP_WATCHSTOP set.
23310Sstevel@tonic-gate  * See holdwatch() for details.
23320Sstevel@tonic-gate  */
23330Sstevel@tonic-gate int
pr_allstopped(proc_t * p,int watchstop)23340Sstevel@tonic-gate pr_allstopped(proc_t *p, int watchstop)
23350Sstevel@tonic-gate {
23360Sstevel@tonic-gate 	kthread_t *t;
23370Sstevel@tonic-gate 	int rv = 0;
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)	/* waiting for vfork'd child to exec */
23420Sstevel@tonic-gate 		return (-1);
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
23450Sstevel@tonic-gate 		do {
23460Sstevel@tonic-gate 			if (t == curthread || VSTOPPED(t) ||
23470Sstevel@tonic-gate 			    (watchstop && (t->t_proc_flag & TP_WATCHSTOP)))
23480Sstevel@tonic-gate 				continue;
23490Sstevel@tonic-gate 			thread_lock(t);
23500Sstevel@tonic-gate 			switch (t->t_state) {
23510Sstevel@tonic-gate 			case TS_ZOMB:
23520Sstevel@tonic-gate 			case TS_STOPPED:
23530Sstevel@tonic-gate 				break;
23540Sstevel@tonic-gate 			case TS_SLEEP:
23550Sstevel@tonic-gate 				if (!(t->t_flag & T_WAKEABLE) ||
23560Sstevel@tonic-gate 				    t->t_wchan0 == NULL)
23570Sstevel@tonic-gate 					rv = 1;
23580Sstevel@tonic-gate 				break;
23590Sstevel@tonic-gate 			default:
23600Sstevel@tonic-gate 				rv = 1;
23610Sstevel@tonic-gate 				break;
23620Sstevel@tonic-gate 			}
23630Sstevel@tonic-gate 			thread_unlock(t);
23640Sstevel@tonic-gate 		} while (rv == 0 && (t = t->t_forw) != p->p_tlist);
23650Sstevel@tonic-gate 	}
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 	return (rv);
23680Sstevel@tonic-gate }
23690Sstevel@tonic-gate 
23700Sstevel@tonic-gate /*
23710Sstevel@tonic-gate  * Cause all lwps in the process to pause (for watchpoint operations).
23720Sstevel@tonic-gate  */
23730Sstevel@tonic-gate static void
pauselwps(proc_t * p)23740Sstevel@tonic-gate pauselwps(proc_t *p)
23750Sstevel@tonic-gate {
23760Sstevel@tonic-gate 	kthread_t *t;
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
23790Sstevel@tonic-gate 	ASSERT(p != curproc);
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
23820Sstevel@tonic-gate 		do {
23830Sstevel@tonic-gate 			thread_lock(t);
23840Sstevel@tonic-gate 			t->t_proc_flag |= TP_PAUSE;
23850Sstevel@tonic-gate 			aston(t);
23863792Sakolb 			if ((ISWAKEABLE(t) && (t->t_wchan0 == NULL)) ||
23873792Sakolb 			    ISWAITING(t)) {
23883792Sakolb 				setrun_locked(t);
23890Sstevel@tonic-gate 			}
23900Sstevel@tonic-gate 			prpokethread(t);
23910Sstevel@tonic-gate 			thread_unlock(t);
23920Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
23930Sstevel@tonic-gate 	}
23940Sstevel@tonic-gate }
23950Sstevel@tonic-gate 
23960Sstevel@tonic-gate /*
23970Sstevel@tonic-gate  * undo the effects of pauselwps()
23980Sstevel@tonic-gate  */
23990Sstevel@tonic-gate static void
unpauselwps(proc_t * p)24000Sstevel@tonic-gate unpauselwps(proc_t *p)
24010Sstevel@tonic-gate {
24020Sstevel@tonic-gate 	kthread_t *t;
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
24050Sstevel@tonic-gate 	ASSERT(p != curproc);
24060Sstevel@tonic-gate 
24070Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
24080Sstevel@tonic-gate 		do {
24090Sstevel@tonic-gate 			thread_lock(t);
24100Sstevel@tonic-gate 			t->t_proc_flag &= ~TP_PAUSE;
24110Sstevel@tonic-gate 			if (t->t_state == TS_STOPPED) {
24120Sstevel@tonic-gate 				t->t_schedflag |= TS_UNPAUSE;
24130Sstevel@tonic-gate 				t->t_dtrace_stop = 0;
24140Sstevel@tonic-gate 				setrun_locked(t);
24150Sstevel@tonic-gate 			}
24160Sstevel@tonic-gate 			thread_unlock(t);
24170Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
24180Sstevel@tonic-gate 	}
24190Sstevel@tonic-gate }
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate /*
24220Sstevel@tonic-gate  * Cancel all watched areas.  Called from prclose().
24230Sstevel@tonic-gate  */
24240Sstevel@tonic-gate proc_t *
pr_cancel_watch(prnode_t * pnp)24250Sstevel@tonic-gate pr_cancel_watch(prnode_t *pnp)
24260Sstevel@tonic-gate {
24270Sstevel@tonic-gate 	proc_t *p = pnp->pr_pcommon->prc_proc;
24280Sstevel@tonic-gate 	struct as *as;
24290Sstevel@tonic-gate 	kthread_t *t;
24300Sstevel@tonic-gate 
24310Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock) && (p->p_proc_flag & P_PR_LOCK));
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	if (!pr_watch_active(p))
24340Sstevel@tonic-gate 		return (p);
24350Sstevel@tonic-gate 
24360Sstevel@tonic-gate 	/*
24370Sstevel@tonic-gate 	 * Pause the process before dealing with the watchpoints.
24380Sstevel@tonic-gate 	 */
24390Sstevel@tonic-gate 	if (p == curproc) {
24400Sstevel@tonic-gate 		prunlock(pnp);
24410Sstevel@tonic-gate 		while (holdwatch() != 0)
24420Sstevel@tonic-gate 			continue;
24430Sstevel@tonic-gate 		p = pr_p_lock(pnp);
24440Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
24450Sstevel@tonic-gate 		ASSERT(p == curproc);
24460Sstevel@tonic-gate 	} else {
24470Sstevel@tonic-gate 		pauselwps(p);
24480Sstevel@tonic-gate 		while (p != NULL && pr_allstopped(p, 0) > 0) {
24490Sstevel@tonic-gate 			/*
24500Sstevel@tonic-gate 			 * This cv/mutex pair is persistent even
24510Sstevel@tonic-gate 			 * if the process disappears after we
24520Sstevel@tonic-gate 			 * unmark it and drop p->p_lock.
24530Sstevel@tonic-gate 			 */
24540Sstevel@tonic-gate 			kcondvar_t *cv = &pr_pid_cv[p->p_slot];
24550Sstevel@tonic-gate 			kmutex_t *mp = &p->p_lock;
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 			prunmark(p);
24580Sstevel@tonic-gate 			(void) cv_wait(cv, mp);
24590Sstevel@tonic-gate 			mutex_exit(mp);
24600Sstevel@tonic-gate 			p = pr_p_lock(pnp);  /* NULL if process disappeared */
24610Sstevel@tonic-gate 			mutex_exit(&pr_pidlock);
24620Sstevel@tonic-gate 		}
24630Sstevel@tonic-gate 	}
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate 	if (p == NULL)		/* the process disappeared */
24660Sstevel@tonic-gate 		return (NULL);
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	ASSERT(p == pnp->pr_pcommon->prc_proc);
24690Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock) && (p->p_proc_flag & P_PR_LOCK));
24700Sstevel@tonic-gate 
24710Sstevel@tonic-gate 	if (pr_watch_active(p)) {
24720Sstevel@tonic-gate 		pr_free_watchpoints(p);
24730Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
24740Sstevel@tonic-gate 			do {
24750Sstevel@tonic-gate 				watch_disable(t);
24760Sstevel@tonic-gate 
24770Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
24780Sstevel@tonic-gate 		}
24790Sstevel@tonic-gate 	}
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	if ((as = p->p_as) != NULL) {
24820Sstevel@tonic-gate 		avl_tree_t *tree;
24830Sstevel@tonic-gate 		struct watched_page *pwp;
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 		/*
24860Sstevel@tonic-gate 		 * If this is the parent of a vfork, the watched page
24870Sstevel@tonic-gate 		 * list has been moved temporarily to p->p_wpage.
24880Sstevel@tonic-gate 		 */
24890Sstevel@tonic-gate 		if (avl_numnodes(&p->p_wpage) != 0)
24900Sstevel@tonic-gate 			tree = &p->p_wpage;
24910Sstevel@tonic-gate 		else
24920Sstevel@tonic-gate 			tree = &as->a_wpage;
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
24950Sstevel@tonic-gate 		AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 		for (pwp = avl_first(tree); pwp != NULL;
24980Sstevel@tonic-gate 		    pwp = AVL_NEXT(tree, pwp)) {
24990Sstevel@tonic-gate 			pwp->wp_read = 0;
25000Sstevel@tonic-gate 			pwp->wp_write = 0;
25010Sstevel@tonic-gate 			pwp->wp_exec = 0;
25020Sstevel@tonic-gate 			if ((pwp->wp_flags & WP_SETPROT) == 0) {
25030Sstevel@tonic-gate 				pwp->wp_flags |= WP_SETPROT;
25040Sstevel@tonic-gate 				pwp->wp_prot = pwp->wp_oprot;
25050Sstevel@tonic-gate 				pwp->wp_list = p->p_wprot;
25060Sstevel@tonic-gate 				p->p_wprot = pwp;
25070Sstevel@tonic-gate 			}
25080Sstevel@tonic-gate 		}
25090Sstevel@tonic-gate 
25100Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
25110Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
25120Sstevel@tonic-gate 	}
25130Sstevel@tonic-gate 
25140Sstevel@tonic-gate 	/*
25150Sstevel@tonic-gate 	 * Unpause the process now.
25160Sstevel@tonic-gate 	 */
25170Sstevel@tonic-gate 	if (p == curproc)
25180Sstevel@tonic-gate 		continuelwps(p);
25190Sstevel@tonic-gate 	else
25200Sstevel@tonic-gate 		unpauselwps(p);
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate 	return (p);
25230Sstevel@tonic-gate }
2524