Print this page
NEX-9665 libcfgadm: memory leak in do_list_common()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-9634 cfgadm_plugins/shp: memory leaks in cfga_list_ext()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-8148 Alerts should be sent if cores are created on a system (lint fix)
NEX-8148 Alerts should be sent if cores are created on a system
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/os/core.c
+++ new/usr/src/uts/common/os/core.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 /*
23 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2011, Joyent Inc. All rights reserved.
25 25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 + * Copyright 2017 Nexenta Systems, Inc.
26 27 */
27 28
28 29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 30 /* All Rights Reserved */
30 31
31 32 #include <sys/param.h>
32 33 #include <sys/types.h>
33 34 #include <sys/time.h>
34 35 #include <sys/sysmacros.h>
35 36 #include <sys/proc.h>
36 37 #include <sys/systm.h>
37 38 #include <sys/cred.h>
38 39 #include <sys/user.h>
39 40 #include <sys/utsname.h>
40 41 #include <sys/errno.h>
41 42 #include <sys/signal.h>
42 43 #include <sys/siginfo.h>
43 44 #include <sys/fault.h>
44 45 #include <sys/syscall.h>
45 46 #include <sys/ucontext.h>
46 47 #include <sys/prsystm.h>
47 48 #include <sys/vnode.h>
48 49 #include <sys/var.h>
49 50 #include <sys/file.h>
50 51 #include <sys/pathname.h>
51 52 #include <sys/vfs.h>
52 53 #include <sys/exec.h>
53 54 #include <sys/debug.h>
54 55 #include <sys/stack.h>
55 56 #include <sys/kmem.h>
56 57 #include <sys/schedctl.h>
|
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
57 58 #include <sys/core.h>
58 59 #include <sys/corectl.h>
59 60 #include <sys/cmn_err.h>
60 61 #include <vm/as.h>
61 62 #include <sys/rctl.h>
62 63 #include <sys/nbmlock.h>
63 64 #include <sys/stat.h>
64 65 #include <sys/zone.h>
65 66 #include <sys/contract/process_impl.h>
66 67 #include <sys/ddi.h>
68 +#include <sys/fm/protocol.h>
69 +#include <sys/fm/util.h>
70 +#include <sys/fm/sw/core.h>
71 +#include <sys/sysevent.h>
67 72
68 73 /*
69 74 * Processes running within a zone potentially dump core in 3 locations,
70 75 * based on the per-process, per-zone, and the global zone's core settings.
71 76 *
72 77 * Per-zone and global zone settings are often referred to as "global"
73 78 * settings since they apply to the system (or zone) as a whole, as
74 79 * opposed to a particular process.
75 80 */
76 81 enum core_types {
77 82 CORE_PROC, /* Use per-process settings */
78 83 CORE_ZONE, /* Use per-zone settings */
79 84 CORE_GLOBAL /* Use global zone settings */
80 85 };
81 86
82 87 /*
83 88 * Log information about "global" core dumps to syslog.
84 89 */
85 90 static void
86 91 core_log(struct core_globals *cg, int error, const char *why, const char *path,
87 92 zoneid_t zoneid)
88 93 {
89 94 proc_t *p = curproc;
90 95 pid_t pid = p->p_pid;
91 96 char *fn = PTOU(p)->u_comm;
92 97
93 98 if (!(cg->core_options & CC_GLOBAL_LOG))
94 99 return;
95 100
96 101 if (path == NULL)
|
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
97 102 zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s", fn, pid, why);
98 103 else if (error == 0)
99 104 zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s: %s", fn, pid,
100 105 why, path);
101 106 else
102 107 zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s, errno=%d: %s",
103 108 fn, pid, why, error, path);
104 109 }
105 110
106 111 /*
112 + * Generate FMA e-report for a core.
113 + */
114 +static void
115 +gen_ereport(const char *path, int sig)
116 +{
117 + nvlist_t *ereport = NULL;
118 + nvlist_t *fmri = NULL;
119 + nvlist_t *sw_obj = NULL;
120 + uint64_t ena;
121 + proc_t *p = curproc;
122 + int err = 0;
123 +
124 + if ((ereport = fm_nvlist_create(NULL)) == NULL)
125 + return;
126 + if ((fmri = fm_nvlist_create(NULL)) == NULL)
127 + goto out;
128 + if ((sw_obj = fm_nvlist_create(NULL)) == NULL)
129 + goto out;
130 + ena = fm_ena_generate(0, FM_ENA_FMT1);
131 +
132 + err |= nvlist_add_uint8(fmri, FM_VERSION, FM_SW_SCHEME_VERSION);
133 + err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW);
134 + err |= nvlist_add_string(sw_obj, FM_FMRI_SW_OBJ_PATH, path);
135 + err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_OBJ, sw_obj);
136 +
137 + if (err != 0)
138 + goto out;
139 +
140 + fm_ereport_set(ereport, FM_EREPORT_VERSION, CORE_ERROR_CLASS,
141 + ena, fmri, NULL);
142 +
143 + fm_payload_set(ereport,
144 + FM_EREPORT_PAYLOAD_CORE_COMMAND, DATA_TYPE_STRING,
145 + p->p_exec->v_path ? p->p_exec->v_path : p->p_user.u_comm,
146 + FM_EREPORT_PAYLOAD_CORE_PSARGS, DATA_TYPE_STRING,
147 + p->p_user.u_psargs,
148 + FM_EREPORT_PAYLOAD_CORE_SIGNAL, DATA_TYPE_INT32, sig,
149 + FM_EREPORT_PAYLOAD_CORE_PATH, DATA_TYPE_STRING, path,
150 + NULL);
151 +
152 + fm_ereport_post(ereport, EVCH_SLEEP);
153 +
154 +out:
155 + fm_nvlist_destroy(sw_obj, FM_NVA_FREE);
156 + fm_nvlist_destroy(ereport, FM_NVA_FREE);
157 + fm_nvlist_destroy(fmri, FM_NVA_FREE);
158 +}
159 +
160 +/*
107 161 * Private version of vn_remove().
108 162 * Refuse to unlink a directory or an unwritable file.
109 163 * Also allow the process to access files normally inaccessible due to
110 164 * chroot(2) or Zone limitations.
111 165 */
112 166 static int
113 167 remove_core_file(char *fp, enum core_types core_type)
114 168 {
115 169 vnode_t *vp = NULL; /* entry vnode */
116 170 vnode_t *dvp; /* ptr to parent dir vnode */
117 171 vfs_t *dvfsp;
118 172 int error;
119 173 int in_crit = 0;
120 174 pathname_t pn; /* name of entry */
121 175 vnode_t *startvp, *rootvp;
122 176
123 177 if ((error = pn_get(fp, UIO_SYSSPACE, &pn)) != 0)
124 178 return (error);
125 179 /*
126 180 * Determine what rootvp to use.
127 181 */
128 182 if (core_type == CORE_PROC) {
129 183 rootvp = (PTOU(curproc)->u_rdir == NULL ?
130 184 curproc->p_zone->zone_rootvp : PTOU(curproc)->u_rdir);
131 185 startvp = (fp[0] == '/' ? rootvp : PTOU(curproc)->u_cdir);
132 186 } else if (core_type == CORE_ZONE) {
133 187 startvp = curproc->p_zone->zone_rootvp;
134 188 rootvp = curproc->p_zone->zone_rootvp;
135 189 } else {
136 190 ASSERT(core_type == CORE_GLOBAL);
137 191 startvp = rootdir;
138 192 rootvp = rootdir;
139 193 }
140 194 VN_HOLD(startvp);
141 195 if (rootvp != rootdir)
142 196 VN_HOLD(rootvp);
143 197 if ((error = lookuppnvp(&pn, NULL, NO_FOLLOW, &dvp, &vp, rootvp,
144 198 startvp, CRED())) != 0) {
145 199 pn_free(&pn);
146 200 return (error);
147 201 }
148 202 /*
149 203 * Succeed if there is no file.
150 204 * Fail if the file is not a regular file.
151 205 * Fail if the filesystem is mounted read-only.
152 206 * Fail if the file is not writeable.
153 207 * Fail if the file has NBMAND share reservations.
154 208 */
155 209 if (vp == NULL)
156 210 error = 0;
157 211 else if (vp->v_type != VREG)
158 212 error = EACCES;
159 213 else if ((dvfsp = dvp->v_vfsp) != NULL &&
160 214 (dvfsp->vfs_flag & VFS_RDONLY))
161 215 error = EROFS;
162 216 else if ((error = VOP_ACCESS(vp, VWRITE, 0, CRED(), NULL)) == 0) {
163 217 if (nbl_need_check(vp)) {
164 218 nbl_start_crit(vp, RW_READER);
165 219 in_crit = 1;
166 220 if (nbl_share_conflict(vp, NBL_REMOVE, NULL)) {
167 221 error = EACCES;
168 222 }
169 223 }
170 224 if (!error) {
171 225 error = VOP_REMOVE(dvp, pn.pn_path, CRED(), NULL, 0);
172 226 }
173 227 }
174 228
175 229 pn_free(&pn);
176 230 if (vp != NULL) {
177 231 if (in_crit)
178 232 nbl_end_crit(vp);
179 233 VN_RELE(vp);
180 234 }
181 235 VN_RELE(dvp);
182 236 return (error);
183 237 }
184 238
185 239 /*
186 240 * Create the core file in a location that may be normally inaccessible due
187 241 * to chroot(2) or Zone limitations.
188 242 */
189 243 static int
190 244 create_core_file(char *fp, enum core_types core_type, vnode_t **vpp)
191 245 {
192 246 int error;
193 247 mode_t perms = (S_IRUSR | S_IWUSR);
194 248 pathname_t pn;
195 249 char *file;
196 250 vnode_t *vp;
197 251 vnode_t *dvp;
198 252 vattr_t vattr;
199 253 cred_t *credp = CRED();
200 254
201 255 if (core_type == CORE_PROC) {
202 256 file = fp;
203 257 dvp = NULL; /* regular lookup */
204 258 } else {
205 259 vnode_t *startvp, *rootvp;
206 260
207 261 ASSERT(core_type == CORE_ZONE || core_type == CORE_GLOBAL);
208 262 /*
209 263 * This is tricky because we want to dump the core in
210 264 * a location which may normally be inaccessible
211 265 * to us (due to chroot(2) limitations, or zone
212 266 * membership), and hence need to overcome u_rdir
213 267 * restrictions. The basic idea is to separate
214 268 * the path from the filename, lookup the
215 269 * pathname separately (starting from the global
216 270 * zone's root directory), and then open the
217 271 * file starting at the directory vnode.
218 272 */
219 273 if (error = pn_get(fp, UIO_SYSSPACE, &pn))
220 274 return (error);
221 275
222 276 if (core_type == CORE_ZONE) {
223 277 startvp = rootvp = curproc->p_zone->zone_rootvp;
224 278 } else {
225 279 startvp = rootvp = rootdir;
226 280 }
227 281 /*
228 282 * rootvp and startvp will be VN_RELE()'d by lookuppnvp() if
229 283 * necessary.
230 284 */
231 285 VN_HOLD(startvp);
232 286 if (rootvp != rootdir)
233 287 VN_HOLD(rootvp);
234 288 /*
235 289 * Do a lookup on the full path, ignoring the actual file, but
236 290 * finding the vnode for the directory. It's OK if the file
237 291 * doesn't exist -- it most likely won't since we just removed
238 292 * it.
239 293 */
240 294 error = lookuppnvp(&pn, NULL, FOLLOW, &dvp, NULLVPP,
241 295 rootvp, startvp, credp);
242 296 pn_free(&pn);
243 297 if (error != 0)
244 298 return (error);
245 299 ASSERT(dvp != NULL);
246 300 /*
247 301 * Now find the final component in the path (ie, the name of
248 302 * the core file).
249 303 */
250 304 if (error = pn_get(fp, UIO_SYSSPACE, &pn)) {
251 305 VN_RELE(dvp);
252 306 return (error);
253 307 }
254 308 pn_setlast(&pn);
255 309 file = pn.pn_path;
256 310 }
257 311 error = vn_openat(file, UIO_SYSSPACE,
258 312 FWRITE | FTRUNC | FEXCL | FCREAT | FOFFMAX,
259 313 perms, &vp, CRCREAT, PTOU(curproc)->u_cmask, dvp, -1);
260 314 if (core_type != CORE_PROC) {
261 315 VN_RELE(dvp);
262 316 pn_free(&pn);
263 317 }
264 318 /*
265 319 * Don't dump a core file owned by "nobody".
266 320 */
267 321 vattr.va_mask = AT_UID;
268 322 if (error == 0 &&
269 323 (VOP_GETATTR(vp, &vattr, 0, credp, NULL) != 0 ||
270 324 vattr.va_uid != crgetuid(credp))) {
271 325 (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0,
272 326 credp, NULL);
273 327 VN_RELE(vp);
274 328 (void) remove_core_file(fp, core_type);
275 329 error = EACCES;
276 330 }
277 331 *vpp = vp;
278 332 return (error);
279 333 }
280 334
281 335 /*
282 336 * Install the specified held cred into the process, and return a pointer to
283 337 * the held cred which was previously the value of p->p_cred.
284 338 */
285 339 static cred_t *
286 340 set_cred(proc_t *p, cred_t *newcr)
287 341 {
288 342 cred_t *oldcr;
289 343 uid_t olduid, newuid;
290 344
291 345 /*
292 346 * Place a hold on the existing cred, and then install the new
293 347 * cred into the proc structure.
294 348 */
295 349 mutex_enter(&p->p_crlock);
296 350 oldcr = p->p_cred;
297 351 crhold(oldcr);
298 352 p->p_cred = newcr;
299 353 mutex_exit(&p->p_crlock);
300 354
301 355 ASSERT(crgetzoneid(oldcr) == crgetzoneid(newcr));
302 356
303 357 /*
304 358 * If the real uid is changing, keep the per-user process
305 359 * counts accurate.
306 360 */
307 361 olduid = crgetruid(oldcr);
308 362 newuid = crgetruid(newcr);
309 363 if (olduid != newuid) {
310 364 zoneid_t zoneid = crgetzoneid(newcr);
311 365
312 366 mutex_enter(&pidlock);
313 367 upcount_dec(olduid, zoneid);
314 368 upcount_inc(newuid, zoneid);
315 369 mutex_exit(&pidlock);
316 370 }
317 371
318 372 /*
319 373 * Broadcast the new cred to all the other threads. The old
320 374 * cred can be safely returned because we have a hold on it.
321 375 */
322 376 crset(p, newcr);
323 377 return (oldcr);
324 378 }
325 379
326 380 static int
327 381 do_core(char *fp, int sig, enum core_types core_type, struct core_globals *cg)
328 382 {
329 383 proc_t *p = curproc;
330 384 cred_t *credp = CRED();
331 385 rlim64_t rlimit;
332 386 vnode_t *vp;
333 387 int error = 0;
334 388 struct execsw *eswp;
335 389 cred_t *ocredp = NULL;
336 390 int is_setid = 0;
337 391 core_content_t content;
338 392 uid_t uid;
339 393 gid_t gid;
340 394
341 395 if (core_type == CORE_GLOBAL || core_type == CORE_ZONE) {
342 396 mutex_enter(&cg->core_lock);
343 397 content = cg->core_content;
344 398 mutex_exit(&cg->core_lock);
345 399 rlimit = cg->core_rlimit;
346 400 } else {
347 401 mutex_enter(&p->p_lock);
348 402 rlimit = rctl_enforced_value(rctlproc_legacy[RLIMIT_CORE],
349 403 p->p_rctls, p);
350 404 content = corectl_content_value(p->p_content);
351 405 mutex_exit(&p->p_lock);
352 406 }
353 407
354 408 if (rlimit == 0)
355 409 return (EFBIG);
356 410
357 411 /*
358 412 * If SNOCD is set, or if the effective, real, and saved ids do
359 413 * not match up, no one but a privileged user is allowed to view
360 414 * this core file. Set the credentials and the owner to root.
361 415 */
362 416 if ((p->p_flag & SNOCD) ||
363 417 (uid = crgetuid(credp)) != crgetruid(credp) ||
364 418 uid != crgetsuid(credp) ||
365 419 (gid = crgetgid(credp)) != crgetrgid(credp) ||
366 420 gid != crgetsgid(credp)) {
367 421 /*
368 422 * Because this is insecure against certain forms of file
369 423 * system attack, do it only if set-id core files have been
370 424 * enabled via corectl(CC_GLOBAL_SETID | CC_PROCESS_SETID).
371 425 */
372 426 if (((core_type == CORE_GLOBAL || core_type == CORE_ZONE) &&
373 427 !(cg->core_options & CC_GLOBAL_SETID)) ||
374 428 (core_type == CORE_PROC &&
375 429 !(cg->core_options & CC_PROCESS_SETID)))
376 430 return (ENOTSUP);
377 431
378 432 is_setid = 1;
379 433 }
380 434
381 435 /*
382 436 * If we are doing a "global" core dump or a set-id core dump,
383 437 * use kcred to do the dumping.
384 438 */
385 439 if (core_type == CORE_GLOBAL || core_type == CORE_ZONE || is_setid) {
386 440 /*
387 441 * Use the zone's "kcred" to prevent privilege
388 442 * escalation.
389 443 */
390 444 credp = zone_get_kcred(getzoneid());
391 445 ASSERT(credp != NULL);
392 446 ocredp = set_cred(p, credp);
393 447 }
394 448
395 449 /*
396 450 * First remove any existing core file, then
397 451 * open the new core file with (O_EXCL|O_CREAT).
398 452 *
399 453 * The reasons for doing this are manifold:
400 454 *
401 455 * For security reasons, we don't want root processes
402 456 * to dump core through a symlink because that would
403 457 * allow a malicious user to clobber any file on
404 458 * the system if they could convince a root process,
405 459 * perhaps a set-uid root process that they started,
406 460 * to dump core in a directory writable by that user.
407 461 * Similar security reasons apply to hard links.
408 462 * For symmetry we do this unconditionally, not
409 463 * just for root processes.
410 464 *
411 465 * If the process has the core file mmap()d into the
412 466 * address space, we would be modifying the address
413 467 * space that we are trying to dump if we did not first
414 468 * remove the core file. (The command "file core"
415 469 * is the canonical example of this possibility.)
416 470 *
417 471 * Opening the core file with O_EXCL|O_CREAT ensures than
418 472 * two concurrent core dumps don't clobber each other.
419 473 * One is bound to lose; we don't want to make both lose.
420 474 */
421 475 if ((error = remove_core_file(fp, core_type)) == 0) {
422 476 error = create_core_file(fp, core_type, &vp);
423 477 }
424 478
425 479 /*
426 480 * Now that vn_open is complete, reset the process's credentials if
427 481 * we changed them, and make 'credp' point to kcred used
428 482 * above. We use 'credp' to do i/o on the core file below, but leave
429 483 * p->p_cred set to the original credential to allow the core file
430 484 * to record this information.
431 485 */
432 486 if (ocredp != NULL)
433 487 credp = set_cred(p, ocredp);
434 488
435 489 if (error == 0) {
436 490 int closerr;
437 491 #if defined(__sparc)
438 492 (void) flush_user_windows_to_stack(NULL);
439 493 #endif
440 494 if ((eswp = PTOU(curproc)->u_execsw) == NULL ||
441 495 (eswp = findexec_by_magic(eswp->exec_magic)) == NULL) {
442 496 error = ENOSYS;
443 497 } else {
444 498 error = eswp->exec_core(vp, p, credp, rlimit, sig,
445 499 content);
446 500 rw_exit(eswp->exec_lock);
447 501 }
448 502
449 503 closerr = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, credp, NULL);
450 504 VN_RELE(vp);
451 505 if (error == 0)
452 506 error = closerr;
453 507 }
454 508
455 509 if (ocredp != NULL)
456 510 crfree(credp);
457 511
458 512 return (error);
459 513 }
460 514
461 515 /*
462 516 * Convert a core name pattern to a pathname.
463 517 */
464 518 static int
465 519 expand_string(const char *pat, char *fp, int size, cred_t *cr)
466 520 {
467 521 proc_t *p = curproc;
468 522 char buf[24];
469 523 int len, i;
470 524 char *s;
471 525 char c;
472 526
473 527 while ((c = *pat++) != '\0') {
474 528 if (size < 2)
475 529 return (ENAMETOOLONG);
476 530 if (c != '%') {
477 531 size--;
478 532 *fp++ = c;
479 533 continue;
480 534 }
481 535 if ((c = *pat++) == '\0') {
482 536 size--;
483 537 *fp++ = '%';
484 538 break;
485 539 }
486 540 switch (c) {
487 541 case 'p': /* pid */
488 542 (void) sprintf((s = buf), "%d", p->p_pid);
489 543 break;
490 544 case 'u': /* effective uid */
491 545 (void) sprintf((s = buf), "%u", crgetuid(p->p_cred));
492 546 break;
493 547 case 'g': /* effective gid */
494 548 (void) sprintf((s = buf), "%u", crgetgid(p->p_cred));
495 549 break;
496 550 case 'f': /* exec'd filename */
497 551 s = PTOU(p)->u_comm;
498 552 break;
499 553 case 'd': /* exec'd dirname */
500 554 /*
501 555 * Even if pathname caching is disabled, we should
502 556 * be able to lookup the pathname for a directory.
503 557 */
504 558 if (p->p_execdir != NULL && vnodetopath(NULL,
505 559 p->p_execdir, fp, size, cr) == 0) {
506 560 len = (int)strlen(fp);
507 561 ASSERT(len < size);
508 562 ASSERT(len >= 1);
509 563 ASSERT(fp[0] == '/');
510 564
511 565 /*
512 566 * Strip off the leading slash.
513 567 */
514 568 for (i = 0; i < len; i++) {
515 569 fp[i] = fp[i + 1];
516 570 }
517 571
518 572 len--;
519 573
520 574 size -= len;
521 575 fp += len;
522 576 } else {
523 577 *fp = '\0';
524 578 }
525 579
526 580 continue;
527 581 case 'n': /* system nodename */
528 582 s = uts_nodename();
529 583 break;
530 584 case 'm': /* machine (sun4u, etc) */
531 585 s = utsname.machine;
532 586 break;
533 587 case 't': /* decimal value of time(2) */
534 588 (void) sprintf((s = buf), "%ld", gethrestime_sec());
535 589 break;
536 590 case 'z':
537 591 s = p->p_zone->zone_name;
538 592 break;
539 593 case 'Z':
540 594 /* This is zonepath + "/root/", except for GZ */
541 595 s = p->p_zone->zone_rootpath;
542 596 break;
543 597 case '%':
544 598 (void) strcpy((s = buf), "%");
545 599 break;
546 600 default:
547 601 s = buf;
548 602 buf[0] = '%';
549 603 buf[1] = c;
550 604 buf[2] = '\0';
551 605 break;
552 606 }
553 607 len = (int)strlen(s);
554 608 if ((size -= len) <= 0)
555 609 return (ENAMETOOLONG);
556 610 (void) strcpy(fp, s);
557 611 /* strip trailing "/root/" from non-GZ zonepath string */
558 612 if (c == 'Z' && len > 6) {
559 613 len -= 6;
560 614 ASSERT(strncmp(fp + len, "/root/", 6) == 0);
561 615 }
562 616 fp += len;
563 617 }
564 618
565 619 *fp = '\0';
566 620 return (0);
567 621 }
568 622
569 623 static int
570 624 dump_one_core(int sig, rlim64_t rlimit, enum core_types core_type,
571 625 struct core_globals *cg, char **name)
572 626 {
573 627 refstr_t *rp;
574 628 proc_t *p = curproc;
575 629 zoneid_t zoneid;
576 630 int error;
577 631 char *fp;
578 632 cred_t *cr;
579 633
580 634 ASSERT(core_type == CORE_ZONE || core_type == CORE_GLOBAL);
581 635 zoneid = (core_type == CORE_ZONE ? getzoneid() : GLOBAL_ZONEID);
582 636
583 637 mutex_enter(&cg->core_lock);
584 638 if ((rp = cg->core_file) != NULL)
585 639 refstr_hold(rp);
586 640 mutex_exit(&cg->core_lock);
587 641 if (rp == NULL) {
588 642 core_log(cg, 0, "no global core file pattern exists", NULL,
589 643 zoneid);
590 644 return (1); /* core file not generated */
591 645 }
592 646 fp = kmem_alloc(MAXPATHLEN, KM_SLEEP);
593 647 cr = zone_get_kcred(getzoneid());
594 648 error = expand_string(refstr_value(rp), fp, MAXPATHLEN, cr);
595 649 crfree(cr);
596 650 if (error != 0) {
597 651 core_log(cg, 0, "global core file pattern too long",
598 652 refstr_value(rp), zoneid);
599 653 } else if ((error = do_core(fp, sig, core_type, cg)) == 0) {
600 654 core_log(cg, 0, "core dumped", fp, zoneid);
601 655 } else if (error == ENOTSUP) {
602 656 core_log(cg, 0, "setid process, core not dumped", fp, zoneid);
603 657 } else if (error == ENOSPC) {
604 658 core_log(cg, 0, "no space left on device, core truncated",
605 659 fp, zoneid);
606 660 } else if (error == EFBIG) {
607 661 if (rlimit == 0)
608 662 core_log(cg, 0, "core rlimit is zero, core not dumped",
609 663 fp, zoneid);
610 664 else
611 665 core_log(cg, 0, "core rlimit exceeded, core truncated",
612 666 fp, zoneid);
613 667 /*
614 668 * In addition to the core result logging, we
615 669 * may also have explicit actions defined on
616 670 * core file size violations via the resource
617 671 * control framework.
618 672 */
619 673 mutex_enter(&p->p_lock);
620 674 (void) rctl_action(rctlproc_legacy[RLIMIT_CORE],
621 675 p->p_rctls, p, RCA_SAFE);
622 676 mutex_exit(&p->p_lock);
623 677 } else {
624 678 core_log(cg, error, "core dump failed", fp, zoneid);
625 679 }
626 680 refstr_rele(rp);
627 681 if (name != NULL)
628 682 *name = fp;
629 683 else
630 684 kmem_free(fp, MAXPATHLEN);
631 685 return (error);
632 686 }
633 687
634 688 int
635 689 core(int sig, int ext)
636 690 {
637 691 proc_t *p = curproc;
638 692 klwp_t *lwp = ttolwp(curthread);
639 693 refstr_t *rp;
640 694 char *fp_process = NULL, *fp_global = NULL, *fp_zone = NULL;
641 695 int error1 = 1;
642 696 int error2 = 1;
643 697 int error3 = 1;
644 698 k_sigset_t sigmask;
645 699 k_sigset_t sighold;
646 700 rlim64_t rlimit;
647 701 struct core_globals *my_cg, *global_cg;
648 702
649 703 global_cg = zone_getspecific(core_zone_key, global_zone);
650 704 ASSERT(global_cg != NULL);
651 705
652 706 my_cg = zone_getspecific(core_zone_key, curproc->p_zone);
653 707 ASSERT(my_cg != NULL);
654 708
655 709 /* core files suppressed? */
656 710 if (!(my_cg->core_options & (CC_PROCESS_PATH|CC_GLOBAL_PATH)) &&
657 711 !(global_cg->core_options & CC_GLOBAL_PATH)) {
658 712 if (!ext && p->p_ct_process != NULL)
659 713 contract_process_core(p->p_ct_process, p, sig,
660 714 NULL, NULL, NULL);
661 715 return (1);
662 716 }
663 717
664 718 /*
665 719 * Block all signals except SIGHUP, SIGINT, SIGKILL, and SIGTERM; no
666 720 * other signal may interrupt a core dump. For each signal, we
667 721 * explicitly unblock it and set it in p_siginfo to allow for some
668 722 * minimal error reporting. Additionally, we get the current limit on
669 723 * core file size for handling later error reporting.
670 724 */
671 725 mutex_enter(&p->p_lock);
672 726
673 727 p->p_flag |= SDOCORE;
674 728 schedctl_finish_sigblock(curthread);
675 729 sigmask = curthread->t_hold; /* remember for later */
676 730 sigfillset(&sighold);
677 731 if (!sigismember(&sigmask, SIGHUP))
678 732 sigdelset(&sighold, SIGHUP);
679 733 if (!sigismember(&sigmask, SIGINT))
680 734 sigdelset(&sighold, SIGINT);
681 735 if (!sigismember(&sigmask, SIGKILL))
682 736 sigdelset(&sighold, SIGKILL);
683 737 if (!sigismember(&sigmask, SIGTERM))
684 738 sigdelset(&sighold, SIGTERM);
685 739
686 740 sigaddset(&p->p_siginfo, SIGHUP);
687 741 sigaddset(&p->p_siginfo, SIGINT);
688 742 sigaddset(&p->p_siginfo, SIGKILL);
689 743 sigaddset(&p->p_siginfo, SIGTERM);
690 744
691 745 curthread->t_hold = sighold;
692 746
693 747 rlimit = rctl_enforced_value(rctlproc_legacy[RLIMIT_CORE], p->p_rctls,
694 748 p);
695 749
696 750 mutex_exit(&p->p_lock);
697 751
698 752 /*
699 753 * Undo any watchpoints.
700 754 */
701 755 pr_free_watched_pages(p);
702 756
703 757 /*
704 758 * The presence of a current signal prevents file i/o
705 759 * from succeeding over a network. We copy the current
706 760 * signal information to the side and cancel the current
707 761 * signal so that the core dump will succeed.
708 762 */
709 763 ASSERT(lwp->lwp_cursig == sig);
710 764 lwp->lwp_cursig = 0;
711 765 lwp->lwp_extsig = 0;
712 766 if (lwp->lwp_curinfo == NULL) {
713 767 bzero(&lwp->lwp_siginfo, sizeof (k_siginfo_t));
714 768 lwp->lwp_siginfo.si_signo = sig;
715 769 lwp->lwp_siginfo.si_code = SI_NOINFO;
716 770 } else {
717 771 bcopy(&lwp->lwp_curinfo->sq_info,
718 772 &lwp->lwp_siginfo, sizeof (k_siginfo_t));
719 773 siginfofree(lwp->lwp_curinfo);
720 774 lwp->lwp_curinfo = NULL;
721 775 }
722 776
723 777 /*
724 778 * Convert the core file name patterns into path names
725 779 * and call do_core() to write the core files.
726 780 */
727 781
728 782 if (my_cg->core_options & CC_PROCESS_PATH) {
729 783 mutex_enter(&p->p_lock);
730 784 if (p->p_corefile != NULL)
731 785 rp = corectl_path_value(p->p_corefile);
732 786 else
733 787 rp = NULL;
734 788 mutex_exit(&p->p_lock);
735 789 if (rp != NULL) {
736 790 fp_process = kmem_alloc(MAXPATHLEN, KM_SLEEP);
737 791 error1 = expand_string(refstr_value(rp),
738 792 fp_process, MAXPATHLEN, p->p_cred);
739 793 if (error1 == 0)
740 794 error1 = do_core(fp_process, sig, CORE_PROC,
741 795 my_cg);
742 796 refstr_rele(rp);
743 797 }
744 798 }
745 799
746 800 if (my_cg->core_options & CC_GLOBAL_PATH)
747 801 error2 = dump_one_core(sig, rlimit, CORE_ZONE, my_cg,
748 802 &fp_global);
749 803 if (global_cg != my_cg && (global_cg->core_options & CC_GLOBAL_PATH))
750 804 error3 = dump_one_core(sig, rlimit, CORE_GLOBAL, global_cg,
751 805 &fp_zone);
752 806
753 807 /*
754 808 * Restore the signal hold mask.
755 809 */
|
↓ open down ↓ |
639 lines elided |
↑ open up ↑ |
756 810 mutex_enter(&p->p_lock);
757 811 curthread->t_hold = sigmask;
758 812 mutex_exit(&p->p_lock);
759 813
760 814 if (!ext && p->p_ct_process != NULL)
761 815 contract_process_core(p->p_ct_process, p, sig,
762 816 error1 == 0 ? fp_process : NULL,
763 817 error2 == 0 ? fp_global : NULL,
764 818 error3 == 0 ? fp_zone : NULL);
765 819
820 + /*
821 + * FMA ereport is currently generated only for global zone cores
822 + * with global path.
823 + */
824 + if (error2 == 0 && global_cg == my_cg)
825 + gen_ereport(fp_global, sig);
826 +
766 827 if (fp_process != NULL)
767 828 kmem_free(fp_process, MAXPATHLEN);
768 829 if (fp_global != NULL)
769 830 kmem_free(fp_global, MAXPATHLEN);
770 831 if (fp_zone != NULL)
771 832 kmem_free(fp_zone, MAXPATHLEN);
772 833
773 834 /*
774 835 * Return non-zero if no core file was created.
775 836 */
776 837 return (error1 != 0 && error2 != 0 && error3 != 0);
777 838 }
778 839
779 840 /*
780 841 * Maximum chunk size for dumping core files,
781 842 * size in pages, patchable in /etc/system
782 843 */
783 844 uint_t core_chunk = 32;
784 845
785 846 /*
786 847 * The delay between core_write() calls, in microseconds. The default
787 848 * matches one "normal" clock tick, or 10 milliseconds.
788 849 */
789 850 clock_t core_delay_usec = 10000;
790 851
791 852 /*
792 853 * Common code to core dump process memory. The core_seg routine does i/o
793 854 * using core_write() below, and so it has the same failure semantics.
794 855 */
795 856 int
796 857 core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
797 858 rlim64_t rlimit, cred_t *credp)
798 859 {
799 860 caddr_t eaddr;
800 861 caddr_t base;
801 862 size_t len;
802 863 int err = 0;
803 864
804 865 eaddr = addr + size;
805 866 for (base = addr; base < eaddr; base += len) {
806 867 len = eaddr - base;
807 868 if (as_memory(p->p_as, &base, &len) != 0)
808 869 return (0);
809 870
810 871 /*
811 872 * Reduce len to a reasonable value so that we don't
812 873 * overwhelm the VM system with a monstrously large
813 874 * single write and cause pageout to stop running.
814 875 */
815 876 if (len > (size_t)core_chunk * PAGESIZE)
816 877 len = (size_t)core_chunk * PAGESIZE;
817 878
818 879 err = core_write(vp, UIO_USERSPACE,
819 880 offset + (size_t)(base - addr), base, len, rlimit, credp);
820 881
821 882 if (err)
822 883 return (err);
823 884
824 885 /*
825 886 * If we have taken a signal, return EINTR to allow the dump
826 887 * to be aborted.
827 888 */
828 889 if (issig(JUSTLOOKING) && issig(FORREAL))
829 890 return (EINTR);
830 891 }
831 892
832 893 return (0);
833 894 }
834 895
835 896 /*
836 897 * Wrapper around vn_rdwr to perform writes to a core file. For core files,
837 898 * we always want to write as much as we possibly can, and then make sure to
838 899 * return either 0 to the caller (for success), or the actual errno value.
839 900 * By using this function, the caller can omit additional code for handling
840 901 * retries and errors for partial writes returned by vn_rdwr. If vn_rdwr
841 902 * unexpectedly returns zero but no progress has been made, we return ENOSPC.
842 903 */
843 904 int
844 905 core_write(vnode_t *vp, enum uio_seg segflg, offset_t offset,
845 906 const void *buf, size_t len, rlim64_t rlimit, cred_t *credp)
846 907 {
847 908 ssize_t resid = len;
848 909 int error = 0;
849 910
850 911 while (len != 0) {
851 912 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len, offset,
852 913 segflg, 0, rlimit, credp, &resid);
853 914
854 915 if (error != 0)
855 916 break;
856 917
857 918 if (resid >= len)
858 919 return (ENOSPC);
859 920
860 921 buf = (const char *)buf + len - resid;
861 922 offset += len - resid;
862 923 len = resid;
863 924 }
864 925
865 926 return (error);
866 927 }
|
↓ open down ↓ |
91 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX