1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/proc.h> 27 #include <sys/systm.h> 28 #include <sys/param.h> 29 #include <sys/atomic.h> 30 #include <sys/kmem.h> 31 #include <sys/sysmacros.h> 32 #include <sys/procset.h> 33 #include <sys/corectl.h> 34 #include <sys/zone.h> 35 #include <sys/cmn_err.h> 36 #include <sys/policy.h> 37 38 /* 39 * Core File Settings 40 * ------------------ 41 * 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. 50 * 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. 61 * 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. 65 */ 66 67 zone_key_t core_zone_key; 68 69 static int set_proc_info(pid_t pid, const char *path, core_content_t content); 70 71 static corectl_content_t * 72 corectl_content_alloc(core_content_t cc) 73 { 74 corectl_content_t *ccp; 75 76 ccp = kmem_zalloc(sizeof (corectl_content_t), KM_SLEEP); 77 ccp->ccc_content = cc; 78 ccp->ccc_refcnt = 1; 79 80 return (ccp); 81 } 82 83 core_content_t 84 corectl_content_value(corectl_content_t *ccp) 85 { 86 core_content_t content; 87 88 mutex_enter(&ccp->ccc_mtx); 89 content = ccp->ccc_content; 90 mutex_exit(&ccp->ccc_mtx); 91 92 return (content); 93 } 94 95 static void 96 corectl_content_set(corectl_content_t *ccp, core_content_t content) 97 { 98 mutex_enter(&ccp->ccc_mtx); 99 ccp->ccc_content = content; 100 mutex_exit(&ccp->ccc_mtx); 101 } 102 103 void 104 corectl_content_hold(corectl_content_t *ccp) 105 { 106 atomic_inc_32(&ccp->ccc_refcnt); 107 } 108 109 void 110 corectl_content_rele(corectl_content_t *ccp) 111 { 112 if (atomic_dec_32_nv(&ccp->ccc_refcnt) == 0) 113 kmem_free(ccp, sizeof (corectl_content_t)); 114 } 115 116 117 static corectl_path_t * 118 corectl_path_alloc(const char *path) 119 { 120 corectl_path_t *ccp; 121 122 ccp = kmem_zalloc(sizeof (corectl_path_t), KM_SLEEP); 123 ccp->ccp_path = refstr_alloc(path); 124 ccp->ccp_refcnt = 1; 125 126 return (ccp); 127 } 128 129 refstr_t * 130 corectl_path_value(corectl_path_t *ccp) 131 { 132 refstr_t *path; 133 134 mutex_enter(&ccp->ccp_mtx); 135 refstr_hold(path = ccp->ccp_path); 136 mutex_exit(&ccp->ccp_mtx); 137 138 return (path); 139 } 140 141 static void 142 corectl_path_set(corectl_path_t *ccp, const char *path) 143 { 144 refstr_t *npath = refstr_alloc(path); 145 146 mutex_enter(&ccp->ccp_mtx); 147 refstr_rele(ccp->ccp_path); 148 ccp->ccp_path = npath; 149 mutex_exit(&ccp->ccp_mtx); 150 } 151 152 void 153 corectl_path_hold(corectl_path_t *ccp) 154 { 155 atomic_inc_32(&ccp->ccp_refcnt); 156 } 157 158 void 159 corectl_path_rele(corectl_path_t *ccp) 160 { 161 if (atomic_dec_32_nv(&ccp->ccp_refcnt) == 0) { 162 refstr_rele(ccp->ccp_path); 163 kmem_free(ccp, sizeof (corectl_path_t)); 164 } 165 } 166 167 /* 168 * Constructor routine to be called when a zone is created. 169 */ 170 /*ARGSUSED*/ 171 static void * 172 core_init_zone(zoneid_t zoneid) 173 { 174 struct core_globals *cg; 175 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); 184 185 return (cg); 186 } 187 188 /* 189 * Destructor routine to be called when a zone is destroyed. 190 */ 191 /*ARGSUSED*/ 192 static void 193 core_free_zone(zoneid_t zoneid, void *arg) 194 { 195 struct core_globals *cg = arg; 196 197 if (cg == NULL) 198 return; 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)); 204 } 205 206 /* 207 * Called from start_init_common(), to set init's core file path and content. 208 */ 209 void 210 init_core(void) 211 { 212 struct core_globals *cg; 213 214 /* 215 * The first time we hit this, in the global zone, we have to 216 * initialize the zsd key. 217 */ 218 if (INGLOBALZONE(curproc)) { 219 zone_key_create(&core_zone_key, core_init_zone, NULL, 220 core_free_zone); 221 } 222 223 /* 224 * zone_key_create will have called core_init_zone for the 225 * global zone, which sets up the default path and content 226 * variables. 227 */ 228 VERIFY((cg = zone_getspecific(core_zone_key, curproc->p_zone)) != NULL); 229 230 corectl_path_hold(cg->core_default_path); 231 corectl_content_hold(cg->core_default_content); 232 233 curproc->p_corefile = cg->core_default_path; 234 curproc->p_content = cg->core_default_content; 235 } 236 237 int 238 corectl(int subcode, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) 239 { 240 int error = 0; 241 proc_t *p; 242 refstr_t *rp; 243 size_t size; 244 char *path; 245 core_content_t content = CC_CONTENT_INVALID; 246 struct core_globals *cg; 247 zone_t *zone = curproc->p_zone; 248 249 cg = zone_getspecific(core_zone_key, zone); 250 ASSERT(cg != NULL); 251 252 switch (subcode) { 253 case CC_SET_OPTIONS: 254 if ((error = secpolicy_coreadm(CRED())) == 0) { 255 if (arg1 & ~CC_OPTIONS) 256 error = EINVAL; 257 else 258 cg->core_options = (uint32_t)arg1; 259 } 260 break; 261 262 case CC_GET_OPTIONS: 263 return (cg->core_options); 264 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) 271 refstr_hold(rp); 272 mutex_exit(&cg->core_lock); 273 } else if (subcode == CC_GET_DEFAULT_PATH) { 274 rp = corectl_path_value(cg->core_default_path); 275 } else { 276 rp = NULL; 277 mutex_enter(&pidlock); 278 if ((p = prfind((pid_t)arg3)) == NULL || 279 p->p_stat == SIDL) { 280 mutex_exit(&pidlock); 281 error = ESRCH; 282 } else { 283 mutex_enter(&p->p_lock); 284 mutex_exit(&pidlock); 285 mutex_enter(&p->p_crlock); 286 if (!hasprocperm(p->p_cred, CRED())) 287 error = EPERM; 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); 292 } 293 } 294 if (rp == NULL) { 295 if (error == 0 && suword8((void *)arg1, 0)) 296 error = EFAULT; 297 } else { 298 error = copyoutstr(refstr_value(rp), (char *)arg1, 299 (size_t)arg2, NULL); 300 refstr_rele(rp); 301 } 302 break; 303 304 case CC_SET_GLOBAL_PATH: 305 case CC_SET_DEFAULT_PATH: 306 if ((error = secpolicy_coreadm(CRED())) != 0) 307 break; 308 309 /* FALLTHROUGH */ 310 case CC_SET_PROCESS_PATH: 311 if ((size = MIN((size_t)arg2, MAXPATHLEN)) == 0) { 312 error = EINVAL; 313 break; 314 } 315 path = kmem_alloc(size, KM_SLEEP); 316 error = copyinstr((char *)arg1, path, size, NULL); 317 if (error == 0) { 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 != '/') { 323 error = EINVAL; 324 } else { 325 refstr_t *nrp = refstr_alloc(path); 326 327 mutex_enter(&cg->core_lock); 328 rp = cg->core_file; 329 if (*path == '\0') 330 cg->core_file = NULL; 331 else 332 refstr_hold(cg->core_file = nrp); 333 mutex_exit(&cg->core_lock); 334 335 if (rp != NULL) 336 refstr_rele(rp); 337 338 refstr_rele(nrp); 339 } 340 } 341 kmem_free(path, size); 342 break; 343 344 case CC_SET_GLOBAL_CONTENT: 345 case CC_SET_DEFAULT_CONTENT: 346 if ((error = secpolicy_coreadm(CRED())) != 0) 347 break; 348 349 /* FALLTHROUGH */ 350 case CC_SET_PROCESS_CONTENT: 351 error = copyin((void *)arg1, &content, sizeof (content)); 352 if (error != 0) 353 break; 354 355 /* 356 * If any unknown bits are set, don't let this charade 357 * continue. 358 */ 359 if (content & ~CC_CONTENT_ALL) { 360 error = EINVAL; 361 break; 362 } 363 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); 368 } else { 369 mutex_enter(&cg->core_lock); 370 cg->core_content = content; 371 mutex_exit(&cg->core_lock); 372 } 373 374 break; 375 376 case CC_GET_GLOBAL_CONTENT: 377 content = cg->core_content; 378 error = copyout(&content, (void *)arg1, sizeof (content)); 379 break; 380 381 case CC_GET_DEFAULT_CONTENT: 382 content = corectl_content_value(cg->core_default_content); 383 error = copyout(&content, (void *)arg1, sizeof (content)); 384 break; 385 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); 390 error = ESRCH; 391 break; 392 } 393 394 mutex_enter(&p->p_lock); 395 mutex_exit(&pidlock); 396 mutex_enter(&p->p_crlock); 397 if (!hasprocperm(p->p_cred, CRED())) 398 error = EPERM; 399 else if (p->p_content == NULL) 400 content = CC_CONTENT_NONE; 401 else 402 content = corectl_content_value(p->p_content); 403 mutex_exit(&p->p_crlock); 404 mutex_exit(&p->p_lock); 405 406 if (error == 0) 407 error = copyout(&content, (void *)arg1, 408 sizeof (content)); 409 break; 410 411 default: 412 error = EINVAL; 413 break; 414 } 415 416 if (error) 417 return (set_errno(error)); 418 return (0); 419 } 420 421 typedef struct { 422 int cc_count; 423 corectl_path_t *cc_path; 424 corectl_content_t *cc_content; 425 } counter_t; 426 427 static int 428 set_one_proc_info(proc_t *p, counter_t *counterp) 429 { 430 corectl_path_t *corefile; 431 corectl_content_t *content; 432 433 mutex_enter(&p->p_crlock); 434 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); 446 } else { 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); 452 if (content != NULL) 453 corectl_content_rele(content); 454 } 455 } else { 456 mutex_exit(&p->p_crlock); 457 } 458 459 return (0); 460 } 461 462 static int 463 set_proc_info(pid_t pid, const char *path, core_content_t content) 464 { 465 proc_t *p; 466 counter_t counter; 467 int error = 0; 468 469 counter.cc_count = 0; 470 /* 471 * Only one of the core file path or content can be set at a time. 472 */ 473 if (path != NULL) { 474 counter.cc_path = corectl_path_alloc(path); 475 counter.cc_content = NULL; 476 } else { 477 counter.cc_path = NULL; 478 counter.cc_content = corectl_content_alloc(content); 479 } 480 481 if (pid == -1) { 482 procset_t set; 483 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) 487 error = EPERM; 488 } else if (pid > 0) { 489 mutex_enter(&pidlock); 490 if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) { 491 error = ESRCH; 492 } else { 493 (void) set_one_proc_info(p, &counter); 494 if (counter.cc_count == 0) 495 error = EPERM; 496 } 497 mutex_exit(&pidlock); 498 } else { 499 int nfound = 0; 500 pid_t pgid; 501 502 if (pid == 0) 503 pgid = curproc->p_pgrp; 504 else 505 pgid = -pid; 506 507 mutex_enter(&pidlock); 508 for (p = pgfind(pgid); p != NULL; p = p->p_pglink) { 509 if (p->p_stat != SIDL) { 510 nfound++; 511 (void) set_one_proc_info(p, &counter); 512 } 513 } 514 mutex_exit(&pidlock); 515 if (nfound == 0) 516 error = ESRCH; 517 else if (counter.cc_count == 0) 518 error = EPERM; 519 } 520 521 if (path != NULL) 522 corectl_path_rele(counter.cc_path); 523 else 524 corectl_content_rele(counter.cc_content); 525 526 if (error) 527 return (set_errno(error)); 528 return (0); 529 } 530 531 /* 532 * Give current process the default core settings for its current zone; 533 * used for processes entering a zone via zone_enter. 534 */ 535 void 536 set_core_defaults(void) 537 { 538 proc_t *p = curproc; 539 struct core_globals *cg; 540 corectl_path_t *oldpath, *newpath; 541 corectl_content_t *oldcontent, *newcontent; 542 543 cg = zone_getspecific(core_zone_key, p->p_zone); 544 545 /* make local copies of default values to protect against change */ 546 newpath = cg->core_default_path; 547 newcontent = cg->core_default_content; 548 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); 557 if (oldpath != NULL) 558 corectl_path_rele(oldpath); 559 if (oldcontent != NULL) 560 corectl_content_rele(oldcontent); 561 } 562