#include <sys/mutex.h>
#include <sys/debug.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/kmem.h>
#include <sys/thread.h>
#include <sys/id_space.h>
#include <sys/avl.h>
#include <sys/list.h>
#include <sys/sysmacros.h>
#include <sys/proc.h>
#include <sys/contract.h>
#include <sys/contract_impl.h>
#include <sys/contract/process.h>
#include <sys/contract/process_impl.h>
#include <sys/cmn_err.h>
#include <sys/nvpair.h>
#include <sys/policy.h>
#include <sys/refstr.h>
#include <sys/sunddi.h>
ct_type_t *process_type;
ctmpl_process_t *sys_process_tmpl;
refstr_t *conp_svc_aux_default;
#define EVSENDP(ctp, flag) \
((ctp->conp_contract.ct_ev_info | ctp->conp_contract.ct_ev_crit) & flag)
#define EVINFOP(ctp, flag) \
((ctp->conp_contract.ct_ev_crit & flag) == 0)
#define EVFATALP(ctp, flag) \
(ctp->conp_ev_fatal & flag)
static struct ct_template *
ctmpl_process_dup(struct ct_template *template)
{
ctmpl_process_t *new;
ctmpl_process_t *old = template->ctmpl_data;
new = kmem_alloc(sizeof (ctmpl_process_t), KM_SLEEP);
ctmpl_copy(&new->ctp_ctmpl, template);
new->ctp_ctmpl.ctmpl_data = new;
new->ctp_subsume = old->ctp_subsume;
if (new->ctp_subsume)
contract_hold(new->ctp_subsume);
new->ctp_params = old->ctp_params;
new->ctp_ev_fatal = old->ctp_ev_fatal;
new->ctp_svc_fmri = old->ctp_svc_fmri;
if (new->ctp_svc_fmri != NULL) {
refstr_hold(new->ctp_svc_fmri);
}
new->ctp_svc_aux = old->ctp_svc_aux;
if (new->ctp_svc_aux != NULL) {
refstr_hold(new->ctp_svc_aux);
}
return (&new->ctp_ctmpl);
}
static void
ctmpl_process_free(struct ct_template *template)
{
ctmpl_process_t *ctp = template->ctmpl_data;
if (ctp->ctp_subsume)
contract_rele(ctp->ctp_subsume);
if (ctp->ctp_svc_fmri != NULL) {
refstr_rele(ctp->ctp_svc_fmri);
}
if (ctp->ctp_svc_aux != NULL) {
refstr_rele(ctp->ctp_svc_aux);
}
kmem_free(template, sizeof (ctmpl_process_t));
}
#define SAFE_EV (CT_PR_EV_EMPTY)
#define EXCESS(ctp, value) \
(((value) & ~((ctp)->ctp_ev_fatal | SAFE_EV)) || \
(((value) & ~SAFE_EV) && (ctp->ctp_params & CT_PR_PGRPONLY)))
static int
ctmpl_process_set(struct ct_template *tmpl, ct_kparam_t *kparam,
const cred_t *cr)
{
ctmpl_process_t *ctp = tmpl->ctmpl_data;
ct_param_t *param = &kparam->param;
contract_t *ct;
int error;
uint64_t param_value = 0;
char *str_value;
if ((param->ctpm_id == CTPP_SVC_FMRI) ||
(param->ctpm_id == CTPP_CREATOR_AUX)) {
str_value = (char *)kparam->ctpm_kbuf;
str_value[param->ctpm_size - 1] = '\0';
} else {
if (param->ctpm_size < sizeof (uint64_t))
return (EINVAL);
param_value = *(uint64_t *)kparam->ctpm_kbuf;
if (param_value & ~UINT32_MAX)
return (EINVAL);
}
switch (param->ctpm_id) {
case CTPP_SUBSUME:
if (param_value != 0) {
ct = contract_type_ptr(process_type, param_value,
curproc->p_zone->zone_uniqid);
if (ct == NULL)
return (ESRCH);
if (ct->ct_owner != curproc) {
contract_rele(ct);
return (EACCES);
}
if (((cont_process_t *)ct->ct_data)->conp_nmembers) {
contract_rele(ct);
return (ENOTEMPTY);
}
} else {
ct = NULL;
}
if (ctp->ctp_subsume)
contract_rele(ctp->ctp_subsume);
ctp->ctp_subsume = ct;
break;
case CTPP_PARAMS:
if (param_value & ~CT_PR_ALLPARAM)
return (EINVAL);
ctp->ctp_params = param_value;
if ((ctp->ctp_params & CT_PR_PGRPONLY) &&
EXCESS(ctp, tmpl->ctmpl_ev_crit) &&
!secpolicy_contract_event_choice(cr)) {
tmpl->ctmpl_ev_info |= (tmpl->ctmpl_ev_crit & ~SAFE_EV);
tmpl->ctmpl_ev_crit &= SAFE_EV;
}
break;
case CTPP_SVC_FMRI:
if (error = secpolicy_contract_identity(cr))
return (error);
if (ctp->ctp_svc_fmri != NULL)
refstr_rele(ctp->ctp_svc_fmri);
if (strcmp(CT_PR_SVC_DEFAULT, str_value) == 0)
ctp->ctp_svc_fmri = NULL;
else
ctp->ctp_svc_fmri =
refstr_alloc(str_value);
break;
case CTPP_CREATOR_AUX:
if (ctp->ctp_svc_aux != NULL)
refstr_rele(ctp->ctp_svc_aux);
if (param->ctpm_size == 1)
ctp->ctp_svc_aux = NULL;
else
ctp->ctp_svc_aux =
refstr_alloc(str_value);
break;
case CTP_EV_CRITICAL:
if (EXCESS(ctp, param_value) &&
(error = secpolicy_contract_event(cr)) != 0)
return (error);
tmpl->ctmpl_ev_crit = param_value;
break;
case CTPP_EV_FATAL:
if (param_value & ~CT_PR_ALLFATAL)
return (EINVAL);
ctp->ctp_ev_fatal = param_value;
if (EXCESS(ctp, tmpl->ctmpl_ev_crit) &&
!secpolicy_contract_event_choice(cr)) {
int allowed =
SAFE_EV | (ctp->ctp_params & CT_PR_PGRPONLY) ?
0 : ctp->ctp_ev_fatal;
tmpl->ctmpl_ev_info |= (tmpl->ctmpl_ev_crit & ~allowed);
tmpl->ctmpl_ev_crit &= allowed;
}
break;
default:
return (EINVAL);
}
return (0);
}
static int
ctmpl_process_get(struct ct_template *template, ct_kparam_t *kparam)
{
ctmpl_process_t *ctp = template->ctmpl_data;
ct_param_t *param = &kparam->param;
uint64_t *param_value = kparam->ctpm_kbuf;
if (param->ctpm_id == CTPP_SUBSUME ||
param->ctpm_id == CTPP_PARAMS ||
param->ctpm_id == CTPP_EV_FATAL) {
if (param->ctpm_size < sizeof (uint64_t))
return (EINVAL);
kparam->ret_size = sizeof (uint64_t);
}
switch (param->ctpm_id) {
case CTPP_SUBSUME:
*param_value = ctp->ctp_subsume ?
ctp->ctp_subsume->ct_id : 0;
break;
case CTPP_PARAMS:
*param_value = ctp->ctp_params;
break;
case CTPP_SVC_FMRI:
if (ctp->ctp_svc_fmri == NULL) {
kparam->ret_size =
strlcpy((char *)kparam->ctpm_kbuf,
CT_PR_SVC_DEFAULT, param->ctpm_size);
} else {
kparam->ret_size =
strlcpy((char *)kparam->ctpm_kbuf,
refstr_value(ctp->ctp_svc_fmri), param->ctpm_size);
}
kparam->ret_size++;
break;
case CTPP_CREATOR_AUX:
if (ctp->ctp_svc_aux == NULL) {
kparam->ret_size =
strlcpy((char *)kparam->ctpm_kbuf,
refstr_value(conp_svc_aux_default),
param->ctpm_size);
} else {
kparam->ret_size =
strlcpy((char *)kparam->ctpm_kbuf,
refstr_value(ctp->ctp_svc_aux), param->ctpm_size);
}
kparam->ret_size++;
break;
case CTPP_EV_FATAL:
*param_value = ctp->ctp_ev_fatal;
break;
default:
return (EINVAL);
}
return (0);
}
static ctmplops_t ctmpl_process_ops = {
ctmpl_process_dup,
ctmpl_process_free,
ctmpl_process_set,
ctmpl_process_get,
ctmpl_create_inval,
CT_PR_ALLEVENT
};
static ct_template_t *
contract_process_default(void)
{
ctmpl_process_t *new;
new = kmem_alloc(sizeof (ctmpl_process_t), KM_SLEEP);
ctmpl_init(&new->ctp_ctmpl, &ctmpl_process_ops, process_type, new);
new->ctp_subsume = NULL;
new->ctp_params = 0;
new->ctp_ctmpl.ctmpl_ev_info = CT_PR_EV_CORE | CT_PR_EV_SIGNAL;
new->ctp_ctmpl.ctmpl_ev_crit = CT_PR_EV_EMPTY | CT_PR_EV_HWERR;
new->ctp_ev_fatal = CT_PR_EV_HWERR;
new->ctp_svc_fmri = NULL;
new->ctp_svc_aux = NULL;
return (&new->ctp_ctmpl);
}
static void
contract_process_free(contract_t *ct)
{
cont_process_t *ctp = ct->ct_data;
crfree(ctp->conp_cred);
list_destroy(&ctp->conp_members);
list_destroy(&ctp->conp_inherited);
if (ctp->conp_svc_fmri != NULL) {
refstr_rele(ctp->conp_svc_fmri);
}
if (ctp->conp_svc_aux != NULL) {
refstr_rele(ctp->conp_svc_aux);
}
if (ctp->conp_svc_creator != NULL) {
refstr_rele(ctp->conp_svc_creator);
}
kmem_free(ctp, sizeof (cont_process_t));
}
static int
contract_process_cankill(proc_t *tp, proc_t *sp, cont_process_t *ctp)
{
int cankill;
mutex_enter(&tp->p_crlock);
cankill = hasprocperm(tp->p_cred, ctp->conp_cred);
mutex_exit(&tp->p_crlock);
if (cankill || (sp && prochasprocperm(tp, sp, CRED())))
return (1);
return (0);
}
static void
contract_process_kill(contract_t *ct, proc_t *ex, int checkpriv)
{
cont_process_t *ctp = ct->ct_data;
proc_t *p;
pid_t pgrp = -1;
ASSERT(MUTEX_HELD(&ct->ct_lock));
if (ex && (ctp->conp_params & CT_PR_PGRPONLY)) {
pgrp = ex->p_pgrp;
mutex_enter(&pidlock);
}
for (p = list_head(&ctp->conp_members); p != NULL;
p = list_next(&ctp->conp_members, p)) {
if ((p == ex) ||
(pgrp != -1 && (p->p_stat == SIDL || p->p_pgrp != pgrp)) ||
(checkpriv && !contract_process_cankill(p, ex, ctp)))
continue;
psignal(p, SIGKILL);
}
if (pgrp != -1)
mutex_exit(&pidlock);
}
int
contract_process_accept(contract_t *parent)
{
cont_process_t *ctp = parent->ct_data;
ASSERT(parent->ct_type == process_type);
return (ctp->conp_params & CT_PR_REGENT);
}
void
contract_process_take(contract_t *parent, contract_t *child)
{
cont_process_t *ctp = parent->ct_data;
ASSERT(MUTEX_HELD(&parent->ct_lock));
ASSERT(MUTEX_HELD(&child->ct_lock));
ASSERT(parent->ct_type == process_type);
ASSERT(ctp->conp_params & CT_PR_REGENT);
list_insert_head(&ctp->conp_inherited, child);
ctp->conp_ninherited++;
}
void
contract_process_adopt(contract_t *ct, proc_t *p)
{
cont_process_t *parent = p->p_ct_process;
ASSERT(MUTEX_HELD(&parent->conp_contract.ct_lock));
ASSERT(MUTEX_HELD(&ct->ct_lock));
list_remove(&parent->conp_inherited, ct);
parent->conp_ninherited--;
mutex_exit(&parent->conp_contract.ct_lock);
}
static void
contract_process_abandon(contract_t *ct)
{
cont_process_t *ctp = ct->ct_data;
ASSERT(MUTEX_HELD(&ct->ct_lock));
if (list_head(&ctp->conp_members) == NULL) {
contract_destroy(ct);
} else {
if (ctp->conp_params & CT_PR_NOORPHAN)
contract_process_kill(ct, NULL, B_TRUE);
contract_orphan(ct);
mutex_exit(&ct->ct_lock);
contract_rele(ct);
}
}
static void
contract_process_destroy(contract_t *ct)
{
cont_process_t *ctp = ct->ct_data;
contract_t *cct;
ASSERT(MUTEX_HELD(&ct->ct_lock));
while (cct = list_head(&ctp->conp_inherited)) {
mutex_enter(&cct->ct_lock);
ASSERT(cct->ct_state == CTS_INHERITED);
list_remove(&ctp->conp_inherited, cct);
ctp->conp_ninherited--;
cct->ct_regent = NULL;
cct->ct_type->ct_type_ops->contop_abandon(cct);
}
}
static void
contract_process_status(contract_t *ct, zone_t *zone, int detail, nvlist_t *nvl,
void *status, model_t model)
{
cont_process_t *ctp = ct->ct_data;
uint32_t *pids, *ctids;
uint_t npids, nctids;
uint_t spids, sctids;
ctid_t local_svc_zone_enter;
if (detail == CTD_FIXED) {
mutex_enter(&ct->ct_lock);
contract_status_common(ct, zone, status, model);
local_svc_zone_enter = ctp->conp_svc_zone_enter;
mutex_exit(&ct->ct_lock);
pids = NULL;
ctids = NULL;
} else {
contract_t *cnext;
proc_t *pnext;
uint_t loc;
ASSERT(detail == CTD_ALL);
mutex_enter(&ct->ct_lock);
for (;;) {
spids = ctp->conp_nmembers + 5;
sctids = ctp->conp_ninherited + 5;
mutex_exit(&ct->ct_lock);
pids = kmem_alloc(spids * sizeof (uint32_t), KM_SLEEP);
ctids = kmem_alloc(sctids * sizeof (uint32_t),
KM_SLEEP);
mutex_enter(&ct->ct_lock);
npids = ctp->conp_nmembers;
nctids = ctp->conp_ninherited;
if (spids >= npids && sctids >= nctids)
break;
kmem_free(pids, spids * sizeof (uint32_t));
kmem_free(ctids, sctids * sizeof (uint32_t));
}
contract_status_common(ct, zone, status, model);
for (loc = 0, cnext = list_head(&ctp->conp_inherited); cnext;
cnext = list_next(&ctp->conp_inherited, cnext))
ctids[loc++] = cnext->ct_id;
ASSERT(loc == nctids);
for (loc = 0, pnext = list_head(&ctp->conp_members); pnext;
pnext = list_next(&ctp->conp_members, pnext))
pids[loc++] = pnext->p_pid;
ASSERT(loc == npids);
local_svc_zone_enter = ctp->conp_svc_zone_enter;
mutex_exit(&ct->ct_lock);
}
VERIFY(nvlist_add_uint32(nvl, CTPS_PARAMS, ctp->conp_params) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPS_EV_FATAL, ctp->conp_ev_fatal) == 0);
if (detail == CTD_ALL) {
VERIFY(nvlist_add_uint32_array(nvl, CTPS_MEMBERS, pids,
npids) == 0);
VERIFY(nvlist_add_uint32_array(nvl, CTPS_CONTRACTS, ctids,
nctids) == 0);
VERIFY(nvlist_add_string(nvl, CTPS_CREATOR_AUX,
refstr_value(ctp->conp_svc_aux)) == 0);
VERIFY(nvlist_add_string(nvl, CTPS_SVC_CREATOR,
refstr_value(ctp->conp_svc_creator)) == 0);
}
if (ctids != NULL)
kmem_free(ctids, sctids * sizeof (uint32_t));
if (pids != NULL)
kmem_free(pids, spids * sizeof (uint32_t));
if (local_svc_zone_enter == 0 ||
zone->zone_uniqid == GLOBAL_ZONEUNIQID) {
if (detail > CTD_COMMON) {
VERIFY(nvlist_add_int32(nvl, CTPS_SVC_CTID,
ctp->conp_svc_ctid) == 0);
VERIFY(nvlist_add_string(nvl, CTPS_SVC_FMRI,
refstr_value(ctp->conp_svc_fmri)) == 0);
}
} else {
if (detail > CTD_COMMON) {
VERIFY(nvlist_add_int32(nvl, CTPS_SVC_CTID,
local_svc_zone_enter) == 0);
VERIFY(nvlist_add_string(nvl, CTPS_SVC_FMRI,
CT_PR_SVC_FMRI_ZONE_ENTER) == 0);
}
}
}
static int
contract_process_newct(contract_t *ct)
{
return (0);
}
static contops_t contract_process_ops = {
contract_process_free,
contract_process_abandon,
contract_process_destroy,
contract_process_status,
contract_ack_inval,
contract_ack_inval,
contract_qack_inval,
contract_process_newct
};
void
contract_process_init(void)
{
process_type = contract_type_init(CTT_PROCESS, "process",
&contract_process_ops, contract_process_default);
sys_process_tmpl = kmem_alloc(sizeof (ctmpl_process_t), KM_SLEEP);
ctmpl_init(&sys_process_tmpl->ctp_ctmpl, &ctmpl_process_ops,
process_type, sys_process_tmpl);
sys_process_tmpl->ctp_subsume = NULL;
sys_process_tmpl->ctp_params = CT_PR_NOORPHAN;
sys_process_tmpl->ctp_ev_fatal = CT_PR_EV_HWERR;
sys_process_tmpl->ctp_svc_fmri =
refstr_alloc("svc:/system/init:default");
sys_process_tmpl->ctp_svc_aux = refstr_alloc("");
conp_svc_aux_default = sys_process_tmpl->ctp_svc_aux;
refstr_hold(conp_svc_aux_default);
}
static cont_process_t *
contract_process_create(ctmpl_process_t *tmpl, proc_t *parent, int canfail)
{
cont_process_t *ctp;
ASSERT(tmpl != NULL);
(void) contract_type_pbundle(process_type, parent);
ctp = kmem_zalloc(sizeof (cont_process_t), KM_SLEEP);
list_create(&ctp->conp_members, sizeof (proc_t),
offsetof(proc_t, p_ct_member));
list_create(&ctp->conp_inherited, sizeof (contract_t),
offsetof(contract_t, ct_ctlist));
mutex_enter(&tmpl->ctp_ctmpl.ctmpl_lock);
ctp->conp_params = tmpl->ctp_params;
ctp->conp_ev_fatal = tmpl->ctp_ev_fatal;
crhold(ctp->conp_cred = CRED());
if (contract_ctor(&ctp->conp_contract, process_type, &tmpl->ctp_ctmpl,
ctp, (ctp->conp_params & CT_PR_INHERIT) ? CTF_INHERIT : 0,
parent, canfail)) {
mutex_exit(&tmpl->ctp_ctmpl.ctmpl_lock);
contract_process_free(&ctp->conp_contract);
return (NULL);
}
if (tmpl->ctp_svc_fmri == NULL) {
ctp->conp_svc_fmri = parent->p_ct_process->conp_svc_fmri;
ctp->conp_svc_ctid = parent->p_ct_process->conp_svc_ctid;
ctp->conp_svc_zone_enter =
parent->p_ct_process->conp_svc_zone_enter;
} else {
ctp->conp_svc_fmri = tmpl->ctp_svc_fmri;
ctp->conp_svc_ctid = ctp->conp_contract.ct_id;
ctp->conp_svc_zone_enter = 0;
}
refstr_hold(ctp->conp_svc_fmri);
if (tmpl->ctp_svc_aux == NULL) {
ctp->conp_svc_aux = conp_svc_aux_default;
} else {
ctp->conp_svc_aux = tmpl->ctp_svc_aux;
}
refstr_hold(ctp->conp_svc_aux);
if (parent->p_pidp == &pid0)
ctp->conp_svc_creator = refstr_alloc("sched");
else
ctp->conp_svc_creator = refstr_alloc(parent->p_user.u_comm);
if (tmpl->ctp_subsume && tmpl->ctp_subsume->ct_owner == parent) {
cont_process_t *sct = tmpl->ctp_subsume->ct_data;
contract_t *ct;
mutex_enter(&tmpl->ctp_subsume->ct_lock);
mutex_enter(&ctp->conp_contract.ct_lock);
while (ct = list_head(&sct->conp_inherited)) {
mutex_enter(&ct->ct_lock);
list_remove(&sct->conp_inherited, ct);
list_insert_tail(&ctp->conp_inherited, ct);
ct->ct_regent = &ctp->conp_contract;
mutex_exit(&ct->ct_lock);
}
ctp->conp_ninherited += sct->conp_ninherited;
sct->conp_ninherited = 0;
mutex_exit(&ctp->conp_contract.ct_lock);
mutex_exit(&tmpl->ctp_subsume->ct_lock);
(void) contract_abandon(tmpl->ctp_subsume, parent, 1);
}
mutex_exit(&tmpl->ctp_ctmpl.ctmpl_lock);
return (ctp);
}
void
contract_process_exit(cont_process_t *ctp, proc_t *p, int exitstatus)
{
contract_t *ct = &ctp->conp_contract;
ct_kevent_t *event;
int empty;
mutex_enter(&ct->ct_lock);
list_remove(&ctp->conp_members, p);
ctp->conp_nmembers--;
mutex_enter(&p->p_lock);
p->p_ct_process = NULL;
mutex_exit(&p->p_lock);
empty = (list_head(&ctp->conp_members) == NULL);
if (EVSENDP(ctp, CT_PR_EV_EXIT)) {
nvlist_t *nvl;
mutex_exit(&ct->ct_lock);
VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0);
VERIFY(nvlist_add_int32(nvl, CTPE_EXITSTATUS, exitstatus) == 0);
event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP);
event->cte_flags = EVINFOP(ctp, CT_PR_EV_EXIT) ? CTE_INFO : 0;
event->cte_type = CT_PR_EV_EXIT;
(void) cte_publish_all(ct, event, nvl, NULL);
mutex_enter(&ct->ct_lock);
}
if (empty) {
if (EVSENDP(ctp, CT_PR_EV_EMPTY)) {
nvlist_t *nvl;
mutex_exit(&ct->ct_lock);
VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME,
KM_SLEEP) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0);
event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP);
event->cte_flags = EVINFOP(ctp, CT_PR_EV_EMPTY) ?
CTE_INFO : 0;
event->cte_type = CT_PR_EV_EMPTY;
(void) cte_publish_all(ct, event, nvl, NULL);
mutex_enter(&ct->ct_lock);
}
if (ct->ct_state == CTS_ORPHAN) {
contract_destroy(ct);
return;
}
}
mutex_exit(&ct->ct_lock);
contract_rele(ct);
}
cont_process_t *
contract_process_fork(ctmpl_process_t *rtmpl, proc_t *cp, proc_t *pp,
int canfail)
{
contract_t *ct;
cont_process_t *ctp;
ct_kevent_t *event;
ct_template_t *tmpl;
if (rtmpl == NULL && (tmpl = ttolwp(curthread)->lwp_ct_active[
process_type->ct_type_index]) != NULL)
rtmpl = tmpl->ctmpl_data;
if (rtmpl == NULL)
ctp = curproc->p_ct_process;
else if ((ctp = contract_process_create(rtmpl, pp, canfail)) == NULL)
return (NULL);
ct = &ctp->conp_contract;
mutex_enter(&ct->ct_lock);
mutex_enter(&pp->p_lock);
if (ctp == curproc->p_ct_process && (pp->p_flag & SKILLED) != 0 &&
canfail) {
mutex_exit(&pp->p_lock);
mutex_exit(&ct->ct_lock);
return (NULL);
}
cp->p_ct_process = ctp;
mutex_exit(&pp->p_lock);
contract_hold(ct);
list_insert_head(&ctp->conp_members, cp);
ctp->conp_nmembers++;
mutex_exit(&ct->ct_lock);
if (EVSENDP(ctp, CT_PR_EV_FORK)) {
nvlist_t *nvl;
VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_PID, cp->p_pid) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_PPID, pp->p_pid) == 0);
event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP);
event->cte_flags = EVINFOP(ctp, CT_PR_EV_FORK) ? CTE_INFO : 0;
event->cte_type = CT_PR_EV_FORK;
(void) cte_publish_all(ct, event, nvl, NULL);
}
return (ctp);
}
void
contract_process_core(cont_process_t *ctp, proc_t *p, int sig,
const char *process, const char *global, const char *zone)
{
contract_t *ct = &ctp->conp_contract;
if (EVSENDP(ctp, CT_PR_EV_CORE)) {
ct_kevent_t *event;
nvlist_t *nvl, *gnvl = NULL;
VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_SIGNAL, sig) == 0);
if (process)
VERIFY(nvlist_add_string(nvl, CTPE_PCOREFILE,
(char *)process) == 0);
if (global)
VERIFY(nvlist_add_string(nvl, CTPE_GCOREFILE,
(char *)global) == 0);
if (zone) {
VERIFY(nvlist_alloc(&gnvl, NV_UNIQUE_NAME,
KM_SLEEP) == 0);
VERIFY(nvlist_add_string(gnvl, CTPE_ZCOREFILE,
(char *)zone) == 0);
}
event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP);
event->cte_flags = EVINFOP(ctp, CT_PR_EV_CORE) ? CTE_INFO : 0;
event->cte_type = CT_PR_EV_CORE;
(void) cte_publish_all(ct, event, nvl, gnvl);
}
if (EVFATALP(ctp, CT_PR_EV_CORE)) {
mutex_enter(&ct->ct_lock);
contract_process_kill(ct, p, B_TRUE);
mutex_exit(&ct->ct_lock);
}
}
void
contract_process_hwerr(cont_process_t *ctp, proc_t *p)
{
contract_t *ct = &ctp->conp_contract;
if (EVSENDP(ctp, CT_PR_EV_HWERR)) {
ct_kevent_t *event;
nvlist_t *nvl;
VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0);
event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP);
event->cte_flags = EVINFOP(ctp, CT_PR_EV_HWERR) ? CTE_INFO : 0;
event->cte_type = CT_PR_EV_HWERR;
(void) cte_publish_all(ct, event, nvl, NULL);
}
if (EVFATALP(ctp, CT_PR_EV_HWERR)) {
mutex_enter(&ct->ct_lock);
contract_process_kill(ct, p, B_FALSE);
mutex_exit(&ct->ct_lock);
}
}
void
contract_process_sig(cont_process_t *ctp, proc_t *p, int sig, pid_t pid,
ctid_t ctid, zoneid_t zoneid)
{
contract_t *ct = &ctp->conp_contract;
if (EVSENDP(ctp, CT_PR_EV_SIGNAL)) {
ct_kevent_t *event;
nvlist_t *dest, *nvl, *gnvl = NULL;
VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_PID, p->p_pid) == 0);
VERIFY(nvlist_add_uint32(nvl, CTPE_SIGNAL, sig) == 0);
if (zoneid >= 0 && p->p_zone->zone_id != zoneid) {
VERIFY(nvlist_alloc(&gnvl, NV_UNIQUE_NAME,
KM_SLEEP) == 0);
dest = gnvl;
} else {
dest = nvl;
}
if (pid != -1)
VERIFY(nvlist_add_uint32(dest, CTPE_SENDER, pid) == 0);
if (ctid != 0)
VERIFY(nvlist_add_uint32(dest, CTPE_SENDCT, ctid) == 0);
event = kmem_zalloc(sizeof (ct_kevent_t), KM_SLEEP);
event->cte_flags = EVINFOP(ctp, CT_PR_EV_SIGNAL) ? CTE_INFO : 0;
event->cte_type = CT_PR_EV_SIGNAL;
(void) cte_publish_all(ct, event, nvl, gnvl);
}
if (EVFATALP(ctp, CT_PR_EV_SIGNAL)) {
mutex_enter(&ct->ct_lock);
contract_process_kill(ct, p, B_TRUE);
mutex_exit(&ct->ct_lock);
}
}