xref: /illumos-gate/usr/src/uts/common/fs/proc/prcontrol.c (revision ed093b41)
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.
29*ed093b41SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
30f971a346SBryan Cantrill  */
31f971a346SBryan Cantrill 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/uio.h>
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
367c478bd9Sstevel@tonic-gate #include <sys/cred.h>
377c478bd9Sstevel@tonic-gate #include <sys/policy.h>
387c478bd9Sstevel@tonic-gate #include <sys/debug.h>
397c478bd9Sstevel@tonic-gate #include <sys/errno.h>
407c478bd9Sstevel@tonic-gate #include <sys/file.h>
417c478bd9Sstevel@tonic-gate #include <sys/inline.h>
427c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
437c478bd9Sstevel@tonic-gate #include <sys/proc.h>
44eb9dbf0cSRoger A. Faulkner #include <sys/brand.h>
457c478bd9Sstevel@tonic-gate #include <sys/regset.h>
467c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
477c478bd9Sstevel@tonic-gate #include <sys/systm.h>
487c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
497c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
507c478bd9Sstevel@tonic-gate #include <sys/signal.h>
517c478bd9Sstevel@tonic-gate #include <sys/auxv.h>
527c478bd9Sstevel@tonic-gate #include <sys/user.h>
537c478bd9Sstevel@tonic-gate #include <sys/class.h>
547c478bd9Sstevel@tonic-gate #include <sys/fault.h>
557c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
567c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
577c478bd9Sstevel@tonic-gate #include <sys/zone.h>
587c478bd9Sstevel@tonic-gate #include <sys/copyops.h>
597c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
607c478bd9Sstevel@tonic-gate #include <vm/as.h>
617c478bd9Sstevel@tonic-gate #include <vm/seg.h>
627c478bd9Sstevel@tonic-gate #include <fs/proc/prdata.h>
637c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h>
64*ed093b41SRobert Mustacchi #include <sys/stdalign.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static	void	pr_settrace(proc_t *, sigset_t *);
677c478bd9Sstevel@tonic-gate static	int	pr_setfpregs(prnode_t *, prfpregset_t *);
687c478bd9Sstevel@tonic-gate static	int	pr_setxregs(prnode_t *, prxregset_t *);
697c478bd9Sstevel@tonic-gate static	int	pr_setvaddr(prnode_t *, caddr_t);
707c478bd9Sstevel@tonic-gate static	int	pr_clearsig(prnode_t *);
717c478bd9Sstevel@tonic-gate static	int	pr_clearflt(prnode_t *);
727c478bd9Sstevel@tonic-gate static	int	pr_watch(prnode_t *, prwatch_t *, int *);
737c478bd9Sstevel@tonic-gate static	int	pr_agent(prnode_t *, prgregset_t, int *);
747c478bd9Sstevel@tonic-gate static	int	pr_rdwr(proc_t *, enum uio_rw, priovec_t *);
757c478bd9Sstevel@tonic-gate static	int	pr_scred(proc_t *, prcred_t *, cred_t *, boolean_t);
767c478bd9Sstevel@tonic-gate static	int	pr_spriv(proc_t *, prpriv_t *, cred_t *);
777c478bd9Sstevel@tonic-gate static	int	pr_szoneid(proc_t *, zoneid_t, cred_t *);
787c478bd9Sstevel@tonic-gate static	void	pauselwps(proc_t *);
797c478bd9Sstevel@tonic-gate static	void	unpauselwps(proc_t *);
807c478bd9Sstevel@tonic-gate 
81*ed093b41SRobert Mustacchi /*
82*ed093b41SRobert Mustacchi  * This union represents the size of commands that are generally fixed size in
83*ed093b41SRobert Mustacchi  * /proc. There are some commands that are variable size because the actual data
84*ed093b41SRobert Mustacchi  * is structured. Of things in the latter category, some of these are the same
85*ed093b41SRobert Mustacchi  * across all architectures (e.g. prcred_t, prpriv_t) and some vary and are
86*ed093b41SRobert Mustacchi  * opaque (e.g. the prxregset_t).
87*ed093b41SRobert Mustacchi  */
887c478bd9Sstevel@tonic-gate typedef union {
897c478bd9Sstevel@tonic-gate 	long		sig;		/* PCKILL, PCUNKILL */
907c478bd9Sstevel@tonic-gate 	long		nice;		/* PCNICE */
917c478bd9Sstevel@tonic-gate 	long		timeo;		/* PCTWSTOP */
927c478bd9Sstevel@tonic-gate 	ulong_t		flags;		/* PCRUN, PCSET, PCUNSET */
937c478bd9Sstevel@tonic-gate 	caddr_t		vaddr;		/* PCSVADDR */
947c478bd9Sstevel@tonic-gate 	siginfo_t	siginfo;	/* PCSSIG */
957c478bd9Sstevel@tonic-gate 	sigset_t	sigset;		/* PCSTRACE, PCSHOLD */
967c478bd9Sstevel@tonic-gate 	fltset_t	fltset;		/* PCSFAULT */
977c478bd9Sstevel@tonic-gate 	sysset_t	sysset;		/* PCSENTRY, PCSEXIT */
987c478bd9Sstevel@tonic-gate 	prgregset_t	prgregset;	/* PCSREG, PCAGENT */
997c478bd9Sstevel@tonic-gate 	prfpregset_t	prfpregset;	/* PCSFPREG */
1007c478bd9Sstevel@tonic-gate 	prwatch_t	prwatch;	/* PCWATCH */
1017c478bd9Sstevel@tonic-gate 	priovec_t	priovec;	/* PCREAD, PCWRITE */
1027c478bd9Sstevel@tonic-gate 	prcred_t	prcred;		/* PCSCRED */
1037c478bd9Sstevel@tonic-gate 	prpriv_t	prpriv;		/* PCSPRIV */
1047c478bd9Sstevel@tonic-gate 	long		przoneid;	/* PCSZONE */
1057c478bd9Sstevel@tonic-gate } arg_t;
1067c478bd9Sstevel@tonic-gate 
107*ed093b41SRobert Mustacchi static boolean_t
prwritectl_pcscredx_sizef(const void * datap,size_t * sizep)108*ed093b41SRobert Mustacchi prwritectl_pcscredx_sizef(const void *datap, size_t *sizep)
1097c478bd9Sstevel@tonic-gate {
110*ed093b41SRobert Mustacchi 	const prcred_t *cred = datap;
1117c478bd9Sstevel@tonic-gate 
112*ed093b41SRobert Mustacchi 	if (cred->pr_ngroups < 0 || cred->pr_ngroups > ngroups_max) {
113*ed093b41SRobert Mustacchi 		return (B_FALSE);
114*ed093b41SRobert Mustacchi 	}
115*ed093b41SRobert Mustacchi 
116*ed093b41SRobert Mustacchi 	if (cred->pr_ngroups == 0) {
117*ed093b41SRobert Mustacchi 		*sizep = 0;
118*ed093b41SRobert Mustacchi 	} else {
119*ed093b41SRobert Mustacchi 		*sizep = (cred->pr_ngroups - 1) * sizeof (gid_t);
120*ed093b41SRobert Mustacchi 	}
121*ed093b41SRobert Mustacchi 	return (B_TRUE);
122*ed093b41SRobert Mustacchi }
123*ed093b41SRobert Mustacchi 
124*ed093b41SRobert Mustacchi static boolean_t
prwritectl_pcspriv_sizef(const void * datap,size_t * sizep)125*ed093b41SRobert Mustacchi prwritectl_pcspriv_sizef(const void *datap, size_t *sizep)
126*ed093b41SRobert Mustacchi {
127*ed093b41SRobert Mustacchi 	const prpriv_t *priv = datap;
128*ed093b41SRobert Mustacchi 	*sizep = priv_prgetprivsize(priv) - sizeof (prpriv_t);
129*ed093b41SRobert Mustacchi 	return (B_TRUE);
130*ed093b41SRobert Mustacchi }
131*ed093b41SRobert Mustacchi 
1327c478bd9Sstevel@tonic-gate /*
133*ed093b41SRobert Mustacchi  * This structure represents a single /proc write command that we support and
134*ed093b41SRobert Mustacchi  * metadata about how to ensure we have sufficient data for it. To determine the
135*ed093b41SRobert Mustacchi  * data that we need to read, this combines information from three different
136*ed093b41SRobert Mustacchi  * sources for a given named command in 'pcs_cmd'. The main goal is to first
137*ed093b41SRobert Mustacchi  * make sure we have the right minimum amount of information so we can read and
138*ed093b41SRobert Mustacchi  * validate the data around variable length structures.
139*ed093b41SRobert Mustacchi  *
140*ed093b41SRobert Mustacchi  *   o Most commands have a fixed static size. This is represented in the
141*ed093b41SRobert Mustacchi  *     pcs_size member. This also is used to represent the base structure size
142*ed093b41SRobert Mustacchi  *     in the case of entries like PCSCREDX.
143*ed093b41SRobert Mustacchi  *
144*ed093b41SRobert Mustacchi  *   o Other commands have an unknown minimum size to determine how much data
145*ed093b41SRobert Mustacchi  *     there is and they use the pcs_minf() function to determine the right
146*ed093b41SRobert Mustacchi  *     value. This is often unknown at compile time because it is say a
147*ed093b41SRobert Mustacchi  *     machdep or ISA based feature (ala PCSXREGS) and we'd rather not #ifdef
148*ed093b41SRobert Mustacchi  *     this code to death. This may be skipped and is for most things. The value
149*ed093b41SRobert Mustacchi  *     it returns is added to the static value.
150*ed093b41SRobert Mustacchi  *
151*ed093b41SRobert Mustacchi  *   o The final piece is the pcs_sizef() function pointer which determines the
152*ed093b41SRobert Mustacchi  *     total required size for this. It is given a pointer that has at least
153*ed093b41SRobert Mustacchi  *     pcs_size and pcs_minf() bytes. This is used to determine the total
154*ed093b41SRobert Mustacchi  *     expected size of the structure. Callers must not dereference data beyond
155*ed093b41SRobert Mustacchi  *     what they've indicated previously. This should only return extra bytes
156*ed093b41SRobert Mustacchi  *     that are required beyond what was already indicated between the two
157*ed093b41SRobert Mustacchi  *     functions.
158*ed093b41SRobert Mustacchi  *
159*ed093b41SRobert Mustacchi  * In all cases, the core prwritectl() logic will determine if there is
160*ed093b41SRobert Mustacchi  * sufficient step along the way for each of these to proceed.
1617c478bd9Sstevel@tonic-gate  */
162*ed093b41SRobert Mustacchi typedef struct proc_control_info {
163*ed093b41SRobert Mustacchi 	long	pcs_cmd;
164*ed093b41SRobert Mustacchi 	size_t	pcs_size;
165*ed093b41SRobert Mustacchi 	boolean_t (*pcs_minf)(size_t *);
166*ed093b41SRobert Mustacchi 	boolean_t (*pcs_sizef)(const void *, size_t *);
167*ed093b41SRobert Mustacchi } proc_control_info_t;
1687c478bd9Sstevel@tonic-gate 
169*ed093b41SRobert Mustacchi static const proc_control_info_t proc_ctl_info[] = {
170*ed093b41SRobert Mustacchi 	{ PCNULL,	0,			NULL,		NULL },
171*ed093b41SRobert Mustacchi 	{ PCSTOP,	0,			NULL,		NULL },
172*ed093b41SRobert Mustacchi 	{ PCDSTOP,	0,			NULL,		NULL },
173*ed093b41SRobert Mustacchi 	{ PCWSTOP,	0,			NULL,		NULL },
174*ed093b41SRobert Mustacchi 	{ PCCSIG,	0,			NULL,		NULL },
175*ed093b41SRobert Mustacchi 	{ PCCFAULT,	0,			NULL,		NULL },
176*ed093b41SRobert Mustacchi 	{ PCSSIG,	sizeof (siginfo_t),	NULL,		NULL },
177*ed093b41SRobert Mustacchi 	{ PCTWSTOP,	sizeof (long),		NULL,		NULL },
178*ed093b41SRobert Mustacchi 	{ PCKILL,	sizeof (long),		NULL,		NULL },
179*ed093b41SRobert Mustacchi 	{ PCUNKILL,	sizeof (long),		NULL,		NULL },
180*ed093b41SRobert Mustacchi 	{ PCNICE,	sizeof (long),		NULL,		NULL },
181*ed093b41SRobert Mustacchi 	{ PCRUN,	sizeof (ulong_t),	NULL,		NULL },
182*ed093b41SRobert Mustacchi 	{ PCSET,	sizeof (ulong_t),	NULL,		NULL },
183*ed093b41SRobert Mustacchi 	{ PCUNSET,	sizeof (ulong_t),	NULL,		NULL },
184*ed093b41SRobert Mustacchi 	{ PCSTRACE,	sizeof (sigset_t),	NULL,		NULL },
185*ed093b41SRobert Mustacchi 	{ PCSHOLD,	sizeof (sigset_t),	NULL,		NULL },
186*ed093b41SRobert Mustacchi 	{ PCSFAULT,	sizeof (fltset_t),	NULL,		NULL },
187*ed093b41SRobert Mustacchi 	{ PCSENTRY,	sizeof (sysset_t),	NULL,		NULL },
188*ed093b41SRobert Mustacchi 	{ PCSEXIT,	sizeof (sysset_t),	NULL,		NULL },
189*ed093b41SRobert Mustacchi 	{ PCSREG,	sizeof (prgregset_t),	NULL,		NULL },
190*ed093b41SRobert Mustacchi 	{ PCAGENT,	sizeof (prgregset_t),	NULL,		NULL },
191*ed093b41SRobert Mustacchi 	{ PCSFPREG,	sizeof (prfpregset_t),	NULL,		NULL },
192*ed093b41SRobert Mustacchi 	{ PCSXREG,	0,			prwriteminxreg,
193*ed093b41SRobert Mustacchi 	    prwritesizexreg },
194*ed093b41SRobert Mustacchi 	{ PCWATCH,	sizeof (prwatch_t),	NULL,		NULL },
195*ed093b41SRobert Mustacchi 	{ PCREAD,	sizeof (priovec_t),	NULL,		NULL },
196*ed093b41SRobert Mustacchi 	{ PCWRITE,	sizeof (priovec_t),	NULL,		NULL },
197*ed093b41SRobert Mustacchi 	{ PCSCRED,	sizeof (prcred_t),	NULL,		NULL },
198*ed093b41SRobert Mustacchi 	{ PCSCREDX,	sizeof (prcred_t),	NULL,
199*ed093b41SRobert Mustacchi 	    prwritectl_pcscredx_sizef },
200*ed093b41SRobert Mustacchi 	{ PCSPRIV,	sizeof (prpriv_t),	NULL,
201*ed093b41SRobert Mustacchi 	    prwritectl_pcspriv_sizef },
202*ed093b41SRobert Mustacchi 	{ PCSZONE,	sizeof (long),		NULL,		NULL },
203*ed093b41SRobert Mustacchi };
204*ed093b41SRobert Mustacchi 
205*ed093b41SRobert Mustacchi /*
206*ed093b41SRobert Mustacchi  * We need a default buffer that we're going to allocate when we need memory to
207*ed093b41SRobert Mustacchi  * read control operations. This is on average large enough to hold multiple
208*ed093b41SRobert Mustacchi  * control operations. We leave this as a smaller value on debug builds just
209*ed093b41SRobert Mustacchi  * to exercise our reallocation logic.
210*ed093b41SRobert Mustacchi  */
211*ed093b41SRobert Mustacchi #ifdef	DEBUG
212*ed093b41SRobert Mustacchi #define	PROC_CTL_DEFSIZE	32
213*ed093b41SRobert Mustacchi #else
214*ed093b41SRobert Mustacchi #define	PROC_CTL_DEFSIZE	1024
215*ed093b41SRobert Mustacchi #endif
216*ed093b41SRobert Mustacchi 
217*ed093b41SRobert Mustacchi /*
218*ed093b41SRobert Mustacchi  * This structure is used to track all of the information that we have around a
219*ed093b41SRobert Mustacchi  * prwritectl call. This is used to reduce function parameters and make state
220*ed093b41SRobert Mustacchi  * clear.
221*ed093b41SRobert Mustacchi  */
222*ed093b41SRobert Mustacchi typedef struct {
223*ed093b41SRobert Mustacchi 	void	*prwc_buf;
224*ed093b41SRobert Mustacchi 	size_t	prwc_buflen;
225*ed093b41SRobert Mustacchi 	size_t	prwc_curvalid;
226*ed093b41SRobert Mustacchi 	uio_t	*prwc_uiop;
227*ed093b41SRobert Mustacchi 	prnode_t *prwc_pnp;
228*ed093b41SRobert Mustacchi 	boolean_t prwc_locked;
229*ed093b41SRobert Mustacchi 	boolean_t prwc_need32;
230*ed093b41SRobert Mustacchi 	void	*prwc_buf32;
231*ed093b41SRobert Mustacchi } prwritectl_t;
232*ed093b41SRobert Mustacchi 
233*ed093b41SRobert Mustacchi /*
234*ed093b41SRobert Mustacchi  * Ensure that we have at least "needed" data marked as valid and present. If we
235*ed093b41SRobert Mustacchi  * require additional data, then we will read that in from uio_t. When we read
236*ed093b41SRobert Mustacchi  * data, we try to buffer as much data as will fit in our internal buffers in
237*ed093b41SRobert Mustacchi  * one go.
238*ed093b41SRobert Mustacchi  */
239*ed093b41SRobert Mustacchi static int
prwritectl_readin(prwritectl_t * prwc,size_t needed)240*ed093b41SRobert Mustacchi prwritectl_readin(prwritectl_t *prwc, size_t needed)
241*ed093b41SRobert Mustacchi {
242*ed093b41SRobert Mustacchi 	int ret;
243*ed093b41SRobert Mustacchi 	size_t toread;
244*ed093b41SRobert Mustacchi 	void *start;
245*ed093b41SRobert Mustacchi 
246*ed093b41SRobert Mustacchi 	/*
247*ed093b41SRobert Mustacchi 	 * If we have as much data as we need then we're good to go.
248*ed093b41SRobert Mustacchi 	 */
249*ed093b41SRobert Mustacchi 	if (prwc->prwc_curvalid > needed) {
250*ed093b41SRobert Mustacchi 		ASSERT3U(prwc->prwc_buflen, >=, prwc->prwc_curvalid);
251*ed093b41SRobert Mustacchi 		ASSERT3U(prwc->prwc_buflen, >=, needed);
25233955159SSuhasini Peddada 		return (0);
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 
255*ed093b41SRobert Mustacchi 	/*
256*ed093b41SRobert Mustacchi 	 * We don't have all of our data. We must make sure of several things:
257*ed093b41SRobert Mustacchi 	 *
258*ed093b41SRobert Mustacchi 	 *   1. That there actually is enough data in the uio_t for what we
259*ed093b41SRobert Mustacchi 	 *	need, considering what we've already read.
260*ed093b41SRobert Mustacchi 	 *   2. If the process is locked, at this point, we want to unlock it
261*ed093b41SRobert Mustacchi 	 *	before we deal with any I/O or memory allocation. Otherwise we
262*ed093b41SRobert Mustacchi 	 *	can wreak havoc with p_lock / paging.
263*ed093b41SRobert Mustacchi 	 *   3. We need to make sure that our buffer is large enough to actually
264*ed093b41SRobert Mustacchi 	 *	fit it all.
265*ed093b41SRobert Mustacchi 	 *   4. Only at that point can we actually perform the read.
266*ed093b41SRobert Mustacchi 	 */
267*ed093b41SRobert Mustacchi 	if (needed - prwc->prwc_curvalid > prwc->prwc_uiop->uio_resid) {
268*ed093b41SRobert Mustacchi 		return (EINVAL);
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
271*ed093b41SRobert Mustacchi 	if (prwc->prwc_locked) {
272*ed093b41SRobert Mustacchi 		prunlock(prwc->prwc_pnp);
273*ed093b41SRobert Mustacchi 		prwc->prwc_locked = B_FALSE;
274*ed093b41SRobert Mustacchi 	}
275*ed093b41SRobert Mustacchi 
276*ed093b41SRobert Mustacchi 	if (needed > prwc->prwc_buflen) {
277*ed093b41SRobert Mustacchi 		size_t new_len = P2ROUNDUP(needed, PROC_CTL_DEFSIZE);
278*ed093b41SRobert Mustacchi 		prwc->prwc_buf = kmem_rezalloc(prwc->prwc_buf,
279*ed093b41SRobert Mustacchi 		    prwc->prwc_buflen, new_len, KM_SLEEP);
280*ed093b41SRobert Mustacchi 		if (prwc->prwc_need32) {
281*ed093b41SRobert Mustacchi 			prwc->prwc_buf32 = kmem_rezalloc(prwc->prwc_buf32,
282*ed093b41SRobert Mustacchi 			    prwc->prwc_buflen, new_len, KM_SLEEP);
283*ed093b41SRobert Mustacchi 		}
284*ed093b41SRobert Mustacchi 		prwc->prwc_buflen = new_len;
285*ed093b41SRobert Mustacchi 	}
286*ed093b41SRobert Mustacchi 
287*ed093b41SRobert Mustacchi 	toread = MIN(prwc->prwc_buflen - prwc->prwc_curvalid,
288*ed093b41SRobert Mustacchi 	    prwc->prwc_uiop->uio_resid);
289*ed093b41SRobert Mustacchi 	ASSERT3U(toread, >=, needed - prwc->prwc_curvalid);
290*ed093b41SRobert Mustacchi 	start = (void *)((uintptr_t)prwc->prwc_buf + prwc->prwc_curvalid);
291*ed093b41SRobert Mustacchi 	if ((ret = uiomove(start, toread, UIO_WRITE, prwc->prwc_uiop)) != 0) {
292*ed093b41SRobert Mustacchi 		return (ret);
293*ed093b41SRobert Mustacchi 	}
294*ed093b41SRobert Mustacchi 
295*ed093b41SRobert Mustacchi 	prwc->prwc_curvalid += toread;
2967c478bd9Sstevel@tonic-gate 	return (0);
297*ed093b41SRobert Mustacchi }
298*ed093b41SRobert Mustacchi 
299*ed093b41SRobert Mustacchi static const proc_control_info_t *
prwritectl_cmd_identify(const prwritectl_t * prwc,const proc_control_info_t * info,size_t ninfo,size_t cmdsize)300*ed093b41SRobert Mustacchi prwritectl_cmd_identify(const prwritectl_t *prwc,
301*ed093b41SRobert Mustacchi     const proc_control_info_t *info, size_t ninfo, size_t cmdsize)
302*ed093b41SRobert Mustacchi {
303*ed093b41SRobert Mustacchi 	long cmd;
304*ed093b41SRobert Mustacchi 
305*ed093b41SRobert Mustacchi 	ASSERT(cmdsize == sizeof (int32_t) || cmdsize == sizeof (long));
306*ed093b41SRobert Mustacchi 	if (cmdsize == 4) {
307*ed093b41SRobert Mustacchi 		cmd = (long)*(int32_t *)prwc->prwc_buf;
308*ed093b41SRobert Mustacchi 	} else {
309*ed093b41SRobert Mustacchi 		cmd = *(long *)prwc->prwc_buf;
310*ed093b41SRobert Mustacchi 	}
311*ed093b41SRobert Mustacchi 
312*ed093b41SRobert Mustacchi 
313*ed093b41SRobert Mustacchi 	for (size_t i = 0; i < ninfo; i++) {
314*ed093b41SRobert Mustacchi 		if (info[i].pcs_cmd == cmd) {
315*ed093b41SRobert Mustacchi 			return (&info[i]);
316*ed093b41SRobert Mustacchi 		}
317*ed093b41SRobert Mustacchi 	}
318*ed093b41SRobert Mustacchi 
319*ed093b41SRobert Mustacchi 	return (NULL);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate  * Control operations (lots).
324*ed093b41SRobert Mustacchi  *
325*ed093b41SRobert Mustacchi  * Users can submit one or more commands to us in the uio_t. They are required
326*ed093b41SRobert Mustacchi  * to always be complete messages. The first one that fails will cause all
327*ed093b41SRobert Mustacchi  * subsequent things to fail. Processing this can be a little tricky as the
328*ed093b41SRobert Mustacchi  * actual data size that may be required is variable, not all structures are
329*ed093b41SRobert Mustacchi  * fixed sizes and some vary based on the instructing set (e.g. x86 vs.
330*ed093b41SRobert Mustacchi  * something else).
331*ed093b41SRobert Mustacchi  *
332*ed093b41SRobert Mustacchi  * The way that we handle process locking deserves some consideration. Prior to
333*ed093b41SRobert Mustacchi  * the colonization of prwritectl and the support for dynamic sizing of data,
334*ed093b41SRobert Mustacchi  * the logic would try to read in a large chunk of data and keep a process
335*ed093b41SRobert Mustacchi  * locked throughout that period and then unlock it before reading more data. As
336*ed093b41SRobert Mustacchi  * such, we mimic that logically and basically lock it before executing the
337*ed093b41SRobert Mustacchi  * first (or any subsequent) command and then only unlock it either when we're
338*ed093b41SRobert Mustacchi  * done entirely or we need to allocate memory or read from the process.
339*ed093b41SRobert Mustacchi  *
340*ed093b41SRobert Mustacchi  * This function is a common implementation for both the ILP32 and LP64 entry
341*ed093b41SRobert Mustacchi  * points as they are mostly the same except for the sizing and control function
342*ed093b41SRobert Mustacchi  * we call.
3437c478bd9Sstevel@tonic-gate  */
3447c478bd9Sstevel@tonic-gate int
prwritectl_common(vnode_t * vp,uio_t * uiop,cred_t * cr,const proc_control_info_t * proc_info,size_t ninfo,size_t cmdsize,int (* pr_controlf)(long,void *,prnode_t *,cred_t *))345*ed093b41SRobert Mustacchi prwritectl_common(vnode_t *vp, uio_t *uiop, cred_t *cr,
346*ed093b41SRobert Mustacchi     const proc_control_info_t *proc_info, size_t ninfo, size_t cmdsize,
347*ed093b41SRobert Mustacchi     int (*pr_controlf)(long, void *, prnode_t *, cred_t *))
3487c478bd9Sstevel@tonic-gate {
349*ed093b41SRobert Mustacchi 	int ret;
350*ed093b41SRobert Mustacchi 	prwritectl_t prwc;
3517c478bd9Sstevel@tonic-gate 
352*ed093b41SRobert Mustacchi 	VERIFY(cmdsize == sizeof (int32_t) || cmdsize == sizeof (long));
353*ed093b41SRobert Mustacchi 
354*ed093b41SRobert Mustacchi 	bzero(&prwc, sizeof (prwc));
355*ed093b41SRobert Mustacchi 	prwc.prwc_pnp = VTOP(vp);
356*ed093b41SRobert Mustacchi 	prwc.prwc_uiop = uiop;
357*ed093b41SRobert Mustacchi 	prwc.prwc_need32 = (cmdsize == sizeof (int32_t));
358*ed093b41SRobert Mustacchi 
3597c478bd9Sstevel@tonic-gate 	/*
360*ed093b41SRobert Mustacchi 	 * We may have multiple commands to read and want to try to minimize the
361*ed093b41SRobert Mustacchi 	 * amount of reading that we do. Our callers expect us to have a
362*ed093b41SRobert Mustacchi 	 * contiguous buffer for a command's actual implementation. However, we
363*ed093b41SRobert Mustacchi 	 * must have at least a single long worth of data, otherwise it's not
364*ed093b41SRobert Mustacchi 	 * worth continuing.
3657c478bd9Sstevel@tonic-gate 	 */
366*ed093b41SRobert Mustacchi 	while (uiop->uio_resid > 0 || prwc.prwc_curvalid > 0) {
367*ed093b41SRobert Mustacchi 		const proc_control_info_t *proc_cmd;
368*ed093b41SRobert Mustacchi 		void *data;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 		/*
371*ed093b41SRobert Mustacchi 		 * Check if we have enough data to identify a command. If not,
372*ed093b41SRobert Mustacchi 		 * we read as much as we can in one gulp.
3737c478bd9Sstevel@tonic-gate 		 */
374*ed093b41SRobert Mustacchi 		if ((ret = prwritectl_readin(&prwc, cmdsize)) != 0) {
375*ed093b41SRobert Mustacchi 			goto out;
3767c478bd9Sstevel@tonic-gate 		}
3777c478bd9Sstevel@tonic-gate 
378*ed093b41SRobert Mustacchi 		/*
379*ed093b41SRobert Mustacchi 		 * Identify the command and figure out how how much data we
380*ed093b41SRobert Mustacchi 		 * should have read in the kernel. Some commands have a variable
381*ed093b41SRobert Mustacchi 		 * length and we need to make sure the minimum is met before
382*ed093b41SRobert Mustacchi 		 * asking how much there is in general. Most things know what
383*ed093b41SRobert Mustacchi 		 * the minimum length is and this pcs_minf() is not implemented.
384*ed093b41SRobert Mustacchi 		 * However things that are ISA-specific require us to ask that
385*ed093b41SRobert Mustacchi 		 * first.
386*ed093b41SRobert Mustacchi 		 *
387*ed093b41SRobert Mustacchi 		 * We also must be aware that there may not actually be enough
388*ed093b41SRobert Mustacchi 		 * data present in the uio_t.
389*ed093b41SRobert Mustacchi 		 */
390*ed093b41SRobert Mustacchi 		if ((proc_cmd = prwritectl_cmd_identify(&prwc, proc_info,
391*ed093b41SRobert Mustacchi 		    ninfo, cmdsize)) == NULL) {
392*ed093b41SRobert Mustacchi 			ret = EINVAL;
393*ed093b41SRobert Mustacchi 			goto out;
394*ed093b41SRobert Mustacchi 		}
395*ed093b41SRobert Mustacchi 
396*ed093b41SRobert Mustacchi 		size_t needed_data = cmdsize + proc_cmd->pcs_size;
397*ed093b41SRobert Mustacchi 		if (proc_cmd->pcs_minf != NULL) {
398*ed093b41SRobert Mustacchi 			size_t min;
399*ed093b41SRobert Mustacchi 
400*ed093b41SRobert Mustacchi 			if (!proc_cmd->pcs_minf(&min)) {
401*ed093b41SRobert Mustacchi 				ret = EINVAL;
402*ed093b41SRobert Mustacchi 				goto out;
403*ed093b41SRobert Mustacchi 			}
404*ed093b41SRobert Mustacchi 
405*ed093b41SRobert Mustacchi 			needed_data += min;
406*ed093b41SRobert Mustacchi 		}
407*ed093b41SRobert Mustacchi 
408*ed093b41SRobert Mustacchi 		if (proc_cmd->pcs_sizef != NULL) {
409*ed093b41SRobert Mustacchi 			size_t extra;
410*ed093b41SRobert Mustacchi 
411*ed093b41SRobert Mustacchi 			/*
412*ed093b41SRobert Mustacchi 			 * Make sure we have the minimum amount of data that
413*ed093b41SRobert Mustacchi 			 * they asked us to between the static and minf
414*ed093b41SRobert Mustacchi 			 * function.
415*ed093b41SRobert Mustacchi 			 */
416*ed093b41SRobert Mustacchi 			if ((ret = prwritectl_readin(&prwc, needed_data)) !=
417*ed093b41SRobert Mustacchi 			    0) {
418*ed093b41SRobert Mustacchi 				goto out;
419*ed093b41SRobert Mustacchi 			}
420*ed093b41SRobert Mustacchi 
421*ed093b41SRobert Mustacchi 			VERIFY3U(prwc.prwc_curvalid, >, cmdsize);
422*ed093b41SRobert Mustacchi 			data = (void *)((uintptr_t)prwc.prwc_buf + cmdsize);
423*ed093b41SRobert Mustacchi 			if (!proc_cmd->pcs_sizef(data, &extra)) {
424*ed093b41SRobert Mustacchi 				ret = EINVAL;
425*ed093b41SRobert Mustacchi 				goto out;
426*ed093b41SRobert Mustacchi 			}
427*ed093b41SRobert Mustacchi 
428*ed093b41SRobert Mustacchi 			needed_data += extra;
429*ed093b41SRobert Mustacchi 		}
430*ed093b41SRobert Mustacchi 
431*ed093b41SRobert Mustacchi 		/*
432*ed093b41SRobert Mustacchi 		 * Now that we know how much data we're supposed to have,
433*ed093b41SRobert Mustacchi 		 * finally ensure we have the total amount we need.
434*ed093b41SRobert Mustacchi 		 */
435*ed093b41SRobert Mustacchi 		if ((ret = prwritectl_readin(&prwc, needed_data)) != 0) {
436*ed093b41SRobert Mustacchi 			goto out;
437*ed093b41SRobert Mustacchi 		}
438*ed093b41SRobert Mustacchi 
439*ed093b41SRobert Mustacchi 		/*
440*ed093b41SRobert Mustacchi 		 * /proc has traditionally assumed control writes come in
441*ed093b41SRobert Mustacchi 		 * multiples of a long. This is 4 bytes for ILP32 and 8 bytes
442*ed093b41SRobert Mustacchi 		 * for LP64. When calculating the required size for a structure,
443*ed093b41SRobert Mustacchi 		 * it would always round that up to the next long. However, the
444*ed093b41SRobert Mustacchi 		 * exact combination of circumstances changes with the
445*ed093b41SRobert Mustacchi 		 * introduction of the 64-bit kernel. For 64-bit processes we
446*ed093b41SRobert Mustacchi 		 * round up when the current command we're processing isn't the
447*ed093b41SRobert Mustacchi 		 * last one.
448*ed093b41SRobert Mustacchi 		 *
449*ed093b41SRobert Mustacchi 		 * Because of our tracking structures and caching we need to
450*ed093b41SRobert Mustacchi 		 * look beyond the uio_t to make this determination. In
451*ed093b41SRobert Mustacchi 		 * particular, the uio_t can have a zero resid, but we may still
452*ed093b41SRobert Mustacchi 		 * have additional data to read as indicated by prwc_curvalid
453*ed093b41SRobert Mustacchi 		 * exceeding the current command size. In the end, we must check
454*ed093b41SRobert Mustacchi 		 * both of these cases.
455*ed093b41SRobert Mustacchi 		 */
456*ed093b41SRobert Mustacchi 		if ((needed_data % cmdsize) != 0) {
457*ed093b41SRobert Mustacchi 			if (cmdsize == sizeof (int32_t) ||
458*ed093b41SRobert Mustacchi 			    prwc.prwc_curvalid > needed_data ||
459*ed093b41SRobert Mustacchi 			    prwc.prwc_uiop->uio_resid > 0) {
460*ed093b41SRobert Mustacchi 				needed_data = P2ROUNDUP(needed_data,
461*ed093b41SRobert Mustacchi 				    cmdsize);
462*ed093b41SRobert Mustacchi 				if ((ret = prwritectl_readin(&prwc,
463*ed093b41SRobert Mustacchi 				    needed_data)) != 0) {
464*ed093b41SRobert Mustacchi 					goto out;
4657c478bd9Sstevel@tonic-gate 				}
4667c478bd9Sstevel@tonic-gate 			}
467*ed093b41SRobert Mustacchi 		}
468*ed093b41SRobert Mustacchi 
469*ed093b41SRobert Mustacchi 		if (!prwc.prwc_locked) {
470*ed093b41SRobert Mustacchi 			ret = prlock(prwc.prwc_pnp, ZNO);
471*ed093b41SRobert Mustacchi 			if (ret != 0) {
472*ed093b41SRobert Mustacchi 				goto out;
473*ed093b41SRobert Mustacchi 			}
474*ed093b41SRobert Mustacchi 			prwc.prwc_locked = B_TRUE;
475*ed093b41SRobert Mustacchi 		}
476*ed093b41SRobert Mustacchi 
477*ed093b41SRobert Mustacchi 		/*
478*ed093b41SRobert Mustacchi 		 * Run our actual command. When there is an error, then the
479*ed093b41SRobert Mustacchi 		 * underlying pr_control call will have unlocked the prnode_t
480*ed093b41SRobert Mustacchi 		 * on our behalf. pr_control can return -1, which is a special
481*ed093b41SRobert Mustacchi 		 * error indicating a timeout occurred. In such a case the node
482*ed093b41SRobert Mustacchi 		 * is unlocked; however, that we are supposed to continue
483*ed093b41SRobert Mustacchi 		 * processing commands regardless.
484*ed093b41SRobert Mustacchi 		 *
485*ed093b41SRobert Mustacchi 		 * Finally, we must deal with with one actual wrinkle. The LP64
486*ed093b41SRobert Mustacchi 		 * based logic always guarantees that we have data that is
487*ed093b41SRobert Mustacchi 		 * 8-byte aligned. However, the ILP32 logic is 4-byte aligned
488*ed093b41SRobert Mustacchi 		 * and the rest of the /proc code assumes it can always
489*ed093b41SRobert Mustacchi 		 * dereference it. If we're not aligned, we have to bcopy it to
490*ed093b41SRobert Mustacchi 		 * a temporary buffer.
491*ed093b41SRobert Mustacchi 		 */
492*ed093b41SRobert Mustacchi 		data = (void *)((uintptr_t)prwc.prwc_buf + cmdsize);
493*ed093b41SRobert Mustacchi #ifdef	DEBUG
494*ed093b41SRobert Mustacchi 		if (cmdsize == sizeof (long)) {
495*ed093b41SRobert Mustacchi 			ASSERT0((uintptr_t)data % alignof (long));
496*ed093b41SRobert Mustacchi 		}
497*ed093b41SRobert Mustacchi #endif
498*ed093b41SRobert Mustacchi 		if (prwc.prwc_need32 && ((uintptr_t)data % alignof (long)) !=
499*ed093b41SRobert Mustacchi 		    0 && needed_data > cmdsize) {
500*ed093b41SRobert Mustacchi 			bcopy(data, prwc.prwc_buf32, needed_data - cmdsize);
501*ed093b41SRobert Mustacchi 			data = prwc.prwc_buf32;
502*ed093b41SRobert Mustacchi 		}
503*ed093b41SRobert Mustacchi 		ret = pr_controlf(proc_cmd->pcs_cmd, data, prwc.prwc_pnp, cr);
504*ed093b41SRobert Mustacchi 		if (ret != 0) {
505*ed093b41SRobert Mustacchi 			prwc.prwc_locked = B_FALSE;
506*ed093b41SRobert Mustacchi 			if (ret > 0) {
507*ed093b41SRobert Mustacchi 				goto out;
508*ed093b41SRobert Mustacchi 			}
509*ed093b41SRobert Mustacchi 		}
510*ed093b41SRobert Mustacchi 
511*ed093b41SRobert Mustacchi 		/*
512*ed093b41SRobert Mustacchi 		 * Finally, now that we have processed this command, we need to
513*ed093b41SRobert Mustacchi 		 * move on. To make our life simple, we basically shift all the
514*ed093b41SRobert Mustacchi 		 * data in our buffer over to indicate it's been consumed. While
515*ed093b41SRobert Mustacchi 		 * a little wasteful, this simplifies buffer management and
516*ed093b41SRobert Mustacchi 		 * guarantees that command processing uses a semi-sanitized
517*ed093b41SRobert Mustacchi 		 * state. Visually, this is the following transformation:
518*ed093b41SRobert Mustacchi 		 *
519*ed093b41SRobert Mustacchi 		 *  0			20		prwc.prwc_curvalid
520*ed093b41SRobert Mustacchi 		 *   +------------------+----------------+
521*ed093b41SRobert Mustacchi 		 *   |   needed_data    | remaining_data |
522*ed093b41SRobert Mustacchi 		 *   +------------------+----------------+
523*ed093b41SRobert Mustacchi 		 *
524*ed093b41SRobert Mustacchi 		 * In the above example we are shifting all the data over by 20,
525*ed093b41SRobert Mustacchi 		 * so remaining data starts at 0. This leaves us needed_data
526*ed093b41SRobert Mustacchi 		 * bytes to clean up from what was valid.
527*ed093b41SRobert Mustacchi 		 */
528*ed093b41SRobert Mustacchi 		if (prwc.prwc_buf32 != NULL) {
529*ed093b41SRobert Mustacchi 			bzero(prwc.prwc_buf32, needed_data - cmdsize);
530*ed093b41SRobert Mustacchi 		}
531*ed093b41SRobert Mustacchi 
532*ed093b41SRobert Mustacchi 		if (prwc.prwc_curvalid > needed_data) {
533*ed093b41SRobert Mustacchi 			size_t save_size = prwc.prwc_curvalid - needed_data;
534*ed093b41SRobert Mustacchi 			void *first_save = (void *)((uintptr_t)prwc.prwc_buf +
535*ed093b41SRobert Mustacchi 			    needed_data);
536*ed093b41SRobert Mustacchi 			memmove(prwc.prwc_buf, first_save, save_size);
537*ed093b41SRobert Mustacchi 			void *first_zero = (void *)((uintptr_t)prwc.prwc_buf +
538*ed093b41SRobert Mustacchi 			    save_size);
539*ed093b41SRobert Mustacchi 			bzero(first_zero, needed_data);
540*ed093b41SRobert Mustacchi 		} else {
541*ed093b41SRobert Mustacchi 			bzero(prwc.prwc_buf, prwc.prwc_curvalid);
542*ed093b41SRobert Mustacchi 		}
543*ed093b41SRobert Mustacchi 		prwc.prwc_curvalid -= needed_data;
544*ed093b41SRobert Mustacchi 	}
545*ed093b41SRobert Mustacchi 
546*ed093b41SRobert Mustacchi 	/*
547*ed093b41SRobert Mustacchi 	 * We've managed to successfully process everything. We can actually say
548*ed093b41SRobert Mustacchi 	 * this was successful now.
549*ed093b41SRobert Mustacchi 	 */
550*ed093b41SRobert Mustacchi 	ret = 0;
551*ed093b41SRobert Mustacchi 
552*ed093b41SRobert Mustacchi out:
553*ed093b41SRobert Mustacchi 	if (prwc.prwc_locked) {
554*ed093b41SRobert Mustacchi 		prunlock(prwc.prwc_pnp);
555*ed093b41SRobert Mustacchi 		prwc.prwc_locked = B_FALSE;
556*ed093b41SRobert Mustacchi 	}
557*ed093b41SRobert Mustacchi 
558*ed093b41SRobert Mustacchi 	if (prwc.prwc_buf != NULL) {
559*ed093b41SRobert Mustacchi 		kmem_free(prwc.prwc_buf, prwc.prwc_buflen);
560*ed093b41SRobert Mustacchi 	}
561*ed093b41SRobert Mustacchi 
562*ed093b41SRobert Mustacchi 	if (prwc.prwc_buf32 != NULL) {
563*ed093b41SRobert Mustacchi 		VERIFY(prwc.prwc_need32);
564*ed093b41SRobert Mustacchi 		kmem_free(prwc.prwc_buf32, prwc.prwc_buflen);
565*ed093b41SRobert Mustacchi 	}
566*ed093b41SRobert Mustacchi 
567*ed093b41SRobert Mustacchi 	return (ret);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate static int
pr_control(long cmd,void * generic,prnode_t * pnp,cred_t * cr)571*ed093b41SRobert Mustacchi pr_control(long cmd, void *generic, prnode_t *pnp, cred_t *cr)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
5747c478bd9Sstevel@tonic-gate 	proc_t *p;
5757c478bd9Sstevel@tonic-gate 	int unlocked;
5767c478bd9Sstevel@tonic-gate 	int error = 0;
577*ed093b41SRobert Mustacchi 	arg_t *argp = generic;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	if (cmd == PCNULL)
5807c478bd9Sstevel@tonic-gate 		return (0);
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;
5837c478bd9Sstevel@tonic-gate 	p = pcp->prc_proc;
5847c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
5857c478bd9Sstevel@tonic-gate 
58635a5a358SJonathan Adams 	/* System processes defy control. */
58735a5a358SJonathan Adams 	if (p->p_flag & SSYS) {
58835a5a358SJonathan Adams 		prunlock(pnp);
58935a5a358SJonathan Adams 		return (EBUSY);
59035a5a358SJonathan Adams 	}
59135a5a358SJonathan Adams 
5927c478bd9Sstevel@tonic-gate 	switch (cmd) {
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	default:
5957c478bd9Sstevel@tonic-gate 		error = EINVAL;
5967c478bd9Sstevel@tonic-gate 		break;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	case PCSTOP:	/* direct process or lwp to stop and wait for stop */
5997c478bd9Sstevel@tonic-gate 	case PCDSTOP:	/* direct process or lwp to stop, don't wait */
6007c478bd9Sstevel@tonic-gate 	case PCWSTOP:	/* wait for process or lwp to stop */
6017c478bd9Sstevel@tonic-gate 	case PCTWSTOP:	/* wait for process or lwp to stop, with timeout */
6027c478bd9Sstevel@tonic-gate 		{
6037c478bd9Sstevel@tonic-gate 			time_t timeo;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 			/*
6067c478bd9Sstevel@tonic-gate 			 * Can't apply to a system process.
6077c478bd9Sstevel@tonic-gate 			 */
60835a5a358SJonathan Adams 			if (p->p_as == &kas) {
6097c478bd9Sstevel@tonic-gate 				error = EBUSY;
6107c478bd9Sstevel@tonic-gate 				break;
6117c478bd9Sstevel@tonic-gate 			}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 			if (cmd == PCSTOP || cmd == PCDSTOP)
6147c478bd9Sstevel@tonic-gate 				pr_stop(pnp);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 			if (cmd == PCDSTOP)
6177c478bd9Sstevel@tonic-gate 				break;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 			/*
620bda89588Sjp151216 			 * If an lwp is waiting for itself or its process,
621bda89588Sjp151216 			 * don't wait. The stopped lwp would never see the
622bda89588Sjp151216 			 * fact that it is stopped.
6237c478bd9Sstevel@tonic-gate 			 */
6247c478bd9Sstevel@tonic-gate 			if ((pcp->prc_flags & PRC_LWP)?
6257c478bd9Sstevel@tonic-gate 			    (pcp->prc_thread == curthread) : (p == curproc)) {
6267c478bd9Sstevel@tonic-gate 				if (cmd == PCWSTOP || cmd == PCTWSTOP)
6277c478bd9Sstevel@tonic-gate 					error = EBUSY;
6287c478bd9Sstevel@tonic-gate 				break;
6297c478bd9Sstevel@tonic-gate 			}
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 			timeo = (cmd == PCTWSTOP)? (time_t)argp->timeo : 0;
6327c478bd9Sstevel@tonic-gate 			if ((error = pr_wait_stop(pnp, timeo)) != 0)
6337c478bd9Sstevel@tonic-gate 				return (error);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 			break;
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	case PCRUN:	/* make lwp or process runnable */
6397c478bd9Sstevel@tonic-gate 		error = pr_setrun(pnp, argp->flags);
6407c478bd9Sstevel@tonic-gate 		break;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	case PCSTRACE:	/* set signal trace mask */
6437c478bd9Sstevel@tonic-gate 		pr_settrace(p,  &argp->sigset);
6447c478bd9Sstevel@tonic-gate 		break;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	case PCSSIG:	/* set current signal */
6477c478bd9Sstevel@tonic-gate 		error = pr_setsig(pnp, &argp->siginfo);
6487c478bd9Sstevel@tonic-gate 		if (argp->siginfo.si_signo == SIGKILL && error == 0) {
6497c478bd9Sstevel@tonic-gate 			prunlock(pnp);
6507c478bd9Sstevel@tonic-gate 			pr_wait_die(pnp);
6517c478bd9Sstevel@tonic-gate 			return (-1);
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 		break;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	case PCKILL:	/* send signal */
6567c478bd9Sstevel@tonic-gate 		error = pr_kill(pnp, (int)argp->sig, cr);
6577c478bd9Sstevel@tonic-gate 		if (error == 0 && argp->sig == SIGKILL) {
6587c478bd9Sstevel@tonic-gate 			prunlock(pnp);
6597c478bd9Sstevel@tonic-gate 			pr_wait_die(pnp);
6607c478bd9Sstevel@tonic-gate 			return (-1);
6617c478bd9Sstevel@tonic-gate 		}
6627c478bd9Sstevel@tonic-gate 		break;
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	case PCUNKILL:	/* delete a pending signal */
6657c478bd9Sstevel@tonic-gate 		error = pr_unkill(pnp, (int)argp->sig);
6667c478bd9Sstevel@tonic-gate 		break;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	case PCNICE:	/* set nice priority */
6697c478bd9Sstevel@tonic-gate 		error = pr_nice(p, (int)argp->nice, cr);
6707c478bd9Sstevel@tonic-gate 		break;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	case PCSENTRY:	/* set syscall entry bit mask */
6737c478bd9Sstevel@tonic-gate 	case PCSEXIT:	/* set syscall exit bit mask */
6747c478bd9Sstevel@tonic-gate 		pr_setentryexit(p, &argp->sysset, cmd == PCSENTRY);
6757c478bd9Sstevel@tonic-gate 		break;
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	case PCSET:	/* set process flags */
6787c478bd9Sstevel@tonic-gate 		error = pr_set(p, argp->flags);
6797c478bd9Sstevel@tonic-gate 		break;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	case PCUNSET:	/* unset process flags */
6827c478bd9Sstevel@tonic-gate 		error = pr_unset(p, argp->flags);
6837c478bd9Sstevel@tonic-gate 		break;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	case PCSREG:	/* set general registers */
6867c478bd9Sstevel@tonic-gate 		{
6877c478bd9Sstevel@tonic-gate 			kthread_t *t = pr_thread(pnp);
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 			if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
6907c478bd9Sstevel@tonic-gate 				thread_unlock(t);
6917c478bd9Sstevel@tonic-gate 				error = EBUSY;
6927c478bd9Sstevel@tonic-gate 			} else {
6937c478bd9Sstevel@tonic-gate 				thread_unlock(t);
6947c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
6957c478bd9Sstevel@tonic-gate 				prsetprregs(ttolwp(t), argp->prgregset, 0);
6967c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
6977c478bd9Sstevel@tonic-gate 			}
6987c478bd9Sstevel@tonic-gate 			break;
6997c478bd9Sstevel@tonic-gate 		}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	case PCSFPREG:	/* set floating-point registers */
7027c478bd9Sstevel@tonic-gate 		error = pr_setfpregs(pnp, &argp->prfpregset);
7037c478bd9Sstevel@tonic-gate 		break;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	case PCSXREG:	/* set extra registers */
706*ed093b41SRobert Mustacchi 		error = pr_setxregs(pnp, (prxregset_t *)argp);
7077c478bd9Sstevel@tonic-gate 		break;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	case PCSVADDR:	/* set virtual address at which to resume */
7107c478bd9Sstevel@tonic-gate 		error = pr_setvaddr(pnp, argp->vaddr);
7117c478bd9Sstevel@tonic-gate 		break;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	case PCSHOLD:	/* set signal-hold mask */
7147c478bd9Sstevel@tonic-gate 		pr_sethold(pnp, &argp->sigset);
7157c478bd9Sstevel@tonic-gate 		break;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	case PCSFAULT:	/* set mask of traced faults */
7187c478bd9Sstevel@tonic-gate 		pr_setfault(p, &argp->fltset);
7197c478bd9Sstevel@tonic-gate 		break;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	case PCCSIG:	/* clear current signal */
7227c478bd9Sstevel@tonic-gate 		error = pr_clearsig(pnp);
7237c478bd9Sstevel@tonic-gate 		break;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	case PCCFAULT:	/* clear current fault */
7267c478bd9Sstevel@tonic-gate 		error = pr_clearflt(pnp);
7277c478bd9Sstevel@tonic-gate 		break;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	case PCWATCH:	/* set or clear watched areas */
7307c478bd9Sstevel@tonic-gate 		error = pr_watch(pnp, &argp->prwatch, &unlocked);
7317c478bd9Sstevel@tonic-gate 		if (error && unlocked)
7327c478bd9Sstevel@tonic-gate 			return (error);
7337c478bd9Sstevel@tonic-gate 		break;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	case PCAGENT:	/* create the /proc agent lwp in the target process */
7367c478bd9Sstevel@tonic-gate 		error = pr_agent(pnp, argp->prgregset, &unlocked);
7377c478bd9Sstevel@tonic-gate 		if (error && unlocked)
7387c478bd9Sstevel@tonic-gate 			return (error);
7397c478bd9Sstevel@tonic-gate 		break;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	case PCREAD:	/* read from the address space */
7427c478bd9Sstevel@tonic-gate 		error = pr_rdwr(p, UIO_READ, &argp->priovec);
7437c478bd9Sstevel@tonic-gate 		break;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	case PCWRITE:	/* write to the address space */
7467c478bd9Sstevel@tonic-gate 		error = pr_rdwr(p, UIO_WRITE, &argp->priovec);
7477c478bd9Sstevel@tonic-gate 		break;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	case PCSCRED:	/* set the process credentials */
7507c478bd9Sstevel@tonic-gate 	case PCSCREDX:
7517c478bd9Sstevel@tonic-gate 		error = pr_scred(p, &argp->prcred, cr, cmd == PCSCREDX);
7527c478bd9Sstevel@tonic-gate 		break;
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	case PCSPRIV:	/* set the process privileges */
7557c478bd9Sstevel@tonic-gate 		error = pr_spriv(p, &argp->prpriv, cr);
7567c478bd9Sstevel@tonic-gate 		break;
7577c478bd9Sstevel@tonic-gate 	case PCSZONE:	/* set the process's zoneid credentials */
7587c478bd9Sstevel@tonic-gate 		error = pr_szoneid(p, (zoneid_t)argp->przoneid, cr);
7597c478bd9Sstevel@tonic-gate 		break;
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	if (error)
7637c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7647c478bd9Sstevel@tonic-gate 	return (error);
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate 
767*ed093b41SRobert Mustacchi int
prwritectl(vnode_t * vp,uio_t * uiop,cred_t * cr)768*ed093b41SRobert Mustacchi prwritectl(vnode_t *vp, uio_t *uiop, cred_t *cr)
769*ed093b41SRobert Mustacchi {
770*ed093b41SRobert Mustacchi 	return (prwritectl_common(vp, uiop, cr, proc_ctl_info,
771*ed093b41SRobert Mustacchi 	    ARRAY_SIZE(proc_ctl_info), sizeof (long), pr_control));
772*ed093b41SRobert Mustacchi }
773*ed093b41SRobert Mustacchi 
7747c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate typedef union {
7777c478bd9Sstevel@tonic-gate 	int32_t		sig;		/* PCKILL, PCUNKILL */
7787c478bd9Sstevel@tonic-gate 	int32_t		nice;		/* PCNICE */
7797c478bd9Sstevel@tonic-gate 	int32_t		timeo;		/* PCTWSTOP */
7807c478bd9Sstevel@tonic-gate 	uint32_t	flags;		/* PCRUN, PCSET, PCUNSET */
7817c478bd9Sstevel@tonic-gate 	caddr32_t	vaddr;		/* PCSVADDR */
7827c478bd9Sstevel@tonic-gate 	siginfo32_t	siginfo;	/* PCSSIG */
7837c478bd9Sstevel@tonic-gate 	sigset_t	sigset;		/* PCSTRACE, PCSHOLD */
7847c478bd9Sstevel@tonic-gate 	fltset_t	fltset;		/* PCSFAULT */
7857c478bd9Sstevel@tonic-gate 	sysset_t	sysset;		/* PCSENTRY, PCSEXIT */
7867c478bd9Sstevel@tonic-gate 	prgregset32_t	prgregset;	/* PCSREG, PCAGENT */
7877c478bd9Sstevel@tonic-gate 	prfpregset32_t	prfpregset;	/* PCSFPREG */
7887c478bd9Sstevel@tonic-gate 	prwatch32_t	prwatch;	/* PCWATCH */
7897c478bd9Sstevel@tonic-gate 	priovec32_t	priovec;	/* PCREAD, PCWRITE */
7907c478bd9Sstevel@tonic-gate 	prcred32_t	prcred;		/* PCSCRED */
7917c478bd9Sstevel@tonic-gate 	prpriv_t	prpriv;		/* PCSPRIV */
7927c478bd9Sstevel@tonic-gate 	int32_t		przoneid;	/* PCSZONE */
7937c478bd9Sstevel@tonic-gate } arg32_t;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate static	int	pr_setfpregs32(prnode_t *, prfpregset32_t *);
7967c478bd9Sstevel@tonic-gate 
797*ed093b41SRobert Mustacchi static boolean_t
prwritectl_pcscredx32_sizef(const void * datap,size_t * sizep)798*ed093b41SRobert Mustacchi prwritectl_pcscredx32_sizef(const void *datap, size_t *sizep)
7997c478bd9Sstevel@tonic-gate {
800*ed093b41SRobert Mustacchi 	const prcred32_t *cred = datap;
8017c478bd9Sstevel@tonic-gate 
802*ed093b41SRobert Mustacchi 	if (cred->pr_ngroups < 0 || cred->pr_ngroups > ngroups_max) {
803*ed093b41SRobert Mustacchi 		return (B_FALSE);
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 
806*ed093b41SRobert Mustacchi 	if (cred->pr_ngroups == 0) {
807*ed093b41SRobert Mustacchi 		*sizep = 0;
808*ed093b41SRobert Mustacchi 	} else {
809*ed093b41SRobert Mustacchi 		*sizep = (cred->pr_ngroups - 1) * sizeof (gid32_t);
810*ed093b41SRobert Mustacchi 	}
811*ed093b41SRobert Mustacchi 	return (B_TRUE);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate /*
815*ed093b41SRobert Mustacchi  * When dealing with ILP32 code, we are not at a point where we can assume
816*ed093b41SRobert Mustacchi  * 64-bit aligned data. Any functions that are operating here must be aware of
817*ed093b41SRobert Mustacchi  * that.
8187c478bd9Sstevel@tonic-gate  */
819*ed093b41SRobert Mustacchi static const proc_control_info_t proc_ctl_info32[] = {
820*ed093b41SRobert Mustacchi 	{ PCNULL,	0,			NULL,		NULL },
821*ed093b41SRobert Mustacchi 	{ PCSTOP,	0,			NULL,		NULL },
822*ed093b41SRobert Mustacchi 	{ PCDSTOP,	0,			NULL,		NULL },
823*ed093b41SRobert Mustacchi 	{ PCWSTOP,	0,			NULL,		NULL },
824*ed093b41SRobert Mustacchi 	{ PCCSIG,	0,			NULL,		NULL },
825*ed093b41SRobert Mustacchi 	{ PCCFAULT,	0,			NULL,		NULL },
826*ed093b41SRobert Mustacchi 	{ PCSSIG,	sizeof (siginfo32_t),	NULL,		NULL },
827*ed093b41SRobert Mustacchi 	{ PCTWSTOP,	sizeof (int32_t),	NULL,		NULL },
828*ed093b41SRobert Mustacchi 	{ PCKILL,	sizeof (int32_t),	NULL,		NULL },
829*ed093b41SRobert Mustacchi 	{ PCUNKILL,	sizeof (int32_t),	NULL,		NULL },
830*ed093b41SRobert Mustacchi 	{ PCNICE,	sizeof (int32_t),	NULL,		NULL },
831*ed093b41SRobert Mustacchi 	{ PCRUN,	sizeof (uint32_t),	NULL,		NULL },
832*ed093b41SRobert Mustacchi 	{ PCSET,	sizeof (uint32_t),	NULL,		NULL },
833*ed093b41SRobert Mustacchi 	{ PCUNSET,	sizeof (uint32_t),	NULL,		NULL },
834*ed093b41SRobert Mustacchi 	{ PCSVADDR,	sizeof (caddr32_t),	NULL,		NULL },
835*ed093b41SRobert Mustacchi 	{ PCSTRACE,	sizeof (sigset_t),	NULL,		NULL },
836*ed093b41SRobert Mustacchi 	{ PCSHOLD,	sizeof (sigset_t),	NULL,		NULL },
837*ed093b41SRobert Mustacchi 	{ PCSFAULT,	sizeof (fltset_t),	NULL,		NULL },
838*ed093b41SRobert Mustacchi 	{ PCSENTRY,	sizeof (sysset_t),	NULL,		NULL },
839*ed093b41SRobert Mustacchi 	{ PCSEXIT,	sizeof (sysset_t),	NULL,		NULL },
840*ed093b41SRobert Mustacchi 	{ PCSREG,	sizeof (prgregset32_t),	NULL,		NULL },
841*ed093b41SRobert Mustacchi 	{ PCAGENT,	sizeof (prgregset32_t),	NULL,		NULL },
842*ed093b41SRobert Mustacchi 	{ PCSFPREG,	sizeof (prfpregset32_t), NULL,		NULL },
843*ed093b41SRobert Mustacchi 	{ PCSXREG,	0,			prwriteminxreg,
844*ed093b41SRobert Mustacchi 	    prwritesizexreg },
845*ed093b41SRobert Mustacchi 	{ PCWATCH,	sizeof (prwatch32_t),	NULL,		NULL },
846*ed093b41SRobert Mustacchi 	{ PCREAD,	sizeof (priovec32_t),	NULL,		NULL },
847*ed093b41SRobert Mustacchi 	{ PCWRITE,	sizeof (priovec32_t),	NULL,		NULL },
848*ed093b41SRobert Mustacchi 	{ PCSCRED,	sizeof (prcred32_t),	NULL,		NULL },
849*ed093b41SRobert Mustacchi 	{ PCSCREDX,	sizeof (prcred32_t),	NULL,
850*ed093b41SRobert Mustacchi 	    prwritectl_pcscredx32_sizef },
851*ed093b41SRobert Mustacchi 	{ PCSPRIV,	sizeof (prpriv_t),	NULL,
852*ed093b41SRobert Mustacchi 	    prwritectl_pcspriv_sizef },
853*ed093b41SRobert Mustacchi 	{ PCSZONE,	sizeof (long),		NULL,		NULL },
854*ed093b41SRobert Mustacchi };
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate static int
pr_control32(long cmd,void * generic,prnode_t * pnp,cred_t * cr)857*ed093b41SRobert Mustacchi pr_control32(long cmd, void *generic, prnode_t *pnp, cred_t *cr)
8587c478bd9Sstevel@tonic-gate {
8597c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
8607c478bd9Sstevel@tonic-gate 	proc_t *p;
8617c478bd9Sstevel@tonic-gate 	int unlocked;
8627c478bd9Sstevel@tonic-gate 	int error = 0;
863*ed093b41SRobert Mustacchi 	arg32_t *argp = generic;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	if (cmd == PCNULL)
8667c478bd9Sstevel@tonic-gate 		return (0);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;
8697c478bd9Sstevel@tonic-gate 	p = pcp->prc_proc;
8707c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
8717c478bd9Sstevel@tonic-gate 
87235a5a358SJonathan Adams 	if (p->p_flag & SSYS) {
87335a5a358SJonathan Adams 		prunlock(pnp);
87435a5a358SJonathan Adams 		return (EBUSY);
87535a5a358SJonathan Adams 	}
87635a5a358SJonathan Adams 
8777c478bd9Sstevel@tonic-gate 	switch (cmd) {
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	default:
8807c478bd9Sstevel@tonic-gate 		error = EINVAL;
8817c478bd9Sstevel@tonic-gate 		break;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	case PCSTOP:	/* direct process or lwp to stop and wait for stop */
8847c478bd9Sstevel@tonic-gate 	case PCDSTOP:	/* direct process or lwp to stop, don't wait */
8857c478bd9Sstevel@tonic-gate 	case PCWSTOP:	/* wait for process or lwp to stop */
8867c478bd9Sstevel@tonic-gate 	case PCTWSTOP:	/* wait for process or lwp to stop, with timeout */
8877c478bd9Sstevel@tonic-gate 		{
8887c478bd9Sstevel@tonic-gate 			time_t timeo;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 			/*
8917c478bd9Sstevel@tonic-gate 			 * Can't apply to a system process.
8927c478bd9Sstevel@tonic-gate 			 */
89335a5a358SJonathan Adams 			if (p->p_as == &kas) {
8947c478bd9Sstevel@tonic-gate 				error = EBUSY;
8957c478bd9Sstevel@tonic-gate 				break;
8967c478bd9Sstevel@tonic-gate 			}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 			if (cmd == PCSTOP || cmd == PCDSTOP)
8997c478bd9Sstevel@tonic-gate 				pr_stop(pnp);
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 			if (cmd == PCDSTOP)
9027c478bd9Sstevel@tonic-gate 				break;
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 			/*
905bda89588Sjp151216 			 * If an lwp is waiting for itself or its process,
906bda89588Sjp151216 			 * don't wait. The lwp will never see the fact that
907bda89588Sjp151216 			 * itself is stopped.
9087c478bd9Sstevel@tonic-gate 			 */
9097c478bd9Sstevel@tonic-gate 			if ((pcp->prc_flags & PRC_LWP)?
9107c478bd9Sstevel@tonic-gate 			    (pcp->prc_thread == curthread) : (p == curproc)) {
9117c478bd9Sstevel@tonic-gate 				if (cmd == PCWSTOP || cmd == PCTWSTOP)
9127c478bd9Sstevel@tonic-gate 					error = EBUSY;
9137c478bd9Sstevel@tonic-gate 				break;
9147c478bd9Sstevel@tonic-gate 			}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 			timeo = (cmd == PCTWSTOP)? (time_t)argp->timeo : 0;
9177c478bd9Sstevel@tonic-gate 			if ((error = pr_wait_stop(pnp, timeo)) != 0)
9187c478bd9Sstevel@tonic-gate 				return (error);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 			break;
9217c478bd9Sstevel@tonic-gate 		}
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	case PCRUN:	/* make lwp or process runnable */
9247c478bd9Sstevel@tonic-gate 		error = pr_setrun(pnp, (ulong_t)argp->flags);
9257c478bd9Sstevel@tonic-gate 		break;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	case PCSTRACE:	/* set signal trace mask */
9287c478bd9Sstevel@tonic-gate 		pr_settrace(p,  &argp->sigset);
9297c478bd9Sstevel@tonic-gate 		break;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	case PCSSIG:	/* set current signal */
9327c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
9337c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
9347c478bd9Sstevel@tonic-gate 		else {
9357c478bd9Sstevel@tonic-gate 			int sig = (int)argp->siginfo.si_signo;
9367c478bd9Sstevel@tonic-gate 			siginfo_t siginfo;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
9397c478bd9Sstevel@tonic-gate 			siginfo_32tok(&argp->siginfo, (k_siginfo_t *)&siginfo);
9407c478bd9Sstevel@tonic-gate 			error = pr_setsig(pnp, &siginfo);
9417c478bd9Sstevel@tonic-gate 			if (sig == SIGKILL && error == 0) {
9427c478bd9Sstevel@tonic-gate 				prunlock(pnp);
9437c478bd9Sstevel@tonic-gate 				pr_wait_die(pnp);
9447c478bd9Sstevel@tonic-gate 				return (-1);
9457c478bd9Sstevel@tonic-gate 			}
9467c478bd9Sstevel@tonic-gate 		}
9477c478bd9Sstevel@tonic-gate 		break;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	case PCKILL:	/* send signal */
9507c478bd9Sstevel@tonic-gate 		error = pr_kill(pnp, (int)argp->sig, cr);
9517c478bd9Sstevel@tonic-gate 		if (error == 0 && argp->sig == SIGKILL) {
9527c478bd9Sstevel@tonic-gate 			prunlock(pnp);
9537c478bd9Sstevel@tonic-gate 			pr_wait_die(pnp);
9547c478bd9Sstevel@tonic-gate 			return (-1);
9557c478bd9Sstevel@tonic-gate 		}
9567c478bd9Sstevel@tonic-gate 		break;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	case PCUNKILL:	/* delete a pending signal */
9597c478bd9Sstevel@tonic-gate 		error = pr_unkill(pnp, (int)argp->sig);
9607c478bd9Sstevel@tonic-gate 		break;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	case PCNICE:	/* set nice priority */
9637c478bd9Sstevel@tonic-gate 		error = pr_nice(p, (int)argp->nice, cr);
9647c478bd9Sstevel@tonic-gate 		break;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	case PCSENTRY:	/* set syscall entry bit mask */
9677c478bd9Sstevel@tonic-gate 	case PCSEXIT:	/* set syscall exit bit mask */
9687c478bd9Sstevel@tonic-gate 		pr_setentryexit(p, &argp->sysset, cmd == PCSENTRY);
9697c478bd9Sstevel@tonic-gate 		break;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	case PCSET:	/* set process flags */
9727c478bd9Sstevel@tonic-gate 		error = pr_set(p, (long)argp->flags);
9737c478bd9Sstevel@tonic-gate 		break;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	case PCUNSET:	/* unset process flags */
9767c478bd9Sstevel@tonic-gate 		error = pr_unset(p, (long)argp->flags);
9777c478bd9Sstevel@tonic-gate 		break;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	case PCSREG:	/* set general registers */
9807c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
9817c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
9827c478bd9Sstevel@tonic-gate 		else {
9837c478bd9Sstevel@tonic-gate 			kthread_t *t = pr_thread(pnp);
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 			if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
9867c478bd9Sstevel@tonic-gate 				thread_unlock(t);
9877c478bd9Sstevel@tonic-gate 				error = EBUSY;
9887c478bd9Sstevel@tonic-gate 			} else {
9897c478bd9Sstevel@tonic-gate 				prgregset_t prgregset;
9907c478bd9Sstevel@tonic-gate 				klwp_t *lwp = ttolwp(t);
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 				thread_unlock(t);
9937c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
9947c478bd9Sstevel@tonic-gate 				prgregset_32ton(lwp, argp->prgregset,
9957c478bd9Sstevel@tonic-gate 				    prgregset);
9967c478bd9Sstevel@tonic-gate 				prsetprregs(lwp, prgregset, 0);
9977c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
9987c478bd9Sstevel@tonic-gate 			}
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 		break;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	case PCSFPREG:	/* set floating-point registers */
10037c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
10047c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
10057c478bd9Sstevel@tonic-gate 		else
10067c478bd9Sstevel@tonic-gate 			error = pr_setfpregs32(pnp, &argp->prfpregset);
10077c478bd9Sstevel@tonic-gate 		break;
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	case PCSXREG:	/* set extra registers */
10107c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
10117c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
10127c478bd9Sstevel@tonic-gate 		else
1013*ed093b41SRobert Mustacchi 			error = pr_setxregs(pnp, (prxregset_t *)argp);
10147c478bd9Sstevel@tonic-gate 		break;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	case PCSVADDR:	/* set virtual address at which to resume */
10177c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
10187c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
10197c478bd9Sstevel@tonic-gate 		else
10207c478bd9Sstevel@tonic-gate 			error = pr_setvaddr(pnp,
10217c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)argp->vaddr);
10227c478bd9Sstevel@tonic-gate 		break;
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	case PCSHOLD:	/* set signal-hold mask */
10257c478bd9Sstevel@tonic-gate 		pr_sethold(pnp, &argp->sigset);
10267c478bd9Sstevel@tonic-gate 		break;
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	case PCSFAULT:	/* set mask of traced faults */
10297c478bd9Sstevel@tonic-gate 		pr_setfault(p, &argp->fltset);
10307c478bd9Sstevel@tonic-gate 		break;
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	case PCCSIG:	/* clear current signal */
10337c478bd9Sstevel@tonic-gate 		error = pr_clearsig(pnp);
10347c478bd9Sstevel@tonic-gate 		break;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	case PCCFAULT:	/* clear current fault */
10377c478bd9Sstevel@tonic-gate 		error = pr_clearflt(pnp);
10387c478bd9Sstevel@tonic-gate 		break;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	case PCWATCH:	/* set or clear watched areas */
10417c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
10427c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
10437c478bd9Sstevel@tonic-gate 		else {
10447c478bd9Sstevel@tonic-gate 			prwatch_t prwatch;
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 			prwatch.pr_vaddr = argp->prwatch.pr_vaddr;
10477c478bd9Sstevel@tonic-gate 			prwatch.pr_size = argp->prwatch.pr_size;
10487c478bd9Sstevel@tonic-gate 			prwatch.pr_wflags = argp->prwatch.pr_wflags;
10497c478bd9Sstevel@tonic-gate 			prwatch.pr_pad = argp->prwatch.pr_pad;
10507c478bd9Sstevel@tonic-gate 			error = pr_watch(pnp, &prwatch, &unlocked);
10517c478bd9Sstevel@tonic-gate 			if (error && unlocked)
10527c478bd9Sstevel@tonic-gate 				return (error);
10537c478bd9Sstevel@tonic-gate 		}
10547c478bd9Sstevel@tonic-gate 		break;
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	case PCAGENT:	/* create the /proc agent lwp in the target process */
10577c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p))
10587c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
10597c478bd9Sstevel@tonic-gate 		else {
10607c478bd9Sstevel@tonic-gate 			prgregset_t prgregset;
10617c478bd9Sstevel@tonic-gate 			kthread_t *t = pr_thread(pnp);
10627c478bd9Sstevel@tonic-gate 			klwp_t *lwp = ttolwp(t);
10637c478bd9Sstevel@tonic-gate 			thread_unlock(t);
10647c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
10657c478bd9Sstevel@tonic-gate 			prgregset_32ton(lwp, argp->prgregset, prgregset);
10667c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
10677c478bd9Sstevel@tonic-gate 			error = pr_agent(pnp, prgregset, &unlocked);
10687c478bd9Sstevel@tonic-gate 			if (error && unlocked)
10697c478bd9Sstevel@tonic-gate 				return (error);
10707c478bd9Sstevel@tonic-gate 		}
10717c478bd9Sstevel@tonic-gate 		break;
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	case PCREAD:	/* read from the address space */
10747c478bd9Sstevel@tonic-gate 	case PCWRITE:	/* write to the address space */
1075d1b18d1aSBryan Cantrill 		if (PROCESS_NOT_32BIT(p) || (pnp->pr_flags & PR_OFFMAX))
10767c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
10777c478bd9Sstevel@tonic-gate 		else {
10787c478bd9Sstevel@tonic-gate 			enum uio_rw rw = (cmd == PCREAD)? UIO_READ : UIO_WRITE;
10797c478bd9Sstevel@tonic-gate 			priovec_t priovec;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 			priovec.pio_base =
10827c478bd9Sstevel@tonic-gate 			    (void *)(uintptr_t)argp->priovec.pio_base;
10837c478bd9Sstevel@tonic-gate 			priovec.pio_len = (size_t)argp->priovec.pio_len;
10847c478bd9Sstevel@tonic-gate 			priovec.pio_offset = (off_t)
10857c478bd9Sstevel@tonic-gate 			    (uint32_t)argp->priovec.pio_offset;
10867c478bd9Sstevel@tonic-gate 			error = pr_rdwr(p, rw, &priovec);
10877c478bd9Sstevel@tonic-gate 		}
10887c478bd9Sstevel@tonic-gate 		break;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	case PCSCRED:	/* set the process credentials */
10917c478bd9Sstevel@tonic-gate 	case PCSCREDX:
10927c478bd9Sstevel@tonic-gate 		{
10937c478bd9Sstevel@tonic-gate 			/*
1094bda89588Sjp151216 			 * All the fields in these structures are exactly the
1095bda89588Sjp151216 			 * same and so the structures are compatible.  In case
1096bda89588Sjp151216 			 * this ever changes, we catch this with the ASSERT
1097bda89588Sjp151216 			 * below.
10987c478bd9Sstevel@tonic-gate 			 */
10997c478bd9Sstevel@tonic-gate 			prcred_t *prcred = (prcred_t *)&argp->prcred;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate #ifndef __lint
11027c478bd9Sstevel@tonic-gate 			ASSERT(sizeof (prcred_t) == sizeof (prcred32_t));
11037c478bd9Sstevel@tonic-gate #endif
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 			error = pr_scred(p, prcred, cr, cmd == PCSCREDX);
11067c478bd9Sstevel@tonic-gate 			break;
11077c478bd9Sstevel@tonic-gate 		}
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	case PCSPRIV:	/* set the process privileges */
11107c478bd9Sstevel@tonic-gate 		error = pr_spriv(p, &argp->prpriv, cr);
11117c478bd9Sstevel@tonic-gate 		break;
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	case PCSZONE:	/* set the process's zoneid */
11147c478bd9Sstevel@tonic-gate 		error = pr_szoneid(p, (zoneid_t)argp->przoneid, cr);
11157c478bd9Sstevel@tonic-gate 		break;
11167c478bd9Sstevel@tonic-gate 	}
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	if (error)
11197c478bd9Sstevel@tonic-gate 		prunlock(pnp);
11207c478bd9Sstevel@tonic-gate 	return (error);
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate 
1123*ed093b41SRobert Mustacchi int
prwritectl32(struct vnode * vp,struct uio * uiop,cred_t * cr)1124*ed093b41SRobert Mustacchi prwritectl32(struct vnode *vp, struct uio *uiop, cred_t *cr)
1125*ed093b41SRobert Mustacchi {
1126*ed093b41SRobert Mustacchi 	return (prwritectl_common(vp, uiop, cr, proc_ctl_info32,
1127*ed093b41SRobert Mustacchi 	    ARRAY_SIZE(proc_ctl_info32), sizeof (int32_t), pr_control32));
1128*ed093b41SRobert Mustacchi }
11297c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate /*
11327c478bd9Sstevel@tonic-gate  * Return the specific or chosen thread/lwp for a control operation.
11337c478bd9Sstevel@tonic-gate  * Returns with the thread locked via thread_lock(t).
11347c478bd9Sstevel@tonic-gate  */
11357c478bd9Sstevel@tonic-gate kthread_t *
pr_thread(prnode_t * pnp)11367c478bd9Sstevel@tonic-gate pr_thread(prnode_t *pnp)
11377c478bd9Sstevel@tonic-gate {
11387c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
11397c478bd9Sstevel@tonic-gate 	kthread_t *t;
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {
11427c478bd9Sstevel@tonic-gate 		t = pcp->prc_thread;
11437c478bd9Sstevel@tonic-gate 		ASSERT(t != NULL);
11447c478bd9Sstevel@tonic-gate 		thread_lock(t);
11457c478bd9Sstevel@tonic-gate 	} else {
11467c478bd9Sstevel@tonic-gate 		proc_t *p = pcp->prc_proc;
11477c478bd9Sstevel@tonic-gate 		t = prchoose(p);	/* returns locked thread */
11487c478bd9Sstevel@tonic-gate 		ASSERT(t != NULL);
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	return (t);
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate /*
11557c478bd9Sstevel@tonic-gate  * Direct the process or lwp to stop.
11567c478bd9Sstevel@tonic-gate  */
11577c478bd9Sstevel@tonic-gate void
pr_stop(prnode_t * pnp)11587c478bd9Sstevel@tonic-gate pr_stop(prnode_t *pnp)
11597c478bd9Sstevel@tonic-gate {
11607c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
11617c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
11627c478bd9Sstevel@tonic-gate 	kthread_t *t;
11637c478bd9Sstevel@tonic-gate 	vnode_t *vp;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	/*
11667c478bd9Sstevel@tonic-gate 	 * If already stopped, do nothing; otherwise flag
11677c478bd9Sstevel@tonic-gate 	 * it to be stopped the next time it tries to run.
11687c478bd9Sstevel@tonic-gate 	 * If sleeping at interruptible priority, set it
11697c478bd9Sstevel@tonic-gate 	 * running so it will stop within cv_wait_sig().
11707c478bd9Sstevel@tonic-gate 	 *
11717c478bd9Sstevel@tonic-gate 	 * Take care to cooperate with jobcontrol: if an lwp
11727c478bd9Sstevel@tonic-gate 	 * is stopped due to the default action of a jobcontrol
11737c478bd9Sstevel@tonic-gate 	 * stop signal, flag it to be stopped the next time it
11747c478bd9Sstevel@tonic-gate 	 * starts due to a SIGCONT signal.
11757c478bd9Sstevel@tonic-gate 	 */
11767c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP)
11777c478bd9Sstevel@tonic-gate 		t = pcp->prc_thread;
11787c478bd9Sstevel@tonic-gate 	else
11797c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
11807c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	do {
11837c478bd9Sstevel@tonic-gate 		int notify;
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 		notify = 0;
11867c478bd9Sstevel@tonic-gate 		thread_lock(t);
11877c478bd9Sstevel@tonic-gate 		if (!ISTOPPED(t)) {
11887c478bd9Sstevel@tonic-gate 			t->t_proc_flag |= TP_PRSTOP;
11897c478bd9Sstevel@tonic-gate 			t->t_sig_check = 1;	/* do ISSIG */
11907c478bd9Sstevel@tonic-gate 		}
1191c97ad5cdSakolb 
1192c97ad5cdSakolb 		/* Move the thread from wait queue to run queue */
1193c97ad5cdSakolb 		if (ISWAITING(t))
1194c97ad5cdSakolb 			setrun_locked(t);
1195c97ad5cdSakolb 
1196c97ad5cdSakolb 		if (ISWAKEABLE(t)) {
11977c478bd9Sstevel@tonic-gate 			if (t->t_wchan0 == NULL)
11987c478bd9Sstevel@tonic-gate 				setrun_locked(t);
11997c478bd9Sstevel@tonic-gate 			else if (!VSTOPPED(t)) {
12007c478bd9Sstevel@tonic-gate 				/*
12017c478bd9Sstevel@tonic-gate 				 * Mark it virtually stopped.
12027c478bd9Sstevel@tonic-gate 				 */
12037c478bd9Sstevel@tonic-gate 				t->t_proc_flag |= TP_PRVSTOP;
12047c478bd9Sstevel@tonic-gate 				notify = 1;
12057c478bd9Sstevel@tonic-gate 			}
12067c478bd9Sstevel@tonic-gate 		}
12077c478bd9Sstevel@tonic-gate 		/*
12087c478bd9Sstevel@tonic-gate 		 * force the thread into the kernel
12097c478bd9Sstevel@tonic-gate 		 * if it is not already there.
12107c478bd9Sstevel@tonic-gate 		 */
12117c478bd9Sstevel@tonic-gate 		prpokethread(t);
12127c478bd9Sstevel@tonic-gate 		thread_unlock(t);
12137c478bd9Sstevel@tonic-gate 		if (notify &&
12147c478bd9Sstevel@tonic-gate 		    (vp = p->p_lwpdir[t->t_dslot].ld_entry->le_trace) != NULL)
12157c478bd9Sstevel@tonic-gate 			prnotify(vp);
12167c478bd9Sstevel@tonic-gate 		if (pcp->prc_flags & PRC_LWP)
12177c478bd9Sstevel@tonic-gate 			break;
12187c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	/*
12217c478bd9Sstevel@tonic-gate 	 * We do this just in case the thread we asked
12227c478bd9Sstevel@tonic-gate 	 * to stop is in holdlwps() (called from cfork()).
12237c478bd9Sstevel@tonic-gate 	 */
12247c478bd9Sstevel@tonic-gate 	cv_broadcast(&p->p_holdlwps);
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate /*
12287c478bd9Sstevel@tonic-gate  * Sleep until the lwp stops, but cooperate with
12297c478bd9Sstevel@tonic-gate  * jobcontrol:  Don't wake up if the lwp is stopped
12307c478bd9Sstevel@tonic-gate  * due to the default action of a jobcontrol stop signal.
12317c478bd9Sstevel@tonic-gate  * If this is the process file descriptor, sleep
12327c478bd9Sstevel@tonic-gate  * until all of the process's lwps stop.
12337c478bd9Sstevel@tonic-gate  */
12347c478bd9Sstevel@tonic-gate int
pr_wait_stop(prnode_t * pnp,time_t timeo)12357c478bd9Sstevel@tonic-gate pr_wait_stop(prnode_t *pnp, time_t timeo)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
12387c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
12397c478bd9Sstevel@tonic-gate 	timestruc_t rqtime;
12407c478bd9Sstevel@tonic-gate 	timestruc_t *rqtp = NULL;
12413348528fSdm120769 	int timecheck = 0;
12427c478bd9Sstevel@tonic-gate 	kthread_t *t;
12437c478bd9Sstevel@tonic-gate 	int error;
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	if (timeo > 0) {	/* millisecond timeout */
12467c478bd9Sstevel@tonic-gate 		/*
12477c478bd9Sstevel@tonic-gate 		 * Determine the precise future time of the requested timeout.
12487c478bd9Sstevel@tonic-gate 		 */
12497c478bd9Sstevel@tonic-gate 		timestruc_t now;
12507c478bd9Sstevel@tonic-gate 
12513348528fSdm120769 		timecheck = timechanged;
12527c478bd9Sstevel@tonic-gate 		gethrestime(&now);
12537c478bd9Sstevel@tonic-gate 		rqtp = &rqtime;
12547c478bd9Sstevel@tonic-gate 		rqtp->tv_sec = timeo / MILLISEC;
12557c478bd9Sstevel@tonic-gate 		rqtp->tv_nsec = (timeo % MILLISEC) * MICROSEC;
12567c478bd9Sstevel@tonic-gate 		timespecadd(rqtp, &now);
12577c478bd9Sstevel@tonic-gate 	}
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP) {	/* lwp file descriptor */
12607c478bd9Sstevel@tonic-gate 		t = pcp->prc_thread;
12617c478bd9Sstevel@tonic-gate 		ASSERT(t != NULL);
12627c478bd9Sstevel@tonic-gate 		thread_lock(t);
12637c478bd9Sstevel@tonic-gate 		while (!ISTOPPED(t) && !VSTOPPED(t)) {
12647c478bd9Sstevel@tonic-gate 			thread_unlock(t);
12657c478bd9Sstevel@tonic-gate 			mutex_enter(&pcp->prc_mutex);
12667c478bd9Sstevel@tonic-gate 			prunlock(pnp);
12673348528fSdm120769 			error = pr_wait(pcp, rqtp, timecheck);
12687c478bd9Sstevel@tonic-gate 			if (error)	/* -1 is timeout */
12697c478bd9Sstevel@tonic-gate 				return (error);
12707c478bd9Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0)
12717c478bd9Sstevel@tonic-gate 				return (error);
12727c478bd9Sstevel@tonic-gate 			ASSERT(p == pcp->prc_proc);
12737c478bd9Sstevel@tonic-gate 			ASSERT(t == pcp->prc_thread);
12747c478bd9Sstevel@tonic-gate 			thread_lock(t);
12757c478bd9Sstevel@tonic-gate 		}
12767c478bd9Sstevel@tonic-gate 		thread_unlock(t);
12777c478bd9Sstevel@tonic-gate 	} else {			/* process file descriptor */
12787c478bd9Sstevel@tonic-gate 		t = prchoose(p);	/* returns locked thread */
12797c478bd9Sstevel@tonic-gate 		ASSERT(t != NULL);
12807c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&p->p_lock));
12817c478bd9Sstevel@tonic-gate 		while ((!ISTOPPED(t) && !VSTOPPED(t) && !SUSPENDED(t)) ||
12827c478bd9Sstevel@tonic-gate 		    (p->p_flag & SEXITLWPS)) {
12837c478bd9Sstevel@tonic-gate 			thread_unlock(t);
12847c478bd9Sstevel@tonic-gate 			mutex_enter(&pcp->prc_mutex);
12857c478bd9Sstevel@tonic-gate 			prunlock(pnp);
12863348528fSdm120769 			error = pr_wait(pcp, rqtp, timecheck);
12877c478bd9Sstevel@tonic-gate 			if (error)	/* -1 is timeout */
12887c478bd9Sstevel@tonic-gate 				return (error);
12897c478bd9Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0)
12907c478bd9Sstevel@tonic-gate 				return (error);
12917c478bd9Sstevel@tonic-gate 			ASSERT(p == pcp->prc_proc);
12927c478bd9Sstevel@tonic-gate 			t = prchoose(p);	/* returns locked t */
12937c478bd9Sstevel@tonic-gate 			ASSERT(t != NULL);
12947c478bd9Sstevel@tonic-gate 		}
12957c478bd9Sstevel@tonic-gate 		thread_unlock(t);
12967c478bd9Sstevel@tonic-gate 	}
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	ASSERT(!(pcp->prc_flags & PRC_DESTROY) && p->p_stat != SZOMB &&
12997c478bd9Sstevel@tonic-gate 	    t != NULL && t->t_state != TS_ZOMB);
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	return (0);
13027c478bd9Sstevel@tonic-gate }
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate int
pr_setrun(prnode_t * pnp,ulong_t flags)13057c478bd9Sstevel@tonic-gate pr_setrun(prnode_t *pnp, ulong_t flags)
13067c478bd9Sstevel@tonic-gate {
13077c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
13087c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
13097c478bd9Sstevel@tonic-gate 	kthread_t *t;
13107c478bd9Sstevel@tonic-gate 	klwp_t *lwp;
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	/*
13137c478bd9Sstevel@tonic-gate 	 * Cannot set an lwp running if it is not stopped.
13147c478bd9Sstevel@tonic-gate 	 * Also, no lwp other than the /proc agent lwp can
13157c478bd9Sstevel@tonic-gate 	 * be set running so long as the /proc agent lwp exists.
13167c478bd9Sstevel@tonic-gate 	 */
13177c478bd9Sstevel@tonic-gate 	t = pr_thread(pnp);	/* returns locked thread */
13187c478bd9Sstevel@tonic-gate 	if ((!ISTOPPED(t) && !VSTOPPED(t) &&
13197c478bd9Sstevel@tonic-gate 	    !(t->t_proc_flag & TP_PRSTOP)) ||
13207c478bd9Sstevel@tonic-gate 	    (p->p_agenttp != NULL &&
13217c478bd9Sstevel@tonic-gate 	    (t != p->p_agenttp || !(pcp->prc_flags & PRC_LWP)))) {
13227c478bd9Sstevel@tonic-gate 		thread_unlock(t);
13237c478bd9Sstevel@tonic-gate 		return (EBUSY);
13247c478bd9Sstevel@tonic-gate 	}
13257c478bd9Sstevel@tonic-gate 	thread_unlock(t);
13267c478bd9Sstevel@tonic-gate 	if (flags & ~(PRCSIG|PRCFAULT|PRSTEP|PRSTOP|PRSABORT))
13277c478bd9Sstevel@tonic-gate 		return (EINVAL);
13287c478bd9Sstevel@tonic-gate 	lwp = ttolwp(t);
13297c478bd9Sstevel@tonic-gate 	if ((flags & PRCSIG) && lwp->lwp_cursig != SIGKILL) {
13307c478bd9Sstevel@tonic-gate 		/*
13317c478bd9Sstevel@tonic-gate 		 * Discard current siginfo_t, if any.
13327c478bd9Sstevel@tonic-gate 		 */
13337c478bd9Sstevel@tonic-gate 		lwp->lwp_cursig = 0;
13347c478bd9Sstevel@tonic-gate 		lwp->lwp_extsig = 0;
13357c478bd9Sstevel@tonic-gate 		if (lwp->lwp_curinfo) {
13367c478bd9Sstevel@tonic-gate 			siginfofree(lwp->lwp_curinfo);
13377c478bd9Sstevel@tonic-gate 			lwp->lwp_curinfo = NULL;
13387c478bd9Sstevel@tonic-gate 		}
13397c478bd9Sstevel@tonic-gate 	}
13407c478bd9Sstevel@tonic-gate 	if (flags & PRCFAULT)
13417c478bd9Sstevel@tonic-gate 		lwp->lwp_curflt = 0;
13427c478bd9Sstevel@tonic-gate 	/*
13437c478bd9Sstevel@tonic-gate 	 * We can't hold p->p_lock when we touch the lwp's registers.
13447c478bd9Sstevel@tonic-gate 	 * It may be swapped out and we will get a page fault.
13457c478bd9Sstevel@tonic-gate 	 */
13467c478bd9Sstevel@tonic-gate 	if (flags & PRSTEP) {
13477c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
13487c478bd9Sstevel@tonic-gate 		prstep(lwp, 0);
13497c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
13507c478bd9Sstevel@tonic-gate 	}
13517c478bd9Sstevel@tonic-gate 	if (flags & PRSTOP) {
13527c478bd9Sstevel@tonic-gate 		t->t_proc_flag |= TP_PRSTOP;
13537c478bd9Sstevel@tonic-gate 		t->t_sig_check = 1;	/* do ISSIG */
13547c478bd9Sstevel@tonic-gate 	}
13557c478bd9Sstevel@tonic-gate 	if (flags & PRSABORT)
13567c478bd9Sstevel@tonic-gate 		lwp->lwp_sysabort = 1;
13577c478bd9Sstevel@tonic-gate 	thread_lock(t);
13587c478bd9Sstevel@tonic-gate 	if ((pcp->prc_flags & PRC_LWP) || (flags & (PRSTEP|PRSTOP))) {
13597c478bd9Sstevel@tonic-gate 		/*
13607c478bd9Sstevel@tonic-gate 		 * Here, we are dealing with a single lwp.
13617c478bd9Sstevel@tonic-gate 		 */
13627c478bd9Sstevel@tonic-gate 		if (ISTOPPED(t)) {
13637c478bd9Sstevel@tonic-gate 			t->t_schedflag |= TS_PSTART;
13647c478bd9Sstevel@tonic-gate 			t->t_dtrace_stop = 0;
13657c478bd9Sstevel@tonic-gate 			setrun_locked(t);
13667c478bd9Sstevel@tonic-gate 		} else if (flags & PRSABORT) {
13677c478bd9Sstevel@tonic-gate 			t->t_proc_flag &=
13687c478bd9Sstevel@tonic-gate 			    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
13697c478bd9Sstevel@tonic-gate 			setrun_locked(t);
13707c478bd9Sstevel@tonic-gate 		} else if (!(flags & PRSTOP)) {
13717c478bd9Sstevel@tonic-gate 			t->t_proc_flag &=
13727c478bd9Sstevel@tonic-gate 			    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
13737c478bd9Sstevel@tonic-gate 		}
13747c478bd9Sstevel@tonic-gate 		thread_unlock(t);
13757c478bd9Sstevel@tonic-gate 	} else {
13767c478bd9Sstevel@tonic-gate 		/*
13777c478bd9Sstevel@tonic-gate 		 * Here, we are dealing with the whole process.
13787c478bd9Sstevel@tonic-gate 		 */
13797c478bd9Sstevel@tonic-gate 		if (ISTOPPED(t)) {
13807c478bd9Sstevel@tonic-gate 			/*
13817c478bd9Sstevel@tonic-gate 			 * The representative lwp is stopped on an event
13827c478bd9Sstevel@tonic-gate 			 * of interest.  We demote it to PR_REQUESTED and
13837c478bd9Sstevel@tonic-gate 			 * choose another representative lwp.  If the new
13847c478bd9Sstevel@tonic-gate 			 * representative lwp is not stopped on an event of
13857c478bd9Sstevel@tonic-gate 			 * interest (other than PR_REQUESTED), we set the
13867c478bd9Sstevel@tonic-gate 			 * whole process running, else we leave the process
13877c478bd9Sstevel@tonic-gate 			 * stopped showing the next event of interest.
13887c478bd9Sstevel@tonic-gate 			 */
13897c478bd9Sstevel@tonic-gate 			kthread_t *tx = NULL;
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 			if (!(flags & PRSABORT) &&
13927c478bd9Sstevel@tonic-gate 			    t->t_whystop == PR_SYSENTRY &&
13937c478bd9Sstevel@tonic-gate 			    t->t_whatstop == SYS_lwp_exit)
13947c478bd9Sstevel@tonic-gate 				tx = t;		/* remember the exiting lwp */
13957c478bd9Sstevel@tonic-gate 			t->t_whystop = PR_REQUESTED;
13967c478bd9Sstevel@tonic-gate 			t->t_whatstop = 0;
13977c478bd9Sstevel@tonic-gate 			thread_unlock(t);
13987c478bd9Sstevel@tonic-gate 			t = prchoose(p);	/* returns locked t */
13997c478bd9Sstevel@tonic-gate 			ASSERT(ISTOPPED(t) || VSTOPPED(t));
14007c478bd9Sstevel@tonic-gate 			if (VSTOPPED(t) ||
14017c478bd9Sstevel@tonic-gate 			    t->t_whystop == PR_REQUESTED) {
14027c478bd9Sstevel@tonic-gate 				thread_unlock(t);
14037c478bd9Sstevel@tonic-gate 				allsetrun(p);
14047c478bd9Sstevel@tonic-gate 			} else {
14057c478bd9Sstevel@tonic-gate 				thread_unlock(t);
14067c478bd9Sstevel@tonic-gate 				/*
14077c478bd9Sstevel@tonic-gate 				 * As a special case, if the old representative
14087c478bd9Sstevel@tonic-gate 				 * lwp was stopped on entry to _lwp_exit()
14097c478bd9Sstevel@tonic-gate 				 * (and we are not aborting the system call),
14107c478bd9Sstevel@tonic-gate 				 * we set the old representative lwp running.
14117c478bd9Sstevel@tonic-gate 				 * We do this so that the next process stop
14127c478bd9Sstevel@tonic-gate 				 * will find the exiting lwp gone.
14137c478bd9Sstevel@tonic-gate 				 */
14147c478bd9Sstevel@tonic-gate 				if (tx != NULL) {
14157c478bd9Sstevel@tonic-gate 					thread_lock(tx);
14167c478bd9Sstevel@tonic-gate 					tx->t_schedflag |= TS_PSTART;
14177c478bd9Sstevel@tonic-gate 					t->t_dtrace_stop = 0;
14187c478bd9Sstevel@tonic-gate 					setrun_locked(tx);
14197c478bd9Sstevel@tonic-gate 					thread_unlock(tx);
14207c478bd9Sstevel@tonic-gate 				}
14217c478bd9Sstevel@tonic-gate 			}
14227c478bd9Sstevel@tonic-gate 		} else {
14237c478bd9Sstevel@tonic-gate 			/*
14247c478bd9Sstevel@tonic-gate 			 * No event of interest; set all of the lwps running.
14257c478bd9Sstevel@tonic-gate 			 */
14267c478bd9Sstevel@tonic-gate 			if (flags & PRSABORT) {
14277c478bd9Sstevel@tonic-gate 				t->t_proc_flag &=
14287c478bd9Sstevel@tonic-gate 				    ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
14297c478bd9Sstevel@tonic-gate 				setrun_locked(t);
14307c478bd9Sstevel@tonic-gate 			}
14317c478bd9Sstevel@tonic-gate 			thread_unlock(t);
14327c478bd9Sstevel@tonic-gate 			allsetrun(p);
14337c478bd9Sstevel@tonic-gate 		}
14347c478bd9Sstevel@tonic-gate 	}
14357c478bd9Sstevel@tonic-gate 	return (0);
14367c478bd9Sstevel@tonic-gate }
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate /*
14397c478bd9Sstevel@tonic-gate  * Wait until process/lwp stops or until timer expires.
14407c478bd9Sstevel@tonic-gate  * Return EINTR for an interruption, -1 for timeout, else 0.
14417c478bd9Sstevel@tonic-gate  */
14427c478bd9Sstevel@tonic-gate int
pr_wait(prcommon_t * pcp,timestruc_t * ts,int timecheck)14437c478bd9Sstevel@tonic-gate pr_wait(prcommon_t *pcp,	/* prcommon referring to process/lwp */
14443348528fSdm120769     timestruc_t *ts,		/* absolute time of timeout, if any */
14453348528fSdm120769     int timecheck)
14467c478bd9Sstevel@tonic-gate {
14477c478bd9Sstevel@tonic-gate 	int rval;
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pcp->prc_mutex));
14503348528fSdm120769 	rval = cv_waituntil_sig(&pcp->prc_wait, &pcp->prc_mutex, ts, timecheck);
14517c478bd9Sstevel@tonic-gate 	mutex_exit(&pcp->prc_mutex);
14527c478bd9Sstevel@tonic-gate 	switch (rval) {
14537c478bd9Sstevel@tonic-gate 	case 0:
14547c478bd9Sstevel@tonic-gate 		return (EINTR);
14557c478bd9Sstevel@tonic-gate 	case -1:
14567c478bd9Sstevel@tonic-gate 		return (-1);
14577c478bd9Sstevel@tonic-gate 	default:
14587c478bd9Sstevel@tonic-gate 		return (0);
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate /*
14637c478bd9Sstevel@tonic-gate  * Make all threads in the process runnable.
14647c478bd9Sstevel@tonic-gate  */
14657c478bd9Sstevel@tonic-gate void
allsetrun(proc_t * p)14667c478bd9Sstevel@tonic-gate allsetrun(proc_t *p)
14677c478bd9Sstevel@tonic-gate {
14687c478bd9Sstevel@tonic-gate 	kthread_t *t;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
14737c478bd9Sstevel@tonic-gate 		do {
14747c478bd9Sstevel@tonic-gate 			thread_lock(t);
14757c478bd9Sstevel@tonic-gate 			ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
14767c478bd9Sstevel@tonic-gate 			t->t_proc_flag &= ~(TP_PRSTOP|TP_PRVSTOP|TP_STOPPING);
14777c478bd9Sstevel@tonic-gate 			if (ISTOPPED(t)) {
14787c478bd9Sstevel@tonic-gate 				t->t_schedflag |= TS_PSTART;
14797c478bd9Sstevel@tonic-gate 				t->t_dtrace_stop = 0;
14807c478bd9Sstevel@tonic-gate 				setrun_locked(t);
14817c478bd9Sstevel@tonic-gate 			}
14827c478bd9Sstevel@tonic-gate 			thread_unlock(t);
14837c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
14847c478bd9Sstevel@tonic-gate 	}
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate /*
14887c478bd9Sstevel@tonic-gate  * Wait for the process to die.
14897c478bd9Sstevel@tonic-gate  * We do this after sending SIGKILL because we know it will
14907c478bd9Sstevel@tonic-gate  * die soon and we want subsequent operations to return ENOENT.
14917c478bd9Sstevel@tonic-gate  */
14927c478bd9Sstevel@tonic-gate void
pr_wait_die(prnode_t * pnp)14937c478bd9Sstevel@tonic-gate pr_wait_die(prnode_t *pnp)
14947c478bd9Sstevel@tonic-gate {
14957c478bd9Sstevel@tonic-gate 	proc_t *p;
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
14987c478bd9Sstevel@tonic-gate 	while ((p = pnp->pr_common->prc_proc) != NULL && p->p_stat != SZOMB) {
14997c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&p->p_srwchan_cv, &pidlock))
15007c478bd9Sstevel@tonic-gate 			break;
15017c478bd9Sstevel@tonic-gate 	}
15027c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
15037c478bd9Sstevel@tonic-gate }
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate static void
pr_settrace(proc_t * p,sigset_t * sp)15067c478bd9Sstevel@tonic-gate pr_settrace(proc_t *p, sigset_t *sp)
15077c478bd9Sstevel@tonic-gate {
15087c478bd9Sstevel@tonic-gate 	prdelset(sp, SIGKILL);
15097c478bd9Sstevel@tonic-gate 	prassignset(&p->p_sigmask, sp);
15107c478bd9Sstevel@tonic-gate 	if (!sigisempty(&p->p_sigmask))
15117c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
15127c478bd9Sstevel@tonic-gate 	else if (prisempty(&p->p_fltmask)) {
15137c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
15147c478bd9Sstevel@tonic-gate 		if (up->u_systrap == 0)
15157c478bd9Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
15167c478bd9Sstevel@tonic-gate 	}
15177c478bd9Sstevel@tonic-gate }
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate int
pr_setsig(prnode_t * pnp,siginfo_t * sip)15207c478bd9Sstevel@tonic-gate pr_setsig(prnode_t *pnp, siginfo_t *sip)
15217c478bd9Sstevel@tonic-gate {
1522eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
15237c478bd9Sstevel@tonic-gate 	int sig = sip->si_signo;
15247c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
15257c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
15267c478bd9Sstevel@tonic-gate 	kthread_t *t;
15277c478bd9Sstevel@tonic-gate 	klwp_t *lwp;
15287c478bd9Sstevel@tonic-gate 	int error = 0;
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	t = pr_thread(pnp);	/* returns locked thread */
15317c478bd9Sstevel@tonic-gate 	thread_unlock(t);
15327c478bd9Sstevel@tonic-gate 	lwp = ttolwp(t);
1533eb9dbf0cSRoger A. Faulkner 	if (sig < 0 || sig >= nsig)
15347c478bd9Sstevel@tonic-gate 		/* Zero allowed here */
15357c478bd9Sstevel@tonic-gate 		error = EINVAL;
15367c478bd9Sstevel@tonic-gate 	else if (lwp->lwp_cursig == SIGKILL)
15377c478bd9Sstevel@tonic-gate 		/* "can't happen", but just in case */
15387c478bd9Sstevel@tonic-gate 		error = EBUSY;
15397c478bd9Sstevel@tonic-gate 	else if ((lwp->lwp_cursig = (uchar_t)sig) == 0) {
15407c478bd9Sstevel@tonic-gate 		lwp->lwp_extsig = 0;
15417c478bd9Sstevel@tonic-gate 		/*
15427c478bd9Sstevel@tonic-gate 		 * Discard current siginfo_t, if any.
15437c478bd9Sstevel@tonic-gate 		 */
15447c478bd9Sstevel@tonic-gate 		if (lwp->lwp_curinfo) {
15457c478bd9Sstevel@tonic-gate 			siginfofree(lwp->lwp_curinfo);
15467c478bd9Sstevel@tonic-gate 			lwp->lwp_curinfo = NULL;
15477c478bd9Sstevel@tonic-gate 		}
15487c478bd9Sstevel@tonic-gate 	} else {
15497c478bd9Sstevel@tonic-gate 		kthread_t *tx;
15507c478bd9Sstevel@tonic-gate 		sigqueue_t *sqp;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 		/* drop p_lock to do kmem_alloc(KM_SLEEP) */
15537c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
15547c478bd9Sstevel@tonic-gate 		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
15557c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 		if (lwp->lwp_curinfo == NULL)
15587c478bd9Sstevel@tonic-gate 			lwp->lwp_curinfo = sqp;
15597c478bd9Sstevel@tonic-gate 		else
15607c478bd9Sstevel@tonic-gate 			kmem_free(sqp, sizeof (sigqueue_t));
15617c478bd9Sstevel@tonic-gate 		/*
15627c478bd9Sstevel@tonic-gate 		 * Copy contents of info to current siginfo_t.
15637c478bd9Sstevel@tonic-gate 		 */
15647c478bd9Sstevel@tonic-gate 		bcopy(sip, &lwp->lwp_curinfo->sq_info,
15657c478bd9Sstevel@tonic-gate 		    sizeof (lwp->lwp_curinfo->sq_info));
15667c478bd9Sstevel@tonic-gate 		/*
15677c478bd9Sstevel@tonic-gate 		 * Prevent contents published by si_zoneid-unaware /proc
15687c478bd9Sstevel@tonic-gate 		 * consumers from being incorrectly filtered.  Because
15697c478bd9Sstevel@tonic-gate 		 * an uninitialized si_zoneid is the same as
15707c478bd9Sstevel@tonic-gate 		 * GLOBAL_ZONEID, this means that you can't pr_setsig a
15717c478bd9Sstevel@tonic-gate 		 * process in a non-global zone with a siginfo which
15727c478bd9Sstevel@tonic-gate 		 * appears to come from the global zone.
15737c478bd9Sstevel@tonic-gate 		 */
15747c478bd9Sstevel@tonic-gate 		if (SI_FROMUSER(sip) && sip->si_zoneid == 0)
15757c478bd9Sstevel@tonic-gate 			lwp->lwp_curinfo->sq_info.si_zoneid =
15767c478bd9Sstevel@tonic-gate 			    p->p_zone->zone_id;
15777c478bd9Sstevel@tonic-gate 		/*
15787c478bd9Sstevel@tonic-gate 		 * Side-effects for SIGKILL and jobcontrol signals.
15797c478bd9Sstevel@tonic-gate 		 */
15807c478bd9Sstevel@tonic-gate 		if (sig == SIGKILL) {
15817c478bd9Sstevel@tonic-gate 			p->p_flag |= SKILLED;
15827c478bd9Sstevel@tonic-gate 			p->p_flag &= ~SEXTKILLED;
15837c478bd9Sstevel@tonic-gate 		} else if (sig == SIGCONT) {
15847c478bd9Sstevel@tonic-gate 			p->p_flag |= SSCONT;
15857c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGSTOP);
15867c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTSTP);
15877c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTTOU);
15887c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGTTIN);
15897c478bd9Sstevel@tonic-gate 			sigdiffset(&p->p_sig, &stopdefault);
15907c478bd9Sstevel@tonic-gate 			sigdiffset(&p->p_extsig, &stopdefault);
15917c478bd9Sstevel@tonic-gate 			if ((tx = p->p_tlist) != NULL) {
15927c478bd9Sstevel@tonic-gate 				do {
15937c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGSTOP);
15947c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGTSTP);
15957c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGTTOU);
15967c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGTTIN);
15977c478bd9Sstevel@tonic-gate 					sigdiffset(&tx->t_sig, &stopdefault);
15987c478bd9Sstevel@tonic-gate 					sigdiffset(&tx->t_extsig, &stopdefault);
15997c478bd9Sstevel@tonic-gate 				} while ((tx = tx->t_forw) != p->p_tlist);
16007c478bd9Sstevel@tonic-gate 			}
16017c478bd9Sstevel@tonic-gate 		} else if (sigismember(&stopdefault, sig)) {
16027c478bd9Sstevel@tonic-gate 			if (PTOU(p)->u_signal[sig-1] == SIG_DFL &&
16037c478bd9Sstevel@tonic-gate 			    (sig == SIGSTOP || !p->p_pgidp->pid_pgorphaned))
16047c478bd9Sstevel@tonic-gate 				p->p_flag &= ~SSCONT;
16057c478bd9Sstevel@tonic-gate 			sigdelq(p, NULL, SIGCONT);
16067c478bd9Sstevel@tonic-gate 			sigdelset(&p->p_sig, SIGCONT);
16077c478bd9Sstevel@tonic-gate 			sigdelset(&p->p_extsig, SIGCONT);
16087c478bd9Sstevel@tonic-gate 			if ((tx = p->p_tlist) != NULL) {
16097c478bd9Sstevel@tonic-gate 				do {
16107c478bd9Sstevel@tonic-gate 					sigdelq(p, tx, SIGCONT);
16117c478bd9Sstevel@tonic-gate 					sigdelset(&tx->t_sig, SIGCONT);
16127c478bd9Sstevel@tonic-gate 					sigdelset(&tx->t_extsig, SIGCONT);
16137c478bd9Sstevel@tonic-gate 				} while ((tx = tx->t_forw) != p->p_tlist);
16147c478bd9Sstevel@tonic-gate 			}
16157c478bd9Sstevel@tonic-gate 		}
16167c478bd9Sstevel@tonic-gate 		thread_lock(t);
1617c97ad5cdSakolb 		if (ISWAKEABLE(t) || ISWAITING(t)) {
1618da6c28aaSamw 			/* Set signaled sleeping/waiting lwp running */
16197c478bd9Sstevel@tonic-gate 			setrun_locked(t);
16207c478bd9Sstevel@tonic-gate 		} else if (t->t_state == TS_STOPPED && sig == SIGKILL) {
16217c478bd9Sstevel@tonic-gate 			/* If SIGKILL, set stopped lwp running */
16227c478bd9Sstevel@tonic-gate 			p->p_stopsig = 0;
16237c478bd9Sstevel@tonic-gate 			t->t_schedflag |= TS_XSTART | TS_PSTART;
16247c478bd9Sstevel@tonic-gate 			t->t_dtrace_stop = 0;
16257c478bd9Sstevel@tonic-gate 			setrun_locked(t);
16267c478bd9Sstevel@tonic-gate 		}
16277c478bd9Sstevel@tonic-gate 		t->t_sig_check = 1;	/* so ISSIG will be done */
16287c478bd9Sstevel@tonic-gate 		thread_unlock(t);
16297c478bd9Sstevel@tonic-gate 		/*
16307c478bd9Sstevel@tonic-gate 		 * More jobcontrol side-effects.
16317c478bd9Sstevel@tonic-gate 		 */
16327c478bd9Sstevel@tonic-gate 		if (sig == SIGCONT && (tx = p->p_tlist) != NULL) {
16337c478bd9Sstevel@tonic-gate 			p->p_stopsig = 0;
16347c478bd9Sstevel@tonic-gate 			do {
16357c478bd9Sstevel@tonic-gate 				thread_lock(tx);
16367c478bd9Sstevel@tonic-gate 				if (tx->t_state == TS_STOPPED &&
16377c478bd9Sstevel@tonic-gate 				    tx->t_whystop == PR_JOBCONTROL) {
16387c478bd9Sstevel@tonic-gate 					tx->t_schedflag |= TS_XSTART;
16397c478bd9Sstevel@tonic-gate 					setrun_locked(tx);
16407c478bd9Sstevel@tonic-gate 				}
16417c478bd9Sstevel@tonic-gate 				thread_unlock(tx);
16427c478bd9Sstevel@tonic-gate 			} while ((tx = tx->t_forw) != p->p_tlist);
16437c478bd9Sstevel@tonic-gate 		}
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate 	return (error);
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate int
pr_kill(prnode_t * pnp,int sig,cred_t * cr)16497c478bd9Sstevel@tonic-gate pr_kill(prnode_t *pnp, int sig, cred_t *cr)
16507c478bd9Sstevel@tonic-gate {
1651eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
16527c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
16537c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
16547c478bd9Sstevel@tonic-gate 	k_siginfo_t info;
16557c478bd9Sstevel@tonic-gate 
1656eb9dbf0cSRoger A. Faulkner 	if (sig <= 0 || sig >= nsig)
16577c478bd9Sstevel@tonic-gate 		return (EINVAL);
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	bzero(&info, sizeof (info));
16607c478bd9Sstevel@tonic-gate 	info.si_signo = sig;
16617c478bd9Sstevel@tonic-gate 	info.si_code = SI_USER;
16627c478bd9Sstevel@tonic-gate 	info.si_pid = curproc->p_pid;
16637c478bd9Sstevel@tonic-gate 	info.si_ctid = PRCTID(curproc);
16647c478bd9Sstevel@tonic-gate 	info.si_zoneid = getzoneid();
16657c478bd9Sstevel@tonic-gate 	info.si_uid = crgetruid(cr);
16667c478bd9Sstevel@tonic-gate 	sigaddq(p, (pcp->prc_flags & PRC_LWP)?
16677c478bd9Sstevel@tonic-gate 	    pcp->prc_thread : NULL, &info, KM_NOSLEEP);
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	return (0);
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate int
pr_unkill(prnode_t * pnp,int sig)16737c478bd9Sstevel@tonic-gate pr_unkill(prnode_t *pnp, int sig)
16747c478bd9Sstevel@tonic-gate {
1675eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
16767c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
16777c478bd9Sstevel@tonic-gate 	proc_t *p = pcp->prc_proc;
16787c478bd9Sstevel@tonic-gate 	sigqueue_t *infop = NULL;
16797c478bd9Sstevel@tonic-gate 
1680eb9dbf0cSRoger A. Faulkner 	if (sig <= 0 || sig >= nsig || sig == SIGKILL)
16817c478bd9Sstevel@tonic-gate 		return (EINVAL);
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	if (pcp->prc_flags & PRC_LWP)
16847c478bd9Sstevel@tonic-gate 		sigdeq(p, pcp->prc_thread, sig, &infop);
16857c478bd9Sstevel@tonic-gate 	else
16867c478bd9Sstevel@tonic-gate 		sigdeq(p, NULL, sig, &infop);
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	if (infop)
16897c478bd9Sstevel@tonic-gate 		siginfofree(infop);
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	return (0);
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate int
pr_nice(proc_t * p,int nice,cred_t * cr)16957c478bd9Sstevel@tonic-gate pr_nice(proc_t *p, int nice, cred_t *cr)
16967c478bd9Sstevel@tonic-gate {
16977c478bd9Sstevel@tonic-gate 	kthread_t *t;
16987c478bd9Sstevel@tonic-gate 	int err;
16997c478bd9Sstevel@tonic-gate 	int error = 0;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
17027c478bd9Sstevel@tonic-gate 	do {
17037c478bd9Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
17047c478bd9Sstevel@tonic-gate 		err = CL_DONICE(t, cr, nice, (int *)NULL);
1705d4204c85Sraf 		schedctl_set_cidpri(t);
17067c478bd9Sstevel@tonic-gate 		if (error == 0)
17077c478bd9Sstevel@tonic-gate 			error = err;
17087c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	return (error);
17117c478bd9Sstevel@tonic-gate }
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate void
pr_setentryexit(proc_t * p,sysset_t * sysset,int entry)17147c478bd9Sstevel@tonic-gate pr_setentryexit(proc_t *p, sysset_t *sysset, int entry)
17157c478bd9Sstevel@tonic-gate {
17167c478bd9Sstevel@tonic-gate 	user_t *up = PTOU(p);
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	if (entry) {
17197c478bd9Sstevel@tonic-gate 		prassignset(&up->u_entrymask, sysset);
17207c478bd9Sstevel@tonic-gate 	} else {
17217c478bd9Sstevel@tonic-gate 		prassignset(&up->u_exitmask, sysset);
17227c478bd9Sstevel@tonic-gate 	}
17237c478bd9Sstevel@tonic-gate 	if (!prisempty(&up->u_entrymask) ||
17247c478bd9Sstevel@tonic-gate 	    !prisempty(&up->u_exitmask)) {
17257c478bd9Sstevel@tonic-gate 		up->u_systrap = 1;
17267c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
17277c478bd9Sstevel@tonic-gate 		set_proc_sys(p);	/* set pre and post-sys flags */
17287c478bd9Sstevel@tonic-gate 	} else {
17297c478bd9Sstevel@tonic-gate 		up->u_systrap = 0;
17307c478bd9Sstevel@tonic-gate 		if (sigisempty(&p->p_sigmask) &&
17317c478bd9Sstevel@tonic-gate 		    prisempty(&p->p_fltmask))
17327c478bd9Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
17337c478bd9Sstevel@tonic-gate 	}
17347c478bd9Sstevel@tonic-gate }
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate #define	ALLFLAGS	\
17377c478bd9Sstevel@tonic-gate 	(PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_MSACCT|PR_MSFORK|PR_PTRACE)
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate int
pr_set(proc_t * p,long flags)17407c478bd9Sstevel@tonic-gate pr_set(proc_t *p, long flags)
17417c478bd9Sstevel@tonic-gate {
17427c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
17437c478bd9Sstevel@tonic-gate 		return (EBUSY);
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	if (flags & ~ALLFLAGS)
17467c478bd9Sstevel@tonic-gate 		return (EINVAL);
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 	if (flags & PR_FORK)
17497c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_FORK;
17507c478bd9Sstevel@tonic-gate 	if (flags & PR_RLC)
17517c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_RUNLCL;
17527c478bd9Sstevel@tonic-gate 	if (flags & PR_KLC)
17537c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_KILLCL;
17547c478bd9Sstevel@tonic-gate 	if (flags & PR_ASYNC)
17557c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_ASYNC;
17567c478bd9Sstevel@tonic-gate 	if (flags & PR_BPTADJ)
17577c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_BPTADJ;
17587c478bd9Sstevel@tonic-gate 	if (flags & PR_MSACCT)
17597c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SMSACCT) == 0)
17607c478bd9Sstevel@tonic-gate 			estimate_msacct(p->p_tlist, gethrtime());
17617c478bd9Sstevel@tonic-gate 	if (flags & PR_MSFORK)
17627c478bd9Sstevel@tonic-gate 		p->p_flag |= SMSFORK;
17637c478bd9Sstevel@tonic-gate 	if (flags & PR_PTRACE) {
17647c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_PTRACE;
17657c478bd9Sstevel@tonic-gate 		/* ptraced process must die if parent dead */
17667c478bd9Sstevel@tonic-gate 		if (p->p_ppid == 1)
17677c478bd9Sstevel@tonic-gate 			sigtoproc(p, NULL, SIGKILL);
17687c478bd9Sstevel@tonic-gate 	}
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	return (0);
17717c478bd9Sstevel@tonic-gate }
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate int
pr_unset(proc_t * p,long flags)17747c478bd9Sstevel@tonic-gate pr_unset(proc_t *p, long flags)
17757c478bd9Sstevel@tonic-gate {
17767c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
17777c478bd9Sstevel@tonic-gate 		return (EBUSY);
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	if (flags & ~ALLFLAGS)
17807c478bd9Sstevel@tonic-gate 		return (EINVAL);
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	if (flags & PR_FORK)
17837c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_FORK;
17847c478bd9Sstevel@tonic-gate 	if (flags & PR_RLC)
17857c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_RUNLCL;
17867c478bd9Sstevel@tonic-gate 	if (flags & PR_KLC)
17877c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_KILLCL;
17887c478bd9Sstevel@tonic-gate 	if (flags & PR_ASYNC)
17897c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_ASYNC;
17907c478bd9Sstevel@tonic-gate 	if (flags & PR_BPTADJ)
17917c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_BPTADJ;
17927c478bd9Sstevel@tonic-gate 	if (flags & PR_MSACCT)
17937c478bd9Sstevel@tonic-gate 		disable_msacct(p);
17947c478bd9Sstevel@tonic-gate 	if (flags & PR_MSFORK)
17957c478bd9Sstevel@tonic-gate 		p->p_flag &= ~SMSFORK;
17967c478bd9Sstevel@tonic-gate 	if (flags & PR_PTRACE)
17977c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~P_PR_PTRACE;
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	return (0);
18007c478bd9Sstevel@tonic-gate }
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate static int
pr_setfpregs(prnode_t * pnp,prfpregset_t * prfpregset)18037c478bd9Sstevel@tonic-gate pr_setfpregs(prnode_t *pnp, prfpregset_t *prfpregset)
18047c478bd9Sstevel@tonic-gate {
18057c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
18067c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
18097c478bd9Sstevel@tonic-gate 		thread_unlock(t);
18107c478bd9Sstevel@tonic-gate 		return (EBUSY);
18117c478bd9Sstevel@tonic-gate 	}
18127c478bd9Sstevel@tonic-gate 	if (!prhasfp()) {
18137c478bd9Sstevel@tonic-gate 		thread_unlock(t);
18147c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* No FP support */
18157c478bd9Sstevel@tonic-gate 	}
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
18187c478bd9Sstevel@tonic-gate 	thread_unlock(t);
18197c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
18207c478bd9Sstevel@tonic-gate 	prsetprfpregs(ttolwp(t), prfpregset);
18217c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 	return (0);
18247c478bd9Sstevel@tonic-gate }
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
18277c478bd9Sstevel@tonic-gate static int
pr_setfpregs32(prnode_t * pnp,prfpregset32_t * prfpregset)18287c478bd9Sstevel@tonic-gate pr_setfpregs32(prnode_t *pnp, prfpregset32_t *prfpregset)
18297c478bd9Sstevel@tonic-gate {
18307c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
18317c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
18347c478bd9Sstevel@tonic-gate 		thread_unlock(t);
18357c478bd9Sstevel@tonic-gate 		return (EBUSY);
18367c478bd9Sstevel@tonic-gate 	}
18377c478bd9Sstevel@tonic-gate 	if (!prhasfp()) {
18387c478bd9Sstevel@tonic-gate 		thread_unlock(t);
18397c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* No FP support */
18407c478bd9Sstevel@tonic-gate 	}
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
18437c478bd9Sstevel@tonic-gate 	thread_unlock(t);
18447c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
18457c478bd9Sstevel@tonic-gate 	prsetprfpregs32(ttolwp(t), prfpregset);
18467c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 	return (0);
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate /* ARGSUSED */
18537c478bd9Sstevel@tonic-gate static int
pr_setxregs(prnode_t * pnp,prxregset_t * prxregset)18547c478bd9Sstevel@tonic-gate pr_setxregs(prnode_t *pnp, prxregset_t *prxregset)
18557c478bd9Sstevel@tonic-gate {
1856*ed093b41SRobert Mustacchi 	int error;
18577c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
18587c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
18617c478bd9Sstevel@tonic-gate 		thread_unlock(t);
18627c478bd9Sstevel@tonic-gate 		return (EBUSY);
18637c478bd9Sstevel@tonic-gate 	}
18647c478bd9Sstevel@tonic-gate 	thread_unlock(t);
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 	if (!prhasx(p))
18677c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* No extra register support */
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
18707c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
1871*ed093b41SRobert Mustacchi 	error = prsetprxregs(ttolwp(t), prxregset);
18727c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
18737c478bd9Sstevel@tonic-gate 
1874*ed093b41SRobert Mustacchi 	return (error);
18757c478bd9Sstevel@tonic-gate }
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate static int
pr_setvaddr(prnode_t * pnp,caddr_t vaddr)18787c478bd9Sstevel@tonic-gate pr_setvaddr(prnode_t *pnp, caddr_t vaddr)
18797c478bd9Sstevel@tonic-gate {
18807c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
18817c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	if (!ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
18847c478bd9Sstevel@tonic-gate 		thread_unlock(t);
18857c478bd9Sstevel@tonic-gate 		return (EBUSY);
18867c478bd9Sstevel@tonic-gate 	}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	/* drop p_lock while touching the lwp's stack */
18897c478bd9Sstevel@tonic-gate 	thread_unlock(t);
18907c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
18917c478bd9Sstevel@tonic-gate 	prsvaddr(ttolwp(t), vaddr);
18927c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 	return (0);
18957c478bd9Sstevel@tonic-gate }
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate void
pr_sethold(prnode_t * pnp,sigset_t * sp)18987c478bd9Sstevel@tonic-gate pr_sethold(prnode_t *pnp, sigset_t *sp)
18997c478bd9Sstevel@tonic-gate {
19007c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
19017c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	schedctl_finish_sigblock(t);
19047c478bd9Sstevel@tonic-gate 	sigutok(sp, &t->t_hold);
1905c97ad5cdSakolb 	if (ISWAKEABLE(t) &&
19067c478bd9Sstevel@tonic-gate 	    (fsig(&p->p_sig, t) || fsig(&t->t_sig, t)))
19077c478bd9Sstevel@tonic-gate 		setrun_locked(t);
19087c478bd9Sstevel@tonic-gate 	t->t_sig_check = 1;	/* so thread will see new holdmask */
19097c478bd9Sstevel@tonic-gate 	thread_unlock(t);
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate void
pr_setfault(proc_t * p,fltset_t * fltp)19137c478bd9Sstevel@tonic-gate pr_setfault(proc_t *p, fltset_t *fltp)
19147c478bd9Sstevel@tonic-gate {
19157c478bd9Sstevel@tonic-gate 	prassignset(&p->p_fltmask, fltp);
19167c478bd9Sstevel@tonic-gate 	if (!prisempty(&p->p_fltmask))
19177c478bd9Sstevel@tonic-gate 		p->p_proc_flag |= P_PR_TRACE;
19187c478bd9Sstevel@tonic-gate 	else if (sigisempty(&p->p_sigmask)) {
19197c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
19207c478bd9Sstevel@tonic-gate 		if (up->u_systrap == 0)
19217c478bd9Sstevel@tonic-gate 			p->p_proc_flag &= ~P_PR_TRACE;
19227c478bd9Sstevel@tonic-gate 	}
19237c478bd9Sstevel@tonic-gate }
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate static int
pr_clearsig(prnode_t * pnp)19267c478bd9Sstevel@tonic-gate pr_clearsig(prnode_t *pnp)
19277c478bd9Sstevel@tonic-gate {
19287c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
19297c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	thread_unlock(t);
19327c478bd9Sstevel@tonic-gate 	if (lwp->lwp_cursig == SIGKILL)
19337c478bd9Sstevel@tonic-gate 		return (EBUSY);
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 	/*
19367c478bd9Sstevel@tonic-gate 	 * Discard current siginfo_t, if any.
19377c478bd9Sstevel@tonic-gate 	 */
19387c478bd9Sstevel@tonic-gate 	lwp->lwp_cursig = 0;
19397c478bd9Sstevel@tonic-gate 	lwp->lwp_extsig = 0;
19407c478bd9Sstevel@tonic-gate 	if (lwp->lwp_curinfo) {
19417c478bd9Sstevel@tonic-gate 		siginfofree(lwp->lwp_curinfo);
19427c478bd9Sstevel@tonic-gate 		lwp->lwp_curinfo = NULL;
19437c478bd9Sstevel@tonic-gate 	}
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	return (0);
19467c478bd9Sstevel@tonic-gate }
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate static int
pr_clearflt(prnode_t * pnp)19497c478bd9Sstevel@tonic-gate pr_clearflt(prnode_t *pnp)
19507c478bd9Sstevel@tonic-gate {
19517c478bd9Sstevel@tonic-gate 	kthread_t *t = pr_thread(pnp);	/* returns locked thread */
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	thread_unlock(t);
19547c478bd9Sstevel@tonic-gate 	ttolwp(t)->lwp_curflt = 0;
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	return (0);
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate static int
pr_watch(prnode_t * pnp,prwatch_t * pwp,int * unlocked)19607c478bd9Sstevel@tonic-gate pr_watch(prnode_t *pnp, prwatch_t *pwp, int *unlocked)
19617c478bd9Sstevel@tonic-gate {
19627c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
19637c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
19647c478bd9Sstevel@tonic-gate 	uintptr_t vaddr = pwp->pr_vaddr;
19657c478bd9Sstevel@tonic-gate 	size_t size = pwp->pr_size;
19667c478bd9Sstevel@tonic-gate 	int wflags = pwp->pr_wflags;
19677c478bd9Sstevel@tonic-gate 	ulong_t newpage = 0;
19687c478bd9Sstevel@tonic-gate 	struct watched_area *pwa;
19697c478bd9Sstevel@tonic-gate 	int error;
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	*unlocked = 0;
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	/*
19747c478bd9Sstevel@tonic-gate 	 * Can't apply to a system process.
19757c478bd9Sstevel@tonic-gate 	 */
19767c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
19777c478bd9Sstevel@tonic-gate 		return (EBUSY);
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	/*
19807c478bd9Sstevel@tonic-gate 	 * Verify that the address range does not wrap
19817c478bd9Sstevel@tonic-gate 	 * and that only the proper flags were specified.
19827c478bd9Sstevel@tonic-gate 	 */
19837c478bd9Sstevel@tonic-gate 	if ((wflags & ~WA_TRAPAFTER) == 0)
19847c478bd9Sstevel@tonic-gate 		size = 0;
19857c478bd9Sstevel@tonic-gate 	if (vaddr + size < vaddr ||
19867c478bd9Sstevel@tonic-gate 	    (wflags & ~(WA_READ|WA_WRITE|WA_EXEC|WA_TRAPAFTER)) != 0 ||
19877c478bd9Sstevel@tonic-gate 	    ((wflags & ~WA_TRAPAFTER) != 0 && size == 0))
19887c478bd9Sstevel@tonic-gate 		return (EINVAL);
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 	/*
19917c478bd9Sstevel@tonic-gate 	 * Don't let the address range go above as->a_userlimit.
19927c478bd9Sstevel@tonic-gate 	 * There is no error here, just a limitation.
19937c478bd9Sstevel@tonic-gate 	 */
19947c478bd9Sstevel@tonic-gate 	if (vaddr >= (uintptr_t)as->a_userlimit)
19957c478bd9Sstevel@tonic-gate 		return (0);
19967c478bd9Sstevel@tonic-gate 	if (vaddr + size > (uintptr_t)as->a_userlimit)
19977c478bd9Sstevel@tonic-gate 		size = (uintptr_t)as->a_userlimit - vaddr;
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	/*
20007c478bd9Sstevel@tonic-gate 	 * Compute maximum number of pages this will add.
20017c478bd9Sstevel@tonic-gate 	 */
20027c478bd9Sstevel@tonic-gate 	if ((wflags & ~WA_TRAPAFTER) != 0) {
20037c478bd9Sstevel@tonic-gate 		ulong_t pagespan = (vaddr + size) - (vaddr & PAGEMASK);
20047c478bd9Sstevel@tonic-gate 		newpage = btopr(pagespan);
20057c478bd9Sstevel@tonic-gate 		if (newpage > 2 * prnwatch)
20067c478bd9Sstevel@tonic-gate 			return (E2BIG);
20077c478bd9Sstevel@tonic-gate 	}
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 	/*
20107c478bd9Sstevel@tonic-gate 	 * Force the process to be fully stopped.
20117c478bd9Sstevel@tonic-gate 	 */
20127c478bd9Sstevel@tonic-gate 	if (p == curproc) {
20137c478bd9Sstevel@tonic-gate 		prunlock(pnp);
20147c478bd9Sstevel@tonic-gate 		while (holdwatch() != 0)
20157c478bd9Sstevel@tonic-gate 			continue;
20167c478bd9Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) != 0) {
20177c478bd9Sstevel@tonic-gate 			continuelwps(p);
20187c478bd9Sstevel@tonic-gate 			*unlocked = 1;
20197c478bd9Sstevel@tonic-gate 			return (error);
20207c478bd9Sstevel@tonic-gate 		}
20217c478bd9Sstevel@tonic-gate 	} else {
20227c478bd9Sstevel@tonic-gate 		pauselwps(p);
20237c478bd9Sstevel@tonic-gate 		while (pr_allstopped(p, 0) > 0) {
20247c478bd9Sstevel@tonic-gate 			/*
20257c478bd9Sstevel@tonic-gate 			 * This cv/mutex pair is persistent even
20267c478bd9Sstevel@tonic-gate 			 * if the process disappears after we
20277c478bd9Sstevel@tonic-gate 			 * unmark it and drop p->p_lock.
20287c478bd9Sstevel@tonic-gate 			 */
20297c478bd9Sstevel@tonic-gate 			kcondvar_t *cv = &pr_pid_cv[p->p_slot];
20307c478bd9Sstevel@tonic-gate 			kmutex_t *mp = &p->p_lock;
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 			prunmark(p);
20337c478bd9Sstevel@tonic-gate 			(void) cv_wait(cv, mp);
20347c478bd9Sstevel@tonic-gate 			mutex_exit(mp);
20357c478bd9Sstevel@tonic-gate 			if ((error = prlock(pnp, ZNO)) != 0) {
20367c478bd9Sstevel@tonic-gate 				/*
20377c478bd9Sstevel@tonic-gate 				 * Unpause the process if it exists.
20387c478bd9Sstevel@tonic-gate 				 */
20397c478bd9Sstevel@tonic-gate 				p = pr_p_lock(pnp);
20407c478bd9Sstevel@tonic-gate 				mutex_exit(&pr_pidlock);
20417c478bd9Sstevel@tonic-gate 				if (p != NULL) {
20427c478bd9Sstevel@tonic-gate 					unpauselwps(p);
20437c478bd9Sstevel@tonic-gate 					prunlock(pnp);
20447c478bd9Sstevel@tonic-gate 				}
20457c478bd9Sstevel@tonic-gate 				*unlocked = 1;
20467c478bd9Sstevel@tonic-gate 				return (error);
20477c478bd9Sstevel@tonic-gate 			}
20487c478bd9Sstevel@tonic-gate 		}
20497c478bd9Sstevel@tonic-gate 	}
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	/*
20527c478bd9Sstevel@tonic-gate 	 * Drop p->p_lock in order to perform the rest of this.
20537c478bd9Sstevel@tonic-gate 	 * The process is still locked with the P_PR_LOCK flag.
20547c478bd9Sstevel@tonic-gate 	 */
20557c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	pwa = kmem_alloc(sizeof (struct watched_area), KM_SLEEP);
20587c478bd9Sstevel@tonic-gate 	pwa->wa_vaddr = (caddr_t)vaddr;
20597c478bd9Sstevel@tonic-gate 	pwa->wa_eaddr = (caddr_t)vaddr + size;
20607c478bd9Sstevel@tonic-gate 	pwa->wa_flags = (ulong_t)wflags;
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	error = ((pwa->wa_flags & ~WA_TRAPAFTER) == 0)?
2063bda89588Sjp151216 	    clear_watched_area(p, pwa) : set_watched_area(p, pwa);
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 	if (p == curproc) {
20667c478bd9Sstevel@tonic-gate 		setallwatch();
20677c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
20687c478bd9Sstevel@tonic-gate 		continuelwps(p);
20697c478bd9Sstevel@tonic-gate 	} else {
20707c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
20717c478bd9Sstevel@tonic-gate 		unpauselwps(p);
20727c478bd9Sstevel@tonic-gate 	}
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	return (error);
20757c478bd9Sstevel@tonic-gate }
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate /* jobcontrol stopped, but with a /proc directed stop in effect */
20787c478bd9Sstevel@tonic-gate #define	JDSTOPPED(t)	\
20797c478bd9Sstevel@tonic-gate 	((t)->t_state == TS_STOPPED && \
20807c478bd9Sstevel@tonic-gate 	(t)->t_whystop == PR_JOBCONTROL && \
20817c478bd9Sstevel@tonic-gate 	((t)->t_proc_flag & TP_PRSTOP))
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate /*
20847c478bd9Sstevel@tonic-gate  * pr_agent() creates the agent lwp. If the process is exiting while
20857c478bd9Sstevel@tonic-gate  * we are creating an agent lwp, then exitlwps() waits until the
20867c478bd9Sstevel@tonic-gate  * agent has been created using prbarrier().
20877c478bd9Sstevel@tonic-gate  */
20887c478bd9Sstevel@tonic-gate static int
pr_agent(prnode_t * pnp,prgregset_t prgregset,int * unlocked)20897c478bd9Sstevel@tonic-gate pr_agent(prnode_t *pnp, prgregset_t prgregset, int *unlocked)
20907c478bd9Sstevel@tonic-gate {
20917c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_common->prc_proc;
20927c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
20937c478bd9Sstevel@tonic-gate 	kthread_t *t;
20947c478bd9Sstevel@tonic-gate 	kthread_t *ct;
20957c478bd9Sstevel@tonic-gate 	klwp_t *clwp;
20967c478bd9Sstevel@tonic-gate 	k_sigset_t smask;
20977c478bd9Sstevel@tonic-gate 	int cid;
20987c478bd9Sstevel@tonic-gate 	void *bufp = NULL;
20997c478bd9Sstevel@tonic-gate 	int error;
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	*unlocked = 0;
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	/*
21047c478bd9Sstevel@tonic-gate 	 * Cannot create the /proc agent lwp if :-
21057c478bd9Sstevel@tonic-gate 	 * - the process is not fully stopped or directed to stop.
21067c478bd9Sstevel@tonic-gate 	 * - there is an agent lwp already.
210797eda132Sraf 	 * - the process has been killed.
210897eda132Sraf 	 * - the process is exiting.
21097c478bd9Sstevel@tonic-gate 	 * - it's a vfork(2) parent.
21107c478bd9Sstevel@tonic-gate 	 */
21117c478bd9Sstevel@tonic-gate 	t = prchoose(p);	/* returns locked thread */
21127c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
21137c478bd9Sstevel@tonic-gate 
211497eda132Sraf 	if ((!ISTOPPED(t) && !VSTOPPED(t) && !SUSPENDED(t) && !JDSTOPPED(t)) ||
211597eda132Sraf 	    p->p_agenttp != NULL ||
211697eda132Sraf 	    (p->p_flag & (SKILLED | SEXITING | SVFWAIT))) {
21177c478bd9Sstevel@tonic-gate 		thread_unlock(t);
21187c478bd9Sstevel@tonic-gate 		return (EBUSY);
21197c478bd9Sstevel@tonic-gate 	}
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	thread_unlock(t);
21227c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 	sigfillset(&smask);
21257c478bd9Sstevel@tonic-gate 	sigdiffset(&smask, &cantmask);
21267c478bd9Sstevel@tonic-gate 	clwp = lwp_create(lwp_rtt, NULL, 0, p, TS_STOPPED,
21277c478bd9Sstevel@tonic-gate 	    t->t_pri, &smask, NOCLASS, 0);
21287c478bd9Sstevel@tonic-gate 	if (clwp == NULL) {
21297c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
21307c478bd9Sstevel@tonic-gate 		return (ENOMEM);
21317c478bd9Sstevel@tonic-gate 	}
21327c478bd9Sstevel@tonic-gate 	prsetprregs(clwp, prgregset, 1);
2133f971a346SBryan Cantrill 
2134f971a346SBryan Cantrill 	/*
2135f971a346SBryan Cantrill 	 * Because abandoning the agent inside the target process leads to
2136f971a346SBryan Cantrill 	 * a state that is essentially undebuggable, we record the psinfo of
2137f971a346SBryan Cantrill 	 * the process creating the agent and hang that off of the lwp.
2138f971a346SBryan Cantrill 	 */
2139f971a346SBryan Cantrill 	clwp->lwp_spymaster = kmem_zalloc(sizeof (psinfo_t), KM_SLEEP);
2140f971a346SBryan Cantrill 	mutex_enter(&curproc->p_lock);
2141f971a346SBryan Cantrill 	prgetpsinfo(curproc, clwp->lwp_spymaster);
2142f971a346SBryan Cantrill 	mutex_exit(&curproc->p_lock);
2143f971a346SBryan Cantrill 
2144f971a346SBryan Cantrill 	/*
2145f971a346SBryan Cantrill 	 * We overload pr_time in the spymaster to denote the time at which the
2146f971a346SBryan Cantrill 	 * agent was created.
2147f971a346SBryan Cantrill 	 */
2148f971a346SBryan Cantrill 	gethrestime(&clwp->lwp_spymaster->pr_time);
2149f971a346SBryan Cantrill 
21507c478bd9Sstevel@tonic-gate retry:
21517c478bd9Sstevel@tonic-gate 	cid = t->t_cid;
21527c478bd9Sstevel@tonic-gate 	(void) CL_ALLOC(&bufp, cid, KM_SLEEP);
21537c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
21547c478bd9Sstevel@tonic-gate 	if (cid != t->t_cid) {
21557c478bd9Sstevel@tonic-gate 		/*
21567c478bd9Sstevel@tonic-gate 		 * Someone just changed this thread's scheduling class,
21577c478bd9Sstevel@tonic-gate 		 * so try pre-allocating the buffer again.  Hopefully we
21587c478bd9Sstevel@tonic-gate 		 * don't hit this often.
21597c478bd9Sstevel@tonic-gate 		 */
21607c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
21617c478bd9Sstevel@tonic-gate 		CL_FREE(cid, bufp);
21627c478bd9Sstevel@tonic-gate 		goto retry;
21637c478bd9Sstevel@tonic-gate 	}
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	clwp->lwp_ap = clwp->lwp_arg;
21667c478bd9Sstevel@tonic-gate 	clwp->lwp_eosys = NORMALRETURN;
21677c478bd9Sstevel@tonic-gate 	ct = lwptot(clwp);
21687c478bd9Sstevel@tonic-gate 	ct->t_clfuncs = t->t_clfuncs;
21697c478bd9Sstevel@tonic-gate 	CL_FORK(t, ct, bufp);
21707c478bd9Sstevel@tonic-gate 	ct->t_cid = t->t_cid;
21717c478bd9Sstevel@tonic-gate 	ct->t_proc_flag |= TP_PRSTOP;
21727c478bd9Sstevel@tonic-gate 	/*
21737c478bd9Sstevel@tonic-gate 	 * Setting t_sysnum to zero causes post_syscall()
21747c478bd9Sstevel@tonic-gate 	 * to bypass all syscall checks and go directly to
21757c478bd9Sstevel@tonic-gate 	 *	if (issig()) psig();
21767c478bd9Sstevel@tonic-gate 	 * so that the agent lwp will stop in issig_forreal()
21777c478bd9Sstevel@tonic-gate 	 * showing PR_REQUESTED.
21787c478bd9Sstevel@tonic-gate 	 */
21797c478bd9Sstevel@tonic-gate 	ct->t_sysnum = 0;
21807c478bd9Sstevel@tonic-gate 	ct->t_post_sys = 1;
21817c478bd9Sstevel@tonic-gate 	ct->t_sig_check = 1;
21827c478bd9Sstevel@tonic-gate 	p->p_agenttp = ct;
21837c478bd9Sstevel@tonic-gate 	ct->t_proc_flag &= ~TP_HOLDLWP;
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_pcommon;
21867c478bd9Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 	lwp_create_done(ct);
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 	/*
21917c478bd9Sstevel@tonic-gate 	 * Don't return until the agent is stopped on PR_REQUESTED.
21927c478bd9Sstevel@tonic-gate 	 */
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 	for (;;) {
21957c478bd9Sstevel@tonic-gate 		prunlock(pnp);
21967c478bd9Sstevel@tonic-gate 		*unlocked = 1;
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 		/*
21997c478bd9Sstevel@tonic-gate 		 * Wait for the agent to stop and notify us.
22007c478bd9Sstevel@tonic-gate 		 * If we've been interrupted, return that information.
22017c478bd9Sstevel@tonic-gate 		 */
22023348528fSdm120769 		error = pr_wait(pcp, NULL, 0);
22037c478bd9Sstevel@tonic-gate 		if (error == EINTR) {
22047c478bd9Sstevel@tonic-gate 			error = 0;
22057c478bd9Sstevel@tonic-gate 			break;
22067c478bd9Sstevel@tonic-gate 		}
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 		/*
22097c478bd9Sstevel@tonic-gate 		 * Confirm that the agent LWP has stopped.
22107c478bd9Sstevel@tonic-gate 		 */
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) != 0)
22137c478bd9Sstevel@tonic-gate 			break;
22147c478bd9Sstevel@tonic-gate 		*unlocked = 0;
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 		/*
22177c478bd9Sstevel@tonic-gate 		 * Since we dropped the lock on the process, the agent
22187c478bd9Sstevel@tonic-gate 		 * may have disappeared or changed. Grab the current
22197c478bd9Sstevel@tonic-gate 		 * agent and check fail if it has disappeared.
22207c478bd9Sstevel@tonic-gate 		 */
22217c478bd9Sstevel@tonic-gate 		if ((ct = p->p_agenttp) == NULL) {
22227c478bd9Sstevel@tonic-gate 			error = ENOENT;
22237c478bd9Sstevel@tonic-gate 			break;
22247c478bd9Sstevel@tonic-gate 		}
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
22277c478bd9Sstevel@tonic-gate 		thread_lock(ct);
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate 		if (ISTOPPED(ct)) {
22307c478bd9Sstevel@tonic-gate 			thread_unlock(ct);
22317c478bd9Sstevel@tonic-gate 			mutex_exit(&pcp->prc_mutex);
22327c478bd9Sstevel@tonic-gate 			break;
22337c478bd9Sstevel@tonic-gate 		}
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate 		thread_unlock(ct);
22367c478bd9Sstevel@tonic-gate 	}
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	return (error ? error : -1);
22397c478bd9Sstevel@tonic-gate }
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate static int
pr_rdwr(proc_t * p,enum uio_rw rw,priovec_t * pio)22427c478bd9Sstevel@tonic-gate pr_rdwr(proc_t *p, enum uio_rw rw, priovec_t *pio)
22437c478bd9Sstevel@tonic-gate {
22447c478bd9Sstevel@tonic-gate 	caddr_t base = (caddr_t)pio->pio_base;
22457c478bd9Sstevel@tonic-gate 	size_t cnt = pio->pio_len;
22467c478bd9Sstevel@tonic-gate 	uintptr_t offset = (uintptr_t)pio->pio_offset;
22477c478bd9Sstevel@tonic-gate 	struct uio auio;
22487c478bd9Sstevel@tonic-gate 	struct iovec aiov;
22497c478bd9Sstevel@tonic-gate 	int error = 0;
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
22527c478bd9Sstevel@tonic-gate 		error = EIO;
22537c478bd9Sstevel@tonic-gate 	else if ((base + cnt) < base || (offset + cnt) < offset)
22547c478bd9Sstevel@tonic-gate 		error = EINVAL;
22557c478bd9Sstevel@tonic-gate 	else if (cnt != 0) {
22567c478bd9Sstevel@tonic-gate 		aiov.iov_base = base;
22577c478bd9Sstevel@tonic-gate 		aiov.iov_len = cnt;
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate 		auio.uio_loffset = offset;
22607c478bd9Sstevel@tonic-gate 		auio.uio_iov = &aiov;
22617c478bd9Sstevel@tonic-gate 		auio.uio_iovcnt = 1;
22627c478bd9Sstevel@tonic-gate 		auio.uio_resid = cnt;
22637c478bd9Sstevel@tonic-gate 		auio.uio_segflg = UIO_USERSPACE;
22647c478bd9Sstevel@tonic-gate 		auio.uio_llimit = (longlong_t)MAXOFFSET_T;
22657c478bd9Sstevel@tonic-gate 		auio.uio_fmode = FREAD|FWRITE;
22667c478bd9Sstevel@tonic-gate 		auio.uio_extflg = UIO_COPY_DEFAULT;
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
22697c478bd9Sstevel@tonic-gate 		error = prusrio(p, rw, &auio, 0);
22707c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate 		/*
22737c478bd9Sstevel@tonic-gate 		 * We have no way to return the i/o count,
22747c478bd9Sstevel@tonic-gate 		 * like read() or write() would do, so we
22757c478bd9Sstevel@tonic-gate 		 * return an error if the i/o was truncated.
22767c478bd9Sstevel@tonic-gate 		 */
22777c478bd9Sstevel@tonic-gate 		if (auio.uio_resid != 0 && error == 0)
22787c478bd9Sstevel@tonic-gate 			error = EIO;
22797c478bd9Sstevel@tonic-gate 	}
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 	return (error);
22827c478bd9Sstevel@tonic-gate }
22837c478bd9Sstevel@tonic-gate 
22847c478bd9Sstevel@tonic-gate static int
pr_scred(proc_t * p,prcred_t * prcred,cred_t * cr,boolean_t dogrps)22857c478bd9Sstevel@tonic-gate pr_scred(proc_t *p, prcred_t *prcred, cred_t *cr, boolean_t dogrps)
22867c478bd9Sstevel@tonic-gate {
22877c478bd9Sstevel@tonic-gate 	kthread_t *t;
22887c478bd9Sstevel@tonic-gate 	cred_t *oldcred;
22897c478bd9Sstevel@tonic-gate 	cred_t *newcred;
22907c478bd9Sstevel@tonic-gate 	uid_t oldruid;
22917c478bd9Sstevel@tonic-gate 	int error;
2292bda89588Sjp151216 	zone_t *zone = crgetzone(cr);
22937c478bd9Sstevel@tonic-gate 
2294bda89588Sjp151216 	if (!VALID_UID(prcred->pr_euid, zone) ||
2295bda89588Sjp151216 	    !VALID_UID(prcred->pr_ruid, zone) ||
2296bda89588Sjp151216 	    !VALID_UID(prcred->pr_suid, zone) ||
2297bda89588Sjp151216 	    !VALID_GID(prcred->pr_egid, zone) ||
2298bda89588Sjp151216 	    !VALID_GID(prcred->pr_rgid, zone) ||
2299bda89588Sjp151216 	    !VALID_GID(prcred->pr_sgid, zone))
23007c478bd9Sstevel@tonic-gate 		return (EINVAL);
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	if (dogrps) {
23037c478bd9Sstevel@tonic-gate 		int ngrp = prcred->pr_ngroups;
23047c478bd9Sstevel@tonic-gate 		int i;
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate 		if (ngrp < 0 || ngrp > ngroups_max)
23077c478bd9Sstevel@tonic-gate 			return (EINVAL);
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 		for (i = 0; i < ngrp; i++) {
2310bda89588Sjp151216 			if (!VALID_GID(prcred->pr_groups[i], zone))
23117c478bd9Sstevel@tonic-gate 				return (EINVAL);
23127c478bd9Sstevel@tonic-gate 		}
23137c478bd9Sstevel@tonic-gate 	}
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 	error = secpolicy_allow_setid(cr, prcred->pr_euid, B_FALSE);
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 	if (error == 0 && prcred->pr_ruid != prcred->pr_euid)
23187c478bd9Sstevel@tonic-gate 		error = secpolicy_allow_setid(cr, prcred->pr_ruid, B_FALSE);
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 	if (error == 0 && prcred->pr_suid != prcred->pr_euid &&
23217c478bd9Sstevel@tonic-gate 	    prcred->pr_suid != prcred->pr_ruid)
23227c478bd9Sstevel@tonic-gate 		error = secpolicy_allow_setid(cr, prcred->pr_suid, B_FALSE);
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 	if (error)
23257c478bd9Sstevel@tonic-gate 		return (error);
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 	/* hold old cred so it doesn't disappear while we dup it */
23307c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
23317c478bd9Sstevel@tonic-gate 	crhold(oldcred = p->p_cred);
23327c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
23337c478bd9Sstevel@tonic-gate 	newcred = crdup(oldcred);
23347c478bd9Sstevel@tonic-gate 	oldruid = crgetruid(oldcred);
23357c478bd9Sstevel@tonic-gate 	crfree(oldcred);
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 	/* Error checking done above */
23387c478bd9Sstevel@tonic-gate 	(void) crsetresuid(newcred, prcred->pr_ruid, prcred->pr_euid,
23397c478bd9Sstevel@tonic-gate 	    prcred->pr_suid);
23407c478bd9Sstevel@tonic-gate 	(void) crsetresgid(newcred, prcred->pr_rgid, prcred->pr_egid,
23417c478bd9Sstevel@tonic-gate 	    prcred->pr_sgid);
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	if (dogrps) {
23447c478bd9Sstevel@tonic-gate 		(void) crsetgroups(newcred, prcred->pr_ngroups,
23457c478bd9Sstevel@tonic-gate 		    prcred->pr_groups);
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 	}
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
23507c478bd9Sstevel@tonic-gate 	oldcred = p->p_cred;
23517c478bd9Sstevel@tonic-gate 	p->p_cred = newcred;
23527c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
23537c478bd9Sstevel@tonic-gate 	crfree(oldcred);
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	/*
23567c478bd9Sstevel@tonic-gate 	 * Keep count of processes per uid consistent.
23577c478bd9Sstevel@tonic-gate 	 */
23587c478bd9Sstevel@tonic-gate 	if (oldruid != prcred->pr_ruid) {
23597c478bd9Sstevel@tonic-gate 		zoneid_t zoneid = crgetzoneid(newcred);
23607c478bd9Sstevel@tonic-gate 
23617c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
23627c478bd9Sstevel@tonic-gate 		upcount_dec(oldruid, zoneid);
23637c478bd9Sstevel@tonic-gate 		upcount_inc(prcred->pr_ruid, zoneid);
23647c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
23657c478bd9Sstevel@tonic-gate 	}
23667c478bd9Sstevel@tonic-gate 
23677c478bd9Sstevel@tonic-gate 	/*
23687c478bd9Sstevel@tonic-gate 	 * Broadcast the cred change to the threads.
23697c478bd9Sstevel@tonic-gate 	 */
23707c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
23717c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
23727c478bd9Sstevel@tonic-gate 	do {
23737c478bd9Sstevel@tonic-gate 		t->t_pre_sys = 1; /* so syscall will get new cred */
23747c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 	return (0);
23777c478bd9Sstevel@tonic-gate }
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate /*
23807c478bd9Sstevel@tonic-gate  * Change process credentials to specified zone.  Used to temporarily
23817c478bd9Sstevel@tonic-gate  * set a process to run in the global zone; only transitions between
23827c478bd9Sstevel@tonic-gate  * the process's actual zone and the global zone are allowed.
23837c478bd9Sstevel@tonic-gate  */
23847c478bd9Sstevel@tonic-gate static int
pr_szoneid(proc_t * p,zoneid_t zoneid,cred_t * cr)23857c478bd9Sstevel@tonic-gate pr_szoneid(proc_t *p, zoneid_t zoneid, cred_t *cr)
23867c478bd9Sstevel@tonic-gate {
23877c478bd9Sstevel@tonic-gate 	kthread_t *t;
23887c478bd9Sstevel@tonic-gate 	cred_t *oldcred;
23897c478bd9Sstevel@tonic-gate 	cred_t *newcred;
23907c478bd9Sstevel@tonic-gate 	zone_t *zptr;
2391956b78ccSsl108498 	zoneid_t oldzoneid;
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate 	if (secpolicy_zone_config(cr) != 0)
23947c478bd9Sstevel@tonic-gate 		return (EPERM);
23957c478bd9Sstevel@tonic-gate 	if (zoneid != GLOBAL_ZONEID && zoneid != p->p_zone->zone_id)
23967c478bd9Sstevel@tonic-gate 		return (EINVAL);
23977c478bd9Sstevel@tonic-gate 	if ((zptr = zone_find_by_id(zoneid)) == NULL)
23987c478bd9Sstevel@tonic-gate 		return (EINVAL);
23997c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
24007c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
2401956b78ccSsl108498 	oldcred = p->p_cred;
2402956b78ccSsl108498 	crhold(oldcred);
24037c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
24047c478bd9Sstevel@tonic-gate 	newcred = crdup(oldcred);
2405956b78ccSsl108498 	oldzoneid = crgetzoneid(oldcred);
24067c478bd9Sstevel@tonic-gate 	crfree(oldcred);
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 	crsetzone(newcred, zptr);
24097c478bd9Sstevel@tonic-gate 	zone_rele(zptr);
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
24127c478bd9Sstevel@tonic-gate 	oldcred = p->p_cred;
24137c478bd9Sstevel@tonic-gate 	p->p_cred = newcred;
24147c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
24157c478bd9Sstevel@tonic-gate 	crfree(oldcred);
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate 	/*
2418956b78ccSsl108498 	 * The target process is changing zones (according to its cred), so
2419956b78ccSsl108498 	 * update the per-zone upcounts, which are based on process creds.
2420956b78ccSsl108498 	 */
2421956b78ccSsl108498 	if (oldzoneid != zoneid) {
2422956b78ccSsl108498 		uid_t ruid = crgetruid(newcred);
2423956b78ccSsl108498 
2424956b78ccSsl108498 		mutex_enter(&pidlock);
2425956b78ccSsl108498 		upcount_dec(ruid, oldzoneid);
2426956b78ccSsl108498 		upcount_inc(ruid, zoneid);
2427956b78ccSsl108498 		mutex_exit(&pidlock);
2428956b78ccSsl108498 	}
2429956b78ccSsl108498 	/*
24307c478bd9Sstevel@tonic-gate 	 * Broadcast the cred change to the threads.
24317c478bd9Sstevel@tonic-gate 	 */
24327c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
24337c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
24347c478bd9Sstevel@tonic-gate 	do {
24357c478bd9Sstevel@tonic-gate 		t->t_pre_sys = 1;	/* so syscall will get new cred */
24367c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	return (0);
24397c478bd9Sstevel@tonic-gate }
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate static int
pr_spriv(proc_t * p,prpriv_t * prpriv,cred_t * cr)24427c478bd9Sstevel@tonic-gate pr_spriv(proc_t *p, prpriv_t *prpriv, cred_t *cr)
24437c478bd9Sstevel@tonic-gate {
24447c478bd9Sstevel@tonic-gate 	kthread_t *t;
24457c478bd9Sstevel@tonic-gate 	int err;
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 	if ((err = priv_pr_spriv(p, prpriv, cr)) == 0) {
24507c478bd9Sstevel@tonic-gate 		/*
24517c478bd9Sstevel@tonic-gate 		 * Broadcast the cred change to the threads.
24527c478bd9Sstevel@tonic-gate 		 */
24537c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
24547c478bd9Sstevel@tonic-gate 		do {
24557c478bd9Sstevel@tonic-gate 			t->t_pre_sys = 1; /* so syscall will get new cred */
24567c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
24577c478bd9Sstevel@tonic-gate 	}
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 	return (err);
24607c478bd9Sstevel@tonic-gate }
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate /*
24637c478bd9Sstevel@tonic-gate  * Return -1 if the process is the parent of a vfork(1) whose child has yet to
24647c478bd9Sstevel@tonic-gate  * terminate or perform an exec(2).
24657c478bd9Sstevel@tonic-gate  *
24667c478bd9Sstevel@tonic-gate  * Returns 0 if the process is fully stopped except for the current thread (if
24677c478bd9Sstevel@tonic-gate  * we are operating on our own process), 1 otherwise.
24687c478bd9Sstevel@tonic-gate  *
24697c478bd9Sstevel@tonic-gate  * If the watchstop flag is set, then we ignore threads with TP_WATCHSTOP set.
24707c478bd9Sstevel@tonic-gate  * See holdwatch() for details.
24717c478bd9Sstevel@tonic-gate  */
24727c478bd9Sstevel@tonic-gate int
pr_allstopped(proc_t * p,int watchstop)24737c478bd9Sstevel@tonic-gate pr_allstopped(proc_t *p, int watchstop)
24747c478bd9Sstevel@tonic-gate {
24757c478bd9Sstevel@tonic-gate 	kthread_t *t;
24767c478bd9Sstevel@tonic-gate 	int rv = 0;
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 	if (p->p_flag & SVFWAIT)	/* waiting for vfork'd child to exec */
24817c478bd9Sstevel@tonic-gate 		return (-1);
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
24847c478bd9Sstevel@tonic-gate 		do {
24857c478bd9Sstevel@tonic-gate 			if (t == curthread || VSTOPPED(t) ||
24867c478bd9Sstevel@tonic-gate 			    (watchstop && (t->t_proc_flag & TP_WATCHSTOP)))
24877c478bd9Sstevel@tonic-gate 				continue;
24887c478bd9Sstevel@tonic-gate 			thread_lock(t);
24897c478bd9Sstevel@tonic-gate 			switch (t->t_state) {
24907c478bd9Sstevel@tonic-gate 			case TS_ZOMB:
24917c478bd9Sstevel@tonic-gate 			case TS_STOPPED:
24927c478bd9Sstevel@tonic-gate 				break;
24937c478bd9Sstevel@tonic-gate 			case TS_SLEEP:
24947c478bd9Sstevel@tonic-gate 				if (!(t->t_flag & T_WAKEABLE) ||
24957c478bd9Sstevel@tonic-gate 				    t->t_wchan0 == NULL)
24967c478bd9Sstevel@tonic-gate 					rv = 1;
24977c478bd9Sstevel@tonic-gate 				break;
24987c478bd9Sstevel@tonic-gate 			default:
24997c478bd9Sstevel@tonic-gate 				rv = 1;
25007c478bd9Sstevel@tonic-gate 				break;
25017c478bd9Sstevel@tonic-gate 			}
25027c478bd9Sstevel@tonic-gate 			thread_unlock(t);
25037c478bd9Sstevel@tonic-gate 		} while (rv == 0 && (t = t->t_forw) != p->p_tlist);
25047c478bd9Sstevel@tonic-gate 	}
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate 	return (rv);
25077c478bd9Sstevel@tonic-gate }
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate /*
25107c478bd9Sstevel@tonic-gate  * Cause all lwps in the process to pause (for watchpoint operations).
25117c478bd9Sstevel@tonic-gate  */
25127c478bd9Sstevel@tonic-gate static void
pauselwps(proc_t * p)25137c478bd9Sstevel@tonic-gate pauselwps(proc_t *p)
25147c478bd9Sstevel@tonic-gate {
25157c478bd9Sstevel@tonic-gate 	kthread_t *t;
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
25187c478bd9Sstevel@tonic-gate 	ASSERT(p != curproc);
25197c478bd9Sstevel@tonic-gate 
25207c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
25217c478bd9Sstevel@tonic-gate 		do {
25227c478bd9Sstevel@tonic-gate 			thread_lock(t);
25237c478bd9Sstevel@tonic-gate 			t->t_proc_flag |= TP_PAUSE;
25247c478bd9Sstevel@tonic-gate 			aston(t);
2525c97ad5cdSakolb 			if ((ISWAKEABLE(t) && (t->t_wchan0 == NULL)) ||
2526c97ad5cdSakolb 			    ISWAITING(t)) {
25277c478bd9Sstevel@tonic-gate 				setrun_locked(t);
25287c478bd9Sstevel@tonic-gate 			}
25297c478bd9Sstevel@tonic-gate 			prpokethread(t);
25307c478bd9Sstevel@tonic-gate 			thread_unlock(t);
25317c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
25327c478bd9Sstevel@tonic-gate 	}
25337c478bd9Sstevel@tonic-gate }
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate /*
25367c478bd9Sstevel@tonic-gate  * undo the effects of pauselwps()
25377c478bd9Sstevel@tonic-gate  */
25387c478bd9Sstevel@tonic-gate static void
unpauselwps(proc_t * p)25397c478bd9Sstevel@tonic-gate unpauselwps(proc_t *p)
25407c478bd9Sstevel@tonic-gate {
25417c478bd9Sstevel@tonic-gate 	kthread_t *t;
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
25447c478bd9Sstevel@tonic-gate 	ASSERT(p != curproc);
25457c478bd9Sstevel@tonic-gate 
25467c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL) {
25477c478bd9Sstevel@tonic-gate 		do {
25487c478bd9Sstevel@tonic-gate 			thread_lock(t);
25497c478bd9Sstevel@tonic-gate 			t->t_proc_flag &= ~TP_PAUSE;
25507c478bd9Sstevel@tonic-gate 			if (t->t_state == TS_STOPPED) {
25517c478bd9Sstevel@tonic-gate 				t->t_schedflag |= TS_UNPAUSE;
25527c478bd9Sstevel@tonic-gate 				t->t_dtrace_stop = 0;
25537c478bd9Sstevel@tonic-gate 				setrun_locked(t);
25547c478bd9Sstevel@tonic-gate 			}
25557c478bd9Sstevel@tonic-gate 			thread_unlock(t);
25567c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
25577c478bd9Sstevel@tonic-gate 	}
25587c478bd9Sstevel@tonic-gate }
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate /*
25617c478bd9Sstevel@tonic-gate  * Cancel all watched areas.  Called from prclose().
25627c478bd9Sstevel@tonic-gate  */
25637c478bd9Sstevel@tonic-gate proc_t *
pr_cancel_watch(prnode_t * pnp)25647c478bd9Sstevel@tonic-gate pr_cancel_watch(prnode_t *pnp)
25657c478bd9Sstevel@tonic-gate {
25667c478bd9Sstevel@tonic-gate 	proc_t *p = pnp->pr_pcommon->prc_proc;
25677c478bd9Sstevel@tonic-gate 	struct as *as;
25687c478bd9Sstevel@tonic-gate 	kthread_t *t;
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock) && (p->p_proc_flag & P_PR_LOCK));
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	if (!pr_watch_active(p))
25737c478bd9Sstevel@tonic-gate 		return (p);
25747c478bd9Sstevel@tonic-gate 
25757c478bd9Sstevel@tonic-gate 	/*
25767c478bd9Sstevel@tonic-gate 	 * Pause the process before dealing with the watchpoints.
25777c478bd9Sstevel@tonic-gate 	 */
25787c478bd9Sstevel@tonic-gate 	if (p == curproc) {
25797c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25807c478bd9Sstevel@tonic-gate 		while (holdwatch() != 0)
25817c478bd9Sstevel@tonic-gate 			continue;
25827c478bd9Sstevel@tonic-gate 		p = pr_p_lock(pnp);
25837c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
25847c478bd9Sstevel@tonic-gate 		ASSERT(p == curproc);
25857c478bd9Sstevel@tonic-gate 	} else {
25867c478bd9Sstevel@tonic-gate 		pauselwps(p);
25877c478bd9Sstevel@tonic-gate 		while (p != NULL && pr_allstopped(p, 0) > 0) {
25887c478bd9Sstevel@tonic-gate 			/*
25897c478bd9Sstevel@tonic-gate 			 * This cv/mutex pair is persistent even
25907c478bd9Sstevel@tonic-gate 			 * if the process disappears after we
25917c478bd9Sstevel@tonic-gate 			 * unmark it and drop p->p_lock.
25927c478bd9Sstevel@tonic-gate 			 */
25937c478bd9Sstevel@tonic-gate 			kcondvar_t *cv = &pr_pid_cv[p->p_slot];
25947c478bd9Sstevel@tonic-gate 			kmutex_t *mp = &p->p_lock;
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 			prunmark(p);
25977c478bd9Sstevel@tonic-gate 			(void) cv_wait(cv, mp);
25987c478bd9Sstevel@tonic-gate 			mutex_exit(mp);
25997c478bd9Sstevel@tonic-gate 			p = pr_p_lock(pnp);  /* NULL if process disappeared */
26007c478bd9Sstevel@tonic-gate 			mutex_exit(&pr_pidlock);
26017c478bd9Sstevel@tonic-gate 		}
26027c478bd9Sstevel@tonic-gate 	}
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 	if (p == NULL)		/* the process disappeared */
26057c478bd9Sstevel@tonic-gate 		return (NULL);
26067c478bd9Sstevel@tonic-gate 
26077c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_pcommon->prc_proc);
26087c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock) && (p->p_proc_flag & P_PR_LOCK));
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 	if (pr_watch_active(p)) {
26117c478bd9Sstevel@tonic-gate 		pr_free_watchpoints(p);
26127c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
26137c478bd9Sstevel@tonic-gate 			do {
26147c478bd9Sstevel@tonic-gate 				watch_disable(t);
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
26177c478bd9Sstevel@tonic-gate 		}
26187c478bd9Sstevel@tonic-gate 	}
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 	if ((as = p->p_as) != NULL) {
26217c478bd9Sstevel@tonic-gate 		avl_tree_t *tree;
26227c478bd9Sstevel@tonic-gate 		struct watched_page *pwp;
26237c478bd9Sstevel@tonic-gate 
26247c478bd9Sstevel@tonic-gate 		/*
26257c478bd9Sstevel@tonic-gate 		 * If this is the parent of a vfork, the watched page
26267c478bd9Sstevel@tonic-gate 		 * list has been moved temporarily to p->p_wpage.
26277c478bd9Sstevel@tonic-gate 		 */
26287c478bd9Sstevel@tonic-gate 		if (avl_numnodes(&p->p_wpage) != 0)
26297c478bd9Sstevel@tonic-gate 			tree = &p->p_wpage;
26307c478bd9Sstevel@tonic-gate 		else
26317c478bd9Sstevel@tonic-gate 			tree = &as->a_wpage;
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
2634dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_ENTER(as, RW_WRITER);
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 		for (pwp = avl_first(tree); pwp != NULL;
26377c478bd9Sstevel@tonic-gate 		    pwp = AVL_NEXT(tree, pwp)) {
26387c478bd9Sstevel@tonic-gate 			pwp->wp_read = 0;
26397c478bd9Sstevel@tonic-gate 			pwp->wp_write = 0;
26407c478bd9Sstevel@tonic-gate 			pwp->wp_exec = 0;
26417c478bd9Sstevel@tonic-gate 			if ((pwp->wp_flags & WP_SETPROT) == 0) {
26427c478bd9Sstevel@tonic-gate 				pwp->wp_flags |= WP_SETPROT;
26437c478bd9Sstevel@tonic-gate 				pwp->wp_prot = pwp->wp_oprot;
26447c478bd9Sstevel@tonic-gate 				pwp->wp_list = p->p_wprot;
26457c478bd9Sstevel@tonic-gate 				p->p_wprot = pwp;
26467c478bd9Sstevel@tonic-gate 			}
26477c478bd9Sstevel@tonic-gate 		}
26487c478bd9Sstevel@tonic-gate 
2649dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
26507c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
26517c478bd9Sstevel@tonic-gate 	}
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate 	/*
26547c478bd9Sstevel@tonic-gate 	 * Unpause the process now.
26557c478bd9Sstevel@tonic-gate 	 */
26567c478bd9Sstevel@tonic-gate 	if (p == curproc)
26577c478bd9Sstevel@tonic-gate 		continuelwps(p);
26587c478bd9Sstevel@tonic-gate 	else
26597c478bd9Sstevel@tonic-gate 		unpauselwps(p);
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 	return (p);
26627c478bd9Sstevel@tonic-gate }
2663