Print this page
OS-208 DTrace needs to use zone_did to match zone-limited enablings
INTRO-118 enabling USDT probes in zones should be more scalable


7776                 if (!DTRACE_ISALPHA(c) && (c < '0' || c > '9') &&
7777                     c != '-' && c != '_' && c != '.' && c != '`')
7778                         return (1);
7779         }
7780 
7781         return (0);
7782 }
7783 
7784 static void
7785 dtrace_cred2priv(cred_t *cr, uint32_t *privp, uid_t *uidp, zoneid_t *zoneidp)
7786 {
7787         uint32_t priv;
7788 
7789         if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) {
7790                 /*
7791                  * For DTRACE_PRIV_ALL, the uid and zoneid don't matter.
7792                  */
7793                 priv = DTRACE_PRIV_ALL;
7794         } else {
7795                 *uidp = crgetuid(cr);
7796                 *zoneidp = crgetzoneid(cr);
7797 
7798                 priv = 0;
7799                 if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_KERNEL, B_FALSE))
7800                         priv |= DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER;
7801                 else if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, B_FALSE))
7802                         priv |= DTRACE_PRIV_USER;
7803                 if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, B_FALSE))
7804                         priv |= DTRACE_PRIV_PROC;
7805                 if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, B_FALSE))
7806                         priv |= DTRACE_PRIV_OWNER;
7807                 if (PRIV_POLICY_ONLY(cr, PRIV_PROC_ZONE, B_FALSE))
7808                         priv |= DTRACE_PRIV_ZONEOWNER;
7809         }
7810 
7811         *privp = priv;
7812 }
7813 
7814 #ifdef DTRACE_ERRDEBUG
7815 static void
7816 dtrace_errdebug(const char *str)


8272                     "privilege attributes", name);
8273                 return (EINVAL);
8274         }
8275 
8276         if ((priv & DTRACE_PRIV_KERNEL) &&
8277             (priv & (DTRACE_PRIV_USER | DTRACE_PRIV_OWNER)) &&
8278             pops->dtps_mode == NULL) {
8279                 cmn_err(CE_WARN, "failed to register provider '%s': need "
8280                     "dtps_mode() op for given privilege attributes", name);
8281                 return (EINVAL);
8282         }
8283 
8284         provider = kmem_zalloc(sizeof (dtrace_provider_t), KM_SLEEP);
8285         provider->dtpv_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
8286         (void) strcpy(provider->dtpv_name, name);
8287 
8288         provider->dtpv_attr = *pap;
8289         provider->dtpv_priv.dtpp_flags = priv;
8290         if (cr != NULL) {
8291                 provider->dtpv_priv.dtpp_uid = crgetuid(cr);
8292                 provider->dtpv_priv.dtpp_zoneid = crgetzoneid(cr);
8293         }
8294         provider->dtpv_pops = *pops;
8295 
8296         if (pops->dtps_provide == NULL) {
8297                 ASSERT(pops->dtps_provide_module != NULL);
8298                 provider->dtpv_pops.dtps_provide = dtrace_nullop_provide;
8299         }
8300 
8301         if (pops->dtps_provide_module == NULL) {
8302                 ASSERT(pops->dtps_provide != NULL);
8303                 provider->dtpv_pops.dtps_provide_module = dtrace_nullop_module;
8304         }
8305 
8306         if (pops->dtps_suspend == NULL) {
8307                 ASSERT(pops->dtps_resume == NULL);
8308                 provider->dtpv_pops.dtps_suspend = dtrace_nullop;
8309                 provider->dtpv_pops.dtps_resume = dtrace_nullop;
8310         }
8311 
8312         provider->dtpv_arg = arg;


