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)
  {