Mercurial > illumos > fmac
annotate usr/src/uts/common/contract/process.c @ 7887:f9ded24b041a
[fmac-discuss] [PATCH] Fix more cstyle issues
Fix more cstyle issues introduced by prior patches, in particular the
hasprocperm patch and the secctx patch.
uts/common/syscall/lgrpsys.c is still not clean with regard to
continuation indentation but the remaining warnings were not introduced
by our patches.
author | Stephen Smalley <sds@tycho.nsa.gov> |
---|---|
date | Fri, 17 Oct 2008 13:28:50 -0400 |
parents | e3677dd00778 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
4845 | 5 * Common Development and Distribution License (the "License"). |
6 * You may not use this file except in compliance with the License. | |
0 | 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 /* | |
6073 | 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
0 | 23 * Use is subject to license terms. |
24 */ | |
25 | |
26 #pragma ident "%Z%%M% %I% %E% SMI" | |
27 | |
28 #include <sys/mutex.h> | |
29 #include <sys/debug.h> | |
30 #include <sys/types.h> | |
31 #include <sys/param.h> | |
32 #include <sys/kmem.h> | |
33 #include <sys/thread.h> | |
34 #include <sys/id_space.h> | |
35 #include <sys/avl.h> | |
36 #include <sys/list.h> | |
37 #include <sys/sysmacros.h> | |
38 #include <sys/proc.h> | |
39 #include <sys/contract.h> | |
40 #include <sys/contract_impl.h> | |
41 #include <sys/contract/process.h> | |
42 #include <sys/contract/process_impl.h> | |
43 #include <sys/cmn_err.h> | |
44 #include <sys/nvpair.h> | |
45 #include <sys/policy.h> | |
7873
e3677dd00778
Mediate some process operations
Stephen Smalley <sds@tycho.nsa.gov>
parents:
6196
diff
changeset
|
46 #include <sys/fmac/av_permissions.h> |
6073 | 47 #include <sys/refstr.h> |
48 #include <sys/sunddi.h> | |
0 | 49 |
50 /* | |
51 * Process Contracts | |
52 * ----------------- | |
53 * | |
54 * Generally speaking, a process contract is a contract between a | |
55 * process and a set of its descendent processes. In some cases, when | |
56 * the child processes outlive the author of the contract, the contract | |
57 * may be held by (and therefore be between the child processes and) a | |
58 * successor process which adopts the contract after the death of the | |
59 * original author. | |
60 * | |
61 * The process contract adds two new concepts to the Solaris process | |
62 * model. The first is that a process contract forms a rigid fault | |
63 * boundary around a set of processes. Hardware, software, and even | |
64 * administrator errors impacting a process in a process contract | |
65 * generate specific events and can be requested to atomically shutdown | |
66 * all processes in the contract. The second is that a process | |
67 * contract is a process collective whose leader is not a member of the | |
68 * collective. This means that the leader can reliably react to events | |
69 * in the collective, and may also act upon the collective without | |
70 * special casing itself. | |
71 * | |
72 * A composite outcome of these two concepts is that we can now create | |
73 * a tree of process contracts, rooted at init(1M), which represent | |
74 * services and subservices that are reliably observed and can be | |
75 * restarted when fatal errors occur. The service management framework | |
76 * (SMF) realizes this structure. | |
77 * | |
78 * For more details, see the "restart agreements" case, PSARC 2003/193. | |
79 * | |
80 * There are four sets of routines in this file: the process contract | |
81 * standard template operations, the process contract standard contract | |
82 * operations, a couple routines used only by the contract subsystem to | |
83 * handle process contracts' unique role as a temporary holder of | |
84 * abandoned contracts, and the interfaces which allow the system to | |
85 * create and act upon process contracts. The first two are defined by | |
86 * the contracts framework and won't be discussed further. As for the | |
87 * remaining two: | |
88 * | |
89 * Special framework interfaces | |
90 * ---------------------------- | |
91 * | |
92 * contract_process_accept - determines if a process contract is a | |
93 * regent, i.e. if it can inherit other contracts. | |
94 * | |
95 * contract_process_take - tells a regent process contract to inherit | |
96 * an abandoned contract | |
97 * | |
98 * contract_process_adopt - tells a regent process contract that a | |
99 * contract it has inherited is being adopted by a process. | |
100 * | |
101 * Process contract interfaces | |
102 * --------------------------- | |
103 * | |
104 * contract_process_fork - called when a process is created; adds the | |
105 * new process to an existing contract or to a newly created one. | |
106 * | |
107 * contract_process_exit - called when a process exits | |
108 * | |
109 * contract_process_core - called when a process would have dumped core | |
110 * (even if a core file wasn't generated) | |
111 * | |
112 * contract_process_hwerr - called when a process was killed because of | |
113 * an uncorrectable hardware error | |
114 * | |
115 * contract_process_sig - called when a process was killed by a fatal | |
116 * signal sent by a process in another process contract | |
117 * | |
118 */ | |
119 | |
120 ct_type_t *process_type; | |
121 ctmpl_process_t *sys_process_tmpl; | |
6073 | 122 refstr_t *conp_svc_aux_default; |
0 | 123 |
124 /* | |
125 * Macro predicates for determining when events should be sent and how. | |
126 */ | |
127 #define EVSENDP(ctp, flag) \ | |
128 ((ctp->conp_contract.ct_ev_info | ctp->conp_contract.ct_ev_crit) & flag) | |
129 | |
130 #define EVINFOP(ctp, flag) \ | |
131 ((ctp->conp_contract.ct_ev_crit & flag) == 0) | |
132 | |
133 #define EVFATALP(ctp, flag) \ | |
134 (ctp->conp_ev_fatal & flag) | |
135 | |
136 | |
137 /* | |
138 * Process contract template implementation | |
139 */ | |
140 | |
141 /* | |
142 * ctmpl_process_dup | |
143 * | |
144 * The process contract template dup entry point. Other than the | |
145 * to-be-subsumed contract, which must be held, this simply copies all | |
146 * the fields of the original. | |
147 */ | |
148 static struct ct_template * | |
149 ctmpl_process_dup(struct ct_template *template) | |
150 { | |
151 ctmpl_process_t *new; | |
152 ctmpl_process_t *old = template->ctmpl_data; | |
153 | |
154 new = kmem_alloc(sizeof (ctmpl_process_t), KM_SLEEP); | |
155 | |
156 ctmpl_copy(&new->ctp_ctmpl, template); | |
157 new->ctp_ctmpl.ctmpl_data = new; | |
158 | |
159 new->ctp_subsume = old->ctp_subsume; | |
160 if (new->ctp_subsume) | |
161 contract_hold(new->ctp_subsume); | |
162 new->ctp_params = old->ctp_params; | |
163 new->ctp_ev_fatal = old->ctp_ev_fatal; | |
6073 | 164 new->ctp_svc_fmri = old->ctp_svc_fmri; |
165 if (new->ctp_svc_fmri != NULL) { | |
166 refstr_hold(new->ctp_svc_fmri); | |
167 } | |
168 new->ctp_svc_aux = old->ctp_svc_aux; | |
169 if (new->ctp_svc_aux != NULL) { | |
170 refstr_hold(new->ctp_svc_aux); | |
171 } | |
0 | 172 |
173 return (&new->ctp_ctmpl); | |
174 } | |
175 | |
176 /* | |
6073 | 177 * ctmpl_process_free |
0 | 178 * |
179 * The process contract template free entry point. Just releases a | |
180 * to-be-subsumed contract and frees the template. | |
181 */ | |
182 static void | |
183 ctmpl_process_free(struct ct_template *template) | |
184 { | |
185 ctmpl_process_t *ctp = template->ctmpl_data; | |
186 | |
187 if (ctp->ctp_subsume) | |
188 contract_rele(ctp->ctp_subsume); | |
6073 | 189 if (ctp->ctp_svc_fmri != NULL) { |
190 refstr_rele(ctp->ctp_svc_fmri); | |
191 } | |
192 if (ctp->ctp_svc_aux != NULL) { | |
193 refstr_rele(ctp->ctp_svc_aux); | |
194 } | |
0 | 195 kmem_free(template, sizeof (ctmpl_process_t)); |
196 } | |
197 | |
198 /* | |
199 * SAFE_EV is the set of events which a non-privileged process is | |
200 * allowed to make critical but not fatal or if the PGRPONLY parameter | |
201 * is set. EXCESS tells us if "value", a critical event set, requires | |
202 * additional privilege given the template "ctp". | |
203 */ | |
204 #define SAFE_EV (CT_PR_EV_EMPTY) | |
205 #define EXCESS(ctp, value) \ | |
206 (((value) & ~((ctp)->ctp_ev_fatal | SAFE_EV)) || \ | |
207 (((value) & ~SAFE_EV) && (ctp->ctp_params & CT_PR_PGRPONLY))) | |
208 | |
209 /* | |
210 * ctmpl_process_set | |
211 * | |
212 * The process contract template set entry point. None of the terms | |
213 * may be unconditionally set, and setting the parameters or fatal | |
214 * event set may result in events being implicitly removed from to the | |
215 * critical event set and added to the informative event set. The | |
216 * (admittedly subtle) reason we implicitly change the critical event | |
217 * set when the parameter or fatal event set is modified but not the | |
218 * other way around is because a change to the critical event set only | |
219 * affects the contract's owner, whereas a change to the parameter set | |
220 * and fatal set can affect the execution of the application running in | |
221 * the contract (and should therefore be only made explicitly). We | |
222 * allow implicit changes at all so that setting contract terms doesn't | |
223 * become a complex dance dependent on the template's initial state and | |
224 * the desired terms. | |
225 */ | |
226 static int | |
227 ctmpl_process_set(struct ct_template *tmpl, ct_param_t *param, const cred_t *cr) | |
228 { | |
229 ctmpl_process_t *ctp = tmpl->ctmpl_data; | |
230 contract_t *ct; | |
231 int error; | |
6073 | 232 uint64_t param_value; |
233 char *str_value; | |
0 | 234 |
6073 | 235 if ((param->ctpm_id == CTPP_SVC_FMRI) || |
236 (param->ctpm_id == CTPP_CREATOR_AUX)) { | |
237 str_value = (char *)param->ctpm_value; | |
238 str_value[param->ctpm_size - 1] = '\0'; | |
239 } else { | |
6196
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
240 if (param->ctpm_size < sizeof (uint64_t)) |
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
241 return (EINVAL); |
6073 | 242 param_value = *(uint64_t *)param->ctpm_value; |
243 /* | |
244 * No process contract parameters are > 32 bits. | |
245 * Unless it is a string. | |
246 */ | |
247 if (param_value & ~UINT32_MAX) | |
248 return (EINVAL); | |
249 } | |
0 | 250 |
251 switch (param->ctpm_id) { | |
252 case CTPP_SUBSUME: | |
6073 | 253 if (param_value != 0) { |
0 | 254 /* |
255 * Ensure that the contract exists, that we | |
256 * hold the contract, and that the contract is | |
257 * empty. | |
258 */ | |
6073 | 259 ct = contract_type_ptr(process_type, param_value, |
0 | 260 curproc->p_zone->zone_uniqid); |
261 if (ct == NULL) | |
262 return (ESRCH); | |
263 if (ct->ct_owner != curproc) { | |
264 contract_rele(ct); | |
265 return (EACCES); | |
266 } | |
267 if (((cont_process_t *)ct->ct_data)->conp_nmembers) { | |
268 contract_rele(ct); | |
269 return (ENOTEMPTY); | |
270 } | |
271 } else { | |
272 ct = NULL; | |
273 } | |
274 if (ctp->ctp_subsume) | |
275 contract_rele(ctp->ctp_subsume); | |
276 ctp->ctp_subsume = ct; | |
277 break; | |
278 case CTPP_PARAMS: | |
6073 | 279 if (param_value & ~CT_PR_ALLPARAM) |
0 | 280 return (EINVAL); |
6073 | 281 ctp->ctp_params = param_value; |
0 | 282 /* |
283 * If an unprivileged process requests that | |
284 * CT_PR_PGRPONLY be set, remove any unsafe events from | |
285 * the critical event set and add them to the | |
286 * informative event set. | |
287 */ | |
288 if ((ctp->ctp_params & CT_PR_PGRPONLY) && | |
289 EXCESS(ctp, tmpl->ctmpl_ev_crit) && | |
290 !secpolicy_contract_event_choice(cr)) { | |
291 tmpl->ctmpl_ev_info |= (tmpl->ctmpl_ev_crit & ~SAFE_EV); | |
292 tmpl->ctmpl_ev_crit &= SAFE_EV; | |
293 } | |
294 | |
295 break; | |
6073 | 296 case CTPP_SVC_FMRI: |
297 if (error = secpolicy_contract_identity(cr)) | |
298 return (error); | |
299 if (ctp->ctp_svc_fmri != NULL) | |
300 refstr_rele(ctp->ctp_svc_fmri); | |
301 if (strcmp(CT_PR_SVC_DEFAULT, str_value) == 0) | |
302 ctp->ctp_svc_fmri = NULL; | |
303 else | |
304 ctp->ctp_svc_fmri = | |
305 refstr_alloc(str_value); | |
306 break; | |
307 case CTPP_CREATOR_AUX: | |
308 if (ctp->ctp_svc_aux != NULL) | |
309 refstr_rele(ctp->ctp_svc_aux); | |
310 if (param->ctpm_size == 1) /* empty string */ | |
311 ctp->ctp_svc_aux = NULL; | |
312 else | |
313 ctp->ctp_svc_aux = | |
314 refstr_alloc(str_value); | |
315 break; | |
0 | 316 case CTP_EV_CRITICAL: |
317 /* | |
318 * We simply don't allow adding events to the critical | |
319 * event set which aren't permitted by our policy or by | |
320 * privilege. | |
321 */ | |
6073 | 322 if (EXCESS(ctp, param_value) && |
0 | 323 (error = secpolicy_contract_event(cr)) != 0) |
324 return (error); | |
6073 | 325 tmpl->ctmpl_ev_crit = param_value; |
0 | 326 break; |
327 case CTPP_EV_FATAL: | |
6073 | 328 if (param_value & ~CT_PR_ALLFATAL) |
0 | 329 return (EINVAL); |
6073 | 330 ctp->ctp_ev_fatal = param_value; |
0 | 331 /* |
332 * Check to see if an unprivileged process is | |
333 * requesting that events be removed from the fatal | |
334 * event set which are still in the critical event set. | |
335 */ | |
336 if (EXCESS(ctp, tmpl->ctmpl_ev_crit) && | |
337 !secpolicy_contract_event_choice(cr)) { | |
338 int allowed = | |
339 SAFE_EV | (ctp->ctp_params & CT_PR_PGRPONLY) ? | |
340 0 : ctp->ctp_ev_fatal; | |
341 tmpl->ctmpl_ev_info |= (tmpl->ctmpl_ev_crit & ~allowed); | |
342 tmpl->ctmpl_ev_crit &= allowed; | |
343 } | |
344 break; | |
345 default: | |
346 return (EINVAL); | |
347 } | |
348 | |
349 return (0); | |
350 } | |
351 | |
352 /* | |
353 * ctmpl_process_get | |
354 * | |
355 * The process contract template get entry point. Simply fetches and | |
356 * returns the requested term. | |
357 */ | |
358 static int | |
359 ctmpl_process_get(struct ct_template *template, ct_param_t *param) | |
360 { | |
361 ctmpl_process_t *ctp = template->ctmpl_data; | |
6073 | 362 uint64_t *param_value = param->ctpm_value; |
0 | 363 |
6196
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
364 if (param->ctpm_id == CTPP_SUBSUME || |
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
365 param->ctpm_id == CTPP_PARAMS || |
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
366 param->ctpm_id == CTPP_EV_FATAL) { |
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
367 if (param->ctpm_size < sizeof (uint64_t)) |
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
368 return (EINVAL); |
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
369 param->ctpm_size = sizeof (uint64_t); |
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
370 } |
87d174d915a0
6675747 uninitialized kernel memory returned by ctfs when specially crafted parameter is passed to ioctl
acruz
parents:
6073
diff
changeset
|
371 |
0 | 372 switch (param->ctpm_id) { |
373 case CTPP_SUBSUME: | |
6073 | 374 *param_value = ctp->ctp_subsume ? |
0 | 375 ctp->ctp_subsume->ct_id : 0; |
376 break; | |
377 case CTPP_PARAMS: | |
6073 | 378 *param_value = ctp->ctp_params; |
379 break; | |
380 case CTPP_SVC_FMRI: | |
381 if (ctp->ctp_svc_fmri == NULL) { | |
382 param->ctpm_size = | |
383 strlcpy((char *)param->ctpm_value, | |
384 CT_PR_SVC_DEFAULT, param->ctpm_size); | |
385 } else { | |
386 param->ctpm_size = | |
387 strlcpy((char *)param->ctpm_value, | |
388 refstr_value(ctp->ctp_svc_fmri), param->ctpm_size); | |
389 } | |
390 param->ctpm_size++; | |
391 break; | |
392 case CTPP_CREATOR_AUX: | |
393 if (ctp->ctp_svc_aux == NULL) { | |
394 param->ctpm_size = | |
395 strlcpy((char *)param->ctpm_value, | |
396 refstr_value(conp_svc_aux_default), | |
397 param->ctpm_size); | |
398 } else { | |
399 param->ctpm_size = | |
400 strlcpy((char *)param->ctpm_value, | |
401 refstr_value(ctp->ctp_svc_aux), param->ctpm_size); | |
402 } | |
403 param->ctpm_size++; | |
0 | 404 break; |
405 case CTPP_EV_FATAL: | |
6073 | 406 *param_value = ctp->ctp_ev_fatal; |
0 | 407 break; |
408 default: | |
409 return (EINVAL); | |
410 } | |
411 | |
412 return (0); | |
413 } | |
414 | |
415 static ctmplops_t ctmpl_process_ops = { | |
416 ctmpl_process_dup, /* ctop_dup */ | |
417 ctmpl_process_free, /* ctop_free */ | |
418 ctmpl_process_set, /* ctop_set */ | |
419 ctmpl_process_get, /* ctop_get */ | |
420 ctmpl_create_inval, /* ctop_create */ | |
421 CT_PR_ALLEVENT | |
422 }; | |
423 | |
424 | |
425 /* | |
426 * Process contract implementation | |
427 */ | |
428 | |
429 /* | |
430 * ctmpl_process_default | |
431 * | |
432 * The process contract default template entry point. Creates a | |
433 * process contract template with no parameters set, with informative | |
434 * core and signal events, critical empty and hwerr events, and fatal | |
435 * hwerr events. | |
436 */ | |
437 static ct_template_t * | |
438 contract_process_default(void) | |
439 { | |
440 ctmpl_process_t *new; | |
441 | |
442 new = kmem_alloc(sizeof (ctmpl_process_t), KM_SLEEP); | |
443 ctmpl_init(&new->ctp_ctmpl, &ctmpl_process_ops, process_type, new); | |
444 | |
445 new->ctp_subsume = NULL; | |
446 new->ctp_params = 0; | |
447 new->ctp_ctmpl.ctmpl_ev_info = CT_PR_EV_CORE | CT_PR_EV_SIGNAL; | |
448 new->ctp_ctmpl.ctmpl_ev_crit = CT_PR_EV_EMPTY | CT_PR_EV_HWERR; | |
449 new->ctp_ev_fatal = CT_PR_EV_HWERR; | |
6073 | 450 new->ctp_svc_fmri = NULL; |
451 new->ctp_svc_aux = NULL; | |
0 | 452 |
453 return (&new->ctp_ctmpl); | |
454 } | |
455 | |
456 /* | |
457 * contract_process_free | |
458 * | |
459 * The process contract free entry point. | |
460 */ | |
461 static void | |
462 contract_process_free(contract_t *ct) | |
463 { | |
464 cont_process_t *ctp = ct->ct_data; | |
465 crfree(ctp->conp_cred); | |
466 list_destroy(&ctp->conp_members); | |
467 list_destroy(&ctp->conp_inherited); | |
6073 | 468 if (ctp->conp_svc_fmri != NULL) { |
469 refstr_rele(ctp->conp_svc_fmri); | |
470 } | |
471 if (ctp->conp_svc_aux != NULL) { | |
472 refstr_rele(ctp->conp_svc_aux); | |
473 } | |
474 if (ctp->conp_svc_creator != NULL) { | |
475 refstr_rele(ctp->conp_svc_creator); | |
476 } | |
0 | 477 kmem_free(ctp, sizeof (cont_process_t)); |
478 } | |
479 | |
480 /* | |
481 * contract_process_cankill | |
482 * | |
483 * Determine if the contract author had or if the process generating | |
484 * the event, sp, has adequate privileges to kill process tp. | |
485 */ | |
486 static int | |
487 contract_process_cankill(proc_t *tp, proc_t *sp, cont_process_t *ctp) | |
488 { | |
489 int cankill; | |
490 | |
491 mutex_enter(&tp->p_crlock); | |
7873
e3677dd00778
Mediate some process operations
Stephen Smalley <sds@tycho.nsa.gov>
parents:
6196
diff
changeset
|
492 cankill = hasprocperm(tp->p_cred, ctp->conp_cred, PROCESS__SIGKILL); |
0 | 493 mutex_exit(&tp->p_crlock); |
7873
e3677dd00778
Mediate some process operations
Stephen Smalley <sds@tycho.nsa.gov>
parents:
6196
diff
changeset
|
494 if (cankill || (sp && prochasprocperm(tp, sp, CRED(), |
7887
f9ded24b041a
[fmac-discuss] [PATCH] Fix more cstyle issues
Stephen Smalley <sds@tycho.nsa.gov>
parents:
7873
diff
changeset
|
495 PROCESS__SIGKILL))) |
0 | 496 return (1); |
497 | |
498 return (0); | |
499 } | |
500 | |
501 /* | |
502 * contract_process_kill | |
503 * | |
504 * Kills all processes in a contract, or all processes in the | |
505 * intersection of a contract and ex's process group (if ex is non-NULL | |
506 * and the contract's PGRPONLY parameter is set). If checkpriv is | |
507 * true, only those processes which may be signaled by the contract | |
508 * author or ex are killed. | |
509 */ | |
510 static void | |
511 contract_process_kill(contract_t *ct, proc_t *ex, int checkpriv) | |
512 { | |
513 cont_process_t *ctp = ct->ct_data; | |
514 proc_t *p; | |
515 pid_t pgrp = -1; | |
516 | |
517 ASSERT(MUTEX_HELD(&ct->ct_lock)); | |
518 | |
519 if (ex && (ctp->conp_params & CT_PR_PGRPONLY)) { | |
520 pgrp = ex->p_pgrp; | |
521 mutex_enter(&pidlock); | |
522 } | |
523 | |
524 for (p = list_head(&ctp->conp_members); p != NULL; | |
525 p = list_next(&ctp->conp_members, p)) { | |
526 if ((p == ex) || (pgrp != -1 && p->p_pgrp != pgrp) || | |
527 (checkpriv && !contract_process_cankill(p, ex, ctp))) | |
528 continue; | |
529 | |
530 psignal(p, SIGKILL); | |
531 } | |
532 | |
533 if (pgrp != -1) | |
534 mutex_exit(&pidlock); | |
535 } | |
536 | |
537 | |
538 /* | |
539 * contract_process_accept | |
540 * | |
541 * Tests if the process contract is willing to act as a regent for | |
542 * inherited contracts. Though brief and only called from one place, | |
543 * this functionality is kept here to avoid including knowledge of | |
544 * process contract implementation in the generic contract code. | |
545 */ | |
546 int | |
547 contract_process_accept(contract_t *parent) | |
548 { | |
549 cont_process_t *ctp = parent->ct_data; | |
550 | |
551 ASSERT(parent->ct_type == process_type); | |
552 | |
553 return (ctp->conp_params & CT_PR_REGENT); | |
554 } | |
555 | |
556 /* | |
557 * contract_process_take | |
558 * | |
559 * Executes the process contract side of inheriting a contract. | |
560 */ | |
561 void | |
562 contract_process_take(contract_t *parent, contract_t *child) | |
563 { | |
564 cont_process_t *ctp = parent->ct_data; | |
565 | |
566 ASSERT(MUTEX_HELD(&parent->ct_lock)); | |
567 ASSERT(MUTEX_HELD(&child->ct_lock)); | |
568 ASSERT(parent->ct_type == process_type); | |
569 ASSERT(ctp->conp_params & CT_PR_REGENT); | |
570 | |
571 list_insert_head(&ctp->conp_inherited, child); | |
572 ctp->conp_ninherited++; | |
573 } | |
574 | |
575 /* | |
576 * contract_process_adopt | |
577 * | |
578 * Executes the process contract side of adopting a contract. | |
579 */ | |
580 void | |
581 contract_process_adopt(contract_t *ct, proc_t *p) | |
582 { | |
583 cont_process_t *parent = p->p_ct_process; | |
584 | |
585 ASSERT(MUTEX_HELD(&parent->conp_contract.ct_lock)); | |
586 ASSERT(MUTEX_HELD(&ct->ct_lock)); | |
587 | |
588 list_remove(&parent->conp_inherited, ct); | |
589 parent->conp_ninherited--; | |
590 | |
591 /* | |
592 * We drop the parent lock first because a) we are passing the | |
593 * contract reference to the child, and b) contract_adopt | |
594 * expects us to return with the contract lock held. | |
595 */ | |
596 mutex_exit(&parent->conp_contract.ct_lock); | |
597 } | |
598 | |
599 /* | |
4845 | 600 * contract_process_abandon |
0 | 601 * |
602 * The process contract abandon entry point. | |
603 */ | |
604 static void | |
605 contract_process_abandon(contract_t *ct) | |
606 { | |
607 cont_process_t *ctp = ct->ct_data; | |
608 | |
609 ASSERT(MUTEX_HELD(&ct->ct_lock)); | |
610 | |
611 /* | |
612 * Shall we stay or shall we go? | |
613 */ | |
614 if (list_head(&ctp->conp_members) == NULL) { | |
615 contract_destroy(ct); | |
616 } else { | |
617 /* | |
618 * Strictly speaking, we actually do orphan the contract. | |
619 * Assuming our credentials allow us to kill all | |
620 * processes in the contract, this is only temporary. | |
621 */ | |
622 if (ctp->conp_params & CT_PR_NOORPHAN) | |
623 contract_process_kill(ct, NULL, B_TRUE); | |
624 contract_orphan(ct); | |
625 mutex_exit(&ct->ct_lock); | |
626 contract_rele(ct); | |
627 } | |
628 } | |
629 | |
630 /* | |
631 * contract_process_destroy | |
632 * | |
633 * The process contract destroy entry point. | |
634 */ | |
635 static void | |
636 contract_process_destroy(contract_t *ct) | |
637 { | |
638 cont_process_t *ctp = ct->ct_data; | |
639 contract_t *cct; | |
640 | |
641 ASSERT(MUTEX_HELD(&ct->ct_lock)); | |
642 | |
643 /* | |
644 * contract_destroy all empty children, kill or orphan the rest | |
645 */ | |
646 while (cct = list_head(&ctp->conp_inherited)) { | |
647 mutex_enter(&cct->ct_lock); | |
648 | |
649 ASSERT(cct->ct_state == CTS_INHERITED); | |
650 | |
651 list_remove(&ctp->conp_inherited, cct); | |
652 ctp->conp_ninherited--; | |
653 cct->ct_regent = NULL; | |
654 cct->ct_type->ct_type_ops->contop_abandon(cct); | |
655 } | |
656 } | |
657 | |
658 /* | |
659 * contract_process_status | |
660 * | |
661 * The process contract status entry point. | |
662 */ | |
663 static void | |
664 contract_process_status(contract_t *ct, zone_t *zone, int detail, nvlist_t *nvl, | |
665 void *status, model_t model) | |
666 { | |
667 cont_process_t *ctp = ct->ct_data; | |
668 uint32_t *pids, *ctids; | |
669 uint_t npids, nctids; | |
670 uint_t spids, sctids; | |
6073 | 671 ctid_t local_svc_zone_enter; |
0 | 672 |
673 if (detail == CTD_FIXED) { | |
674 mutex_enter(&ct->ct_lock); | |
675 contract_status_common(ct, zone, status, model); | |
6073 | 676 local_svc_zone_enter = ctp->conp_svc_zone_enter; |
0 | 677 mutex_exit(&ct->ct_lock); |
678 } else { | |
679 contract_t *cnext; | |
680 proc_t *pnext; | |
681 uint_t loc; | |
682 | |
683 ASSERT(detail == CTD_ALL); | |
684 mutex_enter(&ct->ct_lock); | |
685 for (;;) { | |
686 spids = ctp->conp_nmembers + 5; | |
687 sctids = ctp->conp_ninherited + 5; | |
688 mutex_exit(&ct->ct_lock); | |
689 | |
690 pids = kmem_alloc(spids * sizeof (uint32_t), KM_SLEEP); | |
691 ctids = kmem_alloc(sctids * sizeof (uint32_t), | |
692 KM_SLEEP); | |
693 | |
694 mutex_enter(&ct->ct_lock); | |
695 npids = ctp->conp_nmembers; | |
696 nctids = ctp->conp_ninherited; | |
697 if (spids >= npids && sctids >= nctids) | |
698 break; | |
699 | |
700 kmem_free(pids, spids * sizeof (uint32_t)); | |
701 kmem_free(ctids, sctids * sizeof (uint32_t)); | |
702 } | |
703 contract_status_common(ct, zone, status, model); | |
704 for (loc = 0, cnext = list_head(&ctp->conp_inherited); cnext; | |
705 cnext = list_next(&ctp->conp_inherited, cnext)) | |
706 ctids[loc++] = cnext->ct_id; | |
707 ASSERT(loc == nctids); | |
708 for (loc = 0, pnext = list_head(&ctp->conp_members); pnext; | |
709 pnext = list_next(&ctp->conp_members, pnext)) | |
710 pids[loc++] = pnext->p_pid; | |
711 ASSERT(loc == npids); | |
6073 | 712 local_svc_zone_enter = ctp->conp_svc_zone_enter; |
0 | 713 mutex_exit(&ct->ct_lock); |
714 } | |
715 | |
716 /* | |
717 * Contract terms are static; there's no need to hold the | |
718 * contract lock while accessing them. | |
719 */ | |
720 VERIFY(nvlist_add_uint32(nvl, CTPS_PARAMS, ctp->conp_params) == 0); | |
721 VERIFY(nvlist_add_uint32(nvl, CTPS_EV_FATAL, ctp->conp_ev_fatal) == 0); | |
722 if (detail == CTD_ALL) { | |
723 VERIFY(nvlist_add_uint32_array(nvl, CTPS_MEMBERS, pids, | |
724 npids) == 0); | |
725 VERIFY(nvlist_add_uint32_array(nvl, CTPS_CONTRACTS, ctids, | |
726 nctids) == 0); | |
6073 | 727 VERIFY(nvlist_add_string(nvl, CTPS_CREATOR_AUX, |
728 refstr_value(ctp->conp_svc_aux)) == 0); | |
729 VERIFY(nvlist_add_string(nvl, CTPS_SVC_CREATOR, | |
730 refstr_value(ctp->conp_svc_creator)) == 0); | |
0 | 731 kmem_free(pids, spids * sizeof (uint32_t)); |
732 kmem_free(ctids, sctids * sizeof (uint32_t)); | |
733 } | |
6073 | 734 |
735 /* | |
736 * if we are in a local zone and svc_fmri was inherited from | |
737 * the global zone, we provide fake svc_fmri and svc_ctid | |
738 */ | |
739 if (local_svc_zone_enter == 0|| | |
740 zone->zone_uniqid == GLOBAL_ZONEUNIQID) { | |
741 if (detail > CTD_COMMON) { | |
742 VERIFY(nvlist_add_int32(nvl, CTPS_SVC_CTID, | |
743 ctp->conp_svc_ctid) == 0); | |
744 } | |
745 if (detail == CTD_ALL) { | |
746 VERIFY(nvlist_add_string(nvl, CTPS_SVC_FMRI, | |
747 refstr_value(ctp->conp_svc_fmri)) == 0); | |
748 } | |
749 } else { | |
750 if (detail > CTD_COMMON) { | |
751 VERIFY(nvlist_add_int32(nvl, CTPS_SVC_CTID, | |
752 local_svc_zone_enter) == 0); | |
753 } | |
754 if (detail == CTD_ALL) { | |
755 VERIFY(nvlist_add_string(nvl, CTPS_SVC_FMRI, | |
756 CT_PR_SVC_FMRI_ZONE_ENTER) == 0); | |
757 } | |
758 } | |
0 | 759 } |
760 | |
4845 | 761 /*ARGSUSED*/ |
762 static int | |
763 contract_process_newct(contract_t *ct) | |
764 { | |
765 return (0); | |
766 } | |
767 | |
768 /* process contracts don't negotiate */ | |
0 | 769 static contops_t contract_process_ops = { |
770 contract_process_free, /* contop_free */ | |
771 contract_process_abandon, /* contop_abandon */ | |
772 contract_process_destroy, /* contop_destroy */ | |
4845 | 773 contract_process_status, /* contop_status */ |
774 contract_ack_inval, /* contop_ack */ | |
775 contract_ack_inval, /* contop_nack */ | |
776 contract_qack_inval, /* contop_qack */ | |
777 contract_process_newct /* contop_newct */ | |
0 | 778 }; |
779 | |
780 /* | |
781 * contract_process_init | |
782 * | |
783 * Initializes the process contract type. Also creates a template for | |
784 * use by newproc() when it creates user processes. | |
785 */ | |
786 void | |
787 contract_process_init(void) | |
788 { | |
789 process_type = contract_type_init(CTT_PROCESS, "process", | |
790 &contract_process_ops, contract_process_default); | |
791 | |
792 /* | |
793 * Create a template for use with init(1M) and other | |
794 * kernel-started processes. | |
795 */ | |
796 sys_process_tmpl = kmem_alloc(sizeof (ctmpl_process_t), KM_SLEEP); | |
797 ctmpl_init(&sys_process_tmpl->ctp_ctmpl, &ctmpl_process_ops, | |
798 process_type, sys_process_tmpl); | |
799 sys_process_tmpl->ctp_subsume = NULL; | |
800 sys_process_tmpl->ctp_params = CT_PR_NOORPHAN; | |
801 sys_process_tmpl->ctp_ev_fatal = CT_PR_EV_HWERR; | |
6073 | 802 sys_process_tmpl->ctp_svc_fmri = |
803 refstr_alloc("svc:/system/init:default"); | |
804 sys_process_tmpl->ctp_svc_aux = refstr_alloc(""); | |
805 conp_svc_aux_default = sys_process_tmpl->ctp_svc_aux; | |
806 refstr_hold(conp_svc_aux_default); | |
0 | 807 } |
808 | |
809 /* | |
810 * contract_process_create | |
811 * | |
812 * create a process contract given template "tmpl" and parent process | |
813 * "parent". May fail and return NULL if project.max-contracts would | |
814 * have been exceeded. | |
815 */ | |
816 static cont_process_t * | |
817 contract_process_create(ctmpl_process_t *tmpl, proc_t *parent, int canfail) | |
818 { | |
819 cont_process_t *ctp; | |
820 | |
821 ASSERT(tmpl != NULL); | |
822 | |
823 (void) contract_type_pbundle(process_type, parent); | |
824 | |
825 ctp = kmem_zalloc(sizeof (cont_process_t), KM_SLEEP); | |
826 | |
827 list_create(&ctp->conp_members, sizeof (proc_t), | |
828 offsetof(proc_t, p_ct_member)); | |
829 list_create(&ctp->conp_inherited, sizeof (contract_t), | |
830 offsetof(contract_t, ct_ctlist)); | |
831 mutex_enter(&tmpl->ctp_ctmpl.ctmpl_lock); | |
832 ctp->conp_params = tmpl->ctp_params; | |
833 ctp->conp_ev_fatal = tmpl->ctp_ev_fatal; | |
834 crhold(ctp->conp_cred = CRED()); | |
835 | |
836 if (contract_ctor(&ctp->conp_contract, process_type, &tmpl->ctp_ctmpl, | |
837 ctp, (ctp->conp_params & CT_PR_INHERIT) ? CTF_INHERIT : 0, | |
838 parent, canfail)) { | |
839 mutex_exit(&tmpl->ctp_ctmpl.ctmpl_lock); | |
840 contract_process_free(&ctp->conp_contract); | |
841 return (NULL); | |
842 } | |
843 | |
844 /* | |
6073 | 845 * inherit svc_fmri if not defined by consumer. In this case, inherit |
846 * also svc_ctid to keep track of the contract id where | |
847 * svc_fmri was set | |
848 */ | |
849 if (tmpl->ctp_svc_fmri == NULL) { | |
850 ctp->conp_svc_fmri = parent->p_ct_process->conp_svc_fmri; | |
851 ctp->conp_svc_ctid = parent->p_ct_process->conp_svc_ctid; | |
852 ctp->conp_svc_zone_enter = | |
853 parent->p_ct_process->conp_svc_zone_enter; | |
854 } else { | |
855 ctp->conp_svc_fmri = tmpl->ctp_svc_fmri; | |
856 ctp->conp_svc_ctid = ctp->conp_contract.ct_id; | |
857 /* make svc_zone_enter flag false when svc_fmri is set */ | |
858 ctp->conp_svc_zone_enter = 0; | |
859 } | |
860 refstr_hold(ctp->conp_svc_fmri); | |
861 /* set svc_aux to default value if not defined in template */ | |
862 if (tmpl->ctp_svc_aux == NULL) { | |
863 ctp->conp_svc_aux = conp_svc_aux_default; | |
864 } else { | |
865 ctp->conp_svc_aux = tmpl->ctp_svc_aux; | |
866 } | |
867 refstr_hold(ctp->conp_svc_aux); | |
868 /* | |
869 * set svc_creator to execname | |
870 * We special case pid0 because when newproc() creates | |
871 * the init process, the p_user.u_comm field of sched's proc_t | |
872 * has not been populated yet. | |
873 */ | |
874 if (parent->p_pidp == &pid0) /* if the kernel is the creator */ | |
875 ctp->conp_svc_creator = refstr_alloc("sched"); | |
876 else | |
877 ctp->conp_svc_creator = refstr_alloc(parent->p_user.u_comm); | |
878 | |
879 /* | |
0 | 880 * Transfer subcontracts only after new contract is visible. |
881 * Also, only transfer contracts if the parent matches -- we | |
882 * don't want to create a cycle in the tree of contracts. | |
883 */ | |
884 if (tmpl->ctp_subsume && tmpl->ctp_subsume->ct_owner == parent) { | |
885 cont_process_t *sct = tmpl->ctp_subsume->ct_data; | |
886 contract_t *ct; | |
887 | |
888 mutex_enter(&tmpl->ctp_subsume->ct_lock); | |
889 mutex_enter(&ctp->conp_contract.ct_lock); | |
890 while (ct = list_head(&sct->conp_inherited)) { | |
891 mutex_enter(&ct->ct_lock); | |
892 list_remove(&sct->conp_inherited, ct); | |
893 list_insert_tail(&ctp->conp_inherited, ct); | |
894 ct->ct_regent = &ctp->conp_contract; | |
895 mutex_exit(&ct->ct_lock); | |
896 } | |
897 ctp->conp_ninherited += sct->conp_ninherited; | |
898 sct->conp_ninherited = 0; | |
899 mutex_exit(&ctp->conp_contract.ct_lock); | |
900 mutex_exit(&tmpl->ctp_subsume->ct_lock); | |
901 | |
902 /* | |
903 * Automatically abandon the contract. | |
904 */ | |
905 (void) contract_abandon(tmpl->ctp_subsume, parent, 1); | |
906 } | |
907 | |
908 mutex_exit(&tmpl->ctp_ctmpl.ctmpl_lock); | |
909 | |
910 return (ctp); | |
911 } | |
912 | |
913 /* | |
914 * contract_process_exit | |
915 * | |
916 * Called on process exit. Removes process p from process contract | |
917 * ctp. Generates an exit event, if requested. Generates an empty | |
918 * event, if p is the last member of the the process contract and empty | |
919 * events were requested. | |
920 */ | |
921 void | |
922 contract_process_exit(cont_process_t *ctp, proc_t *p, int exitstatus) | |
923 { | |
924 contract_t *ct = &ctp->conp_contract; | |
925 ct_kevent_t *event; | |
926 int empty; | |
927 | |
928 /* | |
929 * Remove self from process contract. | |
930 */ | |
931 mutex_enter(&ct->ct_lock); | |
932 list_remove(&ctp->conp_members, p); | |
933 ctp->conp_nmembers--; | |
934 mutex_enter(&p->p_lock); /* in case /proc is watching */ | |
935 p->p_ct_process = NULL; | |
936 mutex_exit(&p->p_lock); | |
937 | |
938 /* | |
939 * We check for emptiness before dropping the contract lock to | |
940 * send the exit event, otherwise we could end up with two | |
941 * empty events. | |
942 */ | |
943 empty = (list_head(&ctp->conp_members) == NULL); | |
944 if (EVSENDP(ctp, CT_PR_EV_EXIT)) { | |
945 nvlist_t *nvl; | |
946 | |
947 mutex_exit(&ct->ct_lock); | |
948 VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); | |
949 VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0); | |
950 VERIFY(nvlist_add_int32(nvl, CTPE_EXITSTATUS, exitstatus) == 0); | |
951 | |
952 event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP); | |
953 event->cte_flags = EVINFOP(ctp, CT_PR_EV_EXIT) ? CTE_INFO : 0; | |
954 event->cte_type = CT_PR_EV_EXIT; | |
4845 | 955 (void) cte_publish_all(ct, event, nvl, NULL); |
0 | 956 mutex_enter(&ct->ct_lock); |
957 } | |
958 if (empty) { | |
959 /* | |
960 * Send EMPTY message. | |
961 */ | |
962 if (EVSENDP(ctp, CT_PR_EV_EMPTY)) { | |
963 nvlist_t *nvl; | |
964 | |
965 mutex_exit(&ct->ct_lock); | |
966 VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, | |
967 KM_SLEEP) == 0); | |
968 VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0); | |
969 | |
970 event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP); | |
971 event->cte_flags = EVINFOP(ctp, CT_PR_EV_EMPTY) ? | |
972 CTE_INFO : 0; | |
973 event->cte_type = CT_PR_EV_EMPTY; | |
4845 | 974 (void) cte_publish_all(ct, event, nvl, NULL); |
0 | 975 mutex_enter(&ct->ct_lock); |
976 } | |
977 | |
978 /* | |
979 * The last one to leave an orphaned contract turns out | |
980 * the lights. | |
981 */ | |
982 if (ct->ct_state == CTS_ORPHAN) { | |
983 contract_destroy(ct); | |
984 return; | |
985 } | |
986 } | |
987 mutex_exit(&ct->ct_lock); | |
988 contract_rele(ct); | |
989 } | |
990 | |
991 /* | |
992 * contract_process_fork | |
993 * | |
994 * Called on process fork. If the current lwp has a active process | |
995 * contract template, we attempt to create a new process contract. | |
996 * Failure to create a process contract when required is a failure in | |
997 * fork so, in such an event, we return NULL. | |
998 * | |
999 * Assuming we succeeded or skipped the previous step, we add the child | |
1000 * process to the new contract (success) or to the parent's process | |
1001 * contract (skip). If requested, we also send a fork event to that | |
1002 * contract. | |
1003 * | |
1004 * Because contract_process_fork() may fail, and because we would | |
1005 * prefer that process contracts not be created for processes which | |
1006 * don't complete forking, this should be the last function called | |
1007 * before the "all clear" point in cfork. | |
1008 */ | |
1009 cont_process_t * | |
1010 contract_process_fork(ctmpl_process_t *rtmpl, proc_t *cp, proc_t *pp, | |
1011 int canfail) | |
1012 { | |
1013 contract_t *ct; | |
1014 cont_process_t *ctp; | |
1015 ct_kevent_t *event; | |
1016 ct_template_t *tmpl; | |
1017 | |
1018 if (rtmpl == NULL && (tmpl = ttolwp(curthread)->lwp_ct_active[ | |
1019 process_type->ct_type_index]) != NULL) | |
1020 rtmpl = tmpl->ctmpl_data; | |
1021 | |
1022 if (rtmpl == NULL) | |
1023 ctp = curproc->p_ct_process; | |
1024 else if ((ctp = contract_process_create(rtmpl, pp, canfail)) == NULL) | |
1025 return (NULL); | |
1026 | |
1027 ct = &ctp->conp_contract; | |
1028 /* | |
1029 * Prevent contract_process_kill() from missing forked children | |
1030 * by failing forks by parents that have just been killed. | |
1031 * It's not worth hoisting the ctp test since contract creation | |
1032 * is by no means the common case. | |
1033 */ | |
1034 mutex_enter(&ct->ct_lock); | |
1035 mutex_enter(&pp->p_lock); | |
1036 if (ctp == curproc->p_ct_process && (pp->p_flag & SKILLED) != 0 && | |
1037 canfail) { | |
1038 mutex_exit(&pp->p_lock); | |
1039 mutex_exit(&ct->ct_lock); | |
1040 return (NULL); | |
1041 } | |
1042 cp->p_ct_process = ctp; | |
1043 mutex_exit(&pp->p_lock); | |
1044 contract_hold(ct); | |
1045 list_insert_head(&ctp->conp_members, cp); | |
1046 ctp->conp_nmembers++; | |
1047 mutex_exit(&ct->ct_lock); | |
1048 if (EVSENDP(ctp, CT_PR_EV_FORK)) { | |
1049 nvlist_t *nvl; | |
1050 | |
1051 VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); | |
1052 VERIFY(nvlist_add_uint32(nvl, CTPE_PID, cp->p_pid) == 0); | |
1053 VERIFY(nvlist_add_uint32(nvl, CTPE_PPID, pp->p_pid) == 0); | |
1054 | |
1055 event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP); | |
1056 event->cte_flags = EVINFOP(ctp, CT_PR_EV_FORK) ? CTE_INFO : 0; | |
1057 event->cte_type = CT_PR_EV_FORK; | |
4845 | 1058 (void) cte_publish_all(ct, event, nvl, NULL); |
0 | 1059 } |
1060 return (ctp); | |
1061 } | |
1062 | |
1063 /* | |
1064 * contract_process_core | |
1065 * | |
1066 * Called on core file generation attempts. Generates a core event, if | |
1067 * requested, containing the names of the process, global, and | |
1068 * system-global ("zone") core files. If dumping core is in the fatal | |
1069 * event set, calls contract_process_kill(). | |
1070 */ | |
1071 void | |
1072 contract_process_core(cont_process_t *ctp, proc_t *p, int sig, | |
1073 const char *process, const char *global, const char *zone) | |
1074 { | |
1075 contract_t *ct = &ctp->conp_contract; | |
1076 | |
1077 if (EVSENDP(ctp, CT_PR_EV_CORE)) { | |
1078 ct_kevent_t *event; | |
1079 nvlist_t *nvl, *gnvl = NULL; | |
1080 | |
1081 VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); | |
1082 VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0); | |
1083 VERIFY(nvlist_add_uint32(nvl, CTPE_SIGNAL, sig) == 0); | |
1084 if (process) | |
1085 VERIFY(nvlist_add_string(nvl, CTPE_PCOREFILE, | |
1086 (char *)process) == 0); | |
1087 if (global) | |
1088 VERIFY(nvlist_add_string(nvl, CTPE_GCOREFILE, | |
1089 (char *)global) == 0); | |
1090 | |
1091 if (zone) { | |
1092 /* | |
1093 * Only the global zone is informed of the | |
1094 * local-zone generated global-zone core. | |
1095 */ | |
1096 VERIFY(nvlist_alloc(&gnvl, NV_UNIQUE_NAME, | |
1097 KM_SLEEP) == 0); | |
1098 VERIFY(nvlist_add_string(gnvl, CTPE_ZCOREFILE, | |
1099 (char *)zone) == 0); | |
1100 } | |
1101 | |
1102 event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP); | |
1103 event->cte_flags = EVINFOP(ctp, CT_PR_EV_CORE) ? CTE_INFO : 0; | |
1104 event->cte_type = CT_PR_EV_CORE; | |
4845 | 1105 (void) cte_publish_all(ct, event, nvl, gnvl); |
0 | 1106 } |
1107 | |
1108 if (EVFATALP(ctp, CT_PR_EV_CORE)) { | |
1109 mutex_enter(&ct->ct_lock); | |
1110 contract_process_kill(ct, p, B_TRUE); | |
1111 mutex_exit(&ct->ct_lock); | |
1112 } | |
1113 } | |
1114 | |
1115 /* | |
1116 * contract_process_hwerr | |
1117 * | |
1118 * Called when a process is killed by an unrecoverable hardware error. | |
1119 * Generates an hwerr event, if requested. If hardware errors are in | |
1120 * the fatal event set, calls contract_process_kill(). | |
1121 */ | |
1122 void | |
1123 contract_process_hwerr(cont_process_t *ctp, proc_t *p) | |
1124 { | |
1125 contract_t *ct = &ctp->conp_contract; | |
1126 | |
1127 if (EVSENDP(ctp, CT_PR_EV_HWERR)) { | |
1128 ct_kevent_t *event; | |
1129 nvlist_t *nvl; | |
1130 | |
1131 VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); | |
1132 VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0); | |
1133 | |
1134 event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP); | |
1135 event->cte_flags = EVINFOP(ctp, CT_PR_EV_HWERR) ? CTE_INFO : 0; | |
1136 event->cte_type = CT_PR_EV_HWERR; | |
4845 | 1137 (void) cte_publish_all(ct, event, nvl, NULL); |
0 | 1138 } |
1139 | |
1140 if (EVFATALP(ctp, CT_PR_EV_HWERR)) { | |
1141 mutex_enter(&ct->ct_lock); | |
1142 contract_process_kill(ct, p, B_FALSE); | |
1143 mutex_exit(&ct->ct_lock); | |
1144 } | |
1145 } | |
1146 | |
1147 /* | |
1148 * contract_process_sig | |
1149 * | |
1150 * Called when a process is killed by a signal originating from a | |
1151 * process outside of its process contract or its process contract's | |
1152 * holder. Generates an signal event, if requested, containing the | |
1153 * signal number, and the sender's pid and contract id (if available). | |
1154 * If signals are in the fatal event set, calls | |
1155 * contract_process_kill(). | |
1156 */ | |
1157 void | |
1158 contract_process_sig(cont_process_t *ctp, proc_t *p, int sig, pid_t pid, | |
1159 ctid_t ctid, zoneid_t zoneid) | |
1160 { | |
1161 contract_t *ct = &ctp->conp_contract; | |
1162 | |
1163 if (EVSENDP(ctp, CT_PR_EV_SIGNAL)) { | |
1164 ct_kevent_t *event; | |
1165 nvlist_t *dest, *nvl, *gnvl = NULL; | |
1166 | |
1167 VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); | |
1168 VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0); | |
1169 VERIFY(nvlist_add_uint32(nvl, CTPE_SIGNAL, sig) == 0); | |
1170 | |
1171 if (zoneid >= 0 && p->p_zone->zone_id != zoneid) { | |
1172 VERIFY(nvlist_alloc(&gnvl, NV_UNIQUE_NAME, | |
1173 KM_SLEEP) == 0); | |
1174 dest = gnvl; | |
1175 } else { | |
1176 dest = nvl; | |
1177 } | |
1178 | |
1179 if (pid != -1) | |
1180 VERIFY(nvlist_add_uint32(dest, CTPE_SENDER, pid) == 0); | |
1181 if (ctid != 0) | |
1182 VERIFY(nvlist_add_uint32(dest, CTPE_SENDCT, ctid) == 0); | |
1183 | |
1184 event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP); | |
1185 event->cte_flags = EVINFOP(ctp, CT_PR_EV_SIGNAL) ? CTE_INFO : 0; | |
1186 event->cte_type = CT_PR_EV_SIGNAL; | |
4845 | 1187 (void) cte_publish_all(ct, event, nvl, gnvl); |
0 | 1188 } |
1189 | |
1190 if (EVFATALP(ctp, CT_PR_EV_SIGNAL)) { | |
1191 mutex_enter(&ct->ct_lock); | |
1192 contract_process_kill(ct, p, B_TRUE); | |
1193 mutex_exit(&ct->ct_lock); | |
1194 } | |
1195 } |