8876                         continue;
8877                 }
8878 
8879                 prov = probe->dtpr_provider;
8880                 func = *((void(**)(void *, dtrace_id_t, void *))
8881                     ((uintptr_t)&prov->dtpv_pops + offs));
8882 
8883                 func(prov->dtpv_arg, i + 1, probe->dtpr_arg);
8884         }
8885 
8886         dtrace_interrupt_enable(cookie);
8887 }
8888 
8889 static int
8890 dtrace_probe_enable(const dtrace_probedesc_t *desc, dtrace_enabling_t *enab)
8891 {
8892         dtrace_probekey_t pkey;
8893         uint32_t priv;
8894         uid_t uid;
8895         zoneid_t zoneid;

8896 
8897         ASSERT(MUTEX_HELD(&dtrace_lock));
8898         dtrace_ecb_create_cache = NULL;
8899 
8900         if (desc == NULL) {
8901                 /*
8902                  * If we're passed a NULL description, we're being asked to
8903                  * create an ECB with a NULL probe.
8904                  */
8905                 (void) dtrace_ecb_create_enable(NULL, enab);
8906                 return (0);
8907         }
8908 
8909         dtrace_probekey(desc, &pkey);
8910         dtrace_cred2priv(enab->dten_vstate->dtvs_state->dts_cred.dcr_cred,
8911             &priv, &uid, &zoneid);
8912 















8913         return (dtrace_match(&pkey, priv, uid, zoneid, dtrace_ecb_create_enable,
8914             enab));
8915 }
8916 
8917 /*
8918  * DTrace Helper Provider Functions
8919  */
8920 static void
8921 dtrace_dofattr2attr(dtrace_attribute_t *attr, const dof_attr_t dofattr)
8922 {
8923         attr->dtat_name = DOF_ATTR_NAME(dofattr);
8924         attr->dtat_data = DOF_ATTR_DATA(dofattr);
8925         attr->dtat_class = DOF_ATTR_CLASS(dofattr);
8926 }
8927 
8928 static void
8929 dtrace_dofprov2hprov(dtrace_helper_provdesc_t *hprov,
8930     const dof_provider_t *dofprov, char *strtab)
8931 {
8932         hprov->dthpv_provname = strtab + dofprov->dofpv_name;


12353 dtrace_enabling_matchall(void)
12354 {
12355         dtrace_enabling_t *enab;
12356 
12357         mutex_enter(&cpu_lock);
12358         mutex_enter(&dtrace_lock);
12359 
12360         /*
12361          * Iterate over all retained enablings to see if any probes match
12362          * against them.  We only perform this operation on enablings for which
12363          * we have sufficient permissions by virtue of being in the global zone
12364          * or in the same zone as the DTrace client.  Because we can be called
12365          * after dtrace_detach() has been called, we cannot assert that there
12366          * are retained enablings.  We can safely load from dtrace_retained,
12367          * however:  the taskq_destroy() at the end of dtrace_detach() will
12368          * block pending our completion.
12369          */
12370         for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) {
12371                 dtrace_cred_t *dcr = &enab->dten_vstate->dtvs_state->dts_cred;
12372                 cred_t *cr = dcr->dcr_cred;
12373                 zoneid_t zone = cr != NULL ? crgetzoneid(cr) : 0;
12374 
12375                 if ((dcr->dcr_visible & DTRACE_CRV_ALLZONE) || (cr != NULL &&
12376                     (zone == GLOBAL_ZONEID || getzoneid() == zone)))
12377                         (void) dtrace_enabling_match(enab, NULL);
12378         }
12379 
12380         mutex_exit(&dtrace_lock);
12381         mutex_exit(&cpu_lock);
12382 }
12383 
12384 /*
12385  * If an enabling is to be enabled without having matched probes (that is, if
12386  * dtrace_state_go() is to be called on the underlying dtrace_state_t), the
12387  * enabling must be _primed_ by creating an ECB for every ECB description.
12388  * This must be done to assure that we know the number of speculations, the
12389  * number of aggregations, the minimum buffer size needed, etc. before we
12390  * transition out of DTRACE_ACTIVITY_INACTIVE.  To do this without actually
12391  * enabling any probes, we create ECBs for every ECB decription, but with a
12392  * NULL probe -- which is exactly what this function does.
12393  */
12394 static void
12395 dtrace_enabling_prime(dtrace_state_t *state)
12396 {




7776                 if (!DTRACE_ISALPHA(c) && (c < '0' || c > '9') &&
7777                     c != '-' && c != '_' && c != '.' && c != '`')
7778                         return (1);
7779         }
7780 
7781         return (0);
7782 }
7783 
7784 static void
7785 dtrace_cred2priv(cred_t *cr, uint32_t *privp, uid_t *uidp, zoneid_t *zoneidp)
7786 {
7787         uint32_t priv;
7788 
7789         if (cr == NULL || PRIV_POLICY_ONLY(cr, PRIV_ALL, B_FALSE)) {
7790                 /*
7791                  * For DTRACE_PRIV_ALL, the uid and zoneid don't matter.
7792                  */
7793                 priv = DTRACE_PRIV_ALL;
7794         } else {
7795                 *uidp = crgetuid(cr);
7796                 *zoneidp = crgetzonedid(cr);
7797 
7798                 priv = 0;
7799                 if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_KERNEL, B_FALSE))
7800                         priv |= DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER;
7801                 else if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, B_FALSE))
7802                         priv |= DTRACE_PRIV_USER;
7803                 if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, B_FALSE))
7804                         priv |= DTRACE_PRIV_PROC;
7805                 if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, B_FALSE))
7806                         priv |= DTRACE_PRIV_OWNER;
7807                 if (PRIV_POLICY_ONLY(cr, PRIV_PROC_ZONE, B_FALSE))
7808                         priv |= DTRACE_PRIV_ZONEOWNER;
7809         }
7810 
7811         *privp = priv;
7812 }
7813 
7814 #ifdef DTRACE_ERRDEBUG
7815 static void
7816 dtrace_errdebug(const char *str)


8272                     "privilege attributes", name);
8273                 return (EINVAL);
8274         }
8275 
8276         if ((priv & DTRACE_PRIV_KERNEL) &&
8277             (priv & (DTRACE_PRIV_USER | DTRACE_PRIV_OWNER)) &&
8278             pops->dtps_mode == NULL) {
8279                 cmn_err(CE_WARN, "failed to register provider '%s': need "
8280                     "dtps_mode() op for given privilege attributes", name);
8281                 return (EINVAL);
8282         }
8283 
8284         provider = kmem_zalloc(sizeof (dtrace_provider_t), KM_SLEEP);
8285         provider->dtpv_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
8286         (void) strcpy(provider->dtpv_name, name);
8287 
8288         provider->dtpv_attr = *pap;
8289         provider->dtpv_priv.dtpp_flags = priv;
8290         if (cr != NULL) {
8291                 provider->dtpv_priv.dtpp_uid = crgetuid(cr);
8292                 provider->dtpv_priv.dtpp_zoneid = crgetzonedid(cr);
8293         }
8294         provider->dtpv_pops = *pops;
8295 
8296         if (pops->dtps_provide == NULL) {
8297                 ASSERT(pops->dtps_provide_module != NULL);
8298                 provider->dtpv_pops.dtps_provide = dtrace_nullop_provide;
8299         }
8300 
8301         if (pops->dtps_provide_module == NULL) {
8302                 ASSERT(pops->dtps_provide != NULL);
8303                 provider->dtpv_pops.dtps_provide_module = dtrace_nullop_module;
8304         }
8305 
8306         if (pops->dtps_suspend == NULL) {
8307                 ASSERT(pops->dtps_resume == NULL);
8308                 provider->dtpv_pops.dtps_suspend = dtrace_nullop;
8309                 provider->dtpv_pops.dtps_resume = dtrace_nullop;
8310         }
8311 
8312         provider->dtpv_arg = arg;


