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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/proc.h> 30 #include <sys/systm.h> 31 #include <sys/param.h> 32 #include <sys/atomic.h> 33 #include <sys/kmem.h> 34 #include <sys/sysmacros.h> 35 #include <sys/procset.h> 36 #include <sys/corectl.h> 37 #include <sys/zone.h> 38 #include <sys/cmn_err.h> 39 #include <sys/policy.h> 40 41 /* 42 * Core File Settings 43 * ------------------ 44 * 45 * A process's core file path and content live in separate reference-counted 46 * structures. The corectl_content_t structure is fairly straightforward -- 47 * the only subtlety is that we only really _need_ the mutex on architectures 48 * on which 64-bit memory operations are not atomic. The corectl_path_t 49 * structure is slightly trickier in that it contains a refstr_t rather than 50 * just a char * string. This is to allow consumers of the data in that 51 * structure (the core dumping sub-system for example) to safely use the 52 * string without holding any locks on it in light of updates. 53 * 54 * At system boot, init_core() sets init(1M)'s core file path and content to 55 * the same value as the fields core_default_path and core_default_content 56 * respectively (for the global zone). All subsequent children of init(1M) 57 * reference those same settings. During boot coreadm(1M) is invoked with 58 * the -u option to update the system settings from /etc/coreadm.conf. This 59 * has the effect of also changing the values in core_default_path and 60 * core_default_content which updates the core file settings for all 61 * processes in the zone. Each zone has different default settings; when 62 * processes enter a non-global zone, their core file path and content are 63 * set to the zone's default path and content. 64 * 65 * Processes that have their core file settings explicitly overridden using 66 * coreadm(1M) no longer reference core_default_path or core_default_content 67 * so subsequent changes to the default will not affect them. 68 */ 69 70 zone_key_t core_zone_key; 71 72 static int set_proc_info(pid_t pid, const char *path, core_content_t content); 73 74 static corectl_content_t * 75 corectl_content_alloc(core_content_t cc) 76 { 77 corectl_content_t *ccp; 78 79 ccp = kmem_zalloc(sizeof (corectl_content_t), KM_SLEEP); 80 ccp->ccc_content = cc; 81 ccp->ccc_refcnt = 1; 82 83 return (ccp); 84 } 85 86 core_content_t 87 corectl_content_value(corectl_content_t *ccp) 88 { 89 core_content_t content; 90 91 mutex_enter(&ccp->ccc_mtx); 92 content = ccp->ccc_content; 93 mutex_exit(&ccp->ccc_mtx); 94 95 return (content); 96 } 97 98 static void 99 corectl_content_set(corectl_content_t *ccp, core_content_t content) 100 { 101 mutex_enter(&ccp->ccc_mtx); 102 ccp->ccc_content = content; 103 mutex_exit(&ccp->ccc_mtx); 104 } 105 106 void 107 corectl_content_hold(corectl_content_t *ccp) 108 { 109 atomic_add_32(&ccp->ccc_refcnt, 1); 110 } 111 112 void 113 corectl_content_rele(corectl_content_t *ccp) 114 { 115 if (atomic_add_32_nv(&ccp->ccc_refcnt, -1) == 0) 116 kmem_free(ccp, sizeof (corectl_content_t)); 117 } 118 119 120 static corectl_path_t * 121 corectl_path_alloc(const char *path) 122 { 123 corectl_path_t *ccp; 124 125 ccp = kmem_zalloc(sizeof (corectl_path_t), KM_SLEEP); 126 ccp->ccp_path = refstr_alloc(path); 127 ccp->ccp_refcnt = 1; 128 129 return (ccp); 130 } 131 132 refstr_t * 133 corectl_path_value(corectl_path_t *ccp) 134 { 135 refstr_t *path; 136 137 mutex_enter(&ccp->ccp_mtx); 138 refstr_hold(path = ccp->ccp_path); 139 mutex_exit(&ccp->ccp_mtx); 140 141 return (path); 142 } 143 144 static void 145 corectl_path_set(corectl_path_t *ccp, const char *path) 146 { 147 refstr_t *npath = refstr_alloc(path); 148 149 mutex_enter(&ccp->ccp_mtx); 150 refstr_rele(ccp->ccp_path); 151 ccp->ccp_path = npath; 152 mutex_exit(&ccp->ccp_mtx); 153 } 154 155 void 156 corectl_path_hold(corectl_path_t *ccp) 157 { 158 atomic_add_32(&ccp->ccp_refcnt, 1); 159 } 160 161 void 162 corectl_path_rele(corectl_path_t *ccp) 163 { 164 if (atomic_add_32_nv(&ccp->ccp_refcnt, -1) == 0) { 165 refstr_rele(ccp->ccp_path); 166 kmem_free(ccp, sizeof (corectl_path_t)); 167 } 168 } 169 170 /* 171 * Constructor routine to be called when a zone is created. 172 */ 173 /*ARGSUSED*/ 174 static void * 175 core_init_zone(zoneid_t zoneid) 176 { 177 struct core_globals *cg; 178 179 cg = kmem_alloc(sizeof (*cg), KM_SLEEP); 180 mutex_init(&cg->core_lock, NULL, MUTEX_DEFAULT, NULL); 181 cg->core_file = NULL; 182 cg->core_options = CC_PROCESS_PATH; 183 cg->core_content = CC_CONTENT_DEFAULT; 184 cg->core_rlimit = RLIM64_INFINITY; 185 cg->core_default_path = corectl_path_alloc("core"); 186 cg->core_default_content = corectl_content_alloc(CC_CONTENT_DEFAULT); 187 188 return (cg); 189 } 190 191 /* 192 * Destructor routine to be called when a zone is destroyed. 193 */ 194 /*ARGSUSED*/ 195 static void 196 core_free_zone(zoneid_t zoneid, void *arg) 197 { 198 struct core_globals *cg = arg; 199 200 if (cg == NULL) 201 return; 202 if (cg->core_file != NULL) 203 refstr_rele(cg->core_file); 204 corectl_path_rele(cg->core_default_path); 205 corectl_content_rele(cg->core_default_content); 206 kmem_free(cg, sizeof (*cg)); 207 } 208 209 /* 210 * Called once, from icode(), to set init's core file path and content. 211 */ 212 void 213 init_core(void) 214 { 215 struct core_globals *cg; 216 217 zone_key_create(&core_zone_key, core_init_zone, NULL, core_free_zone); 218 219 /* 220 * zone_key_create will have called core_init_zone for the 221 * global zone, which sets up the default path and content 222 * variables. 223 */ 224 cg = zone_getspecific(core_zone_key, global_zone); 225 ASSERT(cg != NULL); 226 227 corectl_path_hold(cg->core_default_path); 228 corectl_content_hold(cg->core_default_content); 229 230 curproc->p_corefile = cg->core_default_path; 231 curproc->p_content = cg->core_default_content; 232 } 233 234 int 235 corectl(int subcode, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) 236 { 237 int error = 0; 238 proc_t *p; 239 refstr_t *rp; 240 size_t size; 241 char *path; 242 core_content_t content = CC_CONTENT_INVALID; 243 struct core_globals *cg; 244 zone_t *zone = curproc->p_zone; 245 246 cg = zone_getspecific(core_zone_key, zone); 247 ASSERT(cg != NULL); 248 249 switch (subcode) { 250 case CC_SET_OPTIONS: 251 if ((error = secpolicy_coreadm(CRED())) == 0) { 252 if (arg1 & ~CC_OPTIONS) 253 error = EINVAL; 254 else 255 cg->core_options = (uint32_t)arg1; 256 } 257 break; 258 259 case CC_GET_OPTIONS: 260 return (cg->core_options); 261 262 case CC_GET_GLOBAL_PATH: 263 case CC_GET_DEFAULT_PATH: 264 case CC_GET_PROCESS_PATH: 265 if (subcode == CC_GET_GLOBAL_PATH) { 266 mutex_enter(&cg->core_lock); 267 if ((rp = cg->core_file) != NULL) 268 refstr_hold(rp); 269 mutex_exit(&cg->core_lock); 270 } else if (subcode == CC_GET_DEFAULT_PATH) { 271 rp = corectl_path_value(cg->core_default_path); 272 } else { 273 rp = NULL; 274 mutex_enter(&pidlock); 275 if ((p = prfind((pid_t)arg3)) == NULL || 276 p->p_stat == SIDL) { 277 mutex_exit(&pidlock); 278 error = ESRCH; 279 } else { 280 mutex_enter(&p->p_lock); 281 mutex_exit(&pidlock); 282 mutex_enter(&p->p_crlock); 283 if (!hasprocperm(p->p_cred, CRED())) 284 error = EPERM; 285 else if (p->p_corefile != NULL) 286 rp = corectl_path_value(p->p_corefile); 287 mutex_exit(&p->p_crlock); 288 mutex_exit(&p->p_lock); 289 } 290 } 291 if (rp == NULL) { 292 if (error == 0 && suword8((void *)arg1, 0)) 293 error = EFAULT; 294 } else { 295 error = copyoutstr(refstr_value(rp), (char *)arg1, 296 (size_t)arg2, NULL); 297 refstr_rele(rp); 298 } 299 break; 300 301 case CC_SET_GLOBAL_PATH: 302 case CC_SET_DEFAULT_PATH: 303 if ((error = secpolicy_coreadm(CRED())) != 0) 304 break; 305 306 /* FALLTHROUGH */ 307 case CC_SET_PROCESS_PATH: 308 if ((size = MIN((size_t)arg2, MAXPATHLEN)) == 0) { 309 error = EINVAL; 310 break; 311 } 312 path = kmem_alloc(size, KM_SLEEP); 313 error = copyinstr((char *)arg1, path, size, NULL); 314 if (error == 0) { 315 if (subcode == CC_SET_PROCESS_PATH) { 316 error = set_proc_info((pid_t)arg3, path, 0); 317 } else if (subcode == CC_SET_DEFAULT_PATH) { 318 corectl_path_set(cg->core_default_path, path); 319 } else if (*path != '\0' && *path != '/') { 320 error = EINVAL; 321 } else { 322 refstr_t *nrp = refstr_alloc(path); 323 324 mutex_enter(&cg->core_lock); 325 rp = cg->core_file; 326 if (*path == '\0') 327 cg->core_file = NULL; 328 else 329 refstr_hold(cg->core_file = nrp); 330 mutex_exit(&cg->core_lock); 331 332 if (rp != NULL) 333 refstr_rele(rp); 334 335 refstr_rele(nrp); 336 } 337 } 338 kmem_free(path, size); 339 break; 340 341 case CC_SET_GLOBAL_CONTENT: 342 case CC_SET_DEFAULT_CONTENT: 343 if ((error = secpolicy_coreadm(CRED())) != 0) 344 break; 345 346 /* FALLTHROUGH */ 347 case CC_SET_PROCESS_CONTENT: 348 error = copyin((void *)arg1, &content, sizeof (content)); 349 if (error != 0) 350 break; 351 352 /* 353 * If any unknown bits are set, don't let this charade 354 * continue. 355 */ 356 if (content & ~CC_CONTENT_ALL) { 357 error = EINVAL; 358 break; 359 } 360 361 if (subcode == CC_SET_PROCESS_CONTENT) { 362 error = set_proc_info((pid_t)arg2, NULL, content); 363 } else if (subcode == CC_SET_DEFAULT_CONTENT) { 364 corectl_content_set(cg->core_default_content, content); 365 } else { 366 mutex_enter(&cg->core_lock); 367 cg->core_content = content; 368 mutex_exit(&cg->core_lock); 369 } 370 371 break; 372 373 case CC_GET_GLOBAL_CONTENT: 374 content = cg->core_content; 375 error = copyout(&content, (void *)arg1, sizeof (content)); 376 break; 377 378 case CC_GET_DEFAULT_CONTENT: 379 content = corectl_content_value(cg->core_default_content); 380 error = copyout(&content, (void *)arg1, sizeof (content)); 381 break; 382 383 case CC_GET_PROCESS_CONTENT: 384 mutex_enter(&pidlock); 385 if ((p = prfind((pid_t)arg2)) == NULL || p->p_stat == SIDL) { 386 mutex_exit(&pidlock); 387 error = ESRCH; 388 break; 389 } 390 391 mutex_enter(&p->p_lock); 392 mutex_exit(&pidlock); 393 mutex_enter(&p->p_crlock); 394 if (!hasprocperm(p->p_cred, CRED())) 395 error = EPERM; 396 else if (p->p_content == NULL) 397 content = CC_CONTENT_NONE; 398 else 399 content = corectl_content_value(p->p_content); 400 mutex_exit(&p->p_crlock); 401 mutex_exit(&p->p_lock); 402 403 if (error == 0) 404 error = copyout(&content, (void *)arg1, 405 sizeof (content)); 406 break; 407 408 default: 409 error = EINVAL; 410 break; 411 } 412 413 if (error) 414 return (set_errno(error)); 415 return (0); 416 } 417 418 typedef struct { 419 int cc_count; 420 corectl_path_t *cc_path; 421 corectl_content_t *cc_content; 422 } counter_t; 423 424 static int 425 set_one_proc_info(proc_t *p, counter_t *counterp) 426 { 427 corectl_path_t *corefile; 428 corectl_content_t *content; 429 430 mutex_enter(&p->p_crlock); 431 432 if (!(p->p_flag & SSYS) && hasprocperm(p->p_cred, CRED())) { 433 mutex_exit(&p->p_crlock); 434 counterp->cc_count++; 435 if (counterp->cc_path != NULL) { 436 corectl_path_hold(counterp->cc_path); 437 mutex_enter(&p->p_lock); 438 corefile = p->p_corefile; 439 p->p_corefile = counterp->cc_path; 440 mutex_exit(&p->p_lock); 441 if (corefile != NULL) 442 corectl_path_rele(corefile); 443 } else { 444 corectl_content_hold(counterp->cc_content); 445 mutex_enter(&p->p_lock); 446 content = p->p_content; 447 p->p_content = counterp->cc_content; 448 mutex_exit(&p->p_lock); 449 if (content != NULL) 450 corectl_content_rele(content); 451 } 452 } else { 453 mutex_exit(&p->p_crlock); 454 } 455 456 return (0); 457 } 458 459 static int 460 set_proc_info(pid_t pid, const char *path, core_content_t content) 461 { 462 proc_t *p; 463 counter_t counter; 464 int error = 0; 465 466 counter.cc_count = 0; 467 /* 468 * Only one of the core file path or content can be set at a time. 469 */ 470 if (path != NULL) { 471 counter.cc_path = corectl_path_alloc(path); 472 counter.cc_content = NULL; 473 } else { 474 counter.cc_path = NULL; 475 counter.cc_content = corectl_content_alloc(content); 476 } 477 478 if (pid == -1) { 479 procset_t set; 480 481 setprocset(&set, POP_AND, P_ALL, P_MYID, P_ALL, P_MYID); 482 error = dotoprocs(&set, set_one_proc_info, (char *)&counter); 483 if (error == 0 && counter.cc_count == 0) 484 error = EPERM; 485 } else if (pid > 0) { 486 mutex_enter(&pidlock); 487 if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) { 488 error = ESRCH; 489 } else { 490 (void) set_one_proc_info(p, &counter); 491 if (counter.cc_count == 0) 492 error = EPERM; 493 } 494 mutex_exit(&pidlock); 495 } else { 496 int nfound = 0; 497 pid_t pgid; 498 499 if (pid == 0) 500 pgid = curproc->p_pgrp; 501 else 502 pgid = -pid; 503 504 mutex_enter(&pidlock); 505 for (p = pgfind(pgid); p != NULL; p = p->p_pglink) { 506 if (p->p_stat != SIDL) { 507 nfound++; 508 (void) set_one_proc_info(p, &counter); 509 } 510 } 511 mutex_exit(&pidlock); 512 if (nfound == 0) 513 error = ESRCH; 514 else if (counter.cc_count == 0) 515 error = EPERM; 516 } 517 518 if (path != NULL) 519 corectl_path_rele(counter.cc_path); 520 else 521 corectl_content_rele(counter.cc_content); 522 523 if (error) 524 return (set_errno(error)); 525 return (0); 526 } 527 528 /* 529 * Give current process the default core settings for its current zone; 530 * used for processes entering a zone via zone_enter. 531 */ 532 void 533 set_core_defaults(void) 534 { 535 proc_t *p = curproc; 536 struct core_globals *cg; 537 corectl_path_t *oldpath, *newpath; 538 corectl_content_t *oldcontent, *newcontent; 539 540 cg = zone_getspecific(core_zone_key, p->p_zone); 541 542 /* make local copies of default values to protect against change */ 543 newpath = cg->core_default_path; 544 newcontent = cg->core_default_content; 545 546 corectl_path_hold(newpath); 547 corectl_content_hold(newcontent); 548 mutex_enter(&p->p_lock); 549 oldpath = p->p_corefile; 550 p->p_corefile = newpath; 551 oldcontent = p->p_content; 552 p->p_content = newcontent; 553 mutex_exit(&p->p_lock); 554 if (oldpath != NULL) 555 corectl_path_rele(oldpath); 556 if (oldcontent != NULL) 557 corectl_content_rele(oldcontent); 558 } 559