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
53f2f09c1Sdp  * Common Development and Distribution License (the "License").
63f2f09c1Sdp  * 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  */
217c478bd9Sstevel@tonic-gate /*
223f2f09c1Sdp  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/proc.h>
277c478bd9Sstevel@tonic-gate #include <sys/systm.h>
287c478bd9Sstevel@tonic-gate #include <sys/param.h>
297c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
307c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <sys/procset.h>
337c478bd9Sstevel@tonic-gate #include <sys/corectl.h>
347c478bd9Sstevel@tonic-gate #include <sys/zone.h>
357c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
367c478bd9Sstevel@tonic-gate #include <sys/policy.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * Core File Settings
407c478bd9Sstevel@tonic-gate  * ------------------
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * A process's core file path and content live in separate reference-counted
437c478bd9Sstevel@tonic-gate  * structures. The corectl_content_t structure is fairly straightforward --
447c478bd9Sstevel@tonic-gate  * the only subtlety is that we only really _need_ the mutex on architectures
457c478bd9Sstevel@tonic-gate  * on which 64-bit memory operations are not atomic. The corectl_path_t
467c478bd9Sstevel@tonic-gate  * structure is slightly trickier in that it contains a refstr_t rather than
477c478bd9Sstevel@tonic-gate  * just a char * string. This is to allow consumers of the data in that
487c478bd9Sstevel@tonic-gate  * structure (the core dumping sub-system for example) to safely use the
497c478bd9Sstevel@tonic-gate  * string without holding any locks on it in light of updates.
507c478bd9Sstevel@tonic-gate  *
51*bbf21555SRichard Lowe  * At system and zone boot, init_core() sets init(8)'s core file path and
523f2f09c1Sdp  * content to the same value as the fields core_default_path and
533f2f09c1Sdp  * core_default_content respectively (for the global zone). All subsequent
54*bbf21555SRichard Lowe  * children of init(8) reference those same settings. During boot coreadm(8)
553f2f09c1Sdp  * is invoked with the -u option to update the system settings from
563f2f09c1Sdp  * /etc/coreadm.conf. This has the effect of also changing the values in
573f2f09c1Sdp  * core_default_path and core_default_content which updates the core file
583f2f09c1Sdp  * settings for all processes in the zone.  Each zone has different default
593f2f09c1Sdp  * settings; when processes enter a non-global zone, their core file path and
603f2f09c1Sdp  * content are set to the zone's default path and content.
617c478bd9Sstevel@tonic-gate  *
627c478bd9Sstevel@tonic-gate  * Processes that have their core file settings explicitly overridden using
63*bbf21555SRichard Lowe  * coreadm(8) no longer reference core_default_path or core_default_content
647c478bd9Sstevel@tonic-gate  * so subsequent changes to the default will not affect them.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate zone_key_t	core_zone_key;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate static int set_proc_info(pid_t pid, const char *path, core_content_t content);
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static corectl_content_t *
corectl_content_alloc(core_content_t cc)727c478bd9Sstevel@tonic-gate corectl_content_alloc(core_content_t cc)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate 	corectl_content_t *ccp;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	ccp = kmem_zalloc(sizeof (corectl_content_t), KM_SLEEP);
777c478bd9Sstevel@tonic-gate 	ccp->ccc_content = cc;
787c478bd9Sstevel@tonic-gate 	ccp->ccc_refcnt = 1;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	return (ccp);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate core_content_t
corectl_content_value(corectl_content_t * ccp)847c478bd9Sstevel@tonic-gate corectl_content_value(corectl_content_t *ccp)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	core_content_t content;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	mutex_enter(&ccp->ccc_mtx);
897c478bd9Sstevel@tonic-gate 	content = ccp->ccc_content;
907c478bd9Sstevel@tonic-gate 	mutex_exit(&ccp->ccc_mtx);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	return (content);
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static void
corectl_content_set(corectl_content_t * ccp,core_content_t content)967c478bd9Sstevel@tonic-gate corectl_content_set(corectl_content_t *ccp, core_content_t content)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	mutex_enter(&ccp->ccc_mtx);
997c478bd9Sstevel@tonic-gate 	ccp->ccc_content = content;
1007c478bd9Sstevel@tonic-gate 	mutex_exit(&ccp->ccc_mtx);
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate void
corectl_content_hold(corectl_content_t * ccp)1047c478bd9Sstevel@tonic-gate corectl_content_hold(corectl_content_t *ccp)
1057c478bd9Sstevel@tonic-gate {
1061a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&ccp->ccc_refcnt);
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate void
corectl_content_rele(corectl_content_t * ccp)1107c478bd9Sstevel@tonic-gate corectl_content_rele(corectl_content_t *ccp)
1117c478bd9Sstevel@tonic-gate {
1121a5e258fSJosef 'Jeff' Sipek 	if (atomic_dec_32_nv(&ccp->ccc_refcnt) == 0)
1137c478bd9Sstevel@tonic-gate 		kmem_free(ccp, sizeof (corectl_content_t));
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate static corectl_path_t *
corectl_path_alloc(const char * path)1187c478bd9Sstevel@tonic-gate corectl_path_alloc(const char *path)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	corectl_path_t *ccp;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	ccp = kmem_zalloc(sizeof (corectl_path_t), KM_SLEEP);
1237c478bd9Sstevel@tonic-gate 	ccp->ccp_path = refstr_alloc(path);
1247c478bd9Sstevel@tonic-gate 	ccp->ccp_refcnt = 1;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	return (ccp);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate refstr_t *
corectl_path_value(corectl_path_t * ccp)1307c478bd9Sstevel@tonic-gate corectl_path_value(corectl_path_t *ccp)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	refstr_t *path;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	mutex_enter(&ccp->ccp_mtx);
1357c478bd9Sstevel@tonic-gate 	refstr_hold(path = ccp->ccp_path);
1367c478bd9Sstevel@tonic-gate 	mutex_exit(&ccp->ccp_mtx);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	return (path);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static void
corectl_path_set(corectl_path_t * ccp,const char * path)1427c478bd9Sstevel@tonic-gate corectl_path_set(corectl_path_t *ccp, const char *path)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	refstr_t *npath = refstr_alloc(path);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	mutex_enter(&ccp->ccp_mtx);
1477c478bd9Sstevel@tonic-gate 	refstr_rele(ccp->ccp_path);
1487c478bd9Sstevel@tonic-gate 	ccp->ccp_path = npath;
1497c478bd9Sstevel@tonic-gate 	mutex_exit(&ccp->ccp_mtx);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate void
corectl_path_hold(corectl_path_t * ccp)1537c478bd9Sstevel@tonic-gate corectl_path_hold(corectl_path_t *ccp)
1547c478bd9Sstevel@tonic-gate {
1551a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&ccp->ccp_refcnt);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate void
corectl_path_rele(corectl_path_t * ccp)1597c478bd9Sstevel@tonic-gate corectl_path_rele(corectl_path_t *ccp)
1607c478bd9Sstevel@tonic-gate {
1611a5e258fSJosef 'Jeff' Sipek 	if (atomic_dec_32_nv(&ccp->ccp_refcnt) == 0) {
1627c478bd9Sstevel@tonic-gate 		refstr_rele(ccp->ccp_path);
1637c478bd9Sstevel@tonic-gate 		kmem_free(ccp, sizeof (corectl_path_t));
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * Constructor routine to be called when a zone is created.
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1717c478bd9Sstevel@tonic-gate static void *
core_init_zone(zoneid_t zoneid)1727c478bd9Sstevel@tonic-gate core_init_zone(zoneid_t zoneid)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	struct core_globals *cg;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	cg = kmem_alloc(sizeof (*cg), KM_SLEEP);
1777c478bd9Sstevel@tonic-gate 	mutex_init(&cg->core_lock, NULL, MUTEX_DEFAULT, NULL);
1787c478bd9Sstevel@tonic-gate 	cg->core_file = NULL;
1797c478bd9Sstevel@tonic-gate 	cg->core_options = CC_PROCESS_PATH;
1807c478bd9Sstevel@tonic-gate 	cg->core_content = CC_CONTENT_DEFAULT;
1817c478bd9Sstevel@tonic-gate 	cg->core_rlimit = RLIM64_INFINITY;
1827c478bd9Sstevel@tonic-gate 	cg->core_default_path = corectl_path_alloc("core");
1837c478bd9Sstevel@tonic-gate 	cg->core_default_content = corectl_content_alloc(CC_CONTENT_DEFAULT);
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	return (cg);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * Destructor routine to be called when a zone is destroyed.
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1927c478bd9Sstevel@tonic-gate static void
core_free_zone(zoneid_t zoneid,void * arg)1937c478bd9Sstevel@tonic-gate core_free_zone(zoneid_t zoneid, void *arg)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	struct core_globals *cg = arg;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	if (cg == NULL)
1987c478bd9Sstevel@tonic-gate 		return;
1997c478bd9Sstevel@tonic-gate 	if (cg->core_file != NULL)
2007c478bd9Sstevel@tonic-gate 		refstr_rele(cg->core_file);
2017c478bd9Sstevel@tonic-gate 	corectl_path_rele(cg->core_default_path);
2027c478bd9Sstevel@tonic-gate 	corectl_content_rele(cg->core_default_content);
2037c478bd9Sstevel@tonic-gate 	kmem_free(cg, sizeof (*cg));
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate /*
2073f2f09c1Sdp  * Called from start_init_common(), to set init's core file path and content.
2087c478bd9Sstevel@tonic-gate  */
2097c478bd9Sstevel@tonic-gate void
init_core(void)2107c478bd9Sstevel@tonic-gate init_core(void)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate 	struct core_globals *cg;
2137c478bd9Sstevel@tonic-gate 
2143f2f09c1Sdp 	/*
2153f2f09c1Sdp 	 * The first time we hit this, in the global zone, we have to
2163f2f09c1Sdp 	 * initialize the zsd key.
2173f2f09c1Sdp 	 */
2183f2f09c1Sdp 	if (INGLOBALZONE(curproc)) {
2193f2f09c1Sdp 		zone_key_create(&core_zone_key, core_init_zone, NULL,
2203f2f09c1Sdp 		    core_free_zone);
2213f2f09c1Sdp 	}
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	/*
2247c478bd9Sstevel@tonic-gate 	 * zone_key_create will have called core_init_zone for the
2257c478bd9Sstevel@tonic-gate 	 * global zone, which sets up the default path and content
2267c478bd9Sstevel@tonic-gate 	 * variables.
2277c478bd9Sstevel@tonic-gate 	 */
2283f2f09c1Sdp 	VERIFY((cg = zone_getspecific(core_zone_key, curproc->p_zone)) != NULL);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	corectl_path_hold(cg->core_default_path);
2317c478bd9Sstevel@tonic-gate 	corectl_content_hold(cg->core_default_content);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	curproc->p_corefile = cg->core_default_path;
2347c478bd9Sstevel@tonic-gate 	curproc->p_content = cg->core_default_content;
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate int
corectl(int subcode,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)2387c478bd9Sstevel@tonic-gate corectl(int subcode, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	int error = 0;
2417c478bd9Sstevel@tonic-gate 	proc_t *p;
2427c478bd9Sstevel@tonic-gate 	refstr_t *rp;
2437c478bd9Sstevel@tonic-gate 	size_t size;
2447c478bd9Sstevel@tonic-gate 	char *path;
2457c478bd9Sstevel@tonic-gate 	core_content_t content = CC_CONTENT_INVALID;
2467c478bd9Sstevel@tonic-gate 	struct core_globals *cg;
2477c478bd9Sstevel@tonic-gate 	zone_t *zone = curproc->p_zone;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	cg = zone_getspecific(core_zone_key, zone);
2507c478bd9Sstevel@tonic-gate 	ASSERT(cg != NULL);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	switch (subcode) {
2537c478bd9Sstevel@tonic-gate 	case CC_SET_OPTIONS:
2547c478bd9Sstevel@tonic-gate 		if ((error = secpolicy_coreadm(CRED())) == 0) {
2557c478bd9Sstevel@tonic-gate 			if (arg1 & ~CC_OPTIONS)
2567c478bd9Sstevel@tonic-gate 				error = EINVAL;
2577c478bd9Sstevel@tonic-gate 			else
2587c478bd9Sstevel@tonic-gate 				cg->core_options = (uint32_t)arg1;
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 		break;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	case CC_GET_OPTIONS:
2637c478bd9Sstevel@tonic-gate 		return (cg->core_options);
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	case CC_GET_GLOBAL_PATH:
2667c478bd9Sstevel@tonic-gate 	case CC_GET_DEFAULT_PATH:
2677c478bd9Sstevel@tonic-gate 	case CC_GET_PROCESS_PATH:
2687c478bd9Sstevel@tonic-gate 		if (subcode == CC_GET_GLOBAL_PATH) {
2697c478bd9Sstevel@tonic-gate 			mutex_enter(&cg->core_lock);
2707c478bd9Sstevel@tonic-gate 			if ((rp = cg->core_file) != NULL)
2717c478bd9Sstevel@tonic-gate 				refstr_hold(rp);
2727c478bd9Sstevel@tonic-gate 			mutex_exit(&cg->core_lock);
2737c478bd9Sstevel@tonic-gate 		} else if (subcode == CC_GET_DEFAULT_PATH) {
2747c478bd9Sstevel@tonic-gate 			rp = corectl_path_value(cg->core_default_path);
2757c478bd9Sstevel@tonic-gate 		} else {
2767c478bd9Sstevel@tonic-gate 			rp = NULL;
2777c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
2787c478bd9Sstevel@tonic-gate 			if ((p = prfind((pid_t)arg3)) == NULL ||
2797c478bd9Sstevel@tonic-gate 			    p->p_stat == SIDL) {
2807c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
2817c478bd9Sstevel@tonic-gate 				error = ESRCH;
2827c478bd9Sstevel@tonic-gate 			} else {
2837c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
2847c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
2857c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_crlock);
2867c478bd9Sstevel@tonic-gate 				if (!hasprocperm(p->p_cred, CRED()))
2877c478bd9Sstevel@tonic-gate 					error = EPERM;
2887c478bd9Sstevel@tonic-gate 				else if (p->p_corefile != NULL)
2897c478bd9Sstevel@tonic-gate 					rp = corectl_path_value(p->p_corefile);
2907c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_crlock);
2917c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
2927c478bd9Sstevel@tonic-gate 			}
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate 		if (rp == NULL) {
2957c478bd9Sstevel@tonic-gate 			if (error == 0 && suword8((void *)arg1, 0))
2967c478bd9Sstevel@tonic-gate 				error = EFAULT;
2977c478bd9Sstevel@tonic-gate 		} else {
2987c478bd9Sstevel@tonic-gate 			error = copyoutstr(refstr_value(rp), (char *)arg1,
2993f2f09c1Sdp 			    (size_t)arg2, NULL);
3007c478bd9Sstevel@tonic-gate 			refstr_rele(rp);
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 		break;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	case CC_SET_GLOBAL_PATH:
3057c478bd9Sstevel@tonic-gate 	case CC_SET_DEFAULT_PATH:
3067c478bd9Sstevel@tonic-gate 		if ((error = secpolicy_coreadm(CRED())) != 0)
3077c478bd9Sstevel@tonic-gate 			break;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
3107c478bd9Sstevel@tonic-gate 	case CC_SET_PROCESS_PATH:
3117c478bd9Sstevel@tonic-gate 		if ((size = MIN((size_t)arg2, MAXPATHLEN)) == 0) {
3127c478bd9Sstevel@tonic-gate 			error = EINVAL;
3137c478bd9Sstevel@tonic-gate 			break;
3147c478bd9Sstevel@tonic-gate 		}
3157c478bd9Sstevel@tonic-gate 		path = kmem_alloc(size, KM_SLEEP);
3167c478bd9Sstevel@tonic-gate 		error = copyinstr((char *)arg1, path, size, NULL);
3177c478bd9Sstevel@tonic-gate 		if (error == 0) {
3187c478bd9Sstevel@tonic-gate 			if (subcode == CC_SET_PROCESS_PATH) {
3197c478bd9Sstevel@tonic-gate 				error = set_proc_info((pid_t)arg3, path, 0);
3207c478bd9Sstevel@tonic-gate 			} else if (subcode == CC_SET_DEFAULT_PATH) {
3217c478bd9Sstevel@tonic-gate 				corectl_path_set(cg->core_default_path, path);
3227c478bd9Sstevel@tonic-gate 			} else if (*path != '\0' && *path != '/') {
3237c478bd9Sstevel@tonic-gate 				error = EINVAL;
3247c478bd9Sstevel@tonic-gate 			} else {
3257c478bd9Sstevel@tonic-gate 				refstr_t *nrp = refstr_alloc(path);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 				mutex_enter(&cg->core_lock);
3287c478bd9Sstevel@tonic-gate 				rp = cg->core_file;
3297c478bd9Sstevel@tonic-gate 				if (*path == '\0')
3307c478bd9Sstevel@tonic-gate 					cg->core_file = NULL;
3317c478bd9Sstevel@tonic-gate 				else
3327c478bd9Sstevel@tonic-gate 					refstr_hold(cg->core_file = nrp);
3337c478bd9Sstevel@tonic-gate 				mutex_exit(&cg->core_lock);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 				if (rp != NULL)
3367c478bd9Sstevel@tonic-gate 					refstr_rele(rp);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 				refstr_rele(nrp);
3397c478bd9Sstevel@tonic-gate 			}
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 		kmem_free(path, size);
3427c478bd9Sstevel@tonic-gate 		break;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	case CC_SET_GLOBAL_CONTENT:
3457c478bd9Sstevel@tonic-gate 	case CC_SET_DEFAULT_CONTENT:
3467c478bd9Sstevel@tonic-gate 		if ((error = secpolicy_coreadm(CRED())) != 0)
3477c478bd9Sstevel@tonic-gate 			break;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
3507c478bd9Sstevel@tonic-gate 	case CC_SET_PROCESS_CONTENT:
3517c478bd9Sstevel@tonic-gate 		error = copyin((void *)arg1, &content, sizeof (content));
3527c478bd9Sstevel@tonic-gate 		if (error != 0)
3537c478bd9Sstevel@tonic-gate 			break;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		/*
3567c478bd9Sstevel@tonic-gate 		 * If any unknown bits are set, don't let this charade
3577c478bd9Sstevel@tonic-gate 		 * continue.
3587c478bd9Sstevel@tonic-gate 		 */
3597c478bd9Sstevel@tonic-gate 		if (content & ~CC_CONTENT_ALL) {
3607c478bd9Sstevel@tonic-gate 			error = EINVAL;
3617c478bd9Sstevel@tonic-gate 			break;
3627c478bd9Sstevel@tonic-gate 		}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 		if (subcode == CC_SET_PROCESS_CONTENT) {
3657c478bd9Sstevel@tonic-gate 			error = set_proc_info((pid_t)arg2, NULL, content);
3667c478bd9Sstevel@tonic-gate 		} else if (subcode == CC_SET_DEFAULT_CONTENT) {
3677c478bd9Sstevel@tonic-gate 			corectl_content_set(cg->core_default_content, content);
3687c478bd9Sstevel@tonic-gate 		} else {
3697c478bd9Sstevel@tonic-gate 			mutex_enter(&cg->core_lock);
3707c478bd9Sstevel@tonic-gate 			cg->core_content = content;
3717c478bd9Sstevel@tonic-gate 			mutex_exit(&cg->core_lock);
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 		break;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	case CC_GET_GLOBAL_CONTENT:
3777c478bd9Sstevel@tonic-gate 		content = cg->core_content;
3787c478bd9Sstevel@tonic-gate 		error = copyout(&content, (void *)arg1, sizeof (content));
3797c478bd9Sstevel@tonic-gate 		break;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	case CC_GET_DEFAULT_CONTENT:
3827c478bd9Sstevel@tonic-gate 		content = corectl_content_value(cg->core_default_content);
3837c478bd9Sstevel@tonic-gate 		error = copyout(&content, (void *)arg1, sizeof (content));
3847c478bd9Sstevel@tonic-gate 		break;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	case CC_GET_PROCESS_CONTENT:
3877c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
3887c478bd9Sstevel@tonic-gate 		if ((p = prfind((pid_t)arg2)) == NULL || p->p_stat == SIDL) {
3897c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
3907c478bd9Sstevel@tonic-gate 			error = ESRCH;
3917c478bd9Sstevel@tonic-gate 			break;
3927c478bd9Sstevel@tonic-gate 		}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
3957c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
3967c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_crlock);
3977c478bd9Sstevel@tonic-gate 		if (!hasprocperm(p->p_cred, CRED()))
3987c478bd9Sstevel@tonic-gate 			error = EPERM;
3997c478bd9Sstevel@tonic-gate 		else if (p->p_content == NULL)
4007c478bd9Sstevel@tonic-gate 			content = CC_CONTENT_NONE;
4017c478bd9Sstevel@tonic-gate 		else
4027c478bd9Sstevel@tonic-gate 			content = corectl_content_value(p->p_content);
4037c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_crlock);
4047c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		if (error == 0)
4077c478bd9Sstevel@tonic-gate 			error = copyout(&content, (void *)arg1,
4087c478bd9Sstevel@tonic-gate 			    sizeof (content));
4097c478bd9Sstevel@tonic-gate 		break;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	default:
4127c478bd9Sstevel@tonic-gate 		error = EINVAL;
4137c478bd9Sstevel@tonic-gate 		break;
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (error)
4177c478bd9Sstevel@tonic-gate 		return (set_errno(error));
4187c478bd9Sstevel@tonic-gate 	return (0);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate typedef struct {
4227c478bd9Sstevel@tonic-gate 	int			cc_count;
4237c478bd9Sstevel@tonic-gate 	corectl_path_t		*cc_path;
4247c478bd9Sstevel@tonic-gate 	corectl_content_t	*cc_content;
4257c478bd9Sstevel@tonic-gate } counter_t;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate static int
set_one_proc_info(proc_t * p,counter_t * counterp)4287c478bd9Sstevel@tonic-gate set_one_proc_info(proc_t *p, counter_t *counterp)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	corectl_path_t *corefile;
4317c478bd9Sstevel@tonic-gate 	corectl_content_t *content;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (!(p->p_flag & SSYS) && hasprocperm(p->p_cred, CRED())) {
4367c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_crlock);
4377c478bd9Sstevel@tonic-gate 		counterp->cc_count++;
4387c478bd9Sstevel@tonic-gate 		if (counterp->cc_path != NULL) {
4397c478bd9Sstevel@tonic-gate 			corectl_path_hold(counterp->cc_path);
4407c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
4417c478bd9Sstevel@tonic-gate 			corefile = p->p_corefile;
4427c478bd9Sstevel@tonic-gate 			p->p_corefile = counterp->cc_path;
4437c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
4447c478bd9Sstevel@tonic-gate 			if (corefile != NULL)
4457c478bd9Sstevel@tonic-gate 				corectl_path_rele(corefile);
4467c478bd9Sstevel@tonic-gate 		} else {
4477c478bd9Sstevel@tonic-gate 			corectl_content_hold(counterp->cc_content);
4487c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
4497c478bd9Sstevel@tonic-gate 			content = p->p_content;
4507c478bd9Sstevel@tonic-gate 			p->p_content = counterp->cc_content;
4517c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
4527c478bd9Sstevel@tonic-gate 			if (content != NULL)
4537c478bd9Sstevel@tonic-gate 				corectl_content_rele(content);
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 	} else {
4567c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_crlock);
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	return (0);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate static int
set_proc_info(pid_t pid,const char * path,core_content_t content)4637c478bd9Sstevel@tonic-gate set_proc_info(pid_t pid, const char *path, core_content_t content)
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate 	proc_t *p;
4667c478bd9Sstevel@tonic-gate 	counter_t counter;
4677c478bd9Sstevel@tonic-gate 	int error = 0;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	counter.cc_count = 0;
4707c478bd9Sstevel@tonic-gate 	/*
4717c478bd9Sstevel@tonic-gate 	 * Only one of the core file path or content can be set at a time.
4727c478bd9Sstevel@tonic-gate 	 */
4737c478bd9Sstevel@tonic-gate 	if (path != NULL) {
4747c478bd9Sstevel@tonic-gate 		counter.cc_path = corectl_path_alloc(path);
4757c478bd9Sstevel@tonic-gate 		counter.cc_content = NULL;
4767c478bd9Sstevel@tonic-gate 	} else {
4777c478bd9Sstevel@tonic-gate 		counter.cc_path = NULL;
4787c478bd9Sstevel@tonic-gate 		counter.cc_content = corectl_content_alloc(content);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (pid == -1) {
4827c478bd9Sstevel@tonic-gate 		procset_t set;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 		setprocset(&set, POP_AND, P_ALL, P_MYID, P_ALL, P_MYID);
4857c478bd9Sstevel@tonic-gate 		error = dotoprocs(&set, set_one_proc_info, (char *)&counter);
4867c478bd9Sstevel@tonic-gate 		if (error == 0 && counter.cc_count == 0)
4877c478bd9Sstevel@tonic-gate 			error = EPERM;
4887c478bd9Sstevel@tonic-gate 	} else if (pid > 0) {
4897c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
4907c478bd9Sstevel@tonic-gate 		if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) {
4917c478bd9Sstevel@tonic-gate 			error = ESRCH;
4927c478bd9Sstevel@tonic-gate 		} else {
4937c478bd9Sstevel@tonic-gate 			(void) set_one_proc_info(p, &counter);
4947c478bd9Sstevel@tonic-gate 			if (counter.cc_count == 0)
4957c478bd9Sstevel@tonic-gate 				error = EPERM;
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
4987c478bd9Sstevel@tonic-gate 	} else {
4997c478bd9Sstevel@tonic-gate 		int nfound = 0;
5007c478bd9Sstevel@tonic-gate 		pid_t pgid;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		if (pid == 0)
5037c478bd9Sstevel@tonic-gate 			pgid = curproc->p_pgrp;
5047c478bd9Sstevel@tonic-gate 		else
5057c478bd9Sstevel@tonic-gate 			pgid = -pid;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
5087c478bd9Sstevel@tonic-gate 		for (p = pgfind(pgid); p != NULL; p = p->p_pglink) {
5097c478bd9Sstevel@tonic-gate 			if (p->p_stat != SIDL) {
5107c478bd9Sstevel@tonic-gate 				nfound++;
5117c478bd9Sstevel@tonic-gate 				(void) set_one_proc_info(p, &counter);
5127c478bd9Sstevel@tonic-gate 			}
5137c478bd9Sstevel@tonic-gate 		}
5147c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
5157c478bd9Sstevel@tonic-gate 		if (nfound == 0)
5167c478bd9Sstevel@tonic-gate 			error = ESRCH;
5177c478bd9Sstevel@tonic-gate 		else if (counter.cc_count == 0)
5187c478bd9Sstevel@tonic-gate 			error = EPERM;
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if (path != NULL)
5227c478bd9Sstevel@tonic-gate 		corectl_path_rele(counter.cc_path);
5237c478bd9Sstevel@tonic-gate 	else
5247c478bd9Sstevel@tonic-gate 		corectl_content_rele(counter.cc_content);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	if (error)
5277c478bd9Sstevel@tonic-gate 		return (set_errno(error));
5287c478bd9Sstevel@tonic-gate 	return (0);
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate  * Give current process the default core settings for its current zone;
5337c478bd9Sstevel@tonic-gate  * used for processes entering a zone via zone_enter.
5347c478bd9Sstevel@tonic-gate  */
5357c478bd9Sstevel@tonic-gate void
set_core_defaults(void)5367c478bd9Sstevel@tonic-gate set_core_defaults(void)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	proc_t *p = curproc;
5397c478bd9Sstevel@tonic-gate 	struct core_globals *cg;
5407c478bd9Sstevel@tonic-gate 	corectl_path_t *oldpath, *newpath;
5417c478bd9Sstevel@tonic-gate 	corectl_content_t *oldcontent, *newcontent;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	cg = zone_getspecific(core_zone_key, p->p_zone);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/* make local copies of default values to protect against change */
5467c478bd9Sstevel@tonic-gate 	newpath = cg->core_default_path;
5477c478bd9Sstevel@tonic-gate 	newcontent = cg->core_default_content;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	corectl_path_hold(newpath);
5507c478bd9Sstevel@tonic-gate 	corectl_content_hold(newcontent);
5517c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
5527c478bd9Sstevel@tonic-gate 	oldpath = p->p_corefile;
5537c478bd9Sstevel@tonic-gate 	p->p_corefile = newpath;
5547c478bd9Sstevel@tonic-gate 	oldcontent = p->p_content;
5557c478bd9Sstevel@tonic-gate 	p->p_content = newcontent;
5567c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
5577c478bd9Sstevel@tonic-gate 	if (oldpath != NULL)
5587c478bd9Sstevel@tonic-gate 		corectl_path_rele(oldpath);
5597c478bd9Sstevel@tonic-gate 	if (oldcontent != NULL)
5607c478bd9Sstevel@tonic-gate 		corectl_content_rele(oldcontent);
5617c478bd9Sstevel@tonic-gate }
562