4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <sys/systm.h>
28 #include <sys/param.h>
29 #include <sys/atomic.h>
31 #include <sys/sysmacros.h>
32 #include <sys/procset.h>
33 #include <sys/corectl.h>
35 #include <sys/cmn_err.h>
36 #include <sys/policy.h>
42 * A process's core file path and content live in separate reference-counted
43 * structures. The corectl_content_t structure is fairly straightforward --
44 * the only subtlety is that we only really _need_ the mutex on architectures
45 * on which 64-bit memory operations are not atomic. The corectl_path_t
46 * structure is slightly trickier in that it contains a refstr_t rather than
47 * just a char * string. This is to allow consumers of the data in that
48 * structure (the core dumping sub-system for example) to safely use the
49 * string without holding any locks on it in light of updates.
51 * At system and zone boot, init_core() sets init(8)'s core file path and
52 * content to the same value as the fields core_default_path and
53 * core_default_content respectively (for the global zone). All subsequent
54 * children of init(8) reference those same settings. During boot coreadm(8)
55 * is invoked with the -u option to update the system settings from
56 * /etc/coreadm.conf. This has the effect of also changing the values in
57 * core_default_path and core_default_content which updates the core file
58 * settings for all processes in the zone. Each zone has different default
59 * settings; when processes enter a non-global zone, their core file path and
60 * content are set to the zone's default path and content.
62 * Processes that have their core file settings explicitly overridden using
63 * coreadm(8) no longer reference core_default_path or core_default_content
64 * so subsequent changes to the default will not affect them.
67 zone_key_t core_zone_key
;
69 static int set_proc_info(pid_t pid
, const char *path
, core_content_t content
);
71 static corectl_content_t
*
72 corectl_content_alloc(core_content_t cc
)
74 corectl_content_t
*ccp
;
76 ccp
= kmem_zalloc(sizeof (corectl_content_t
), KM_SLEEP
);
77 ccp
->ccc_content
= cc
;
84 corectl_content_value(corectl_content_t
*ccp
)
86 core_content_t content
;
88 mutex_enter(&ccp
->ccc_mtx
);
89 content
= ccp
->ccc_content
;
90 mutex_exit(&ccp
->ccc_mtx
);
96 corectl_content_set(corectl_content_t
*ccp
, core_content_t content
)
98 mutex_enter(&ccp
->ccc_mtx
);
99 ccp
->ccc_content
= content
;
100 mutex_exit(&ccp
->ccc_mtx
);
104 corectl_content_hold(corectl_content_t
*ccp
)
106 atomic_inc_32(&ccp
->ccc_refcnt
);
110 corectl_content_rele(corectl_content_t
*ccp
)
112 if (atomic_dec_32_nv(&ccp
->ccc_refcnt
) == 0)
113 kmem_free(ccp
, sizeof (corectl_content_t
));
117 static corectl_path_t
*
118 corectl_path_alloc(const char *path
)
122 ccp
= kmem_zalloc(sizeof (corectl_path_t
), KM_SLEEP
);
123 ccp
->ccp_path
= refstr_alloc(path
);
130 corectl_path_value(corectl_path_t
*ccp
)
134 mutex_enter(&ccp
->ccp_mtx
);
135 refstr_hold(path
= ccp
->ccp_path
);
136 mutex_exit(&ccp
->ccp_mtx
);
142 corectl_path_set(corectl_path_t
*ccp
, const char *path
)
144 refstr_t
*npath
= refstr_alloc(path
);
146 mutex_enter(&ccp
->ccp_mtx
);
147 refstr_rele(ccp
->ccp_path
);
148 ccp
->ccp_path
= npath
;
149 mutex_exit(&ccp
->ccp_mtx
);
153 corectl_path_hold(corectl_path_t
*ccp
)
155 atomic_inc_32(&ccp
->ccp_refcnt
);
159 corectl_path_rele(corectl_path_t
*ccp
)
161 if (atomic_dec_32_nv(&ccp
->ccp_refcnt
) == 0) {
162 refstr_rele(ccp
->ccp_path
);
163 kmem_free(ccp
, sizeof (corectl_path_t
));
168 * Constructor routine to be called when a zone is created.
172 core_init_zone(zoneid_t zoneid
)
174 struct core_globals
*cg
;
176 cg
= kmem_alloc(sizeof (*cg
), KM_SLEEP
);
177 mutex_init(&cg
->core_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
178 cg
->core_file
= NULL
;
179 cg
->core_options
= CC_PROCESS_PATH
;
180 cg
->core_content
= CC_CONTENT_DEFAULT
;
181 cg
->core_rlimit
= RLIM64_INFINITY
;
182 cg
->core_default_path
= corectl_path_alloc("core");
183 cg
->core_default_content
= corectl_content_alloc(CC_CONTENT_DEFAULT
);
189 * Destructor routine to be called when a zone is destroyed.
193 core_free_zone(zoneid_t zoneid
, void *arg
)
195 struct core_globals
*cg
= arg
;
199 if (cg
->core_file
!= NULL
)
200 refstr_rele(cg
->core_file
);
201 corectl_path_rele(cg
->core_default_path
);
202 corectl_content_rele(cg
->core_default_content
);
203 kmem_free(cg
, sizeof (*cg
));
207 * Called from start_init_common(), to set init's core file path and content.
212 struct core_globals
*cg
;
215 * The first time we hit this, in the global zone, we have to
216 * initialize the zsd key.
218 if (INGLOBALZONE(curproc
)) {
219 zone_key_create(&core_zone_key
, core_init_zone
, NULL
,
224 * zone_key_create will have called core_init_zone for the
225 * global zone, which sets up the default path and content
228 VERIFY((cg
= zone_getspecific(core_zone_key
, curproc
->p_zone
)) != NULL
);
230 corectl_path_hold(cg
->core_default_path
);
231 corectl_content_hold(cg
->core_default_content
);
233 curproc
->p_corefile
= cg
->core_default_path
;
234 curproc
->p_content
= cg
->core_default_content
;
238 corectl(int subcode
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
)
245 core_content_t content
= CC_CONTENT_INVALID
;
246 struct core_globals
*cg
;
247 zone_t
*zone
= curproc
->p_zone
;
249 cg
= zone_getspecific(core_zone_key
, zone
);
254 if ((error
= secpolicy_coreadm(CRED())) == 0) {
255 if (arg1
& ~CC_OPTIONS
)
258 cg
->core_options
= (uint32_t)arg1
;
263 return (cg
->core_options
);
265 case CC_GET_GLOBAL_PATH
:
266 case CC_GET_DEFAULT_PATH
:
267 case CC_GET_PROCESS_PATH
:
268 if (subcode
== CC_GET_GLOBAL_PATH
) {
269 mutex_enter(&cg
->core_lock
);
270 if ((rp
= cg
->core_file
) != NULL
)
272 mutex_exit(&cg
->core_lock
);
273 } else if (subcode
== CC_GET_DEFAULT_PATH
) {
274 rp
= corectl_path_value(cg
->core_default_path
);
277 mutex_enter(&pidlock
);
278 if ((p
= prfind((pid_t
)arg3
)) == NULL
||
280 mutex_exit(&pidlock
);
283 mutex_enter(&p
->p_lock
);
284 mutex_exit(&pidlock
);
285 mutex_enter(&p
->p_crlock
);
286 if (!hasprocperm(p
->p_cred
, CRED()))
288 else if (p
->p_corefile
!= NULL
)
289 rp
= corectl_path_value(p
->p_corefile
);
290 mutex_exit(&p
->p_crlock
);
291 mutex_exit(&p
->p_lock
);
295 if (error
== 0 && suword8((void *)arg1
, 0))
298 error
= copyoutstr(refstr_value(rp
), (char *)arg1
,
304 case CC_SET_GLOBAL_PATH
:
305 case CC_SET_DEFAULT_PATH
:
306 if ((error
= secpolicy_coreadm(CRED())) != 0)
310 case CC_SET_PROCESS_PATH
:
311 if ((size
= MIN((size_t)arg2
, MAXPATHLEN
)) == 0) {
315 path
= kmem_alloc(size
, KM_SLEEP
);
316 error
= copyinstr((char *)arg1
, path
, size
, NULL
);
318 if (subcode
== CC_SET_PROCESS_PATH
) {
319 error
= set_proc_info((pid_t
)arg3
, path
, 0);
320 } else if (subcode
== CC_SET_DEFAULT_PATH
) {
321 corectl_path_set(cg
->core_default_path
, path
);
322 } else if (*path
!= '\0' && *path
!= '/') {
325 refstr_t
*nrp
= refstr_alloc(path
);
327 mutex_enter(&cg
->core_lock
);
330 cg
->core_file
= NULL
;
332 refstr_hold(cg
->core_file
= nrp
);
333 mutex_exit(&cg
->core_lock
);
341 kmem_free(path
, size
);
344 case CC_SET_GLOBAL_CONTENT
:
345 case CC_SET_DEFAULT_CONTENT
:
346 if ((error
= secpolicy_coreadm(CRED())) != 0)
350 case CC_SET_PROCESS_CONTENT
:
351 error
= copyin((void *)arg1
, &content
, sizeof (content
));
356 * If any unknown bits are set, don't let this charade
359 if (content
& ~CC_CONTENT_ALL
) {
364 if (subcode
== CC_SET_PROCESS_CONTENT
) {
365 error
= set_proc_info((pid_t
)arg2
, NULL
, content
);
366 } else if (subcode
== CC_SET_DEFAULT_CONTENT
) {
367 corectl_content_set(cg
->core_default_content
, content
);
369 mutex_enter(&cg
->core_lock
);
370 cg
->core_content
= content
;
371 mutex_exit(&cg
->core_lock
);
376 case CC_GET_GLOBAL_CONTENT
:
377 content
= cg
->core_content
;
378 error
= copyout(&content
, (void *)arg1
, sizeof (content
));
381 case CC_GET_DEFAULT_CONTENT
:
382 content
= corectl_content_value(cg
->core_default_content
);
383 error
= copyout(&content
, (void *)arg1
, sizeof (content
));
386 case CC_GET_PROCESS_CONTENT
:
387 mutex_enter(&pidlock
);
388 if ((p
= prfind((pid_t
)arg2
)) == NULL
|| p
->p_stat
== SIDL
) {
389 mutex_exit(&pidlock
);
394 mutex_enter(&p
->p_lock
);
395 mutex_exit(&pidlock
);
396 mutex_enter(&p
->p_crlock
);
397 if (!hasprocperm(p
->p_cred
, CRED()))
399 else if (p
->p_content
== NULL
)
400 content
= CC_CONTENT_NONE
;
402 content
= corectl_content_value(p
->p_content
);
403 mutex_exit(&p
->p_crlock
);
404 mutex_exit(&p
->p_lock
);
407 error
= copyout(&content
, (void *)arg1
,
417 return (set_errno(error
));
423 corectl_path_t
*cc_path
;
424 corectl_content_t
*cc_content
;
428 set_one_proc_info(proc_t
*p
, counter_t
*counterp
)
430 corectl_path_t
*corefile
;
431 corectl_content_t
*content
;
433 mutex_enter(&p
->p_crlock
);
435 if (!(p
->p_flag
& SSYS
) && hasprocperm(p
->p_cred
, CRED())) {
436 mutex_exit(&p
->p_crlock
);
437 counterp
->cc_count
++;
438 if (counterp
->cc_path
!= NULL
) {
439 corectl_path_hold(counterp
->cc_path
);
440 mutex_enter(&p
->p_lock
);
441 corefile
= p
->p_corefile
;
442 p
->p_corefile
= counterp
->cc_path
;
443 mutex_exit(&p
->p_lock
);
444 if (corefile
!= NULL
)
445 corectl_path_rele(corefile
);
447 corectl_content_hold(counterp
->cc_content
);
448 mutex_enter(&p
->p_lock
);
449 content
= p
->p_content
;
450 p
->p_content
= counterp
->cc_content
;
451 mutex_exit(&p
->p_lock
);
453 corectl_content_rele(content
);
456 mutex_exit(&p
->p_crlock
);
463 set_proc_info(pid_t pid
, const char *path
, core_content_t content
)
469 counter
.cc_count
= 0;
471 * Only one of the core file path or content can be set at a time.
474 counter
.cc_path
= corectl_path_alloc(path
);
475 counter
.cc_content
= NULL
;
477 counter
.cc_path
= NULL
;
478 counter
.cc_content
= corectl_content_alloc(content
);
484 setprocset(&set
, POP_AND
, P_ALL
, P_MYID
, P_ALL
, P_MYID
);
485 error
= dotoprocs(&set
, set_one_proc_info
, (char *)&counter
);
486 if (error
== 0 && counter
.cc_count
== 0)
488 } else if (pid
> 0) {
489 mutex_enter(&pidlock
);
490 if ((p
= prfind(pid
)) == NULL
|| p
->p_stat
== SIDL
) {
493 (void) set_one_proc_info(p
, &counter
);
494 if (counter
.cc_count
== 0)
497 mutex_exit(&pidlock
);
503 pgid
= curproc
->p_pgrp
;
507 mutex_enter(&pidlock
);
508 for (p
= pgfind(pgid
); p
!= NULL
; p
= p
->p_pglink
) {
509 if (p
->p_stat
!= SIDL
) {
511 (void) set_one_proc_info(p
, &counter
);
514 mutex_exit(&pidlock
);
517 else if (counter
.cc_count
== 0)
522 corectl_path_rele(counter
.cc_path
);
524 corectl_content_rele(counter
.cc_content
);
527 return (set_errno(error
));
532 * Give current process the default core settings for its current zone;
533 * used for processes entering a zone via zone_enter.
536 set_core_defaults(void)
539 struct core_globals
*cg
;
540 corectl_path_t
*oldpath
, *newpath
;
541 corectl_content_t
*oldcontent
, *newcontent
;
543 cg
= zone_getspecific(core_zone_key
, p
->p_zone
);
545 /* make local copies of default values to protect against change */
546 newpath
= cg
->core_default_path
;
547 newcontent
= cg
->core_default_content
;
549 corectl_path_hold(newpath
);
550 corectl_content_hold(newcontent
);
551 mutex_enter(&p
->p_lock
);
552 oldpath
= p
->p_corefile
;
553 p
->p_corefile
= newpath
;
554 oldcontent
= p
->p_content
;
555 p
->p_content
= newcontent
;
556 mutex_exit(&p
->p_lock
);
558 corectl_path_rele(oldpath
);
559 if (oldcontent
!= NULL
)
560 corectl_content_rele(oldcontent
);