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