Print this page
OS-4818 contract template disappears on exec
OS-5311 docker init children not always in the correct contract
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
OS-4937 lxbrand ptracer count updates can race
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
OS-4534 lwp_exit P_PR_LOCK assertion failure
OS-4188 NULL dereference in lwp_hash_in
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
OS-4151 setbrand hooks should be sane during fork
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
OS-4129 lxbrand should not abuse p_brand_data for storing exit signal
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>

*** 23,33 **** * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* ! * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include <sys/param.h> #include <sys/types.h> #include <sys/sysmacros.h> --- 23,33 ---- * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* ! * Copyright 2016, Joyent, Inc. */ #include <sys/param.h> #include <sys/types.h> #include <sys/sysmacros.h>
*** 55,64 **** --- 55,66 ---- #include <sys/lwp_upimutex_impl.h> #include <sys/cpupart.h> #include <sys/lgrp.h> #include <sys/rctl.h> #include <sys/contract_impl.h> + #include <sys/contract/process.h> + #include <sys/contract/process_impl.h> #include <sys/cpc_impl.h> #include <sys/sdt.h> #include <sys/cmn_err.h> #include <sys/brand.h> #include <sys/cyclic.h>
*** 113,123 **** tidhash_t *old_hash = NULL; uint_t old_hashsz = 0; ret_tidhash_t *ret_tidhash = NULL; int i; int rctlfail = 0; ! boolean_t branded = 0; struct ctxop *ctx = NULL; ASSERT(cid != sysdccid); /* system threads must start in SYS */ ASSERT(p != &p0); /* No new LWPs in p0. */ --- 115,125 ---- tidhash_t *old_hash = NULL; uint_t old_hashsz = 0; ret_tidhash_t *ret_tidhash = NULL; int i; int rctlfail = 0; ! void *brand_data = NULL; struct ctxop *ctx = NULL; ASSERT(cid != sysdccid); /* system threads must start in SYS */ ASSERT(p != &p0); /* No new LWPs in p0. */
*** 281,291 **** --- 283,306 ---- /* * Allocate an lwp directory entry for the new lwp. */ lep = kmem_zalloc(sizeof (*lep), KM_SLEEP); + /* + * If necessary, speculatively allocate lwp brand data. This is done + * ahead of time so p_lock need not be dropped during lwp branding. + */ + if (PROC_IS_BRANDED(p) && BROP(p)->b_lwpdata_alloc != NULL) { + if ((brand_data = BROP(p)->b_lwpdata_alloc(p)) == NULL) { mutex_enter(&p->p_lock); + err = 1; + atomic_inc_32(&p->p_zone->zone_ffmisc); + goto error; + } + } + + mutex_enter(&p->p_lock); grow: /* * Grow the lwp (thread) directory and lwpid hash table if necessary. * A note on the growth algorithm: * The new lwp directory size is computed as:
*** 628,649 **** if ((p->p_flag & SLWPWRAP) == 0) break; } while (lwp_hash_lookup(p, t->t_tid) != NULL); } - /* - * If this is a branded process, let the brand do any necessary lwp - * initialization. - */ - if (PROC_IS_BRANDED(p)) { - if (BROP(p)->b_initlwp(lwp)) { - err = 1; - atomic_inc_32(&p->p_zone->zone_ffmisc); - goto error; - } - branded = 1; - } if (t->t_tid == 1) { kpreempt_disable(); ASSERT(t->t_lpl != NULL); p->p_t1_lgrpid = t->t_lpl->lpl_lgrpid; --- 643,652 ----
*** 652,662 **** p->p_tr_lgrpid != p->p_t1_lgrpid) { lgrp_update_trthr_migrations(1); } } - p->p_lwpcnt++; t->t_waitfor = -1; /* * Turn microstate accounting on for thread if on for process. */ --- 655,664 ----
*** 694,705 **** --- 696,726 ---- */ t->t_pre_sys = 1; t->t_post_sys = 1; /* + * Perform lwp branding + * + * The b_initlwp hook is _not_ allowed to drop p->p_lock as it must be + * continuously held between when the tidhash is sized and when the lwp + * is inserted into it. Operations requiring p->p_lock to be + * temporarily dropped can be performed in b_initlwp_post. + */ + if (PROC_IS_BRANDED(p)) { + BROP(p)->b_initlwp(lwp, brand_data); + /* + * The b_initlwp hook is expected to consume any preallocated + * brand_data in a way that prepares it for deallocation by the + * b_freelwp hook. + */ + brand_data = NULL; + } + + /* * Insert the new thread into the list of all threads. */ + p->p_lwpcnt++; if ((tx = p->p_tlist) == NULL) { t->t_back = t; t->t_forw = t; p->p_tlist = t; } else {
*** 716,725 **** --- 737,753 ---- lep->le_thread = t; lep->le_lwpid = t->t_tid; lep->le_start = t->t_start; lwp_hash_in(p, lep, p->p_tidhash, p->p_tidhash_sz, 1); + /* + * Complete lwp branding + */ + if (PROC_IS_BRANDED(p) && BROP(p)->b_initlwp_post != NULL) { + BROP(p)->b_initlwp_post(lwp); + } + if (state == TS_RUN) { /* * We set the new lwp running immediately. */ t->t_proc_flag &= ~TP_HOLDLWP;
*** 751,762 **** p->p_zone->zone_nlwps--; mutex_exit(&p->p_zone->zone_nlwps_lock); if (cid != NOCLASS && bufp != NULL) CL_FREE(cid, bufp); ! if (branded) ! BROP(p)->b_freelwp(lwp); mutex_exit(&p->p_lock); t->t_state = TS_FREE; thread_rele(t); --- 779,791 ---- p->p_zone->zone_nlwps--; mutex_exit(&p->p_zone->zone_nlwps_lock); if (cid != NOCLASS && bufp != NULL) CL_FREE(cid, bufp); ! if (brand_data != NULL) { ! BROP(p)->b_lwpdata_free(brand_data); ! } mutex_exit(&p->p_lock); t->t_state = TS_FREE; thread_rele(t);
*** 825,859 **** lwp_ctmpl_copy(klwp_t *dst, klwp_t *src) { int i; for (i = 0; i < ct_ntypes; i++) { ! dst->lwp_ct_active[i] = ctmpl_dup(src->lwp_ct_active[i]); dst->lwp_ct_latest[i] = NULL; } } /* * Clear an LWP's contract template state. */ void ! lwp_ctmpl_clear(klwp_t *lwp) { ct_template_t *tmpl; int i; for (i = 0; i < ct_ntypes; i++) { - if ((tmpl = lwp->lwp_ct_active[i]) != NULL) { - ctmpl_free(tmpl); - lwp->lwp_ct_active[i] = NULL; - } - if (lwp->lwp_ct_latest[i] != NULL) { contract_rele(lwp->lwp_ct_latest[i]); lwp->lwp_ct_latest[i] = NULL; } } } /* * Individual lwp exit. * If this is the last lwp, exit the whole process. --- 854,919 ---- lwp_ctmpl_copy(klwp_t *dst, klwp_t *src) { int i; for (i = 0; i < ct_ntypes; i++) { ! ct_template_t *tmpl = src->lwp_ct_active[i]; ! ! /* ! * If the process contract template is setup to be preserved ! * across exec, then if we're forking, perform an implicit ! * template_clear now. This ensures that future children of ! * this child will remain in the same contract unless they're ! * explicitly setup differently. We know we're forking if the ! * two LWPs belong to different processes. ! */ ! if (i == CTT_PROCESS && tmpl != NULL) { ! ctmpl_process_t *ctp = tmpl->ctmpl_data; ! ! if (dst->lwp_procp != src->lwp_procp && ! (ctp->ctp_params & CT_PR_KEEP_EXEC) != 0) ! tmpl = NULL; ! } ! ! dst->lwp_ct_active[i] = ctmpl_dup(tmpl); dst->lwp_ct_latest[i] = NULL; + } } /* * Clear an LWP's contract template state. */ void ! lwp_ctmpl_clear(klwp_t *lwp, boolean_t is_exec) { ct_template_t *tmpl; int i; for (i = 0; i < ct_ntypes; i++) { if (lwp->lwp_ct_latest[i] != NULL) { contract_rele(lwp->lwp_ct_latest[i]); lwp->lwp_ct_latest[i] = NULL; } + + if ((tmpl = lwp->lwp_ct_active[i]) != NULL) { + /* + * If we're exec-ing a new program and the process + * contract template is setup to be preserved across + * exec, then don't clear it. + */ + if (is_exec && i == CTT_PROCESS) { + ctmpl_process_t *ctp = tmpl->ctmpl_data; + + if ((ctp->ctp_params & CT_PR_KEEP_EXEC) != 0) + continue; } + + ctmpl_free(tmpl); + lwp->lwp_ct_active[i] = NULL; + } + } } /* * Individual lwp exit. * If this is the last lwp, exit the whole process.
*** 889,905 **** schedctl_lwp_cleanup(t); if (t->t_upimutex != NULL) upimutex_cleanup(); - /* - * Perform any brand specific exit processing, then release any - * brand data associated with the lwp - */ - if (PROC_IS_BRANDED(p)) - BROP(p)->b_lwpexit(lwp); - lwp_pcb_exit(); mutex_enter(&p->p_lock); lwp_cleanup(); --- 949,958 ----
*** 939,948 **** --- 992,1013 ---- } DTRACE_PROC(lwp__exit); /* + * Perform any brand specific exit processing, then release any + * brand data associated with the lwp + */ + if (PROC_IS_BRANDED(p)) { + mutex_exit(&p->p_lock); + BROP(p)->b_lwpexit(lwp); + BROP(p)->b_freelwp(lwp); + mutex_enter(&p->p_lock); + prbarrier(p); + } + + /* * If the lwp is a detached lwp or if the process is exiting, * remove (lwp_hash_out()) the lwp from the lwp directory. * Otherwise null out the lwp's le_thread pointer in the lwp * directory so that other threads will see it as a zombie lwp. */
*** 1099,1109 **** if (t->t_tid == 1) { p->p_t1_lgrpid = LGRP_NONE; } kpreempt_enable(); ! lwp_ctmpl_clear(ttolwp(t)); } int lwp_suspend(kthread_t *t) { --- 1164,1174 ---- if (t->t_tid == 1) { p->p_t1_lgrpid = LGRP_NONE; } kpreempt_enable(); ! lwp_ctmpl_clear(ttolwp(t), B_FALSE); } int lwp_suspend(kthread_t *t) {