xref: /titanic_51/usr/src/uts/common/fs/proc/prcontrol.c (revision dc32d872cbeb56532bcea030255db9cd79bac7da)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5956b78ccSsl108498  * Common Development and Distribution License (the "License").
6956b78ccSsl108498  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2197eda132Sraf 
227c478bd9Sstevel@tonic-gate /*
23eb9dbf0cSRoger A. Faulkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27f971a346SBryan Cantrill /*
28f971a346SBryan Cantrill  * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
29f971a346SBryan Cantrill  */
30f971a346SBryan Cantrill 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/uio.h>
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
357c478bd9Sstevel@tonic-gate #include <sys/cred.h>
367c478bd9Sstevel@tonic-gate #include <sys/policy.h>
377c478bd9Sstevel@tonic-gate #include <sys/debug.h>
387c478bd9Sstevel@tonic-gate #include <sys/errno.h>
397c478bd9Sstevel@tonic-gate #include <sys/file.h>
407c478bd9Sstevel@tonic-gate #include <sys/inline.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/proc.h>
43eb9dbf0cSRoger A. Faulkner #include <sys/brand.h>
447c478bd9Sstevel@tonic-gate #include <sys/regset.h>
457c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
467c478bd9Sstevel@tonic-gate #include <sys/systm.h>
477c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
487c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
497c478bd9Sstevel@tonic-gate #include <sys/signal.h>
507c478bd9Sstevel@tonic-gate #include <sys/auxv.h>
517c478bd9Sstevel@tonic-gate #include <sys/user.h>
527c478bd9Sstevel@tonic-gate #include <sys/class.h>
537c478bd9Sstevel@tonic-gate #include <sys/fault.h>
547c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
557c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
567c478bd9Sstevel@tonic-gate #include <sys/zone.h>
577c478bd9Sstevel@tonic-gate #include <sys/copyops.h>
587c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
597c478bd9Sstevel@tonic-gate #include <vm/as.h>
607c478bd9Sstevel@tonic-gate #include <vm/seg.h>
617c478bd9Sstevel@tonic-gate #include <fs/proc/prdata.h>
627c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static	void	pr_settrace(proc_t *, sigset_t *);
657c478bd9Sstevel@tonic-gate static	int	pr_setfpregs(prnode_t *, prfpregset_t *);
667c478bd9Sstevel@tonic-gate #if defined(__sparc)
677c478bd9Sstevel@tonic-gate static	int	pr_setxregs(prnode_t *, prxregset_t *);
687c478bd9Sstevel@tonic-gate static	int	pr_setasrs(prnode_t *, asrset_t);
697c478bd9Sstevel@tonic-gate #endif
707c478bd9Sstevel@tonic-gate static	int	pr_setvaddr(prnode_t *, caddr_t);
717c478bd9Sstevel@tonic-gate static	int	pr_clearsig(prnode_t *);
727c478bd9Sstevel@tonic-gate static	int	pr_clearflt(prnode_t *);
737c478bd9Sstevel@tonic-gate static	int	pr_watch(prnode_t *, prwatch_t *, int *);
747c478bd9Sstevel@tonic-gate static	int	pr_agent(prnode_t *, prgregset_t, int *);
757c478bd9Sstevel@tonic-gate static	int	pr_rdwr(proc_t *, enum uio_rw, priovec_t *);
767c478bd9Sstevel@tonic-gate static	int	pr_scred(proc_t *, prcred_t *, cred_t *, boolean_t);
777c478bd9Sstevel@tonic-gate static	int	pr_spriv(proc_t *, prpriv_t *, cred_t *);
787c478bd9Sstevel@tonic-gate static	int	pr_szoneid(proc_t *, zoneid_t, cred_t *);
797c478bd9Sstevel@tonic-gate static	void	pauselwps(proc_t *);
807c478bd9Sstevel@tonic-gate static	void	unpauselwps(proc_t *);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate typedef union {
837c478bd9Sstevel@tonic-gate 	long		sig;		/* PCKILL, PCUNKILL */
847c478bd9Sstevel@tonic-gate 	long		nice;		/* PCNICE */
857c478bd9Sstevel@tonic-gate 	long		timeo;		/* PCTWSTOP */
867c478bd9Sstevel@tonic-gate 	ulong_t		flags;		/* PCRUN, PCSET, PCUNSET */
877c478bd9Sstevel@tonic-gate 	caddr_t		vaddr;		/* PCSVADDR */
887c478bd9Sstevel@tonic-gate 	siginfo_t	siginfo;	/* PCSSIG */
897c478bd9Sstevel@tonic-gate 	sigset_t	sigset;		/* PCSTRACE, PCSHOLD */
907c478bd9Sstevel@tonic-gate 	fltset_t	fltset;		/* PCSFAULT */
917c478bd9Sstevel@tonic-gate 	sysset_t	sysset;		/* PCSENTRY, PCSEXIT */
927c478bd9Sstevel@tonic-gate 	prgregset_t	prgregset;	/* PCSREG, PCAGENT */
937c478bd9Sstevel@tonic-gate 	prfpregset_t	prfpregset;	/* PCSFPREG */
947c478bd9Sstevel@tonic-gate #if defined(__sparc)
957c478bd9Sstevel@tonic-gate 	prxregset_t	prxregset;	/* PCSXREG */
967c478bd9Sstevel@tonic-gate 	asrset_t	asrset;		/* PCSASRS */
977c478bd9Sstevel@tonic-gate #endif
987c478bd9Sstevel@tonic-gate 	prwatch_t	prwatch;	/* PCWATCH */
997c478bd9Sstevel@tonic-gate 	priovec_t	priovec;	/* PCREAD, PCWRITE */
1007c478bd9Sstevel@tonic-gate 	prcred_t	prcred;		/* PCSCRED */
1017c478bd9Sstevel@tonic-gate 	prpriv_t	prpriv;		/* PCSPRIV */
1027c478bd9Sstevel@tonic-gate 	long		przoneid;	/* PCSZONE */
1037c478bd9Sstevel@tonic-gate } arg_t;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static	int	pr_control(long, arg_t *, prnode_t *, cred_t *);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static size_t
1087c478bd9Sstevel@tonic-gate ctlsize(long cmd, size_t resid, arg_t *argp)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	size_t size = sizeof (long);
1117c478bd9Sstevel@tonic-gate 	size_t rnd;
1127c478bd9Sstevel@tonic-gate 	int ngrp;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	switch (cmd) {
1157c478bd9Sstevel@tonic-gate 	case PCNULL:
1167c478bd9Sstevel@tonic-gate 	case PCSTOP:
1177c478bd9Sstevel@tonic-gate 	case PCDSTOP:
1187c478bd9Sstevel@tonic-gate 	case PCWSTOP:
1197c478bd9Sstevel@tonic-gate 	case PCCSIG:
1207c478bd9Sstevel@tonic-gate 	case PCCFAULT:
1217c478bd9Sstevel@tonic-gate 		break;
1227c478bd9Sstevel@tonic-gate 	case PCSSIG:
1237c478bd9Sstevel@tonic-gate 		size += sizeof (siginfo_t);
1247c478bd9Sstevel@tonic-gate 		break;
1257c478bd9Sstevel@tonic-gate 	case PCTWSTOP:
1267c478bd9Sstevel@tonic-gate 		size += sizeof (long);
1277c478bd9Sstevel@tonic-gate 		break;
1287c478bd9Sstevel@tonic-gate 	case PCKILL:
1297c478bd9Sstevel@tonic-gate 	case PCUNKILL:
1307c478bd9Sstevel@tonic-gate 	case PCNICE:
1317c478bd9Sstevel@tonic-gate 		size += sizeof (long);
1327c478bd9Sstevel@tonic-gate 		break;
1337c478bd9Sstevel@tonic-gate 	case PCRUN:
1347c478bd9Sstevel@tonic-gate 	case PCSET:
1357c478bd9Sstevel@tonic-gate 	case PCUNSET:
1367c478bd9Sstevel@tonic-gate 		size += sizeof (ulong_t);
1377c478bd9Sstevel@tonic-gate 		break;
1387c478bd9Sstevel@tonic-gate 	case PCSVADDR:
1397c478bd9Sstevel@tonic-gate 		size += sizeof (caddr_t);
1407c478bd9Sstevel@tonic-gate 		break;
1417c478bd9Sstevel@tonic-gate 	case PCSTRACE:
1427c478bd9Sstevel@tonic-gate 	case PCSHOLD:
1437c478bd9Sstevel@tonic-gate 		size += sizeof (sigset_t);
1447c478bd9Sstevel@tonic-gate 		break;
1457c478bd9Sstevel@tonic-gate 	case PCSFAULT:
1467c478bd9Sstevel@tonic-gate 		size += sizeof (fltset_t);
1477c478bd9Sstevel@tonic-gate 		break;
1487c478bd9Sstevel@tonic-gate 	case PCSENTRY:
1497c478bd9Sstevel@tonic-gate 	case PCSEXIT:
1507c478bd9Sstevel@tonic-gate 		size += sizeof (sysset_t);
1517c478bd9Sstevel@tonic-gate 		break;
1527c478bd9Sstevel@tonic-gate 	case PCSREG:
1537c478bd9Sstevel@tonic-gate 	case PCAGENT:
1547c478bd9Sstevel@tonic-gate 		size += sizeof (prgregset_t);
1557c478bd9Sstevel@tonic-gate 		break;
1567c478bd9Sstevel@tonic-gate 	case PCSFPREG:
1577c478bd9Sstevel@tonic-gate 		size += sizeof (prfpregset_t);
1587c478bd9Sstevel@tonic-gate 		break;
1597c478bd9Sstevel@tonic-gate #if defined(__sparc)
1607c478bd9Sstevel@tonic-gate 	case PCSXREG:
1617c478bd9Sstevel@tonic-gate 		size += sizeof (prxregset_t);
1627c478bd9Sstevel@tonic-gate 		break;
1637c478bd9Sstevel@tonic-gate 	case PCSASRS:
1647c478bd9Sstevel@tonic-gate 		size += sizeof (asrset_t);
1657c478bd9Sstevel@tonic-gate 		break;
1667c478bd9Sstevel@tonic-gate #endif
1677c478bd9Sstevel@tonic-gate 	case PCWATCH:
1687c478bd9Sstevel@tonic-gate 		size += sizeof (prwatch_t);
1697c478bd9Sstevel@tonic-gate 		break;
1707c478bd9Sstevel@tonic-gate 	case PCREAD:
1717c478bd9Sstevel@tonic-gate 	case PCWRITE:
1727c478bd9Sstevel@tonic-gate 		size += sizeof (priovec_t);
1737c478bd9Sstevel@tonic-gate 		break;
1747c478bd9Sstevel@tonic-gate 	case PCSCRED:
1757c478bd9Sstevel@tonic-gate 		size += sizeof (prcred_t);
1767c478bd9Sstevel@tonic-gate 		break;
1777c478bd9Sstevel@tonic-gate 	case PCSCREDX:
1787c478bd9Sstevel@tonic-gate 		/*
1797c478bd9Sstevel@tonic-gate 		 * We cannot derefence the pr_ngroups fields if it
1807c478bd9Sstevel@tonic-gate 		 * we don't have enough data.
1817c478bd9Sstevel@tonic-gate 		 */
1827c478bd9Sstevel@tonic-gate 		if (resid < size + sizeof (prcred_t) - sizeof (gid_t))
1837c478bd9Sstevel@tonic-gate 			return (0);
1847c478bd9Sstevel@tonic-gate 		ngrp = argp->prcred.pr_ngroups;
1857c478bd9Sstevel@tonic-gate 		if (ngrp < 0 || ngrp > ngroups_max)
1867c478bd9Sstevel@tonic-gate 			return (0);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 		/* The result can be smaller than sizeof (prcred_t) */
1897c478bd9Sstevel@tonic-gate 		size += sizeof (prcred_t) - sizeof (gid_t);
1907c478bd9Sstevel@tonic-gate 		size += ngrp * sizeof (gid_t);
1917c478bd9Sstevel@tonic-gate 		break;
1927c478bd9Sstevel@tonic-gate 	case PCSPRIV:
1937c478bd9Sstevel@tonic-gate 		if (resid >= size + sizeof (prpriv_t))
1947c478bd9Sstevel@tonic-gate 			size += priv_prgetprivsize(&argp->prpriv);
1957c478bd9Sstevel@tonic-gate 		else
1967c478bd9Sstevel@tonic-gate 			return (0);
1977c478bd9Sstevel@tonic-gate 		break;
1987c478bd9Sstevel@tonic-gate 	case PCSZONE:
1997c478bd9Sstevel@tonic-gate 		size += sizeof (long);
2007c478bd9Sstevel@tonic-gate 		break;
2017c478bd9Sstevel@tonic-gate 	default:
20233955159SSuhasini Peddada 		return (0);
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	/* Round up to a multiple of long, unless exact amount written */
2067c478bd9Sstevel@tonic-gate 	if (size < resid) {
2077c478bd9Sstevel@tonic-gate 		rnd = size & (sizeof (long) - 1);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		if (rnd != 0)
2107c478bd9Sstevel@tonic-gate 			size += sizeof (long) - rnd;
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	if (size > resid)
2147c478bd9Sstevel@tonic-gate 		return (0);
2157c478bd9Sstevel@tonic-gate 	return (size);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * Control operations (lots).
2207c478bd9Sstevel@tonic-gate  */
2217c478bd9Sstevel@tonic-gate int
2227c478bd9Sstevel@tonic-gate prwritectl(vnode_t *vp, uio_t *uiop, cred_t *cr)
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate #define	MY_BUFFER_SIZE \
2257c478bd9Sstevel@tonic-gate 		100 > 1 + sizeof (arg_t) / sizeof (long) ? \
2267c478bd9Sstevel@tonic-gate 		100 : 1 + sizeof (arg_t) / sizeof (long)
2277c478bd9Sstevel@tonic-gate 	long buf[MY_BUFFER_SIZE];
2287c478bd9Sstevel@tonic-gate 	long *bufp;
2297c478bd9Sstevel@tonic-gate 	size_t resid = 0;
2307c478bd9Sstevel@tonic-gate 	size_t size;
2317c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
2327c478bd9Sstevel@tonic-gate 	int error;
2337c478bd9Sstevel@tonic-gate 	int locked = 0;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	while (uiop->uio_resid) {
2367c478bd9Sstevel@tonic-gate 		/*
2377c478bd9Sstevel@tonic-gate 		 * Read several commands in one gulp.
2387c478bd9Sstevel@tonic-gate 		 */
2397c478bd9Sstevel@tonic-gate 		bufp = buf;
2407c478bd9Sstevel@tonic-gate 		if (resid) {	/* move incomplete command to front of buffer */
2417c478bd9Sstevel@tonic-gate 			long *tail;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 			if (resid >= sizeof (buf))
2447c478bd9Sstevel@tonic-gate 				break;
2457c478bd9Sstevel@tonic-gate 			tail = (long *)((char *)buf + sizeof (buf) - resid);
2467c478bd9Sstevel@tonic-gate 			do {
2477c478bd9Sstevel@tonic-gate 				*bufp++ = *tail++;
2487c478bd9Sstevel@tonic-gate 			} while ((resid -= sizeof (long)) != 0);
2497c478bd9Sstevel@tonic-gate 		}
2507c478bd9Sstevel@tonic-gate 		resid = sizeof (buf) - ((char *)bufp - (char *)buf);
2517c478bd9Sstevel@tonic-gate 		if (resid > uiop->uio_resid)
2527c478bd9Sstevel@tonic-gate 			resid = uiop->uio_resid;
2537c478bd9Sstevel@tonic-gate 		if (error = uiomove((caddr_t)bufp, resid, UIO_WRITE, uiop))
2547c478bd9Sstevel@tonic-gate 			return (error);
2557c478bd9Sstevel@tonic-gate 		resid += (char *)bufp - (char *)buf;
2567c478bd9Sstevel@tonic-gate 		bufp = buf;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		do {		/* loop over commands in buffer */
2597c478bd9Sstevel@tonic-gate 			long cmd = bufp[0];
2607c478bd9Sstevel@tonic-gate 			arg_t *argp = (arg_t *)&bufp[1];
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 			size = ctlsize(cmd, resid, argp);
26333955159SSuhasini Peddada 			if (size == 0)	/* incomplete or invalid command */
2647c619e4dSSuhasini Peddada 				break;
2657c478bd9Sstevel@tonic-gate 			/*
2667c478bd9Sstevel@tonic-gate 			 * Perform the specified control operation.
2677c478bd9Sstevel@tonic-gate 			 */
2687c478bd9Sstevel@tonic-gate 			if (!locked) {
2697c478bd9Sstevel@tonic-gate 				if ((error = prlock(pnp, ZNO)) != 0)
2707c478bd9Sstevel@tonic-gate 					return (error);
2717c478bd9Sstevel@tonic-gate 				locked = 1;
2727c478bd9Sstevel@tonic-gate 			}
2737c478bd9Sstevel@tonic-gate 			if (error = pr_control(cmd, argp, pnp, cr)) {
2747c478bd9Sstevel@tonic-gate 				if (error == -1)	/* -1 is timeout */
2757c478bd9Sstevel@tonic-gate 					locked = 0;
2767c478bd9Sstevel@tonic-gate 				else
2777c478bd9Sstevel@tonic-gate 					return (error);
2787c478bd9Sstevel@tonic-gate 			}
2797c478bd9Sstevel@tonic-gate 			bufp = (long *)((char *)bufp + size);
2807c478bd9Sstevel@tonic-gate 		} while ((resid -= size) != 0);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		if (locked) {
2837c478bd9Sstevel@tonic-gate 			prunlock(pnp);
2847c478bd9Sstevel@tonic-gate 			locked = 0;
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 	return (resid? EINVAL : 0);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate static int
2917c478bd9Sstevel@tonic-gate pr_control(long cmd, arg_t *argp, prnode_t *pnp, cred_t *cr)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
2947c478bd9Sstevel@tonic-gate 	proc_t *p;
2957c478bd9Sstevel@tonic-gate 	int unlocked;
2967c478bd9Sstevel@tonic-gate 	int error = 0;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if (cmd == PCNULL)
2997c478bd9Sstevel@tonic-gate 		return (0);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;
3027c478bd9Sstevel@tonic-gate 	p = pcp->prc_proc;
3037c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
3047c478bd9Sstevel@tonic-gate 
30535a5a358SJonathan Adams 	/* System processes defy control. */
30635a5a358SJonathan Adams 	if (p->p_flag & SSYS) {
30735a5a358SJonathan Adams 		prunlock(pnp);
30835a5a358SJonathan Adams 		return (EBUSY);
30935a5a358SJonathan Adams 	}
31035a5a358SJonathan Adams 
3117c478bd9Sstevel@tonic-gate 	switch (cmd) {
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	default:
3147c478bd9Sstevel@tonic-gate 		error = EINVAL;
3157c478bd9Sstevel@tonic-gate 		break;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	case PCSTOP:	/* direct process or lwp to stop and wait for stop */
3187c478bd9Sstevel@tonic-gate 	case PCDSTOP:	/* direct process or lwp to stop, don't wait */
3197c478bd9Sstevel@tonic-gate 	case PCWSTOP:	/* wait for process or lwp to stop */
3207c478bd9Sstevel@tonic-gate 	case PCTWSTOP:	/* wait for process or lwp to stop, with timeout */
3217c478bd9Sstevel@tonic-gate 		{
3227c478bd9Sstevel@tonic-gate 			time_t timeo;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			/*
3257c478bd9Sstevel@tonic-gate 			 * Can't apply to a system process.
3267c478bd9Sstevel@tonic-gate 			 */
32735a5a358SJonathan Adams 			if (p->p_as == &kas) {
3287c478bd9Sstevel@tonic-gate 				error = EBUSY;
3297c478bd9Sstevel@tonic-gate 				break;
3307c478bd9Sstevel@tonic-gate 			}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 			if (cmd == PCSTOP || cmd == PCDSTOP)
3337c478bd9Sstevel@tonic-gate 				pr_stop(pnp);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 			if (cmd == PCDSTOP)
3367c478bd9Sstevel@tonic-gate 				break;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 			/*
339bda89588Sjp151216 			 * If an lwp is waiting for itself or its process,
340bda89588Sjp151216 			 * don't wait. The stopped lwp would never see the
341bda89588Sjp151216 			 * fact that it is stopped.
3427c478bd9Sstevel@tonic-gate 			 */
3437c478bd9Sstevel@tonic-gate 			if ((pcp->prc_flags & PRC_LWP)?
3447c478bd9Sstevel@tonic-gate 			    (pcp->prc_thread == curthread) : (p == curproc)) {
3457c478bd9Sstevel@tonic-gate 				if (cmd == PCWSTOP || cmd == PCTWSTOP)
3467c478bd9Sstevel@tonic-gate 					error = EBUSY;
3477c478bd9Sstevel@tonic-gate 				break;
3487c478bd9Sstevel@tonic-gate 			}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 			timeo = (cmd == PCTWSTOP)? (time_t)argp->timeo : 0;
3517c478bd9Sstevel@tonic-gate 			if ((error = pr_wait_stop(pnp, timeo)) != 0)
3527c478bd9Sstevel@tonic-gate 				return (error);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 			break;
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	case PCRUN:	/* make lwp or process runnable */
3587c478bd9Sstevel@tonic-gate 		error = pr_setrun(pnp, argp->flags);
3597c478bd9Sstevel@tonic-gate 		break;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	case PCSTRACE:	/* set signal trace mask */
3627c478bd9Sstevel@tonic-gate 		pr_settrace(p,  &argp->sigset);
3637c478bd9Sstevel@tonic-gate 		break;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	case PCSSIG:	/* set current signal */
3667c478bd9Sstevel@tonic-gate 		error = pr_setsig(pnp, &argp->siginfo);
3677c478bd9Sstevel@tonic-gate 		if (argp->siginfo.si_signo == SIGKILL && error == 0) {
3687c478bd9Sstevel@tonic-gate 			prunlock(pnp);
3697c478bd9Sstevel@tonic-gate 			pr_wait_die(pnp);
3707c478bd9Sstevel@tonic-gate 			return (-1);
3717c478bd9Sstevel@tonic-gate 		}
3727c478bd9Sstevel@tonic-gate 		break;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	case PCKILL:	/* send signal */
3757c478bd9Sstevel@tonic-gate 		error = pr_kill(pnp, (int)argp->sig, cr);
3767c478bd9Sstevel@tonic-gate 		if (error == 0 && argp->sig == SIGKILL) {
3777c478bd9Sstevel@tonic-gate 			prunlock(pnp);
3787c478bd9Sstevel@tonic-gate 			pr_wait_die(pnp);
3797c478bd9Sstevel@tonic-gate 			return (-1);
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 		break;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	case PCUNKILL:	/* delete a pending signal */
3847c478bd9Sstevel@tonic-gate 		error = pr_unkill(pnp, (int)argp->sig);
3857c478bd9Sstevel@tonic-gate 		break;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	case PCNICE:	/* set nice priority */
3887c478bd9Sstevel@tonic-gate 		error = pr_nice(p, (int)argp->nice, cr);
3897c478bd9Sstevel@tonic-gate 		break;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	case PCSENTRY:	/* set syscall entry bit mask */
3927c478bd9Sstevel@tonic-gate 	case PCSEXIT:	/* set syscall exit bit mask */
3937c478bd9Sstevel@tonic-gate 		pr_setentryexit(p, &argp->sysset, cmd == PCSENTRY);
3947c478bd9Sstevel@tonic-gate 		break;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	case PCSET:	/* set process flags */
3977c478bd9Sstevel@tonic-gate 		error = pr_set(p, argp->flags);
3987c478bd9Sstevel@tonic-gate 		break;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	case PCUNSET:	/* unset process flags */
4017c478bd9Sstevel@tonic-gate 		error = pr_unset(p, argp->flags);
4027c478bd9Sstevel@tonic-gate 		break;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	case PCSREG:	/* set general registers */
4057c478bd9Sstevel@tonic-gate 		{
4067c478bd9Sstevel@tonic-gate 			kthread_t *t = pr_thread(pnp);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 			if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
4097c478bd9Sstevel@tonic-gate 				thread_unlock(t);
4107c478bd9Sstevel@tonic-gate 				error = EBUSY;
4117c478bd9Sstevel@tonic-gate 			} else {
4127c478bd9Sstevel@tonic-gate 				thread_unlock(t);
4137c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
4147c478bd9Sstevel@tonic-gate 				prsetprregs(ttolwp(t), argp->prgregset, 0);
4157c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
4167c478bd9Sstevel@tonic-gate 			}
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	case PCSFPREG:	/* set floating-point registers */
4217c478bd9Sstevel@tonic-gate 		error = pr_setfpregs(pnp, &argp->prfpregset);
4227c478bd9Sstevel@tonic-gate 		break;
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	case PCSXREG:	/* set extra registers */
4257c478bd9Sstevel@tonic-gate #if defined(__sparc)
4267c478bd9Sstevel@tonic-gate 		error = pr_setxregs(pnp, &argp->prxregset);
4277c478bd9Sstevel@tonic-gate #else
4287c478bd9Sstevel@tonic-gate 		error = EINVAL;
4297c478bd9Sstevel@tonic-gate #endif
4307c478bd9Sstevel@tonic-gate 		break;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate #if defined(__sparc)
4337c478bd9Sstevel@tonic-gate 	case PCSASRS:	/* set ancillary state registers */
4347c478bd9Sstevel@tonic-gate 		error = pr_setasrs(pnp, argp->asrset);
4357c478bd9Sstevel@tonic-gate 		break;
4367c478bd9Sstevel@tonic-gate #endif
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	case PCSVADDR:	/* set virtual address at which to resume */
4397c478bd9Sstevel@tonic-gate 		error = pr_setvaddr(pnp, argp->vaddr);
4407c478bd9Sstevel@tonic-gate 		break;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	case PCSHOLD:	/* set signal-hold mask */
4437c478bd9Sstevel@tonic-gate 		pr_sethold(pnp, &argp->sigset);
4447c478bd9Sstevel@tonic-gate 		break;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	case PCSFAULT:	/* set mask of traced faults */
4477c478bd9Sstevel@tonic-gate 		pr_setfault(p, &argp->fltset);
4487c478bd9Sstevel@tonic-gate 		break;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	case PCCSIG:	/* clear current signal */
4517c478bd9Sstevel@tonic-gate 		error = pr_clearsig(pnp);
4527c478bd9Sstevel@tonic-gate 		break;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	case PCCFAULT:	/* clear current fault */
4557c478bd9Sstevel@tonic-gate 		error = pr_clearflt(pnp);
4567c478bd9Sstevel@tonic-gate 		break;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	case PCWATCH:	/* set or clear watched areas */
4597c478bd9Sstevel@tonic-gate 		error = pr_watch(pnp, &argp->prwatch, &unlocked);
4607c478bd9Sstevel@tonic-gate 		if (error && unlocked)
4617c478bd9Sstevel@tonic-gate 			return (error);
4627c478bd9Sstevel@tonic-gate 		break;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	case PCAGENT:	/* create the /proc agent lwp in the target process */
4657c478bd9Sstevel@tonic-gate 		error = pr_agent(pnp, argp->prgregset, &unlocked);
4667c478bd9Sstevel@tonic-gate 		if (error && unlocked)
4677c478bd9Sstevel@tonic-gate 			return (error);
4687c478bd9Sstevel@tonic-gate 		break;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	case PCREAD:	/* read from the address space */
4717c478bd9Sstevel@tonic-gate 		error = pr_rdwr(p, UIO_READ, &argp->priovec);
4727c478bd9Sstevel@tonic-gate 		break;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	case PCWRITE:	/* write to the address space */
4757c478bd9Sstevel@tonic-gate 		error = pr_rdwr(p, UIO_WRITE, &argp->priovec);
4767c478bd9Sstevel@tonic-gate 		break;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	case PCSCRED:	/* set the process credentials */
4797c478bd9Sstevel@tonic-gate 	case PCSCREDX:
4807c478bd9Sstevel@tonic-gate 		error = pr_scred(p, &argp->prcred, cr, cmd == PCSCREDX);
4817c478bd9Sstevel@tonic-gate 		break;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	case PCSPRIV:	/* set the process privileges */
4847c478bd9Sstevel@tonic-gate 		error = pr_spriv(p, &argp->prpriv, cr);
4857c478bd9Sstevel@tonic-gate 		break;
4867c478bd9Sstevel@tonic-gate 	case PCSZONE:	/* set the process's zoneid credentials */
4877c478bd9Sstevel@tonic-gate 		error = pr_szoneid(p, (zoneid_t)argp->przoneid, cr);
4887c478bd9Sstevel@tonic-gate 		break;
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (error)
4927c478bd9Sstevel@tonic-gate 		prunlock(pnp);
4937c478bd9Sstevel@tonic-gate 	return (error);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate typedef union {
4997c478bd9Sstevel@tonic-gate 	int32_t		sig;		/* PCKILL, PCUNKILL */
5007c478bd9Sstevel@tonic-gate 	int32_t		nice;		/* PCNICE */
5017c478bd9Sstevel@tonic-gate 	int32_t		timeo;		/* PCTWSTOP */
5027c478bd9Sstevel@tonic-gate 	uint32_t	flags;		/* PCRUN, PCSET, PCUNSET */
5037c478bd9Sstevel@tonic-gate 	caddr32_t	vaddr;		/* PCSVADDR */
5047c478bd9Sstevel@tonic-gate 	siginfo32_t	siginfo;	/* PCSSIG */
5057c478bd9Sstevel@tonic-gate 	sigset_t	sigset;		/* PCSTRACE, PCSHOLD */
5067c478bd9Sstevel@tonic-gate 	fltset_t	fltset;		/* PCSFAULT */
5077c478bd9Sstevel@tonic-gate 	sysset_t	sysset;		/* PCSENTRY, PCSEXIT */
5087c478bd9Sstevel@tonic-gate 	prgregset32_t	prgregset;	/* PCSREG, PCAGENT */
5097c478bd9Sstevel@tonic-gate 	prfpregset32_t	prfpregset;	/* PCSFPREG */
5107c478bd9Sstevel@tonic-gate #if defined(__sparc)
5117c478bd9Sstevel@tonic-gate 	prxregset_t	prxregset;	/* PCSXREG */
5127c478bd9Sstevel@tonic-gate #endif
5137c478bd9Sstevel@tonic-gate 	prwatch32_t	prwatch;	/* PCWATCH */
5147c478bd9Sstevel@tonic-gate 	priovec32_t	priovec;	/* PCREAD, PCWRITE */
5157c478bd9Sstevel@tonic-gate 	prcred32_t	prcred;		/* PCSCRED */
5167c478bd9Sstevel@tonic-gate 	prpriv_t	prpriv;		/* PCSPRIV */
5177c478bd9Sstevel@tonic-gate 	int32_t		przoneid;	/* PCSZONE */
5187c478bd9Sstevel@tonic-gate } arg32_t;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static	int	pr_control32(int32_t, arg32_t *, prnode_t *, cred_t *);
5217c478bd9Sstevel@tonic-gate static	int	pr_setfpregs32(prnode_t *, prfpregset32_t *);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate  * Note that while ctlsize32() can use argp, it must do so only in a way
5257c478bd9Sstevel@tonic-gate  * that assumes 32-bit rather than 64-bit alignment as argp is a pointer
5267c478bd9Sstevel@tonic-gate  * to an array of 32-bit values and only 32-bit alignment is ensured.
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate static size_t
5297c478bd9Sstevel@tonic-gate ctlsize32(int32_t cmd, size_t resid, arg32_t *argp)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate 	size_t size = sizeof (int32_t);
5327c478bd9Sstevel@tonic-gate 	size_t rnd;
5337c478bd9Sstevel@tonic-gate 	int ngrp;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	switch (cmd) {
5367c478bd9Sstevel@tonic-gate 	case PCNULL:
5377c478bd9Sstevel@tonic-gate 	case PCSTOP:
5387c478bd9Sstevel@tonic-gate 	case PCDSTOP:
5397c478bd9Sstevel@tonic-gate 	case PCWSTOP:
5407c478bd9Sstevel@tonic-gate 	case PCCSIG:
5417c478bd9Sstevel@tonic-gate 	case PCCFAULT:
5427c478bd9Sstevel@tonic-gate 		break;
5437c478bd9Sstevel@tonic-gate 	case PCSSIG:
5447c478bd9Sstevel@tonic-gate 		size += sizeof (siginfo32_t);
5457c478bd9Sstevel@tonic-gate 		break;
5467c478bd9Sstevel@tonic-gate 	case PCTWSTOP:
5477c478bd9Sstevel@tonic-gate 		size += sizeof (int32_t);
5487c478bd9Sstevel@tonic-gate 		break;
5497c478bd9Sstevel@tonic-gate 	case PCKILL:
5507c478bd9Sstevel@tonic-gate 	case PCUNKILL:
5517c478bd9Sstevel@tonic-gate 	case PCNICE:
5527c478bd9Sstevel@tonic-gate 		size += sizeof (int32_t);
5537c478bd9Sstevel@tonic-gate 		break;
5547c478bd9Sstevel@tonic-gate 	case PCRUN:
5557c478bd9Sstevel@tonic-gate 	case PCSET:
5567c478bd9Sstevel@tonic-gate 	case PCUNSET:
5577c478bd9Sstevel@tonic-gate 		size += sizeof (uint32_t);
5587c478bd9Sstevel@tonic-gate 		break;
5597c478bd9Sstevel@tonic-gate 	case PCSVADDR:
5607c478bd9Sstevel@tonic-gate 		size += sizeof (caddr32_t);
5617c478bd9Sstevel@tonic-gate 		break;
5627c478bd9Sstevel@tonic-gate 	case PCSTRACE:
5637c478bd9Sstevel@tonic-gate 	case PCSHOLD:
5647c478bd9Sstevel@tonic-gate 		size += sizeof (sigset_t);
5657c478bd9Sstevel@tonic-gate 		break;
5667c478bd9Sstevel@tonic-gate 	case PCSFAULT:
5677c478bd9Sstevel@tonic-gate 		size += sizeof (fltset_t);
5687c478bd9Sstevel@tonic-gate 		break;
5697c478bd9Sstevel@tonic-gate 	case PCSENTRY:
5707c478bd9Sstevel@tonic-gate 	case PCSEXIT:
5717c478bd9Sstevel@tonic-gate 		size += sizeof (sysset_t);
5727c478bd9Sstevel@tonic-gate 		break;
5737c478bd9Sstevel@tonic-gate 	case PCSREG:
5747c478bd9Sstevel@tonic-gate 	case PCAGENT:
5757c478bd9Sstevel@tonic-gate 		size += sizeof (prgregset32_t);
5767c478bd9Sstevel@tonic-gate 		break;
5777c478bd9Sstevel@tonic-gate 	case PCSFPREG:
5787c478bd9Sstevel@tonic-gate 		size += sizeof (prfpregset32_t);
5797c478bd9Sstevel@tonic-gate 		break;
5807c478bd9Sstevel@tonic-gate #if defined(__sparc)
5817c478bd9Sstevel@tonic-gate 	case PCSXREG:
5827c478bd9Sstevel@tonic-gate 		size += sizeof (prxregset_t);
5837c478bd9Sstevel@tonic-gate 		break;
5847c478bd9Sstevel@tonic-gate #endif
5857c478bd9Sstevel@tonic-gate 	case PCWATCH:
5867c478bd9Sstevel@tonic-gate 		size += sizeof (prwatch32_t);
5877c478bd9Sstevel@tonic-gate 		break;
5887c478bd9Sstevel@tonic-gate 	case PCREAD:
5897c478bd9Sstevel@tonic-gate 	case PCWRITE:
5907c478bd9Sstevel@tonic-gate 		size += sizeof (priovec32_t);
5917c478bd9Sstevel@tonic-gate 		break;
5927c478bd9Sstevel@tonic-gate 	case PCSCRED:
5937c478bd9Sstevel@tonic-gate 		size += sizeof (prcred32_t);
5947c478bd9Sstevel@tonic-gate 		break;
5957c478bd9Sstevel@tonic-gate 	case PCSCREDX:
5967c478bd9Sstevel@tonic-gate 		/*
5977c478bd9Sstevel@tonic-gate 		 * We cannot derefence the pr_ngroups fields if it
5987c478bd9Sstevel@tonic-gate 		 * we don't have enough data.
5997c478bd9Sstevel@tonic-gate 		 */
6007c478bd9Sstevel@tonic-gate 		if (resid < size + sizeof (prcred32_t) - sizeof (gid32_t))
6017c478bd9Sstevel@tonic-gate 			return (0);
6027c478bd9Sstevel@tonic-gate 		ngrp = argp->prcred.pr_ngroups;
6037c478bd9Sstevel@tonic-gate 		if (ngrp < 0 || ngrp > ngroups_max)
6047c478bd9Sstevel@tonic-gate 			return (0);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 		/* The result can be smaller than sizeof (prcred32_t) */
6077c478bd9Sstevel@tonic-gate 		size += sizeof (prcred32_t) - sizeof (gid32_t);
6087c478bd9Sstevel@tonic-gate 		size += ngrp * sizeof (gid32_t);
6097c478bd9Sstevel@tonic-gate 		break;
6107c478bd9Sstevel@tonic-gate 	case PCSPRIV:
6117c478bd9Sstevel@tonic-gate 		if (resid >= size + sizeof (prpriv_t))
6127c478bd9Sstevel@tonic-gate 			size += priv_prgetprivsize(&argp->prpriv);
6137c478bd9Sstevel@tonic-gate 		else
6147c478bd9Sstevel@tonic-gate 			return (0);
6157c478bd9Sstevel@tonic-gate 		break;
6167c478bd9Sstevel@tonic-gate 	case PCSZONE:
6177c478bd9Sstevel@tonic-gate 		size += sizeof (int32_t);
6187c478bd9Sstevel@tonic-gate 		break;
6197c478bd9Sstevel@tonic-gate 	default:
6207c478bd9Sstevel@tonic-gate 		return (0);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	/* Round up to a multiple of int32_t */
6247c478bd9Sstevel@tonic-gate 	rnd = size & (sizeof (int32_t) - 1);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (rnd != 0)
6277c478bd9Sstevel@tonic-gate 		size += sizeof (int32_t) - rnd;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	if (size > resid)
6307c478bd9Sstevel@tonic-gate 		return (0);
6317c478bd9Sstevel@tonic-gate 	return (size);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate /*
6357c478bd9Sstevel@tonic-gate  * Control operations (lots).
6367c478bd9Sstevel@tonic-gate  */
6377c478bd9Sstevel@tonic-gate int
6387c478bd9Sstevel@tonic-gate prwritectl32(struct vnode *vp, struct uio *uiop, cred_t *cr)
6397c478bd9Sstevel@tonic-gate {
6407c478bd9Sstevel@tonic-gate #define	MY_BUFFER_SIZE32 \
6417c478bd9Sstevel@tonic-gate 		100 > 1 + sizeof (arg32_t) / sizeof (int32_t) ? \
6427c478bd9Sstevel@tonic-gate 		100 : 1 + sizeof (arg32_t) / sizeof (int32_t)
6437c478bd9Sstevel@tonic-gate 	int32_t buf[MY_BUFFER_SIZE32];
6447c478bd9Sstevel@tonic-gate 	int32_t *bufp;
6457c478bd9Sstevel@tonic-gate 	arg32_t arg;
6467c478bd9Sstevel@tonic-gate 	size_t resid = 0;
6477c478bd9Sstevel@tonic-gate 	size_t size;
6487c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
6497c478bd9Sstevel@tonic-gate 	int error;
6507c478bd9Sstevel@tonic-gate 	int locked = 0;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	while (uiop->uio_resid) {
6537c478bd9Sstevel@tonic-gate 		/*
6547c478bd9Sstevel@tonic-gate 		 * Read several commands in one gulp.
6557c478bd9Sstevel@tonic-gate 		 */
6567c478bd9Sstevel@tonic-gate 		bufp = buf;
6577c478bd9Sstevel@tonic-gate 		if (resid) {	/* move incomplete command to front of buffer */
6587c478bd9Sstevel@tonic-gate 			int32_t *tail;
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 			if (resid >= sizeof (buf))
6617c478bd9Sstevel@tonic-gate 				break;
6627c478bd9Sstevel@tonic-gate 			tail = (int32_t *)((char *)buf + sizeof (buf) - resid);
6637c478bd9Sstevel@tonic-gate 			do {
6647c478bd9Sstevel@tonic-gate 				*bufp++ = *tail++;
6657c478bd9Sstevel@tonic-gate 			} while ((resid -= sizeof (int32_t)) != 0);
6667c478bd9Sstevel@tonic-gate 		}
6677c478bd9Sstevel@tonic-gate 		resid = sizeof (buf) - ((char *)bufp - (char *)buf);
6687c478bd9Sstevel@tonic-gate 		if (resid > uiop->uio_resid)
6697c478bd9Sstevel@tonic-gate 			resid = uiop->uio_resid;
6707c478bd9Sstevel@tonic-gate 		if (error = uiomove((caddr_t)bufp, resid, UIO_WRITE, uiop))
6717c478bd9Sstevel@tonic-gate 			return (error);
6727c478bd9Sstevel@tonic-gate 		resid += (char *)bufp - (char *)buf;
6737c478bd9Sstevel@tonic-gate 		bufp = buf;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		do {		/* loop over commands in buffer */
6767c478bd9Sstevel@tonic-gate 			int32_t cmd = bufp[0];
6777c478bd9Sstevel@tonic-gate 			arg32_t *argp = (arg32_t *)&bufp[1];
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 			size = ctlsize32(cmd, resid, argp);
68033955159SSuhasini Peddada 			if (size == 0)	/* incomplete or invalid command */
6817c619e4dSSuhasini Peddada 				break;
6827c478bd9Sstevel@tonic-gate 			/*
6837c478bd9Sstevel@tonic-gate 			 * Perform the specified control operation.
6847c478bd9Sstevel@tonic-gate 			 */
6857c478bd9Sstevel@tonic-gate 			if (!locked) {
6867c478bd9Sstevel@tonic-gate 				if ((error = prlock(pnp, ZNO)) != 0)
6877c478bd9Sstevel@tonic-gate 					return (error);
6887c478bd9Sstevel@tonic-gate 				locked = 1;
6897c478bd9Sstevel@tonic-gate 			}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 			/*
6927c478bd9Sstevel@tonic-gate 			 * Since some members of the arg32_t union contain
6937c478bd9Sstevel@tonic-gate 			 * 64-bit values (which must be 64-bit aligned), we
6947c478bd9Sstevel@tonic-gate 			 * can't simply pass a pointer to the structure as
6957c478bd9Sstevel@tonic-gate 			 * it may be unaligned. Note that we do pass the
6967c478bd9Sstevel@tonic-gate 			 * potentially unaligned structure to ctlsize32()
6977c478bd9Sstevel@tonic-gate 			 * above, but that uses it a way that makes no
6987c478bd9Sstevel@tonic-gate 			 * assumptions about alignment.
6997c478bd9Sstevel@tonic-gate 			 */
7007c478bd9Sstevel@tonic-gate 			ASSERT(size - sizeof (cmd) <= sizeof (arg));
7017c478bd9Sstevel@tonic-gate 			bcopy(argp, &arg, size - sizeof (cmd));
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 			if (error = pr_control32(cmd, &arg, pnp, cr)) {
7047c478bd9Sstevel@tonic-gate 				if (error == -1)	/* -1 is timeout */
7057c478bd9Sstevel@tonic-gate 					locked = 0;
7067c478bd9Sstevel@tonic-gate 				else
7077c478bd9Sstevel@tonic-gate 					return (error);
7087c478bd9Sstevel@tonic-gate 			}
7097c478bd9Sstevel@tonic-gate 			bufp = (int32_t *)((char *)bufp + size);
7107c478bd9Sstevel@tonic-gate 		} while ((resid -= size) != 0);
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 		if (locked) {
7137c478bd9Sstevel@tonic-gate 			prunlock(pnp);
7147c478bd9Sstevel@tonic-gate 			locked = 0;
7157c478bd9Sstevel@tonic-gate 		}
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 	return (resid? EINVAL : 0);
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate static int
7217c478bd9Sstevel@tonic-gate pr_control32(int32_t cmd, arg32_t *argp, prnode_t *pnp, cred_t *cr)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
7247c478bd9Sstevel@tonic-gate 	proc_t *p;
7257c478bd9Sstevel@tonic-gate 	int unlocked;
7267c478bd9Sstevel@tonic-gate 	int error = 0;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	if (cmd == PCNULL)
7297c478bd9Sstevel@tonic-gate 		return (0);
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;
7327c478bd9Sstevel@tonic-gate 	p = pcp->prc_proc;
7337c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
7347c478bd9Sstevel@tonic-gate 
73535a5a358SJonathan Adams 	if (p->p_flag & SSYS) {
73635a5a358SJonathan Adams 		prunlock(pnp);
73735a5a358SJonathan Adams 		return (EBUSY);
73835a5a358SJonathan Adams 	}
73935a5a358SJonathan Adams 
7407c478bd9Sstevel@tonic-gate 	switch (cmd) {
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	default:
7437c478bd9Sstevel@tonic-gate 		error = EINVAL;
7447c478bd9Sstevel@tonic-gate 		break;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	case PCSTOP:	/* direct process or lwp to stop and wait for stop */
7477c478bd9Sstevel@tonic-gate 	case PCDSTOP:	/* direct process or lwp to stop, don't wait */
7487c478bd9Sstevel@tonic-gate 	case PCWSTOP:	/* wait for process or lwp to stop */
7497c478bd9Sstevel@tonic-gate 	case PCTWSTOP:	/* wait for process or lwp to stop, with timeout */
7507c478bd9Sstevel@tonic-gate 		{
7517c478bd9Sstevel@tonic-gate 			time_t timeo;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 			/*
7547c478bd9Sstevel@tonic-gate 			 * Can't apply to a system process.
7557c478bd9Sstevel@tonic-gate 			 */
75635a5a358SJonathan Adams 			if (p->p_as == &kas) {
7577c478bd9Sstevel@tonic-gate 				error = EBUSY;
7587c478bd9Sstevel@tonic-gate 				break;
7597c478bd9Sstevel@tonic-gate 			}
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 			if (cmd == PCSTOP || cmd == PCDSTOP)
7627c478bd9Sstevel@tonic-gate 				pr_stop(pnp);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 			if (cmd == PCDSTOP)
7657c478bd9Sstevel@tonic-gate 				break;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 			/*
768bda89588Sjp151216 			 * If an lwp is waiting for itself or its process,
769bda89588Sjp151216 			 * don't wait. The lwp will never see the fact that
770bda89588Sjp151216 			 * itself is stopped.
7717c478bd9Sstevel@tonic-gate 			 */
7727c478bd9Sstevel@tonic-gate 			if ((pcp->prc_flags & PRC_LWP)?
7737c478bd9Sstevel@tonic-gate 			    (pcp->prc_thread == curthread) : (p == curproc)) {
7747c478bd9Sstevel@tonic-gate 				if (cmd == PCWSTOP || cmd == PCTWSTOP)
7757c478bd9Sstevel@tonic-gate 					error = EBUSY;
7767c478bd9Sstevel@tonic-gate 				break;
7777c478bd9Sstevel@tonic-gate 			}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 			timeo = (cmd == PCTWSTOP)? (time_t)argp->timeo : 0;
7807c478bd9Sstevel@tonic-gate 			if ((error = pr_wait_stop(pnp, timeo)) != 0)
7817c478bd9Sstevel@tonic-gate 				return (error);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 			break;
7847c478bd9Sstevel@tonic-gate 		}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	case PCRUN:	/* make lwp or process runnable */
7877c478bd9Sstevel@tonic-gate 		error = pr_setrun(pnp, (ulong_t)argp->flags);
7887c478bd9Sstevel@tonic-gate 		break;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	case PCSTRACE:	/* set signal trace mask */
7917c478bd9Sstevel@tonic-gate 		pr_settrace(p,  &argp->sigset);
7927c478bd9Sstevel@tonic-gate 		break;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	case PCSSIG:	/* set current signal */
7957c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
7967c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
7977c478bd9Sstevel@tonic-gate 		else {
7987c478bd9Sstevel@tonic-gate 			int sig = (int)argp->siginfo.si_signo;
7997c478bd9Sstevel@tonic-gate 			siginfo_t siginfo;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
8027c478bd9Sstevel@tonic-gate 			siginfo_32tok(&argp->siginfo, (k_siginfo_t *)&siginfo);
8037c478bd9Sstevel@tonic-gate 			error = pr_setsig(pnp, &siginfo);
8047c478bd9Sstevel@tonic-gate 			if (sig == SIGKILL && error == 0) {
8057c478bd9Sstevel@tonic-gate 				prunlock(pnp);
8067c478bd9Sstevel@tonic-gate 				pr_wait_die(pnp);
8077c478bd9Sstevel@tonic-gate 				return (-1);
8087c478bd9Sstevel@tonic-gate 			}
8097c478bd9Sstevel@tonic-gate 		}
8107c478bd9Sstevel@tonic-gate 		break;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	case PCKILL:	/* send signal */
8137c478bd9Sstevel@tonic-gate 		error = pr_kill(pnp, (int)argp->sig, cr);
8147c478bd9Sstevel@tonic-gate 		if (error == 0 && argp->sig == SIGKILL) {
8157c478bd9Sstevel@tonic-gate 			prunlock(pnp);
8167c478bd9Sstevel@tonic-gate 			pr_wait_die(pnp);
8177c478bd9Sstevel@tonic-gate 			return (-1);
8187c478bd9Sstevel@tonic-gate 		}
8197c478bd9Sstevel@tonic-gate 		break;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	case PCUNKILL:	/* delete a pending signal */
8227c478bd9Sstevel@tonic-gate 		error = pr_unkill(pnp, (int)argp->sig);
8237c478bd9Sstevel@tonic-gate 		break;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	case PCNICE:	/* set nice priority */
8267c478bd9Sstevel@tonic-gate 		error = pr_nice(p, (int)argp->nice, cr);
8277c478bd9Sstevel@tonic-gate 		break;
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	case PCSENTRY:	/* set syscall entry bit mask */
8307c478bd9Sstevel@tonic-gate 	case PCSEXIT:	/* set syscall exit bit mask */
8317c478bd9Sstevel@tonic-gate 		pr_setentryexit(p, &argp->sysset, cmd == PCSENTRY);
8327c478bd9Sstevel@tonic-gate 		break;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	case PCSET:	/* set process flags */
8357c478bd9Sstevel@tonic-gate 		error = pr_set(p, (long)argp->flags);
8367c478bd9Sstevel@tonic-gate 		break;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	case PCUNSET:	/* unset process flags */
8397c478bd9Sstevel@tonic-gate 		error = pr_unset(p, (long)argp->flags);
8407c478bd9Sstevel@tonic-gate 		break;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	case PCSREG:	/* set general registers */
8437c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
8447c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
8457c478bd9Sstevel@tonic-gate 		else {
8467c478bd9Sstevel@tonic-gate 			kthread_t *t = pr_thread(pnp);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 			if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
8497c478bd9Sstevel@tonic-gate 				thread_unlock(t);
8507c478bd9Sstevel@tonic-gate 				error = EBUSY;
8517c478bd9Sstevel@tonic-gate 			} else {
8527c478bd9Sstevel@tonic-gate 				prgregset_t prgregset;
8537c478bd9Sstevel@tonic-gate 				klwp_t *lwp = ttolwp(t);
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 				thread_unlock(t);
8567c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
8577c478bd9Sstevel@tonic-gate 				prgregset_32ton(lwp, argp->prgregset,
8587c478bd9Sstevel@tonic-gate 				    prgregset);
8597c478bd9Sstevel@tonic-gate 				prsetprregs(lwp, prgregset, 0);
8607c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
8617c478bd9Sstevel@tonic-gate 			}
8627c478bd9Sstevel@tonic-gate 		}
8637c478bd9Sstevel@tonic-gate 		break;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	case PCSFPREG:	/* set floating-point registers */
8667c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
8677c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
8687c478bd9Sstevel@tonic-gate 		else
8697c478bd9Sstevel@tonic-gate 			error = pr_setfpregs32(pnp, &argp->prfpregset);
8707c478bd9Sstevel@tonic-gate 		break;
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	case PCSXREG:	/* set extra registers */
8737c478bd9Sstevel@tonic-gate #if defined(__sparc)
8747c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
8757c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
8767c478bd9Sstevel@tonic-gate 		else
8777c478bd9Sstevel@tonic-gate 			error = pr_setxregs(pnp, &argp->prxregset);
8787c478bd9Sstevel@tonic-gate #else
8797c478bd9Sstevel@tonic-gate 		error = EINVAL;
8807c478bd9Sstevel@tonic-gate #endif
8817c478bd9Sstevel@tonic-gate 		break;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	case PCSVADDR:	/* set virtual address at which to resume */
8847c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
8857c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
8867c478bd9Sstevel@tonic-gate 		else
8877c478bd9Sstevel@tonic-gate 			error = pr_setvaddr(pnp,
8887c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)argp->vaddr);
8897c478bd9Sstevel@tonic-gate 		break;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	case PCSHOLD:	/* set signal-hold mask */
8927c478bd9Sstevel@tonic-gate 		pr_sethold(pnp, &argp->sigset);
8937c478bd9Sstevel@tonic-gate 		break;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	case PCSFAULT:	/* set mask of traced faults */
8967c478bd9Sstevel@tonic-gate 		pr_setfault(p, &argp->fltset);
8977c478bd9Sstevel@tonic-gate 		break;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	case PCCSIG:	/* clear current signal */
9007c478bd9Sstevel@tonic-gate 		error = pr_clearsig(pnp);
9017c478bd9Sstevel@tonic-gate 		break;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	case PCCFAULT:	/* clear current fault */
9047c478bd9Sstevel@tonic-gate 		error = pr_clearflt(pnp);
9057c478bd9Sstevel@tonic-gate 		break;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	case PCWATCH:	/* set or clear watched areas */
9087c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
9097c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
9107c478bd9Sstevel@tonic-gate 		else {
9117c478bd9Sstevel@tonic-gate 			prwatch_t prwatch;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 			prwatch.pr_vaddr = argp->prwatch.pr_vaddr;
9147c478bd9Sstevel@tonic-gate 			prwatch.pr_size = argp->prwatch.pr_size;
9157c478bd9Sstevel@tonic-gate 			prwatch.pr_wflags = argp->prwatch.pr_wflags;
9167c478bd9Sstevel@tonic-gate 			prwatch.pr_pad = argp->prwatch.pr_pad;
9177c478bd9Sstevel@tonic-gate 			error = pr_watch(pnp, &prwatch, &unlocked);
9187c478bd9Sstevel@tonic-gate 			if (error && unlocked)
9197c478bd9Sstevel@tonic-gate 				return (error);
9207c478bd9Sstevel@tonic-gate 		}
9217c478bd9Sstevel@tonic-gate 		break;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	case PCAGENT:	/* create the /proc agent lwp in the target process */
9247c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
9257c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
9267c478bd9Sstevel@tonic-gate 		else {
9277c478bd9Sstevel@tonic-gate 			prgregset_t prgregset;
9287c478bd9Sstevel@tonic-gate 			kthread_t *t = pr_thread(pnp);
9297c478bd9Sstevel@tonic-gate 			klwp_t *lwp = ttolwp(t);
9307c478bd9Sstevel@tonic-gate 			thread_unlock(t);
9317c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
9327c478bd9Sstevel@tonic-gate 			prgregset_32ton(lwp, argp->prgregset, prgregset);
9337c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
9347c478bd9Sstevel@tonic-gate 			error = pr_agent(pnp, prgregset, &unlocked);
9357c478bd9Sstevel@tonic-gate 			if (error && unlocked)
9367c478bd9Sstevel@tonic-gate 				return (error);
9377c478bd9Sstevel@tonic-gate 		}
9387c478bd9Sstevel@tonic-gate 		break;
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	case PCREAD:	/* read from the address space */
9417c478bd9Sstevel@tonic-gate 	case PCWRITE:	/* write to the address space */
942d1b18d1aSBryan Cantrill 		if (PROCESS_NOT_32BIT(p) || (pnp->pr_flags & PR_OFFMAX))
9437c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
9447c478bd9Sstevel@tonic-gate 		else {
9457c478bd9Sstevel@tonic-gate 			enum uio_rw rw = (cmd == PCREAD)? UIO_READ : UIO_WRITE;
9467c478bd9Sstevel@tonic-gate 			priovec_t priovec;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 			priovec.pio_base =
9497c478bd9Sstevel@tonic-gate 			    (void *)(uintptr_t)argp->priovec.pio_base;
9507c478bd9Sstevel@tonic-gate 			priovec.pio_len = (size_t)argp->priovec.pio_len;
9517c478bd9Sstevel@tonic-gate 			priovec.pio_offset = (off_t)
9527c478bd9Sstevel@tonic-gate 			    (uint32_t)argp->priovec.pio_offset;
9537c478bd9Sstevel@tonic-gate 			error = pr_rdwr(p, rw, &priovec);
9547c478bd9Sstevel@tonic-gate 		}
9557c478bd9Sstevel@tonic-gate 		break;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	case PCSCRED:	/* set the process credentials */
9587c478bd9Sstevel@tonic-gate 	case PCSCREDX:
9597c478bd9Sstevel@tonic-gate 		{
9607c478bd9Sstevel@tonic-gate 			/*
961bda89588Sjp151216 			 * All the fields in these structures are exactly the
962bda89588Sjp151216 			 * same and so the structures are compatible.  In case
963bda89588Sjp151216 			 * this ever changes, we catch this with the ASSERT
964bda89588Sjp151216 			 * below.
9657c478bd9Sstevel@tonic-gate 			 */
9667c478bd9Sstevel@tonic-gate 			prcred_t *prcred = (prcred_t *)&argp->prcred;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate #ifndef __lint
9697c478bd9Sstevel@tonic-gate 			ASSERT(sizeof (prcred_t) == sizeof (prcred32_t));
9707c478bd9Sstevel@tonic-gate #endif
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 			error = pr_scred(p, prcred, cr, cmd == PCSCREDX);
9737c478bd9Sstevel@tonic-gate 			break;
9747c478bd9Sstevel@tonic-gate 		}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	case PCSPRIV:	/* set the process privileges */
9777c478bd9Sstevel@tonic-gate 		error = pr_spriv(p, &argp->prpriv, cr);
9787c478bd9Sstevel@tonic-gate 		break;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	case PCSZONE:	/* set the process's zoneid */
9817c478bd9Sstevel@tonic-gate 		error = pr_szoneid(p, (zoneid_t)argp->przoneid, cr);
9827c478bd9Sstevel@tonic-gate 		break;
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	if (error)
9867c478bd9Sstevel@tonic-gate 		prunlock(pnp);
9877c478bd9Sstevel@tonic-gate 	return (error);
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate /*
9937c478bd9Sstevel@tonic-gate  * Return the specific or chosen thread/lwp for a control operation.
9947c478bd9Sstevel@tonic-gate  * Returns with the thread locked via thread_lock(t).
9957c478bd9Sstevel@tonic-gate  */
9967c478bd9Sstevel@tonic-gate kthread_t *
9977c478bd9Sstevel@tonic-gate pr_thread(prnode_t *pnp)
9987c478bd9Sstevel@tonic-gate {
9997c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
10007c478bd9Sstevel@tonic-gate 	kthread_t *t;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {
10037c478bd9Sstevel@tonic-gate 		t = pcp->prc_thread;
10047c478bd9Sstevel@tonic-gate 		ASSERT(t != NULL);
10057c478bd9Sstevel@tonic-gate 		thread_lock(t);
10067c478bd9Sstevel@tonic-gate 	} else {
10077c478bd9Sstevel@tonic-gate 		proc_t *p = pcp->prc_proc;
10087c478bd9Sstevel@tonic-gate 		t = prchoose(p);	/* returns locked thread */
10097c478bd9Sstevel@tonic-gate 		ASSERT(t != NULL);
10107c478bd9Sstevel@tonic-gate 	}
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	return (t);
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate /*
10167c478bd9Sstevel@tonic-gate  * Direct the process or lwp to stop.
10177c478bd9Sstevel@tonic-gate  */
10187c478bd9Sstevel@tonic-gate void
10197c478bd9Sstevel@tonic-gate pr_stop(prnode_t *pnp)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
10227c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
10237c478bd9Sstevel@tonic-gate 	kthread_t *t;
10247c478bd9Sstevel@tonic-gate 	vnode_t *vp;
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	/*
10277c478bd9Sstevel@tonic-gate 	 * If already stopped, do nothing; otherwise flag
10287c478bd9Sstevel@tonic-gate 	 * it to be stopped the next time it tries to run.
10297c478bd9Sstevel@tonic-gate 	 * If sleeping at interruptible priority, set it
10307c478bd9Sstevel@tonic-gate 	 * running so it will stop within cv_wait_sig().
10317c478bd9Sstevel@tonic-gate 	 *
10327c478bd9Sstevel@tonic-gate 	 * Take care to cooperate with jobcontrol: if an lwp
10337c478bd9Sstevel@tonic-gate 	 * is stopped due to the default action of a jobcontrol
10347c478bd9Sstevel@tonic-gate 	 * stop signal, flag it to be stopped the next time it
10357c478bd9Sstevel@tonic-gate 	 * starts due to a SIGCONT signal.
10367c478bd9Sstevel@tonic-gate 	 */
10377c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP)
10387c478bd9Sstevel@tonic-gate 		t = pcp->prc_thread;
10397c478bd9Sstevel@tonic-gate 	else
10407c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
10417c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	do {
10447c478bd9Sstevel@tonic-gate 		int notify;
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 		notify = 0;
10477c478bd9Sstevel@tonic-gate 		thread_lock(t);
10487c478bd9Sstevel@tonic-gate 		if (!ISTOPPED(t)) {
10497c478bd9Sstevel@tonic-gate 			t->t_proc_flag |= TP_PRSTOP;
10507c478bd9Sstevel@tonic-gate 			t->t_sig_check = 1;	/* do ISSIG */
10517c478bd9Sstevel@tonic-gate 		}
1052c97ad5cdSakolb 
1053c97ad5cdSakolb 		/* Move the thread from wait queue to run queue */
1054c97ad5cdSakolb 		if (ISWAITING(t))
1055c97ad5cdSakolb 			setrun_locked(t);
1056c97ad5cdSakolb 
1057c97ad5cdSakolb 		if (ISWAKEABLE(t)) {
10587c478bd9Sstevel@tonic-gate 			if (t->t_wchan0 == NULL)
10597c478bd9Sstevel@tonic-gate 				setrun_locked(t);
10607c478bd9Sstevel@tonic-gate 			else if (!VSTOPPED(t)) {
10617c478bd9Sstevel@tonic-gate 				/*
10627c478bd9Sstevel@tonic-gate 				 * Mark it virtually stopped.
10637c478bd9Sstevel@tonic-gate 				 */
10647c478bd9Sstevel@tonic-gate 				t->t_proc_flag |= TP_PRVSTOP;
10657c478bd9Sstevel@tonic-gate 				notify = 1;
10667c478bd9Sstevel@tonic-gate 			}
10677c478bd9Sstevel@tonic-gate 		}
10687c478bd9Sstevel@tonic-gate 		/*
10697c478bd9Sstevel@tonic-gate 		 * force the thread into the kernel
10707c478bd9Sstevel@tonic-gate 		 * if it is not already there.
10717c478bd9Sstevel@tonic-gate 		 */
10727c478bd9Sstevel@tonic-gate 		prpokethread(t);
10737c478bd9Sstevel@tonic-gate 		thread_unlock(t);
10747c478bd9Sstevel@tonic-gate 		if (notify &&
10757c478bd9Sstevel@tonic-gate 		    (vp = p->p_lwpdir[t->t_dslot].ld_entry->le_trace) != NULL)
10767c478bd9Sstevel@tonic-gate 			prnotify(vp);
10777c478bd9Sstevel@tonic-gate 		if (pcp->prc_flags & PRC_LWP)
10787c478bd9Sstevel@tonic-gate 			break;
10797c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	/*
10827c478bd9Sstevel@tonic-gate 	 * We do this just in case the thread we asked
10837c478bd9Sstevel@tonic-gate 	 * to stop is in holdlwps() (called from cfork()).
10847c478bd9Sstevel@tonic-gate 	 */
10857c478bd9Sstevel@tonic-gate 	cv_broadcast(&p->p_holdlwps);
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate /*
10897c478bd9Sstevel@tonic-gate  * Sleep until the lwp stops, but cooperate with
10907c478bd9Sstevel@tonic-gate  * jobcontrol:  Don't wake up if the lwp is stopped
10917c478bd9Sstevel@tonic-gate  * due to the default action of a jobcontrol stop signal.
10927c478bd9Sstevel@tonic-gate  * If this is the process file descriptor, sleep
10937c478bd9Sstevel@tonic-gate  * until all of the process's lwps stop.
10947c478bd9Sstevel@tonic-gate  */
10957c478bd9Sstevel@tonic-gate int
10967c478bd9Sstevel@tonic-gate pr_wait_stop(prnode_t *pnp, time_t timeo)
10977c478bd9Sstevel@tonic-gate {
10987c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
10997c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
11007c478bd9Sstevel@tonic-gate 	timestruc_t rqtime;
11017c478bd9Sstevel@tonic-gate 	timestruc_t *rqtp = NULL;
11023348528fSdm120769 	int timecheck = 0;
11037c478bd9Sstevel@tonic-gate 	kthread_t *t;
11047c478bd9Sstevel@tonic-gate 	int error;
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	if (timeo > 0) {	/* millisecond timeout */
11077c478bd9Sstevel@tonic-gate 		/*
11087c478bd9Sstevel@tonic-gate 		 * Determine the precise future time of the requested timeout.
11097c478bd9Sstevel@tonic-gate 		 */
11107c478bd9Sstevel@tonic-gate 		timestruc_t now;
11117c478bd9Sstevel@tonic-gate 
11123348528fSdm120769 		timecheck = timechanged;
11137c478bd9Sstevel@tonic-gate 		gethrestime(&now);
11147c478bd9Sstevel@tonic-gate 		rqtp = &rqtime;
11157c478bd9Sstevel@tonic-gate 		rqtp->tv_sec = timeo / MILLISEC;
11167c478bd9Sstevel@tonic-gate 		rqtp->tv_nsec = (timeo % MILLISEC) * MICROSEC;
11177c478bd9Sstevel@tonic-gate 		timespecadd(rqtp, &now);
11187c478bd9Sstevel@tonic-gate 	}
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {	/* lwp file descriptor */
11217c478bd9Sstevel@tonic-gate 		t = pcp->prc_thread;
11227c478bd9Sstevel@tonic-gate 		ASSERT(t != NULL);
11237c478bd9Sstevel@tonic-gate 		thread_lock(t);
11247c478bd9Sstevel@tonic-gate 		while (!ISTOPPED(t) && !VSTOPPED(t)) {
11257c478bd9Sstevel@tonic-gate 			thread_unlock(t);
11267c478bd9Sstevel@tonic-gate 			mutex_enter(&pcp->prc_mutex);
11277c478bd9Sstevel@tonic-gate 			prunlock(pnp);
11283348528fSdm120769 			error = pr_wait(pcp, rqtp, timecheck);
11297c478bd9Sstevel@tonic-gate 			if (error)	/* -1 is timeout */
11307c478bd9Sstevel@tonic-gate 				return (error);
11317c478bd9Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0)
11327c478bd9Sstevel@tonic-gate 				return (error);
11337c478bd9Sstevel@tonic-gate 			ASSERT(p == pcp->prc_proc);
11347c478bd9Sstevel@tonic-gate 			ASSERT(t == pcp->prc_thread);
11357c478bd9Sstevel@tonic-gate 			thread_lock(t);
11367c478bd9Sstevel@tonic-gate 		}
11377c478bd9Sstevel@tonic-gate 		thread_unlock(t);
11387c478bd9Sstevel@tonic-gate 	} else {			/* process file descriptor */
11397c478bd9Sstevel@tonic-gate 		t = prchoose(p);	/* returns locked thread */
11407c478bd9Sstevel@tonic-gate 		ASSERT(t != NULL);
11417c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&p->p_lock));
11427c478bd9Sstevel@tonic-gate 		while ((!ISTOPPED(t) && !VSTOPPED(t) && !SUSPENDED(t)) ||
11437c478bd9Sstevel@tonic-gate 		    (p->p_flag & SEXITLWPS)) {
11447c478bd9Sstevel@tonic-gate 			thread_unlock(t);
11457c478bd9Sstevel@tonic-gate 			mutex_enter(&pcp->prc_mutex);
11467c478bd9Sstevel@tonic-gate 			prunlock(pnp);
11473348528fSdm120769 			error = pr_wait(pcp, rqtp, timecheck);
11487c478bd9Sstevel@tonic-gate 			if (error)	/* -1 is timeout */
11497c478bd9Sstevel@tonic-gate 				return (error);
11507c478bd9Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0)
11517c478bd9Sstevel@tonic-gate 				return (error);
11527c478bd9Sstevel@tonic-gate 			ASSERT(p == pcp->prc_proc);
11537c478bd9Sstevel@tonic-gate 			t = prchoose(p);	/* returns locked t */
11547c478bd9Sstevel@tonic-gate 			ASSERT(t != NULL);
11557c478bd9Sstevel@tonic-gate 		}
11567c478bd9Sstevel@tonic-gate 		thread_unlock(t);
11577c478bd9Sstevel@tonic-gate 	}
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	ASSERT(!(pcp->prc_flags & PRC_DESTROY) && p->p_stat != SZOMB &&
11607c478bd9Sstevel@tonic-gate 	    t != NULL && t->t_state != TS_ZOMB);
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	return (0);
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate int
11667c478bd9Sstevel@tonic-gate pr_setrun(prnode_t *pnp, ulong_t flags)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
11697c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
11707c478bd9Sstevel@tonic-gate 	kthread_t *t;
11717c478bd9Sstevel@tonic-gate 	klwp_t *lwp;
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	/*
11747c478bd9Sstevel@tonic-gate 	 * Cannot set an lwp running if it is not stopped.
11757c478bd9Sstevel@tonic-gate 	 * Also, no lwp other than the /proc agent lwp can
11767c478bd9Sstevel@tonic-gate 	 * be set running so long as the /proc agent lwp exists.
11777c478bd9Sstevel@tonic-gate 	 */
11787c478bd9Sstevel@tonic-gate 	t = pr_thread(pnp);	/* returns locked thread */
11797c478bd9Sstevel@tonic-gate 	if ((!ISTOPPED(t) && !VSTOPPED(t) &&
11807c478bd9Sstevel@tonic-gate 	    !(t->t_proc_flag & TP_PRSTOP)) ||
11817c478bd9Sstevel@tonic-gate 	    (p->p_agenttp != NULL &&
11827c478bd9Sstevel@tonic-gate 	    (t != p->p_agenttp || !(pcp->prc_flags & PRC_LWP)))) {
11837c478bd9Sstevel@tonic-gate 		thread_unlock(t);
11847c478bd9Sstevel@tonic-gate 		return (EBUSY);
11857c478bd9Sstevel@tonic-gate 	}
11867c478bd9Sstevel@tonic-gate 	thread_unlock(t);
11877c478bd9Sstevel@tonic-gate 	if (flags & ~(PRCSIG|PRCFAULT|PRSTEP|PRSTOP|PRSABORT))
11887c478bd9Sstevel@tonic-gate 		return (EINVAL);
11897c478bd9Sstevel@tonic-gate 	lwp = ttolwp(t);
11907c478bd9Sstevel@tonic-gate 	if ((flags & PRCSIG) && lwp->lwp_cursig != SIGKILL) {
11917c478bd9Sstevel@tonic-gate 		/*
11927c478bd9Sstevel@tonic-gate 		 * Discard current siginfo_t, if any.
11937c478bd9Sstevel@tonic-gate 		 */
11947c478bd9Sstevel@tonic-gate 		lwp->lwp_cursig = 0;
11957c478bd9Sstevel@tonic-gate 		lwp->lwp_extsig = 0;
11967c478bd9Sstevel@tonic-gate 		if (lwp->lwp_curinfo) {
11977c478bd9Sstevel@tonic-gate 			siginfofree(lwp->lwp_curinfo);
11987c478bd9Sstevel@tonic-gate 			lwp->lwp_curinfo = NULL;
11997c478bd9Sstevel@tonic-gate 		}
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 	if (flags & PRCFAULT)
12027c478bd9Sstevel@tonic-gate 		lwp->lwp_curflt = 0;
12037c478bd9Sstevel@tonic-gate 	/*
12047c478bd9Sstevel@tonic-gate 	 * We can't hold p->p_lock when we touch the lwp's registers.
12057c478bd9Sstevel@tonic-gate 	 * It may be swapped out and we will get a page fault.
12067c478bd9Sstevel@tonic-gate 	 */
12077c478bd9Sstevel@tonic-gate 	if (flags & PRSTEP) {
12087c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
12097c478bd9Sstevel@tonic-gate 		prstep(lwp, 0);
12107c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 	if (flags & PRSTOP) {
12137c478bd9Sstevel@tonic-gate 		t->t_proc_flag |= TP_PRSTOP;
12147c478bd9Sstevel@tonic-gate 		t->t_sig_check = 1;	/* do ISSIG */
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 	if (flags & PRSABORT)
12177c478bd9Sstevel@tonic-gate 		lwp->lwp_sysabort = 1;
12187c478bd9Sstevel@tonic-gate 	thread_lock(t);
12197c478bd9Sstevel@tonic-gate 	if ((pcp->prc_flags & PRC_LWP) || (flags & (PRSTEP|PRSTOP))) {
12207c478bd9Sstevel@tonic-gate 		/*
12217c478bd9Sstevel@tonic-gate 		 * Here, we are dealing with a single lwp.
12227c478bd9Sstevel@tonic-gate 		 */
12237c478bd9Sstevel@tonic-gate 		if (ISTOPPED(t)) {
12247c478bd9Sstevel@tonic-gate 			t->t_schedflag |= TS_PSTART;
12257c478bd9Sstevel@tonic-gate 			t->t_dtrace_stop = 0;
12267c478bd9Sstevel@tonic-gate 			setrun_locked(t);
12277c478bd9Sstevel@tonic-gate 		} else if (flags & PRSABORT) {
12287c478bd9Sstevel@tonic-gate 			t->t_proc_flag &=
12297c478bd9Sstevel@tonic-gate 			    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
12307c478bd9Sstevel@tonic-gate 			setrun_locked(t);
12317c478bd9Sstevel@tonic-gate 		} else if (!(flags & PRSTOP)) {
12327c478bd9Sstevel@tonic-gate 			t->t_proc_flag &=
12337c478bd9Sstevel@tonic-gate 			    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
12347c478bd9Sstevel@tonic-gate 		}
12357c478bd9Sstevel@tonic-gate 		thread_unlock(t);
12367c478bd9Sstevel@tonic-gate 	} else {
12377c478bd9Sstevel@tonic-gate 		/*
12387c478bd9Sstevel@tonic-gate 		 * Here, we are dealing with the whole process.
12397c478bd9Sstevel@tonic-gate 		 */
12407c478bd9Sstevel@tonic-gate 		if (ISTOPPED(t)) {
12417c478bd9Sstevel@tonic-gate 			/*
12427c478bd9Sstevel@tonic-gate 			 * The representative lwp is stopped on an event
12437c478bd9Sstevel@tonic-gate 			 * of interest.  We demote it to PR_REQUESTED and
12447c478bd9Sstevel@tonic-gate 			 * choose another representative lwp.  If the new
12457c478bd9Sstevel@tonic-gate 			 * representative lwp is not stopped on an event of
12467c478bd9Sstevel@tonic-gate 			 * interest (other than PR_REQUESTED), we set the
12477c478bd9Sstevel@tonic-gate 			 * whole process running, else we leave the process
12487c478bd9Sstevel@tonic-gate 			 * stopped showing the next event of interest.
12497c478bd9Sstevel@tonic-gate 			 */
12507c478bd9Sstevel@tonic-gate 			kthread_t *tx = NULL;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 			if (!(flags & PRSABORT) &&
12537c478bd9Sstevel@tonic-gate 			    t->t_whystop == PR_SYSENTRY &&
12547c478bd9Sstevel@tonic-gate 			    t->t_whatstop == SYS_lwp_exit)
12557c478bd9Sstevel@tonic-gate 				tx = t;		/* remember the exiting lwp */
12567c478bd9Sstevel@tonic-gate 			t->t_whystop = PR_REQUESTED;
12577c478bd9Sstevel@tonic-gate 			t->t_whatstop = 0;
12587c478bd9Sstevel@tonic-gate 			thread_unlock(t);
12597c478bd9Sstevel@tonic-gate 			t = prchoose(p);	/* returns locked t */
12607c478bd9Sstevel@tonic-gate 			ASSERT(ISTOPPED(t) || VSTOPPED(t));
12617c478bd9Sstevel@tonic-gate 			if (VSTOPPED(t) ||
12627c478bd9Sstevel@tonic-gate 			    t->t_whystop == PR_REQUESTED) {
12637c478bd9Sstevel@tonic-gate 				thread_unlock(t);
12647c478bd9Sstevel@tonic-gate 				allsetrun(p);
12657c478bd9Sstevel@tonic-gate 			} else {
12667c478bd9Sstevel@tonic-gate 				thread_unlock(t);
12677c478bd9Sstevel@tonic-gate 				/*
12687c478bd9Sstevel@tonic-gate 				 * As a special case, if the old representative
12697c478bd9Sstevel@tonic-gate 				 * lwp was stopped on entry to _lwp_exit()
12707c478bd9Sstevel@tonic-gate 				 * (and we are not aborting the system call),
12717c478bd9Sstevel@tonic-gate 				 * we set the old representative lwp running.
12727c478bd9Sstevel@tonic-gate 				 * We do this so that the next process stop
12737c478bd9Sstevel@tonic-gate 				 * will find the exiting lwp gone.
12747c478bd9Sstevel@tonic-gate 				 */
12757c478bd9Sstevel@tonic-gate 				if (tx != NULL) {
12767c478bd9Sstevel@tonic-gate 					thread_lock(tx);
12777c478bd9Sstevel@tonic-gate 					tx->t_schedflag |= TS_PSTART;
12787c478bd9Sstevel@tonic-gate 					t->t_dtrace_stop = 0;
12797c478bd9Sstevel@tonic-gate 					setrun_locked(tx);
12807c478bd9Sstevel@tonic-gate 					thread_unlock(tx);
12817c478bd9Sstevel@tonic-gate 				}
12827c478bd9Sstevel@tonic-gate 			}
12837c478bd9Sstevel@tonic-gate 		} else {
12847c478bd9Sstevel@tonic-gate 			/*
12857c478bd9Sstevel@tonic-gate 			 * No event of interest; set all of the lwps running.
12867c478bd9Sstevel@tonic-gate 			 */
12877c478bd9Sstevel@tonic-gate 			if (flags & PRSABORT) {
12887c478bd9Sstevel@tonic-gate 				t->t_proc_flag &=
12897c478bd9Sstevel@tonic-gate 				    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
12907c478bd9Sstevel@tonic-gate 				setrun_locked(t);
12917c478bd9Sstevel@tonic-gate 			}
12927c478bd9Sstevel@tonic-gate 			thread_unlock(t);
12937c478bd9Sstevel@tonic-gate 			allsetrun(p);
12947c478bd9Sstevel@tonic-gate 		}
12957c478bd9Sstevel@tonic-gate 	}
12967c478bd9Sstevel@tonic-gate 	return (0);
12977c478bd9Sstevel@tonic-gate }
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate /*
13007c478bd9Sstevel@tonic-gate  * Wait until process/lwp stops or until timer expires.
13017c478bd9Sstevel@tonic-gate  * Return EINTR for an interruption, -1 for timeout, else 0.
13027c478bd9Sstevel@tonic-gate  */
13037c478bd9Sstevel@tonic-gate int
13047c478bd9Sstevel@tonic-gate pr_wait(prcommon_t *pcp,	/* prcommon referring to process/lwp */
13053348528fSdm120769 	timestruc_t *ts,	/* absolute time of timeout, if any */
13063348528fSdm120769 	int timecheck)
13077c478bd9Sstevel@tonic-gate {
13087c478bd9Sstevel@tonic-gate 	int rval;
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pcp->prc_mutex));
13113348528fSdm120769 	rval = cv_waituntil_sig(&pcp->prc_wait, &pcp->prc_mutex, ts, timecheck);
13127c478bd9Sstevel@tonic-gate 	mutex_exit(&pcp->prc_mutex);
13137c478bd9Sstevel@tonic-gate 	switch (rval) {
13147c478bd9Sstevel@tonic-gate 	case 0:
13157c478bd9Sstevel@tonic-gate 		return (EINTR);
13167c478bd9Sstevel@tonic-gate 	case -1:
13177c478bd9Sstevel@tonic-gate 		return (-1);
13187c478bd9Sstevel@tonic-gate 	default:
13197c478bd9Sstevel@tonic-gate 		return (0);
13207c478bd9Sstevel@tonic-gate 	}
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate /*
13247c478bd9Sstevel@tonic-gate  * Make all threads in the process runnable.
13257c478bd9Sstevel@tonic-gate  */
13267c478bd9Sstevel@tonic-gate void
13277c478bd9Sstevel@tonic-gate allsetrun(proc_t *p)
13287c478bd9Sstevel@tonic-gate {
13297c478bd9Sstevel@tonic-gate 	kthread_t *t;
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
13347c478bd9Sstevel@tonic-gate 		do {
13357c478bd9Sstevel@tonic-gate 			thread_lock(t);
13367c478bd9Sstevel@tonic-gate 			ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
13377c478bd9Sstevel@tonic-gate 			t->t_proc_flag &= ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
13387c478bd9Sstevel@tonic-gate 			if (ISTOPPED(t)) {
13397c478bd9Sstevel@tonic-gate 				t->t_schedflag |= TS_PSTART;
13407c478bd9Sstevel@tonic-gate 				t->t_dtrace_stop = 0;
13417c478bd9Sstevel@tonic-gate 				setrun_locked(t);
13427c478bd9Sstevel@tonic-gate 			}
13437c478bd9Sstevel@tonic-gate 			thread_unlock(t);
13447c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
13457c478bd9Sstevel@tonic-gate 	}
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate /*
13497c478bd9Sstevel@tonic-gate  * Wait for the process to die.
13507c478bd9Sstevel@tonic-gate  * We do this after sending SIGKILL because we know it will
13517c478bd9Sstevel@tonic-gate  * die soon and we want subsequent operations to return ENOENT.
13527c478bd9Sstevel@tonic-gate  */
13537c478bd9Sstevel@tonic-gate void
13547c478bd9Sstevel@tonic-gate pr_wait_die(prnode_t *pnp)
13557c478bd9Sstevel@tonic-gate {
13567c478bd9Sstevel@tonic-gate 	proc_t *p;
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
13597c478bd9Sstevel@tonic-gate 	while ((p = pnp->pr_common->prc_proc) != NULL && p->p_stat != SZOMB) {
13607c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&p->p_srwchan_cv, &pidlock))
13617c478bd9Sstevel@tonic-gate 			break;
13627c478bd9Sstevel@tonic-gate 	}
13637c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
13647c478bd9Sstevel@tonic-gate }
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate static void
13677c478bd9Sstevel@tonic-gate pr_settrace(proc_t *p, sigset_t *sp)
13687c478bd9Sstevel@tonic-gate {
13697c478bd9Sstevel@tonic-gate 	prdelset(sp, SIGKILL);
13707c478bd9Sstevel@tonic-gate 	prassignset(&p->p_sigmask, sp);
13717c478bd9Sstevel@tonic-gate 	if (!sigisempty(&p->p_sigmask))
13727c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
13737c478bd9Sstevel@tonic-gate 	else if (prisempty(&p->p_fltmask)) {
13747c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
13757c478bd9Sstevel@tonic-gate 		if (up->u_systrap == 0)
13767c478bd9Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
13777c478bd9Sstevel@tonic-gate 	}
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate int
13817c478bd9Sstevel@tonic-gate pr_setsig(prnode_t *pnp, siginfo_t *sip)
13827c478bd9Sstevel@tonic-gate {
1383eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
13847c478bd9Sstevel@tonic-gate 	int sig = sip->si_signo;
13857c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
13867c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
13877c478bd9Sstevel@tonic-gate 	kthread_t *t;
13887c478bd9Sstevel@tonic-gate 	klwp_t *lwp;
13897c478bd9Sstevel@tonic-gate 	int error = 0;
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	t = pr_thread(pnp);	/* returns locked thread */
13927c478bd9Sstevel@tonic-gate 	thread_unlock(t);
13937c478bd9Sstevel@tonic-gate 	lwp = ttolwp(t);
1394eb9dbf0cSRoger A. Faulkner 	if (sig < 0 || sig >= nsig)
13957c478bd9Sstevel@tonic-gate 		/* Zero allowed here */
13967c478bd9Sstevel@tonic-gate 		error = EINVAL;
13977c478bd9Sstevel@tonic-gate 	else if (lwp->lwp_cursig == SIGKILL)
13987c478bd9Sstevel@tonic-gate 		/* "can't happen", but just in case */
13997c478bd9Sstevel@tonic-gate 		error = EBUSY;
14007c478bd9Sstevel@tonic-gate 	else if ((lwp->lwp_cursig = (uchar_t)sig) == 0) {
14017c478bd9Sstevel@tonic-gate 		lwp->lwp_extsig = 0;
14027c478bd9Sstevel@tonic-gate 		/*
14037c478bd9Sstevel@tonic-gate 		 * Discard current siginfo_t, if any.
14047c478bd9Sstevel@tonic-gate 		 */
14057c478bd9Sstevel@tonic-gate 		if (lwp->lwp_curinfo) {
14067c478bd9Sstevel@tonic-gate 			siginfofree(lwp->lwp_curinfo);
14077c478bd9Sstevel@tonic-gate 			lwp->lwp_curinfo = NULL;
14087c478bd9Sstevel@tonic-gate 		}
14097c478bd9Sstevel@tonic-gate 	} else {
14107c478bd9Sstevel@tonic-gate 		kthread_t *tx;
14117c478bd9Sstevel@tonic-gate 		sigqueue_t *sqp;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 		/* drop p_lock to do kmem_alloc(KM_SLEEP) */
14147c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
14157c478bd9Sstevel@tonic-gate 		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
14167c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 		if (lwp->lwp_curinfo == NULL)
14197c478bd9Sstevel@tonic-gate 			lwp->lwp_curinfo = sqp;
14207c478bd9Sstevel@tonic-gate 		else
14217c478bd9Sstevel@tonic-gate 			kmem_free(sqp, sizeof (sigqueue_t));
14227c478bd9Sstevel@tonic-gate 		/*
14237c478bd9Sstevel@tonic-gate 		 * Copy contents of info to current siginfo_t.
14247c478bd9Sstevel@tonic-gate 		 */
14257c478bd9Sstevel@tonic-gate 		bcopy(sip, &lwp->lwp_curinfo->sq_info,
14267c478bd9Sstevel@tonic-gate 		    sizeof (lwp->lwp_curinfo->sq_info));
14277c478bd9Sstevel@tonic-gate 		/*
14287c478bd9Sstevel@tonic-gate 		 * Prevent contents published by si_zoneid-unaware /proc
14297c478bd9Sstevel@tonic-gate 		 * consumers from being incorrectly filtered.  Because
14307c478bd9Sstevel@tonic-gate 		 * an uninitialized si_zoneid is the same as
14317c478bd9Sstevel@tonic-gate 		 * GLOBAL_ZONEID, this means that you can't pr_setsig a
14327c478bd9Sstevel@tonic-gate 		 * process in a non-global zone with a siginfo which
14337c478bd9Sstevel@tonic-gate 		 * appears to come from the global zone.
14347c478bd9Sstevel@tonic-gate 		 */
14357c478bd9Sstevel@tonic-gate 		if (SI_FROMUSER(sip) && sip->si_zoneid == 0)
14367c478bd9Sstevel@tonic-gate 			lwp->lwp_curinfo->sq_info.si_zoneid =
14377c478bd9Sstevel@tonic-gate 			    p->p_zone->zone_id;
14387c478bd9Sstevel@tonic-gate 		/*
14397c478bd9Sstevel@tonic-gate 		 * Side-effects for SIGKILL and jobcontrol signals.
14407c478bd9Sstevel@tonic-gate 		 */
14417c478bd9Sstevel@tonic-gate 		if (sig == SIGKILL) {
14427c478bd9Sstevel@tonic-gate 			p->p_flag |= SKILLED;
14437c478bd9Sstevel@tonic-gate 			p->p_flag &= ~SEXTKILLED;
14447c478bd9Sstevel@tonic-gate 		} else if (sig == SIGCONT) {
14457c478bd9Sstevel@tonic-gate 			p->p_flag |= SSCONT;
14467c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGSTOP);
14477c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTSTP);
14487c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTTOU);
14497c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTTIN);
14507c478bd9Sstevel@tonic-gate 			sigdiffset(&p->p_sig, &stopdefault);
14517c478bd9Sstevel@tonic-gate 			sigdiffset(&p->p_extsig, &stopdefault);
14527c478bd9Sstevel@tonic-gate 			if ((tx = p->p_tlist) != NULL) {
14537c478bd9Sstevel@tonic-gate 				do {
14547c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGSTOP);
14557c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGTSTP);
14567c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGTTOU);
14577c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGTTIN);
14587c478bd9Sstevel@tonic-gate 					sigdiffset(&tx->t_sig, &stopdefault);
14597c478bd9Sstevel@tonic-gate 					sigdiffset(&tx->t_extsig, &stopdefault);
14607c478bd9Sstevel@tonic-gate 				} while ((tx = tx->t_forw) != p->p_tlist);
14617c478bd9Sstevel@tonic-gate 			}
14627c478bd9Sstevel@tonic-gate 		} else if (sigismember(&stopdefault, sig)) {
14637c478bd9Sstevel@tonic-gate 			if (PTOU(p)->u_signal[sig-1] == SIG_DFL &&
14647c478bd9Sstevel@tonic-gate 			    (sig == SIGSTOP || !p->p_pgidp->pid_pgorphaned))
14657c478bd9Sstevel@tonic-gate 				p->p_flag &= ~SSCONT;
14667c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGCONT);
14677c478bd9Sstevel@tonic-gate 			sigdelset(&p->p_sig, SIGCONT);
14687c478bd9Sstevel@tonic-gate 			sigdelset(&p->p_extsig, SIGCONT);
14697c478bd9Sstevel@tonic-gate 			if ((tx = p->p_tlist) != NULL) {
14707c478bd9Sstevel@tonic-gate 				do {
14717c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGCONT);
14727c478bd9Sstevel@tonic-gate 					sigdelset(&tx->t_sig, SIGCONT);
14737c478bd9Sstevel@tonic-gate 					sigdelset(&tx->t_extsig, SIGCONT);
14747c478bd9Sstevel@tonic-gate 				} while ((tx = tx->t_forw) != p->p_tlist);
14757c478bd9Sstevel@tonic-gate 			}
14767c478bd9Sstevel@tonic-gate 		}
14777c478bd9Sstevel@tonic-gate 		thread_lock(t);
1478c97ad5cdSakolb 		if (ISWAKEABLE(t) || ISWAITING(t)) {
1479da6c28aaSamw 			/* Set signaled sleeping/waiting lwp running */
14807c478bd9Sstevel@tonic-gate 			setrun_locked(t);
14817c478bd9Sstevel@tonic-gate 		} else if (t->t_state == TS_STOPPED && sig == SIGKILL) {
14827c478bd9Sstevel@tonic-gate 			/* If SIGKILL, set stopped lwp running */
14837c478bd9Sstevel@tonic-gate 			p->p_stopsig = 0;
14847c478bd9Sstevel@tonic-gate 			t->t_schedflag |= TS_XSTART | TS_PSTART;
14857c478bd9Sstevel@tonic-gate 			t->t_dtrace_stop = 0;
14867c478bd9Sstevel@tonic-gate 			setrun_locked(t);
14877c478bd9Sstevel@tonic-gate 		}
14887c478bd9Sstevel@tonic-gate 		t->t_sig_check = 1;	/* so ISSIG will be done */
14897c478bd9Sstevel@tonic-gate 		thread_unlock(t);
14907c478bd9Sstevel@tonic-gate 		/*
14917c478bd9Sstevel@tonic-gate 		 * More jobcontrol side-effects.
14927c478bd9Sstevel@tonic-gate 		 */
14937c478bd9Sstevel@tonic-gate 		if (sig == SIGCONT && (tx = p->p_tlist) != NULL) {
14947c478bd9Sstevel@tonic-gate 			p->p_stopsig = 0;
14957c478bd9Sstevel@tonic-gate 			do {
14967c478bd9Sstevel@tonic-gate 				thread_lock(tx);
14977c478bd9Sstevel@tonic-gate 				if (tx->t_state == TS_STOPPED &&
14987c478bd9Sstevel@tonic-gate 				    tx->t_whystop == PR_JOBCONTROL) {
14997c478bd9Sstevel@tonic-gate 					tx->t_schedflag |= TS_XSTART;
15007c478bd9Sstevel@tonic-gate 					setrun_locked(tx);
15017c478bd9Sstevel@tonic-gate 				}
15027c478bd9Sstevel@tonic-gate 				thread_unlock(tx);
15037c478bd9Sstevel@tonic-gate 			} while ((tx = tx->t_forw) != p->p_tlist);
15047c478bd9Sstevel@tonic-gate 		}
15057c478bd9Sstevel@tonic-gate 	}
15067c478bd9Sstevel@tonic-gate 	return (error);
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate int
15107c478bd9Sstevel@tonic-gate pr_kill(prnode_t *pnp, int sig, cred_t *cr)
15117c478bd9Sstevel@tonic-gate {
1512eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
15137c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
15147c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
15157c478bd9Sstevel@tonic-gate 	k_siginfo_t info;
15167c478bd9Sstevel@tonic-gate 
1517eb9dbf0cSRoger A. Faulkner 	if (sig <= 0 || sig >= nsig)
15187c478bd9Sstevel@tonic-gate 		return (EINVAL);
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	bzero(&info, sizeof (info));
15217c478bd9Sstevel@tonic-gate 	info.si_signo = sig;
15227c478bd9Sstevel@tonic-gate 	info.si_code = SI_USER;
15237c478bd9Sstevel@tonic-gate 	info.si_pid = curproc->p_pid;
15247c478bd9Sstevel@tonic-gate 	info.si_ctid = PRCTID(curproc);
15257c478bd9Sstevel@tonic-gate 	info.si_zoneid = getzoneid();
15267c478bd9Sstevel@tonic-gate 	info.si_uid = crgetruid(cr);
15277c478bd9Sstevel@tonic-gate 	sigaddq(p, (pcp->prc_flags & PRC_LWP)?
15287c478bd9Sstevel@tonic-gate 	    pcp->prc_thread : NULL, &info, KM_NOSLEEP);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	return (0);
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate int
15347c478bd9Sstevel@tonic-gate pr_unkill(prnode_t *pnp, int sig)
15357c478bd9Sstevel@tonic-gate {
1536eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
15377c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
15387c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
15397c478bd9Sstevel@tonic-gate 	sigqueue_t *infop = NULL;
15407c478bd9Sstevel@tonic-gate 
1541eb9dbf0cSRoger A. Faulkner 	if (sig <= 0 || sig >= nsig || sig == SIGKILL)
15427c478bd9Sstevel@tonic-gate 		return (EINVAL);
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP)
15457c478bd9Sstevel@tonic-gate 		sigdeq(p, pcp->prc_thread, sig, &infop);
15467c478bd9Sstevel@tonic-gate 	else
15477c478bd9Sstevel@tonic-gate 		sigdeq(p, NULL, sig, &infop);
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	if (infop)
15507c478bd9Sstevel@tonic-gate 		siginfofree(infop);
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	return (0);
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate int
15567c478bd9Sstevel@tonic-gate pr_nice(proc_t *p, int nice, cred_t *cr)
15577c478bd9Sstevel@tonic-gate {
15587c478bd9Sstevel@tonic-gate 	kthread_t *t;
15597c478bd9Sstevel@tonic-gate 	int err;
15607c478bd9Sstevel@tonic-gate 	int error = 0;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
15637c478bd9Sstevel@tonic-gate 	do {
15647c478bd9Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
15657c478bd9Sstevel@tonic-gate 		err = CL_DONICE(t, cr, nice, (int *)NULL);
1566d4204c85Sraf 		schedctl_set_cidpri(t);
15677c478bd9Sstevel@tonic-gate 		if (error == 0)
15687c478bd9Sstevel@tonic-gate 			error = err;
15697c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	return (error);
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate void
15757c478bd9Sstevel@tonic-gate pr_setentryexit(proc_t *p, sysset_t *sysset, int entry)
15767c478bd9Sstevel@tonic-gate {
15777c478bd9Sstevel@tonic-gate 	user_t *up = PTOU(p);
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	if (entry) {
15807c478bd9Sstevel@tonic-gate 		prassignset(&up->u_entrymask, sysset);
15817c478bd9Sstevel@tonic-gate 	} else {
15827c478bd9Sstevel@tonic-gate 		prassignset(&up->u_exitmask, sysset);
15837c478bd9Sstevel@tonic-gate 	}
15847c478bd9Sstevel@tonic-gate 	if (!prisempty(&up->u_entrymask) ||
15857c478bd9Sstevel@tonic-gate 	    !prisempty(&up->u_exitmask)) {
15867c478bd9Sstevel@tonic-gate 		up->u_systrap = 1;
15877c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
15887c478bd9Sstevel@tonic-gate 		set_proc_sys(p);	/* set pre and post-sys flags */
15897c478bd9Sstevel@tonic-gate 	} else {
15907c478bd9Sstevel@tonic-gate 		up->u_systrap = 0;
15917c478bd9Sstevel@tonic-gate 		if (sigisempty(&p->p_sigmask) &&
15927c478bd9Sstevel@tonic-gate 		    prisempty(&p->p_fltmask))
15937c478bd9Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate }
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate #define	ALLFLAGS	\
15987c478bd9Sstevel@tonic-gate 	(PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_MSACCT|PR_MSFORK|PR_PTRACE)
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate int
16017c478bd9Sstevel@tonic-gate pr_set(proc_t *p, long flags)
16027c478bd9Sstevel@tonic-gate {
16037c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
16047c478bd9Sstevel@tonic-gate 		return (EBUSY);
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	if (flags & ~ALLFLAGS)
16077c478bd9Sstevel@tonic-gate 		return (EINVAL);
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	if (flags & PR_FORK)
16107c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_FORK;
16117c478bd9Sstevel@tonic-gate 	if (flags & PR_RLC)
16127c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_RUNLCL;
16137c478bd9Sstevel@tonic-gate 	if (flags & PR_KLC)
16147c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_KILLCL;
16157c478bd9Sstevel@tonic-gate 	if (flags & PR_ASYNC)
16167c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_ASYNC;
16177c478bd9Sstevel@tonic-gate 	if (flags & PR_BPTADJ)
16187c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_BPTADJ;
16197c478bd9Sstevel@tonic-gate 	if (flags & PR_MSACCT)
16207c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SMSACCT) == 0)
16217c478bd9Sstevel@tonic-gate 			estimate_msacct(p->p_tlist, gethrtime());
16227c478bd9Sstevel@tonic-gate 	if (flags & PR_MSFORK)
16237c478bd9Sstevel@tonic-gate 		p->p_flag |= SMSFORK;
16247c478bd9Sstevel@tonic-gate 	if (flags & PR_PTRACE) {
16257c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_PTRACE;
16267c478bd9Sstevel@tonic-gate 		/* ptraced process must die if parent dead */
16277c478bd9Sstevel@tonic-gate 		if (p->p_ppid == 1)
16287c478bd9Sstevel@tonic-gate 			sigtoproc(p, NULL, SIGKILL);
16297c478bd9Sstevel@tonic-gate 	}
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	return (0);
16327c478bd9Sstevel@tonic-gate }
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate int
16357c478bd9Sstevel@tonic-gate pr_unset(proc_t *p, long flags)
16367c478bd9Sstevel@tonic-gate {
16377c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
16387c478bd9Sstevel@tonic-gate 		return (EBUSY);
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	if (flags & ~ALLFLAGS)
16417c478bd9Sstevel@tonic-gate 		return (EINVAL);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	if (flags & PR_FORK)
16447c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_FORK;
16457c478bd9Sstevel@tonic-gate 	if (flags & PR_RLC)
16467c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_RUNLCL;
16477c478bd9Sstevel@tonic-gate 	if (flags & PR_KLC)
16487c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_KILLCL;
16497c478bd9Sstevel@tonic-gate 	if (flags & PR_ASYNC)
16507c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_ASYNC;
16517c478bd9Sstevel@tonic-gate 	if (flags & PR_BPTADJ)
16527c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_BPTADJ;
16537c478bd9Sstevel@tonic-gate 	if (flags & PR_MSACCT)
16547c478bd9Sstevel@tonic-gate 		disable_msacct(p);
16557c478bd9Sstevel@tonic-gate 	if (flags & PR_MSFORK)
16567c478bd9Sstevel@tonic-gate 		p->p_flag &= ~SMSFORK;
16577c478bd9Sstevel@tonic-gate 	if (flags & PR_PTRACE)
16587c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_PTRACE;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	return (0);
16617c478bd9Sstevel@tonic-gate }
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate static int
16647c478bd9Sstevel@tonic-gate pr_setfpregs(prnode_t *pnp, prfpregset_t *prfpregset)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
16677c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
16707c478bd9Sstevel@tonic-gate 		thread_unlock(t);
16717c478bd9Sstevel@tonic-gate 		return (EBUSY);
16727c478bd9Sstevel@tonic-gate 	}
16737c478bd9Sstevel@tonic-gate 	if (!prhasfp()) {
16747c478bd9Sstevel@tonic-gate 		thread_unlock(t);
16757c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* No FP support */
16767c478bd9Sstevel@tonic-gate 	}
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
16797c478bd9Sstevel@tonic-gate 	thread_unlock(t);
16807c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
16817c478bd9Sstevel@tonic-gate 	prsetprfpregs(ttolwp(t), prfpregset);
16827c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	return (0);
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
16887c478bd9Sstevel@tonic-gate static int
16897c478bd9Sstevel@tonic-gate pr_setfpregs32(prnode_t *pnp, prfpregset32_t *prfpregset)
16907c478bd9Sstevel@tonic-gate {
16917c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
16927c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
16957c478bd9Sstevel@tonic-gate 		thread_unlock(t);
16967c478bd9Sstevel@tonic-gate 		return (EBUSY);
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 	if (!prhasfp()) {
16997c478bd9Sstevel@tonic-gate 		thread_unlock(t);
17007c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* No FP support */
17017c478bd9Sstevel@tonic-gate 	}
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
17047c478bd9Sstevel@tonic-gate 	thread_unlock(t);
17057c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17067c478bd9Sstevel@tonic-gate 	prsetprfpregs32(ttolwp(t), prfpregset);
17077c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	return (0);
17107c478bd9Sstevel@tonic-gate }
17117c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate #if defined(__sparc)
17147c478bd9Sstevel@tonic-gate /* ARGSUSED */
17157c478bd9Sstevel@tonic-gate static int
17167c478bd9Sstevel@tonic-gate pr_setxregs(prnode_t *pnp, prxregset_t *prxregset)
17177c478bd9Sstevel@tonic-gate {
17187c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
17197c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
17227c478bd9Sstevel@tonic-gate 		thread_unlock(t);
17237c478bd9Sstevel@tonic-gate 		return (EBUSY);
17247c478bd9Sstevel@tonic-gate 	}
17257c478bd9Sstevel@tonic-gate 	thread_unlock(t);
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 	if (!prhasx(p))
17287c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* No extra register support */
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
17317c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17327c478bd9Sstevel@tonic-gate 	prsetprxregs(ttolwp(t), (caddr_t)prxregset);
17337c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	return (0);
17367c478bd9Sstevel@tonic-gate }
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate static int
17397c478bd9Sstevel@tonic-gate pr_setasrs(prnode_t *pnp, asrset_t asrset)
17407c478bd9Sstevel@tonic-gate {
17417c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
17427c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
17457c478bd9Sstevel@tonic-gate 		thread_unlock(t);
17467c478bd9Sstevel@tonic-gate 		return (EBUSY);
17477c478bd9Sstevel@tonic-gate 	}
17487c478bd9Sstevel@tonic-gate 	thread_unlock(t);
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
17517c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17527c478bd9Sstevel@tonic-gate 	prsetasregs(ttolwp(t), asrset);
17537c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	return (0);
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate #endif
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate static int
17607c478bd9Sstevel@tonic-gate pr_setvaddr(prnode_t *pnp, caddr_t vaddr)
17617c478bd9Sstevel@tonic-gate {
17627c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
17637c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
17667c478bd9Sstevel@tonic-gate 		thread_unlock(t);
17677c478bd9Sstevel@tonic-gate 		return (EBUSY);
17687c478bd9Sstevel@tonic-gate 	}
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
17717c478bd9Sstevel@tonic-gate 	thread_unlock(t);
17727c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17737c478bd9Sstevel@tonic-gate 	prsvaddr(ttolwp(t), vaddr);
17747c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	return (0);
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate void
17807c478bd9Sstevel@tonic-gate pr_sethold(prnode_t *pnp, sigset_t *sp)
17817c478bd9Sstevel@tonic-gate {
17827c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
17837c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	schedctl_finish_sigblock(t);
17867c478bd9Sstevel@tonic-gate 	sigutok(sp, &t->t_hold);
1787c97ad5cdSakolb 	if (ISWAKEABLE(t) &&
17887c478bd9Sstevel@tonic-gate 	    (fsig(&p->p_sig, t) || fsig(&t->t_sig, t)))
17897c478bd9Sstevel@tonic-gate 		setrun_locked(t);
17907c478bd9Sstevel@tonic-gate 	t->t_sig_check = 1;	/* so thread will see new holdmask */
17917c478bd9Sstevel@tonic-gate 	thread_unlock(t);
17927c478bd9Sstevel@tonic-gate }
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate void
17957c478bd9Sstevel@tonic-gate pr_setfault(proc_t *p, fltset_t *fltp)
17967c478bd9Sstevel@tonic-gate {
17977c478bd9Sstevel@tonic-gate 	prassignset(&p->p_fltmask, fltp);
17987c478bd9Sstevel@tonic-gate 	if (!prisempty(&p->p_fltmask))
17997c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
18007c478bd9Sstevel@tonic-gate 	else if (sigisempty(&p->p_sigmask)) {
18017c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
18027c478bd9Sstevel@tonic-gate 		if (up->u_systrap == 0)
18037c478bd9Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
18047c478bd9Sstevel@tonic-gate 	}
18057c478bd9Sstevel@tonic-gate }
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate static int
18087c478bd9Sstevel@tonic-gate pr_clearsig(prnode_t *pnp)
18097c478bd9Sstevel@tonic-gate {
18107c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
18117c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 	thread_unlock(t);
18147c478bd9Sstevel@tonic-gate 	if (lwp->lwp_cursig == SIGKILL)
18157c478bd9Sstevel@tonic-gate 		return (EBUSY);
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	/*
18187c478bd9Sstevel@tonic-gate 	 * Discard current siginfo_t, if any.
18197c478bd9Sstevel@tonic-gate 	 */
18207c478bd9Sstevel@tonic-gate 	lwp->lwp_cursig = 0;
18217c478bd9Sstevel@tonic-gate 	lwp->lwp_extsig = 0;
18227c478bd9Sstevel@tonic-gate 	if (lwp->lwp_curinfo) {
18237c478bd9Sstevel@tonic-gate 		siginfofree(lwp->lwp_curinfo);
18247c478bd9Sstevel@tonic-gate 		lwp->lwp_curinfo = NULL;
18257c478bd9Sstevel@tonic-gate 	}
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	return (0);
18287c478bd9Sstevel@tonic-gate }
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate static int
18317c478bd9Sstevel@tonic-gate pr_clearflt(prnode_t *pnp)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 	thread_unlock(t);
18367c478bd9Sstevel@tonic-gate 	ttolwp(t)->lwp_curflt = 0;
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	return (0);
18397c478bd9Sstevel@tonic-gate }
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate static int
18427c478bd9Sstevel@tonic-gate pr_watch(prnode_t *pnp, prwatch_t *pwp, int *unlocked)
18437c478bd9Sstevel@tonic-gate {
18447c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
18457c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
18467c478bd9Sstevel@tonic-gate 	uintptr_t vaddr = pwp->pr_vaddr;
18477c478bd9Sstevel@tonic-gate 	size_t size = pwp->pr_size;
18487c478bd9Sstevel@tonic-gate 	int wflags = pwp->pr_wflags;
18497c478bd9Sstevel@tonic-gate 	ulong_t newpage = 0;
18507c478bd9Sstevel@tonic-gate 	struct watched_area *pwa;
18517c478bd9Sstevel@tonic-gate 	int error;
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	*unlocked = 0;
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	/*
18567c478bd9Sstevel@tonic-gate 	 * Can't apply to a system process.
18577c478bd9Sstevel@tonic-gate 	 */
18587c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
18597c478bd9Sstevel@tonic-gate 		return (EBUSY);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	/*
18627c478bd9Sstevel@tonic-gate 	 * Verify that the address range does not wrap
18637c478bd9Sstevel@tonic-gate 	 * and that only the proper flags were specified.
18647c478bd9Sstevel@tonic-gate 	 */
18657c478bd9Sstevel@tonic-gate 	if ((wflags & ~WA_TRAPAFTER) == 0)
18667c478bd9Sstevel@tonic-gate 		size = 0;
18677c478bd9Sstevel@tonic-gate 	if (vaddr + size < vaddr ||
18687c478bd9Sstevel@tonic-gate 	    (wflags & ~(WA_READ|WA_WRITE|WA_EXEC|WA_TRAPAFTER)) != 0 ||
18697c478bd9Sstevel@tonic-gate 	    ((wflags & ~WA_TRAPAFTER) != 0 && size == 0))
18707c478bd9Sstevel@tonic-gate 		return (EINVAL);
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	/*
18737c478bd9Sstevel@tonic-gate 	 * Don't let the address range go above as->a_userlimit.
18747c478bd9Sstevel@tonic-gate 	 * There is no error here, just a limitation.
18757c478bd9Sstevel@tonic-gate 	 */
18767c478bd9Sstevel@tonic-gate 	if (vaddr >= (uintptr_t)as->a_userlimit)
18777c478bd9Sstevel@tonic-gate 		return (0);
18787c478bd9Sstevel@tonic-gate 	if (vaddr + size > (uintptr_t)as->a_userlimit)
18797c478bd9Sstevel@tonic-gate 		size = (uintptr_t)as->a_userlimit - vaddr;
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	/*
18827c478bd9Sstevel@tonic-gate 	 * Compute maximum number of pages this will add.
18837c478bd9Sstevel@tonic-gate 	 */
18847c478bd9Sstevel@tonic-gate 	if ((wflags & ~WA_TRAPAFTER) != 0) {
18857c478bd9Sstevel@tonic-gate 		ulong_t pagespan = (vaddr + size) - (vaddr & PAGEMASK);
18867c478bd9Sstevel@tonic-gate 		newpage = btopr(pagespan);
18877c478bd9Sstevel@tonic-gate 		if (newpage > 2 * prnwatch)
18887c478bd9Sstevel@tonic-gate 			return (E2BIG);
18897c478bd9Sstevel@tonic-gate 	}
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	/*
18927c478bd9Sstevel@tonic-gate 	 * Force the process to be fully stopped.
18937c478bd9Sstevel@tonic-gate 	 */
18947c478bd9Sstevel@tonic-gate 	if (p == curproc) {
18957c478bd9Sstevel@tonic-gate 		prunlock(pnp);
18967c478bd9Sstevel@tonic-gate 		while (holdwatch() != 0)
18977c478bd9Sstevel@tonic-gate 			continue;
18987c478bd9Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) != 0) {
18997c478bd9Sstevel@tonic-gate 			continuelwps(p);
19007c478bd9Sstevel@tonic-gate 			*unlocked = 1;
19017c478bd9Sstevel@tonic-gate 			return (error);
19027c478bd9Sstevel@tonic-gate 		}
19037c478bd9Sstevel@tonic-gate 	} else {
19047c478bd9Sstevel@tonic-gate 		pauselwps(p);
19057c478bd9Sstevel@tonic-gate 		while (pr_allstopped(p, 0) > 0) {
19067c478bd9Sstevel@tonic-gate 			/*
19077c478bd9Sstevel@tonic-gate 			 * This cv/mutex pair is persistent even
19087c478bd9Sstevel@tonic-gate 			 * if the process disappears after we
19097c478bd9Sstevel@tonic-gate 			 * unmark it and drop p->p_lock.
19107c478bd9Sstevel@tonic-gate 			 */
19117c478bd9Sstevel@tonic-gate 			kcondvar_t *cv = &pr_pid_cv[p->p_slot];
19127c478bd9Sstevel@tonic-gate 			kmutex_t *mp = &p->p_lock;
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 			prunmark(p);
19157c478bd9Sstevel@tonic-gate 			(void) cv_wait(cv, mp);
19167c478bd9Sstevel@tonic-gate 			mutex_exit(mp);
19177c478bd9Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0) {
19187c478bd9Sstevel@tonic-gate 				/*
19197c478bd9Sstevel@tonic-gate 				 * Unpause the process if it exists.
19207c478bd9Sstevel@tonic-gate 				 */
19217c478bd9Sstevel@tonic-gate 				p = pr_p_lock(pnp);
19227c478bd9Sstevel@tonic-gate 				mutex_exit(&pr_pidlock);
19237c478bd9Sstevel@tonic-gate 				if (p != NULL) {
19247c478bd9Sstevel@tonic-gate 					unpauselwps(p);
19257c478bd9Sstevel@tonic-gate 					prunlock(pnp);
19267c478bd9Sstevel@tonic-gate 				}
19277c478bd9Sstevel@tonic-gate 				*unlocked = 1;
19287c478bd9Sstevel@tonic-gate 				return (error);
19297c478bd9Sstevel@tonic-gate 			}
19307c478bd9Sstevel@tonic-gate 		}
19317c478bd9Sstevel@tonic-gate 	}
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	/*
19347c478bd9Sstevel@tonic-gate 	 * Drop p->p_lock in order to perform the rest of this.
19357c478bd9Sstevel@tonic-gate 	 * The process is still locked with the P_PR_LOCK flag.
19367c478bd9Sstevel@tonic-gate 	 */
19377c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 	pwa = kmem_alloc(sizeof (struct watched_area), KM_SLEEP);
19407c478bd9Sstevel@tonic-gate 	pwa->wa_vaddr = (caddr_t)vaddr;
19417c478bd9Sstevel@tonic-gate 	pwa->wa_eaddr = (caddr_t)vaddr + size;
19427c478bd9Sstevel@tonic-gate 	pwa->wa_flags = (ulong_t)wflags;
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	error = ((pwa->wa_flags & ~WA_TRAPAFTER) == 0)?
1945bda89588Sjp151216 	    clear_watched_area(p, pwa) : set_watched_area(p, pwa);
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	if (p == curproc) {
19487c478bd9Sstevel@tonic-gate 		setallwatch();
19497c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
19507c478bd9Sstevel@tonic-gate 		continuelwps(p);
19517c478bd9Sstevel@tonic-gate 	} else {
19527c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
19537c478bd9Sstevel@tonic-gate 		unpauselwps(p);
19547c478bd9Sstevel@tonic-gate 	}
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	return (error);
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate /* jobcontrol stopped, but with a /proc directed stop in effect */
19607c478bd9Sstevel@tonic-gate #define	JDSTOPPED(t)	\
19617c478bd9Sstevel@tonic-gate 	((t)->t_state == TS_STOPPED && \
19627c478bd9Sstevel@tonic-gate 	(t)->t_whystop == PR_JOBCONTROL && \
19637c478bd9Sstevel@tonic-gate 	((t)->t_proc_flag & TP_PRSTOP))
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate /*
19667c478bd9Sstevel@tonic-gate  * pr_agent() creates the agent lwp. If the process is exiting while
19677c478bd9Sstevel@tonic-gate  * we are creating an agent lwp, then exitlwps() waits until the
19687c478bd9Sstevel@tonic-gate  * agent has been created using prbarrier().
19697c478bd9Sstevel@tonic-gate  */
19707c478bd9Sstevel@tonic-gate static int
19717c478bd9Sstevel@tonic-gate pr_agent(prnode_t *pnp, prgregset_t prgregset, int *unlocked)
19727c478bd9Sstevel@tonic-gate {
19737c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
19747c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
19757c478bd9Sstevel@tonic-gate 	kthread_t *t;
19767c478bd9Sstevel@tonic-gate 	kthread_t *ct;
19777c478bd9Sstevel@tonic-gate 	klwp_t *clwp;
19787c478bd9Sstevel@tonic-gate 	k_sigset_t smask;
19797c478bd9Sstevel@tonic-gate 	int cid;
19807c478bd9Sstevel@tonic-gate 	void *bufp = NULL;
19817c478bd9Sstevel@tonic-gate 	int error;
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	*unlocked = 0;
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 	/*
19867c478bd9Sstevel@tonic-gate 	 * Cannot create the /proc agent lwp if :-
19877c478bd9Sstevel@tonic-gate 	 * - the process is not fully stopped or directed to stop.
19887c478bd9Sstevel@tonic-gate 	 * - there is an agent lwp already.
198997eda132Sraf 	 * - the process has been killed.
199097eda132Sraf 	 * - the process is exiting.
19917c478bd9Sstevel@tonic-gate 	 * - it's a vfork(2) parent.
19927c478bd9Sstevel@tonic-gate 	 */
19937c478bd9Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
19947c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
19957c478bd9Sstevel@tonic-gate 
199697eda132Sraf 	if ((!ISTOPPED(t) && !VSTOPPED(t) && !SUSPENDED(t) && !JDSTOPPED(t)) ||
199797eda132Sraf 	    p->p_agenttp != NULL ||
199897eda132Sraf 	    (p->p_flag & (SKILLED | SEXITING | SVFWAIT))) {
19997c478bd9Sstevel@tonic-gate 		thread_unlock(t);
20007c478bd9Sstevel@tonic-gate 		return (EBUSY);
20017c478bd9Sstevel@tonic-gate 	}
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	thread_unlock(t);
20047c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	sigfillset(&smask);
20077c478bd9Sstevel@tonic-gate 	sigdiffset(&smask, &cantmask);
20087c478bd9Sstevel@tonic-gate 	clwp = lwp_create(lwp_rtt, NULL, 0, p, TS_STOPPED,
20097c478bd9Sstevel@tonic-gate 	    t->t_pri, &smask, NOCLASS, 0);
20107c478bd9Sstevel@tonic-gate 	if (clwp == NULL) {
20117c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
20127c478bd9Sstevel@tonic-gate 		return (ENOMEM);
20137c478bd9Sstevel@tonic-gate 	}
20147c478bd9Sstevel@tonic-gate 	prsetprregs(clwp, prgregset, 1);
2015f971a346SBryan Cantrill 
2016f971a346SBryan Cantrill 	/*
2017f971a346SBryan Cantrill 	 * Because abandoning the agent inside the target process leads to
2018f971a346SBryan Cantrill 	 * a state that is essentially undebuggable, we record the psinfo of
2019f971a346SBryan Cantrill 	 * the process creating the agent and hang that off of the lwp.
2020f971a346SBryan Cantrill 	 */
2021f971a346SBryan Cantrill 	clwp->lwp_spymaster = kmem_zalloc(sizeof (psinfo_t), KM_SLEEP);
2022f971a346SBryan Cantrill 	mutex_enter(&curproc->p_lock);
2023f971a346SBryan Cantrill 	prgetpsinfo(curproc, clwp->lwp_spymaster);
2024f971a346SBryan Cantrill 	mutex_exit(&curproc->p_lock);
2025f971a346SBryan Cantrill 
2026f971a346SBryan Cantrill 	/*
2027f971a346SBryan Cantrill 	 * We overload pr_time in the spymaster to denote the time at which the
2028f971a346SBryan Cantrill 	 * agent was created.
2029f971a346SBryan Cantrill 	 */
2030f971a346SBryan Cantrill 	gethrestime(&clwp->lwp_spymaster->pr_time);
2031f971a346SBryan Cantrill 
20327c478bd9Sstevel@tonic-gate retry:
20337c478bd9Sstevel@tonic-gate 	cid = t->t_cid;
20347c478bd9Sstevel@tonic-gate 	(void) CL_ALLOC(&bufp, cid, KM_SLEEP);
20357c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
20367c478bd9Sstevel@tonic-gate 	if (cid != t->t_cid) {
20377c478bd9Sstevel@tonic-gate 		/*
20387c478bd9Sstevel@tonic-gate 		 * Someone just changed this thread's scheduling class,
20397c478bd9Sstevel@tonic-gate 		 * so try pre-allocating the buffer again.  Hopefully we
20407c478bd9Sstevel@tonic-gate 		 * don't hit this often.
20417c478bd9Sstevel@tonic-gate 		 */
20427c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
20437c478bd9Sstevel@tonic-gate 		CL_FREE(cid, bufp);
20447c478bd9Sstevel@tonic-gate 		goto retry;
20457c478bd9Sstevel@tonic-gate 	}
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	clwp->lwp_ap = clwp->lwp_arg;
20487c478bd9Sstevel@tonic-gate 	clwp->lwp_eosys = NORMALRETURN;
20497c478bd9Sstevel@tonic-gate 	ct = lwptot(clwp);
20507c478bd9Sstevel@tonic-gate 	ct->t_clfuncs = t->t_clfuncs;
20517c478bd9Sstevel@tonic-gate 	CL_FORK(t, ct, bufp);
20527c478bd9Sstevel@tonic-gate 	ct->t_cid = t->t_cid;
20537c478bd9Sstevel@tonic-gate 	ct->t_proc_flag |= TP_PRSTOP;
20547c478bd9Sstevel@tonic-gate 	/*
20557c478bd9Sstevel@tonic-gate 	 * Setting t_sysnum to zero causes post_syscall()
20567c478bd9Sstevel@tonic-gate 	 * to bypass all syscall checks and go directly to
20577c478bd9Sstevel@tonic-gate 	 *	if (issig()) psig();
20587c478bd9Sstevel@tonic-gate 	 * so that the agent lwp will stop in issig_forreal()
20597c478bd9Sstevel@tonic-gate 	 * showing PR_REQUESTED.
20607c478bd9Sstevel@tonic-gate 	 */
20617c478bd9Sstevel@tonic-gate 	ct->t_sysnum = 0;
20627c478bd9Sstevel@tonic-gate 	ct->t_post_sys = 1;
20637c478bd9Sstevel@tonic-gate 	ct->t_sig_check = 1;
20647c478bd9Sstevel@tonic-gate 	p->p_agenttp = ct;
20657c478bd9Sstevel@tonic-gate 	ct->t_proc_flag &= ~TP_HOLDLWP;
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_pcommon;
20687c478bd9Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	lwp_create_done(ct);
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	/*
20737c478bd9Sstevel@tonic-gate 	 * Don't return until the agent is stopped on PR_REQUESTED.
20747c478bd9Sstevel@tonic-gate 	 */
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	for (;;) {
20777c478bd9Sstevel@tonic-gate 		prunlock(pnp);
20787c478bd9Sstevel@tonic-gate 		*unlocked = 1;
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 		/*
20817c478bd9Sstevel@tonic-gate 		 * Wait for the agent to stop and notify us.
20827c478bd9Sstevel@tonic-gate 		 * If we've been interrupted, return that information.
20837c478bd9Sstevel@tonic-gate 		 */
20843348528fSdm120769 		error = pr_wait(pcp, NULL, 0);
20857c478bd9Sstevel@tonic-gate 		if (error == EINTR) {
20867c478bd9Sstevel@tonic-gate 			error = 0;
20877c478bd9Sstevel@tonic-gate 			break;
20887c478bd9Sstevel@tonic-gate 		}
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 		/*
20917c478bd9Sstevel@tonic-gate 		 * Confirm that the agent LWP has stopped.
20927c478bd9Sstevel@tonic-gate 		 */
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) != 0)
20957c478bd9Sstevel@tonic-gate 			break;
20967c478bd9Sstevel@tonic-gate 		*unlocked = 0;
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 		/*
20997c478bd9Sstevel@tonic-gate 		 * Since we dropped the lock on the process, the agent
21007c478bd9Sstevel@tonic-gate 		 * may have disappeared or changed. Grab the current
21017c478bd9Sstevel@tonic-gate 		 * agent and check fail if it has disappeared.
21027c478bd9Sstevel@tonic-gate 		 */
21037c478bd9Sstevel@tonic-gate 		if ((ct = p->p_agenttp) == NULL) {
21047c478bd9Sstevel@tonic-gate 			error = ENOENT;
21057c478bd9Sstevel@tonic-gate 			break;
21067c478bd9Sstevel@tonic-gate 		}
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
21097c478bd9Sstevel@tonic-gate 		thread_lock(ct);
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 		if (ISTOPPED(ct)) {
21127c478bd9Sstevel@tonic-gate 			thread_unlock(ct);
21137c478bd9Sstevel@tonic-gate 			mutex_exit(&pcp->prc_mutex);
21147c478bd9Sstevel@tonic-gate 			break;
21157c478bd9Sstevel@tonic-gate 		}
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 		thread_unlock(ct);
21187c478bd9Sstevel@tonic-gate 	}
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	return (error ? error : -1);
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate static int
21247c478bd9Sstevel@tonic-gate pr_rdwr(proc_t *p, enum uio_rw rw, priovec_t *pio)
21257c478bd9Sstevel@tonic-gate {
21267c478bd9Sstevel@tonic-gate 	caddr_t base = (caddr_t)pio->pio_base;
21277c478bd9Sstevel@tonic-gate 	size_t cnt = pio->pio_len;
21287c478bd9Sstevel@tonic-gate 	uintptr_t offset = (uintptr_t)pio->pio_offset;
21297c478bd9Sstevel@tonic-gate 	struct uio auio;
21307c478bd9Sstevel@tonic-gate 	struct iovec aiov;
21317c478bd9Sstevel@tonic-gate 	int error = 0;
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
21347c478bd9Sstevel@tonic-gate 		error = EIO;
21357c478bd9Sstevel@tonic-gate 	else if ((base + cnt) < base || (offset + cnt) < offset)
21367c478bd9Sstevel@tonic-gate 		error = EINVAL;
21377c478bd9Sstevel@tonic-gate 	else if (cnt != 0) {
21387c478bd9Sstevel@tonic-gate 		aiov.iov_base = base;
21397c478bd9Sstevel@tonic-gate 		aiov.iov_len = cnt;
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate 		auio.uio_loffset = offset;
21427c478bd9Sstevel@tonic-gate 		auio.uio_iov = &aiov;
21437c478bd9Sstevel@tonic-gate 		auio.uio_iovcnt = 1;
21447c478bd9Sstevel@tonic-gate 		auio.uio_resid = cnt;
21457c478bd9Sstevel@tonic-gate 		auio.uio_segflg = UIO_USERSPACE;
21467c478bd9Sstevel@tonic-gate 		auio.uio_llimit = (longlong_t)MAXOFFSET_T;
21477c478bd9Sstevel@tonic-gate 		auio.uio_fmode = FREAD|FWRITE;
21487c478bd9Sstevel@tonic-gate 		auio.uio_extflg = UIO_COPY_DEFAULT;
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
21517c478bd9Sstevel@tonic-gate 		error = prusrio(p, rw, &auio, 0);
21527c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 		/*
21557c478bd9Sstevel@tonic-gate 		 * We have no way to return the i/o count,
21567c478bd9Sstevel@tonic-gate 		 * like read() or write() would do, so we
21577c478bd9Sstevel@tonic-gate 		 * return an error if the i/o was truncated.
21587c478bd9Sstevel@tonic-gate 		 */
21597c478bd9Sstevel@tonic-gate 		if (auio.uio_resid != 0 && error == 0)
21607c478bd9Sstevel@tonic-gate 			error = EIO;
21617c478bd9Sstevel@tonic-gate 	}
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	return (error);
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate static int
21677c478bd9Sstevel@tonic-gate pr_scred(proc_t *p, prcred_t *prcred, cred_t *cr, boolean_t dogrps)
21687c478bd9Sstevel@tonic-gate {
21697c478bd9Sstevel@tonic-gate 	kthread_t *t;
21707c478bd9Sstevel@tonic-gate 	cred_t *oldcred;
21717c478bd9Sstevel@tonic-gate 	cred_t *newcred;
21727c478bd9Sstevel@tonic-gate 	uid_t oldruid;
21737c478bd9Sstevel@tonic-gate 	int error;
2174bda89588Sjp151216 	zone_t *zone = crgetzone(cr);
21757c478bd9Sstevel@tonic-gate 
2176bda89588Sjp151216 	if (!VALID_UID(prcred->pr_euid, zone) ||
2177bda89588Sjp151216 	    !VALID_UID(prcred->pr_ruid, zone) ||
2178bda89588Sjp151216 	    !VALID_UID(prcred->pr_suid, zone) ||
2179bda89588Sjp151216 	    !VALID_GID(prcred->pr_egid, zone) ||
2180bda89588Sjp151216 	    !VALID_GID(prcred->pr_rgid, zone) ||
2181bda89588Sjp151216 	    !VALID_GID(prcred->pr_sgid, zone))
21827c478bd9Sstevel@tonic-gate 		return (EINVAL);
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	if (dogrps) {
21857c478bd9Sstevel@tonic-gate 		int ngrp = prcred->pr_ngroups;
21867c478bd9Sstevel@tonic-gate 		int i;
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 		if (ngrp < 0 || ngrp > ngroups_max)
21897c478bd9Sstevel@tonic-gate 			return (EINVAL);
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 		for (i = 0; i < ngrp; i++) {
2192bda89588Sjp151216 			if (!VALID_GID(prcred->pr_groups[i], zone))
21937c478bd9Sstevel@tonic-gate 				return (EINVAL);
21947c478bd9Sstevel@tonic-gate 		}
21957c478bd9Sstevel@tonic-gate 	}
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 	error = secpolicy_allow_setid(cr, prcred->pr_euid, B_FALSE);
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 	if (error == 0 && prcred->pr_ruid != prcred->pr_euid)
22007c478bd9Sstevel@tonic-gate 		error = secpolicy_allow_setid(cr, prcred->pr_ruid, B_FALSE);
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	if (error == 0 && prcred->pr_suid != prcred->pr_euid &&
22037c478bd9Sstevel@tonic-gate 	    prcred->pr_suid != prcred->pr_ruid)
22047c478bd9Sstevel@tonic-gate 		error = secpolicy_allow_setid(cr, prcred->pr_suid, B_FALSE);
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	if (error)
22077c478bd9Sstevel@tonic-gate 		return (error);
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate 	/* hold old cred so it doesn't disappear while we dup it */
22127c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
22137c478bd9Sstevel@tonic-gate 	crhold(oldcred = p->p_cred);
22147c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22157c478bd9Sstevel@tonic-gate 	newcred = crdup(oldcred);
22167c478bd9Sstevel@tonic-gate 	oldruid = crgetruid(oldcred);
22177c478bd9Sstevel@tonic-gate 	crfree(oldcred);
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate 	/* Error checking done above */
22207c478bd9Sstevel@tonic-gate 	(void) crsetresuid(newcred, prcred->pr_ruid, prcred->pr_euid,
22217c478bd9Sstevel@tonic-gate 	    prcred->pr_suid);
22227c478bd9Sstevel@tonic-gate 	(void) crsetresgid(newcred, prcred->pr_rgid, prcred->pr_egid,
22237c478bd9Sstevel@tonic-gate 	    prcred->pr_sgid);
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 	if (dogrps) {
22267c478bd9Sstevel@tonic-gate 		(void) crsetgroups(newcred, prcred->pr_ngroups,
22277c478bd9Sstevel@tonic-gate 		    prcred->pr_groups);
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate 	}
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
22327c478bd9Sstevel@tonic-gate 	oldcred = p->p_cred;
22337c478bd9Sstevel@tonic-gate 	p->p_cred = newcred;
22347c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22357c478bd9Sstevel@tonic-gate 	crfree(oldcred);
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 	/*
22387c478bd9Sstevel@tonic-gate 	 * Keep count of processes per uid consistent.
22397c478bd9Sstevel@tonic-gate 	 */
22407c478bd9Sstevel@tonic-gate 	if (oldruid != prcred->pr_ruid) {
22417c478bd9Sstevel@tonic-gate 		zoneid_t zoneid = crgetzoneid(newcred);
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
22447c478bd9Sstevel@tonic-gate 		upcount_dec(oldruid, zoneid);
22457c478bd9Sstevel@tonic-gate 		upcount_inc(prcred->pr_ruid, zoneid);
22467c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
22477c478bd9Sstevel@tonic-gate 	}
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	/*
22507c478bd9Sstevel@tonic-gate 	 * Broadcast the cred change to the threads.
22517c478bd9Sstevel@tonic-gate 	 */
22527c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
22537c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
22547c478bd9Sstevel@tonic-gate 	do {
22557c478bd9Sstevel@tonic-gate 		t->t_pre_sys = 1; /* so syscall will get new cred */
22567c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	return (0);
22597c478bd9Sstevel@tonic-gate }
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate /*
22627c478bd9Sstevel@tonic-gate  * Change process credentials to specified zone.  Used to temporarily
22637c478bd9Sstevel@tonic-gate  * set a process to run in the global zone; only transitions between
22647c478bd9Sstevel@tonic-gate  * the process's actual zone and the global zone are allowed.
22657c478bd9Sstevel@tonic-gate  */
22667c478bd9Sstevel@tonic-gate static int
22677c478bd9Sstevel@tonic-gate pr_szoneid(proc_t *p, zoneid_t zoneid, cred_t *cr)
22687c478bd9Sstevel@tonic-gate {
22697c478bd9Sstevel@tonic-gate 	kthread_t *t;
22707c478bd9Sstevel@tonic-gate 	cred_t *oldcred;
22717c478bd9Sstevel@tonic-gate 	cred_t *newcred;
22727c478bd9Sstevel@tonic-gate 	zone_t *zptr;
2273956b78ccSsl108498 	zoneid_t oldzoneid;
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	if (secpolicy_zone_config(cr) != 0)
22767c478bd9Sstevel@tonic-gate 		return (EPERM);
22777c478bd9Sstevel@tonic-gate 	if (zoneid != GLOBAL_ZONEID && zoneid != p->p_zone->zone_id)
22787c478bd9Sstevel@tonic-gate 		return (EINVAL);
22797c478bd9Sstevel@tonic-gate 	if ((zptr = zone_find_by_id(zoneid)) == NULL)
22807c478bd9Sstevel@tonic-gate 		return (EINVAL);
22817c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
22827c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
2283956b78ccSsl108498 	oldcred = p->p_cred;
2284956b78ccSsl108498 	crhold(oldcred);
22857c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22867c478bd9Sstevel@tonic-gate 	newcred = crdup(oldcred);
2287956b78ccSsl108498 	oldzoneid = crgetzoneid(oldcred);
22887c478bd9Sstevel@tonic-gate 	crfree(oldcred);
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate 	crsetzone(newcred, zptr);
22917c478bd9Sstevel@tonic-gate 	zone_rele(zptr);
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
22947c478bd9Sstevel@tonic-gate 	oldcred = p->p_cred;
22957c478bd9Sstevel@tonic-gate 	p->p_cred = newcred;
22967c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
22977c478bd9Sstevel@tonic-gate 	crfree(oldcred);
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 	/*
2300956b78ccSsl108498 	 * The target process is changing zones (according to its cred), so
2301956b78ccSsl108498 	 * update the per-zone upcounts, which are based on process creds.
2302956b78ccSsl108498 	 */
2303956b78ccSsl108498 	if (oldzoneid != zoneid) {
2304956b78ccSsl108498 		uid_t ruid = crgetruid(newcred);
2305956b78ccSsl108498 
2306956b78ccSsl108498 		mutex_enter(&pidlock);
2307956b78ccSsl108498 		upcount_dec(ruid, oldzoneid);
2308956b78ccSsl108498 		upcount_inc(ruid, zoneid);
2309956b78ccSsl108498 		mutex_exit(&pidlock);
2310956b78ccSsl108498 	}
2311956b78ccSsl108498 	/*
23127c478bd9Sstevel@tonic-gate 	 * Broadcast the cred change to the threads.
23137c478bd9Sstevel@tonic-gate 	 */
23147c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
23157c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
23167c478bd9Sstevel@tonic-gate 	do {
23177c478bd9Sstevel@tonic-gate 		t->t_pre_sys = 1;	/* so syscall will get new cred */
23187c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 	return (0);
23217c478bd9Sstevel@tonic-gate }
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate static int
23247c478bd9Sstevel@tonic-gate pr_spriv(proc_t *p, prpriv_t *prpriv, cred_t *cr)
23257c478bd9Sstevel@tonic-gate {
23267c478bd9Sstevel@tonic-gate 	kthread_t *t;
23277c478bd9Sstevel@tonic-gate 	int err;
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate 	if ((err = priv_pr_spriv(p, prpriv, cr)) == 0) {
23327c478bd9Sstevel@tonic-gate 		/*
23337c478bd9Sstevel@tonic-gate 		 * Broadcast the cred change to the threads.
23347c478bd9Sstevel@tonic-gate 		 */
23357c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
23367c478bd9Sstevel@tonic-gate 		do {
23377c478bd9Sstevel@tonic-gate 			t->t_pre_sys = 1; /* so syscall will get new cred */
23387c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
23397c478bd9Sstevel@tonic-gate 	}
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 	return (err);
23427c478bd9Sstevel@tonic-gate }
23437c478bd9Sstevel@tonic-gate 
23447c478bd9Sstevel@tonic-gate /*
23457c478bd9Sstevel@tonic-gate  * Return -1 if the process is the parent of a vfork(1) whose child has yet to
23467c478bd9Sstevel@tonic-gate  * terminate or perform an exec(2).
23477c478bd9Sstevel@tonic-gate  *
23487c478bd9Sstevel@tonic-gate  * Returns 0 if the process is fully stopped except for the current thread (if
23497c478bd9Sstevel@tonic-gate  * we are operating on our own process), 1 otherwise.
23507c478bd9Sstevel@tonic-gate  *
23517c478bd9Sstevel@tonic-gate  * If the watchstop flag is set, then we ignore threads with TP_WATCHSTOP set.
23527c478bd9Sstevel@tonic-gate  * See holdwatch() for details.
23537c478bd9Sstevel@tonic-gate  */
23547c478bd9Sstevel@tonic-gate int
23557c478bd9Sstevel@tonic-gate pr_allstopped(proc_t *p, int watchstop)
23567c478bd9Sstevel@tonic-gate {
23577c478bd9Sstevel@tonic-gate 	kthread_t *t;
23587c478bd9Sstevel@tonic-gate 	int rv = 0;
23597c478bd9Sstevel@tonic-gate 
23607c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
23617c478bd9Sstevel@tonic-gate 
23627c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)	/* waiting for vfork'd child to exec */
23637c478bd9Sstevel@tonic-gate 		return (-1);
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
23667c478bd9Sstevel@tonic-gate 		do {
23677c478bd9Sstevel@tonic-gate 			if (t == curthread || VSTOPPED(t) ||
23687c478bd9Sstevel@tonic-gate 			    (watchstop && (t->t_proc_flag & TP_WATCHSTOP)))
23697c478bd9Sstevel@tonic-gate 				continue;
23707c478bd9Sstevel@tonic-gate 			thread_lock(t);
23717c478bd9Sstevel@tonic-gate 			switch (t->t_state) {
23727c478bd9Sstevel@tonic-gate 			case TS_ZOMB:
23737c478bd9Sstevel@tonic-gate 			case TS_STOPPED:
23747c478bd9Sstevel@tonic-gate 				break;
23757c478bd9Sstevel@tonic-gate 			case TS_SLEEP:
23767c478bd9Sstevel@tonic-gate 				if (!(t->t_flag & T_WAKEABLE) ||
23777c478bd9Sstevel@tonic-gate 				    t->t_wchan0 == NULL)
23787c478bd9Sstevel@tonic-gate 					rv = 1;
23797c478bd9Sstevel@tonic-gate 				break;
23807c478bd9Sstevel@tonic-gate 			default:
23817c478bd9Sstevel@tonic-gate 				rv = 1;
23827c478bd9Sstevel@tonic-gate 				break;
23837c478bd9Sstevel@tonic-gate 			}
23847c478bd9Sstevel@tonic-gate 			thread_unlock(t);
23857c478bd9Sstevel@tonic-gate 		} while (rv == 0 && (t = t->t_forw) != p->p_tlist);
23867c478bd9Sstevel@tonic-gate 	}
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 	return (rv);
23897c478bd9Sstevel@tonic-gate }
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate /*
23927c478bd9Sstevel@tonic-gate  * Cause all lwps in the process to pause (for watchpoint operations).
23937c478bd9Sstevel@tonic-gate  */
23947c478bd9Sstevel@tonic-gate static void
23957c478bd9Sstevel@tonic-gate pauselwps(proc_t *p)
23967c478bd9Sstevel@tonic-gate {
23977c478bd9Sstevel@tonic-gate 	kthread_t *t;
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
24007c478bd9Sstevel@tonic-gate 	ASSERT(p != curproc);
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
24037c478bd9Sstevel@tonic-gate 		do {
24047c478bd9Sstevel@tonic-gate 			thread_lock(t);
24057c478bd9Sstevel@tonic-gate 			t->t_proc_flag |= TP_PAUSE;
24067c478bd9Sstevel@tonic-gate 			aston(t);
2407c97ad5cdSakolb 			if ((ISWAKEABLE(t) && (t->t_wchan0 == NULL)) ||
2408c97ad5cdSakolb 			    ISWAITING(t)) {
24097c478bd9Sstevel@tonic-gate 				setrun_locked(t);
24107c478bd9Sstevel@tonic-gate 			}
24117c478bd9Sstevel@tonic-gate 			prpokethread(t);
24127c478bd9Sstevel@tonic-gate 			thread_unlock(t);
24137c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
24147c478bd9Sstevel@tonic-gate 	}
24157c478bd9Sstevel@tonic-gate }
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate /*
24187c478bd9Sstevel@tonic-gate  * undo the effects of pauselwps()
24197c478bd9Sstevel@tonic-gate  */
24207c478bd9Sstevel@tonic-gate static void
24217c478bd9Sstevel@tonic-gate unpauselwps(proc_t *p)
24227c478bd9Sstevel@tonic-gate {
24237c478bd9Sstevel@tonic-gate 	kthread_t *t;
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
24267c478bd9Sstevel@tonic-gate 	ASSERT(p != curproc);
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
24297c478bd9Sstevel@tonic-gate 		do {
24307c478bd9Sstevel@tonic-gate 			thread_lock(t);
24317c478bd9Sstevel@tonic-gate 			t->t_proc_flag &= ~TP_PAUSE;
24327c478bd9Sstevel@tonic-gate 			if (t->t_state == TS_STOPPED) {
24337c478bd9Sstevel@tonic-gate 				t->t_schedflag |= TS_UNPAUSE;
24347c478bd9Sstevel@tonic-gate 				t->t_dtrace_stop = 0;
24357c478bd9Sstevel@tonic-gate 				setrun_locked(t);
24367c478bd9Sstevel@tonic-gate 			}
24377c478bd9Sstevel@tonic-gate 			thread_unlock(t);
24387c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
24397c478bd9Sstevel@tonic-gate 	}
24407c478bd9Sstevel@tonic-gate }
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate /*
24437c478bd9Sstevel@tonic-gate  * Cancel all watched areas.  Called from prclose().
24447c478bd9Sstevel@tonic-gate  */
24457c478bd9Sstevel@tonic-gate proc_t *
24467c478bd9Sstevel@tonic-gate pr_cancel_watch(prnode_t *pnp)
24477c478bd9Sstevel@tonic-gate {
24487c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_pcommon->prc_proc;
24497c478bd9Sstevel@tonic-gate 	struct as *as;
24507c478bd9Sstevel@tonic-gate 	kthread_t *t;
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock) && (p->p_proc_flag & P_PR_LOCK));
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	if (!pr_watch_active(p))
24557c478bd9Sstevel@tonic-gate 		return (p);
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 	/*
24587c478bd9Sstevel@tonic-gate 	 * Pause the process before dealing with the watchpoints.
24597c478bd9Sstevel@tonic-gate 	 */
24607c478bd9Sstevel@tonic-gate 	if (p == curproc) {
24617c478bd9Sstevel@tonic-gate 		prunlock(pnp);
24627c478bd9Sstevel@tonic-gate 		while (holdwatch() != 0)
24637c478bd9Sstevel@tonic-gate 			continue;
24647c478bd9Sstevel@tonic-gate 		p = pr_p_lock(pnp);
24657c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
24667c478bd9Sstevel@tonic-gate 		ASSERT(p == curproc);
24677c478bd9Sstevel@tonic-gate 	} else {
24687c478bd9Sstevel@tonic-gate 		pauselwps(p);
24697c478bd9Sstevel@tonic-gate 		while (p != NULL && pr_allstopped(p, 0) > 0) {
24707c478bd9Sstevel@tonic-gate 			/*
24717c478bd9Sstevel@tonic-gate 			 * This cv/mutex pair is persistent even
24727c478bd9Sstevel@tonic-gate 			 * if the process disappears after we
24737c478bd9Sstevel@tonic-gate 			 * unmark it and drop p->p_lock.
24747c478bd9Sstevel@tonic-gate 			 */
24757c478bd9Sstevel@tonic-gate 			kcondvar_t *cv = &pr_pid_cv[p->p_slot];
24767c478bd9Sstevel@tonic-gate 			kmutex_t *mp = &p->p_lock;
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 			prunmark(p);
24797c478bd9Sstevel@tonic-gate 			(void) cv_wait(cv, mp);
24807c478bd9Sstevel@tonic-gate 			mutex_exit(mp);
24817c478bd9Sstevel@tonic-gate 			p = pr_p_lock(pnp);  /* NULL if process disappeared */
24827c478bd9Sstevel@tonic-gate 			mutex_exit(&pr_pidlock);
24837c478bd9Sstevel@tonic-gate 		}
24847c478bd9Sstevel@tonic-gate 	}
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	if (p == NULL)		/* the process disappeared */
24877c478bd9Sstevel@tonic-gate 		return (NULL);
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_pcommon->prc_proc);
24907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock) && (p->p_proc_flag & P_PR_LOCK));
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	if (pr_watch_active(p)) {
24937c478bd9Sstevel@tonic-gate 		pr_free_watchpoints(p);
24947c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
24957c478bd9Sstevel@tonic-gate 			do {
24967c478bd9Sstevel@tonic-gate 				watch_disable(t);
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
24997c478bd9Sstevel@tonic-gate 		}
25007c478bd9Sstevel@tonic-gate 	}
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	if ((as = p->p_as) != NULL) {
25037c478bd9Sstevel@tonic-gate 		avl_tree_t *tree;
25047c478bd9Sstevel@tonic-gate 		struct watched_page *pwp;
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate 		/*
25077c478bd9Sstevel@tonic-gate 		 * If this is the parent of a vfork, the watched page
25087c478bd9Sstevel@tonic-gate 		 * list has been moved temporarily to p->p_wpage.
25097c478bd9Sstevel@tonic-gate 		 */
25107c478bd9Sstevel@tonic-gate 		if (avl_numnodes(&p->p_wpage) != 0)
25117c478bd9Sstevel@tonic-gate 			tree = &p->p_wpage;
25127c478bd9Sstevel@tonic-gate 		else
25137c478bd9Sstevel@tonic-gate 			tree = &as->a_wpage;
25147c478bd9Sstevel@tonic-gate 
25157c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
2516*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_ENTER(as, RW_WRITER);
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 		for (pwp = avl_first(tree); pwp != NULL;
25197c478bd9Sstevel@tonic-gate 		    pwp = AVL_NEXT(tree, pwp)) {
25207c478bd9Sstevel@tonic-gate 			pwp->wp_read = 0;
25217c478bd9Sstevel@tonic-gate 			pwp->wp_write = 0;
25227c478bd9Sstevel@tonic-gate 			pwp->wp_exec = 0;
25237c478bd9Sstevel@tonic-gate 			if ((pwp->wp_flags & WP_SETPROT) == 0) {
25247c478bd9Sstevel@tonic-gate 				pwp->wp_flags |= WP_SETPROT;
25257c478bd9Sstevel@tonic-gate 				pwp->wp_prot = pwp->wp_oprot;
25267c478bd9Sstevel@tonic-gate 				pwp->wp_list = p->p_wprot;
25277c478bd9Sstevel@tonic-gate 				p->p_wprot = pwp;
25287c478bd9Sstevel@tonic-gate 			}
25297c478bd9Sstevel@tonic-gate 		}
25307c478bd9Sstevel@tonic-gate 
2531*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
25327c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
25337c478bd9Sstevel@tonic-gate 	}
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 	/*
25367c478bd9Sstevel@tonic-gate 	 * Unpause the process now.
25377c478bd9Sstevel@tonic-gate 	 */
25387c478bd9Sstevel@tonic-gate 	if (p == curproc)
25397c478bd9Sstevel@tonic-gate 		continuelwps(p);
25407c478bd9Sstevel@tonic-gate 	else
25417c478bd9Sstevel@tonic-gate 		unpauselwps(p);
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 	return (p);
25447c478bd9Sstevel@tonic-gate }
2545