8876                         continue;
8877                 }
8878 
8879                 prov = probe->dtpr_provider;
8880                 func = *((void(**)(void *, dtrace_id_t, void *))
8881                     ((uintptr_t)&prov->dtpv_pops + offs));
8882 
8883                 func(prov->dtpv_arg, i + 1, probe->dtpr_arg);
8884         }
8885 
8886         dtrace_interrupt_enable(cookie);
8887 }
8888 
8889 static int
8890 dtrace_probe_enable(const dtrace_probedesc_t *desc, dtrace_enabling_t *enab)
8891 {
8892         dtrace_probekey_t pkey;
8893         uint32_t priv;
8894         uid_t uid;
8895         zoneid_t zoneid;
8896         dtrace_state_t *state = enab->dten_vstate->dtvs_state;
8897 
8898         ASSERT(MUTEX_HELD(&dtrace_lock));
8899         dtrace_ecb_create_cache = NULL;
8900 
8901         if (desc == NULL) {
8902                 /*
8903                  * If we're passed a NULL description, we're being asked to
8904                  * create an ECB with a NULL probe.
8905                  */
8906                 (void) dtrace_ecb_create_enable(NULL, enab);
8907                 return (0);
8908         }
8909 
8910         dtrace_probekey(desc, &pkey);
8911         dtrace_cred2priv(state->dts_cred.dcr_cred, &priv, &uid, &zoneid);

8912 
8913         if ((priv & DTRACE_PRIV_ZONEOWNER) &&
8914             state->dts_options[DTRACEOPT_ZONE] != DTRACEOPT_UNSET) {
8915                 /*
8916                  * If we have the privilege of instrumenting all zones but we
8917                  * have been told to instrument but one, we will spoof this up
8918                  * depriving ourselves of DTRACE_PRIV_ZONEOWNER for purposes
8919                  * of dtrace_match().  (Note that DTRACEOPT_ZONE is not for
8920                  * security but rather for performance: it allows the global
8921                  * zone to instrument USDT probes in a local zone without
8922                  * requiring all zones to be instrumented.)
8923                  */
8924                 priv &= ~DTRACE_PRIV_ZONEOWNER;
8925                 zoneid = state->dts_options[DTRACEOPT_ZONE];
8926         }
8927 
8928         return (dtrace_match(&pkey, priv, uid, zoneid, dtrace_ecb_create_enable,
8929             enab));
8930 }
8931 
8932 /*
8933  * DTrace Helper Provider Functions
8934  */
8935 static void
8936 dtrace_dofattr2attr(dtrace_attribute_t *attr, const dof_attr_t dofattr)
8937 {
8938         attr->dtat_name = DOF_ATTR_NAME(dofattr);
8939         attr->dtat_data = DOF_ATTR_DATA(dofattr);
8940         attr->dtat_class = DOF_ATTR_CLASS(dofattr);
8941 }
8942 
8943 static void
8944 dtrace_dofprov2hprov(dtrace_helper_provdesc_t *hprov,
8945     const dof_provider_t *dofprov, char *strtab)
8946 {
8947         hprov->dthpv_provname = strtab + dofprov->dofpv_name;


12368 dtrace_enabling_matchall(void)
12369 {
12370         dtrace_enabling_t *enab;
12371 
12372         mutex_enter(&cpu_lock);
12373         mutex_enter(&dtrace_lock);
12374 
12375         /*
12376          * Iterate over all retained enablings to see if any probes match
12377          * against them.  We only perform this operation on enablings for which
12378          * we have sufficient permissions by virtue of being in the global zone
12379          * or in the same zone as the DTrace client.  Because we can be called
12380          * after dtrace_detach() has been called, we cannot assert that there
12381          * are retained enablings.  We can safely load from dtrace_retained,
12382          * however:  the taskq_destroy() at the end of dtrace_detach() will
12383          * block pending our completion.
12384          */
12385         for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) {
12386                 dtrace_cred_t *dcr = &enab->dten_vstate->dtvs_state->dts_cred;
12387                 cred_t *cr = dcr->dcr_cred;
12388                 zoneid_t zone = cr != NULL ? crgetzonedid(cr) : 0;
12389 
12390                 if ((dcr->dcr_visible & DTRACE_CRV_ALLZONE) || (cr != NULL &&
12391                     (zone == GLOBAL_ZONEID || getzonedid() == zone)))
12392                         (void) dtrace_enabling_match(enab, NULL);
12393         }
12394 
12395         mutex_exit(&dtrace_lock);
12396         mutex_exit(&cpu_lock);
12397 }
12398 
12399 /*
12400  * If an enabling is to be enabled without having matched probes (that is, if
12401  * dtrace_state_go() is to be called on the underlying dtrace_state_t), the
12402  * enabling must be _primed_ by creating an ECB for every ECB description.
12403  * This must be done to assure that we know the number of speculations, the
12404  * number of aggregations, the minimum buffer size needed, etc. before we
12405  * transition out of DTRACE_ACTIVITY_INACTIVE.  To do this without actually
12406  * enabling any probes, we create ECBs for every ECB decription, but with a
12407  * NULL probe -- which is exactly what this function does.
12408  */
12409 static void
12410 dtrace_enabling_prime(dtrace_state_t *state)
12411 {