Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

1456 DTrace profile and tick probes sometimes don't fire in a zone

Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Eric Schrock <eric.schrock@delphix.com>
Approved by: Garrett D'Amore <garrett@nexenta.com>
  • Loading branch information...
commit 7d5c9b5fdaad32a290692afde7867bd051784395 1 parent c090e5d
@bcantrill bcantrill authored
View
72 usr/src/cmd/dtrace/test/tst/common/privs/tst.noprivdrop.ksh
@@ -0,0 +1,72 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+ppriv -s A=basic,dtrace_user $$
+
+#
+# We expect some number of these profile probes to be silently dropped.
+# Note that this test will fail if something is stuck on all CPUs that
+# whomever is running the test happens to own.
+#
+count=$(/usr/sbin/dtrace -q -s /dev/stdin <<EOF
+BEGIN
+{
+ start = timestamp;
+ @ = count();
+}
+
+ERROR
+{
+ exit(1);
+}
+
+profile-1000hz
+{
+ @ = count();
+}
+
+tick-10ms
+{
+ ticks++;
+}
+
+tick-10ms
+/ticks > 100/
+{
+ printa("%@d", @);
+ exit(0);
+}
+EOF)
+
+cpus=`psrinfo | grep -- on-line | wc -l`
+max=`expr $cpus \* 500`
+
+if [[ $count -gt $max ]]; then
+ echo "count ($count) is greater than allowed max ($max)"
+ exit 1
+fi
+
+echo "count ($count) is within allowed max ($max)"
+exit 0
View
61 usr/src/cmd/dtrace/test/tst/common/privs/tst.noprivrestrict.ksh
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+ppriv -s A=basic,dtrace_user $$
+
+#
+# We expect at least one of these tick probes to error out because only
+# dtrace_user is set, and we are attempting to access arguments. Note that
+# this test will fail if something is stuck on CPU that whomever is running
+# the test happens to own.
+#
+/usr/sbin/dtrace -q -s /dev/stdin <<EOF
+BEGIN
+{
+ start = timestamp;
+}
+
+tick-1000hz
+{
+ @[arg0] = count();
+}
+
+ERROR
+{
+ errcnt++;
+}
+
+tick-10ms
+{
+ ticks++;
+}
+
+tick-10ms
+/ticks > 100/
+{
+ printf("error count is %d\n", errcnt);
+ exit(errcnt != 0 ? 0 : 1);
+}
+EOF
View
55 usr/src/cmd/dtrace/test/tst/common/privs/tst.tick.ksh
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+ppriv -s A=basic,dtrace_user $$
+
+#
+# We expect tick probes to fire if dtrace_user is set
+#
+/usr/sbin/dtrace -q -s /dev/stdin <<EOF
+BEGIN
+{
+ start = timestamp;
+}
+
+tick-10ms
+{
+ ticks++;
+}
+
+tick-10ms
+/ticks > 10 && (this->ms = (timestamp - start) / 1000000) > 2000/
+{
+ printf("expected completion in 100 ms, found %d!\n", this->ms);
+ exit(1);
+}
+
+tick-10ms
+/ticks > 10/
+{
+ printf("completed in %d ms\n", this->ms);
+ exit(0);
+}
+EOF
View
3  usr/src/pkg/manifests/system-dtrace-tests.mf
@@ -1300,7 +1300,10 @@ file path=opt/SUNWdtrt/tst/common/printf/tst.widths1.d mode=0444
file path=opt/SUNWdtrt/tst/common/printf/tst.wp.d mode=0444
file path=opt/SUNWdtrt/tst/common/printf/tst.wp.d.out mode=0444
file path=opt/SUNWdtrt/tst/common/privs/tst.func_access.ksh mode=0444
+file path=opt/SUNWdtrt/tst/common/privs/tst.noprivdrop.ksh mode=0444
+file path=opt/SUNWdtrt/tst/common/privs/tst.noprivrestrict.ksh mode=0444
file path=opt/SUNWdtrt/tst/common/privs/tst.op_access.ksh mode=0444
+file path=opt/SUNWdtrt/tst/common/privs/tst.tick.ksh mode=0444
file path=opt/SUNWdtrt/tst/common/privs/tst.unpriv_funcs.ksh mode=0444
file path=opt/SUNWdtrt/tst/common/probes/err.D_PDESC_ZERO.probeqtn.d mode=0444
file path=opt/SUNWdtrt/tst/common/probes/err.D_PDESC_ZERO.probestar.d \
View
10 usr/src/uts/common/dtrace/dcpc.c
@@ -339,9 +339,13 @@ dcpc_destroy(void *arg, dtrace_id_t id, void *parg)
/*ARGSUSED*/
static int
-dcpc_usermode(void *arg, dtrace_id_t id, void *parg)
+dcpc_mode(void *arg, dtrace_id_t id, void *parg)
{
- return (CPU->cpu_cpcprofile_pc == 0);
+ if (CPU->cpu_cpcprofile_pc == 0) {
+ return (DTRACE_MODE_NOPRIV_DROP | DTRACE_MODE_USER);
+ } else {
+ return (DTRACE_MODE_NOPRIV_DROP | DTRACE_MODE_KERNEL);
+ }
}
static void
@@ -1013,7 +1017,7 @@ static dtrace_pops_t dcpc_pops = {
NULL,
NULL,
NULL,
- dcpc_usermode,
+ dcpc_mode,
dcpc_destroy
};
View
239 usr/src/uts/common/dtrace/dtrace.c
@@ -1108,10 +1108,13 @@ dtrace_priv_proc_common_nocd()
}
static int
-dtrace_priv_proc_destructive(dtrace_state_t *state)
+dtrace_priv_proc_destructive(dtrace_state_t *state, dtrace_mstate_t *mstate)
{
int action = state->dts_cred.dcr_action;
+ if (!(mstate->dtms_access & DTRACE_ACCESS_PROC))
+ goto bad;
+
if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_ALLZONE) == 0) &&
dtrace_priv_proc_common_zone(state) == 0)
goto bad;
@@ -1133,15 +1136,17 @@ dtrace_priv_proc_destructive(dtrace_state_t *state)
}
static int
-dtrace_priv_proc_control(dtrace_state_t *state)
+dtrace_priv_proc_control(dtrace_state_t *state, dtrace_mstate_t *mstate)
{
- if (state->dts_cred.dcr_action & DTRACE_CRA_PROC_CONTROL)
- return (1);
+ if (mstate->dtms_access & DTRACE_ACCESS_PROC) {
+ if (state->dts_cred.dcr_action & DTRACE_CRA_PROC_CONTROL)
+ return (1);
- if (dtrace_priv_proc_common_zone(state) &&
- dtrace_priv_proc_common_user(state) &&
- dtrace_priv_proc_common_nocd())
- return (1);
+ if (dtrace_priv_proc_common_zone(state) &&
+ dtrace_priv_proc_common_user(state) &&
+ dtrace_priv_proc_common_nocd())
+ return (1);
+ }
cpu_core[CPU->cpu_id].cpuc_dtrace_flags |= CPU_DTRACE_UPRIV;
@@ -1149,9 +1154,10 @@ dtrace_priv_proc_control(dtrace_state_t *state)
}
static int
-dtrace_priv_proc(dtrace_state_t *state)
+dtrace_priv_proc(dtrace_state_t *state, dtrace_mstate_t *mstate)
{
- if (state->dts_cred.dcr_action & DTRACE_CRA_PROC)
+ if ((mstate->dtms_access & DTRACE_ACCESS_PROC) &&
+ (state->dts_cred.dcr_action & DTRACE_CRA_PROC))
return (1);
cpu_core[CPU->cpu_id].cpuc_dtrace_flags |= CPU_DTRACE_UPRIV;
@@ -1182,6 +1188,109 @@ dtrace_priv_kernel_destructive(dtrace_state_t *state)
}
/*
+ * Determine if the dte_cond of the specified ECB allows for processing of
+ * the current probe to continue. Note that this routine may allow continued
+ * processing, but with access(es) stripped from the mstate's dtms_access
+ * field.
+ */
+static int
+dtrace_priv_probe(dtrace_state_t *state, dtrace_mstate_t *mstate,
+ dtrace_ecb_t *ecb)
+{
+ dtrace_probe_t *probe = ecb->dte_probe;
+ dtrace_provider_t *prov = probe->dtpr_provider;
+ dtrace_pops_t *pops = &prov->dtpv_pops;
+ int mode = DTRACE_MODE_NOPRIV_DROP;
+
+ ASSERT(ecb->dte_cond);
+
+ if (pops->dtps_mode != NULL) {
+ mode = pops->dtps_mode(prov->dtpv_arg,
+ probe->dtpr_id, probe->dtpr_arg);
+
+ ASSERT((mode & DTRACE_MODE_USER) ||
+ (mode & DTRACE_MODE_KERNEL));
+ ASSERT((mode & DTRACE_MODE_NOPRIV_RESTRICT) ||
+ (mode & DTRACE_MODE_NOPRIV_DROP));
+ }
+
+ /*
+ * If the dte_cond bits indicate that this consumer is only allowed to
+ * see user-mode firings of this probe, call the provider's dtps_mode()
+ * entry point to check that the probe was fired while in a user
+ * context. If that's not the case, use the policy specified by the
+ * provider to determine if we drop the probe or merely restrict
+ * operation.
+ */
+ if (ecb->dte_cond & DTRACE_COND_USERMODE) {
+ ASSERT(mode != DTRACE_MODE_NOPRIV_DROP);
+
+ if (!(mode & DTRACE_MODE_USER)) {
+ if (mode & DTRACE_MODE_NOPRIV_DROP)
+ return (0);
+
+ mstate->dtms_access &= ~DTRACE_ACCESS_ARGS;
+ }
+ }
+
+ /*
+ * This is more subtle than it looks. We have to be absolutely certain
+ * that CRED() isn't going to change out from under us so it's only
+ * legit to examine that structure if we're in constrained situations.
+ * Currently, the only times we'll this check is if a non-super-user
+ * has enabled the profile or syscall providers -- providers that
+ * allow visibility of all processes. For the profile case, the check
+ * above will ensure that we're examining a user context.
+ */
+ if (ecb->dte_cond & DTRACE_COND_OWNER) {
+ cred_t *cr;
+ cred_t *s_cr = state->dts_cred.dcr_cred;
+ proc_t *proc;
+
+ ASSERT(s_cr != NULL);
+
+ if ((cr = CRED()) == NULL ||
+ s_cr->cr_uid != cr->cr_uid ||
+ s_cr->cr_uid != cr->cr_ruid ||
+ s_cr->cr_uid != cr->cr_suid ||
+ s_cr->cr_gid != cr->cr_gid ||
+ s_cr->cr_gid != cr->cr_rgid ||
+ s_cr->cr_gid != cr->cr_sgid ||
+ (proc = ttoproc(curthread)) == NULL ||
+ (proc->p_flag & SNOCD)) {
+ if (mode & DTRACE_MODE_NOPRIV_DROP)
+ return (0);
+
+ mstate->dtms_access &= ~DTRACE_ACCESS_PROC;
+ }
+ }
+
+ /*
+ * If our dte_cond is set to DTRACE_COND_ZONEOWNER and we are not
+ * in our zone, check to see if our mode policy is to restrict rather
+ * than to drop; if to restrict, strip away both DTRACE_ACCESS_PROC
+ * and DTRACE_ACCESS_ARGS
+ */
+ if (ecb->dte_cond & DTRACE_COND_ZONEOWNER) {
+ cred_t *cr;
+ cred_t *s_cr = state->dts_cred.dcr_cred;
+
+ ASSERT(s_cr != NULL);
+
+ if ((cr = CRED()) == NULL ||
+ s_cr->cr_zone->zone_id != cr->cr_zone->zone_id) {
+ if (mode & DTRACE_MODE_NOPRIV_DROP)
+ return (0);
+
+ mstate->dtms_access &=
+ ~(DTRACE_ACCESS_PROC | DTRACE_ACCESS_ARGS);
+ }
+ }
+
+ return (1);
+}
+
+/*
* Note: not called from probe context. This function is called
* asynchronously (and at a regular interval) from outside of probe context to
* clean the dirty dynamic variable lists on all CPUs. Dynamic variable
@@ -2713,6 +2822,12 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
switch (v) {
case DIF_VAR_ARGS:
+ if (!(mstate->dtms_access & DTRACE_ACCESS_ARGS)) {
+ cpu_core[CPU->cpu_id].cpuc_dtrace_flags |=
+ CPU_DTRACE_KPRIV;
+ return (0);
+ }
+
ASSERT(mstate->dtms_present & DTRACE_MSTATE_ARGS);
if (ndx >= sizeof (mstate->dtms_arg) /
sizeof (mstate->dtms_arg[0])) {
@@ -2748,7 +2863,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
case DIF_VAR_UREGS: {
klwp_t *lwp;
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
if ((lwp = curthread->t_lwp) == NULL) {
@@ -2828,7 +2943,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return (mstate->dtms_stackdepth);
case DIF_VAR_USTACKDEPTH:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
if (!(mstate->dtms_present & DTRACE_MSTATE_USTACKDEPTH)) {
/*
@@ -2883,7 +2998,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return (mstate->dtms_caller);
case DIF_VAR_UCALLER:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
if (!(mstate->dtms_present & DTRACE_MSTATE_UCALLER)) {
@@ -2931,7 +3046,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
state, mstate));
case DIF_VAR_PID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -2953,7 +3068,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return ((uint64_t)curthread->t_procp->p_pidp->pid_id);
case DIF_VAR_PPID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -2980,7 +3095,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return ((uint64_t)curthread->t_tid);
case DIF_VAR_EXECNAME:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3000,7 +3115,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
state, mstate));
case DIF_VAR_ZONENAME:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3020,7 +3135,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
state, mstate));
case DIF_VAR_UID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3041,7 +3156,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return ((uint64_t)curthread->t_procp->p_cred->cr_uid);
case DIF_VAR_GID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3063,7 +3178,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
case DIF_VAR_ERRNO: {
klwp_t *lwp;
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3403,7 +3518,7 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
uint64_t size = tupregs[2].dttk_value;
if (!dtrace_destructive_disallow &&
- dtrace_priv_proc_control(state) &&
+ dtrace_priv_proc_control(state, mstate) &&
!dtrace_istoxic(kaddr, size)) {
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
dtrace_copyout(kaddr, uaddr, size, flags);
@@ -3418,7 +3533,7 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
uint64_t size = tupregs[2].dttk_value;
if (!dtrace_destructive_disallow &&
- dtrace_priv_proc_control(state) &&
+ dtrace_priv_proc_control(state, mstate) &&
!dtrace_istoxic(kaddr, size)) {
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
dtrace_copyoutstr(kaddr, uaddr, size, flags);
@@ -5722,6 +5837,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
#endif
mstate.dtms_present = DTRACE_MSTATE_ARGS | DTRACE_MSTATE_PROBE;
+ mstate.dtms_access = DTRACE_ACCESS_ARGS | DTRACE_ACCESS_PROC;
*flags &= ~CPU_DTRACE_ERROR;
if (prov == dtrace_provider) {
@@ -5759,65 +5875,8 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
}
}
- if (ecb->dte_cond) {
- /*
- * If the dte_cond bits indicate that this
- * consumer is only allowed to see user-mode firings
- * of this probe, call the provider's dtps_usermode()
- * entry point to check that the probe was fired
- * while in a user context. Skip this ECB if that's
- * not the case.
- */
- if ((ecb->dte_cond & DTRACE_COND_USERMODE) &&
- prov->dtpv_pops.dtps_usermode(prov->dtpv_arg,
- probe->dtpr_id, probe->dtpr_arg) == 0)
- continue;
-
- /*
- * This is more subtle than it looks. We have to be
- * absolutely certain that CRED() isn't going to
- * change out from under us so it's only legit to
- * examine that structure if we're in constrained
- * situations. Currently, the only times we'll this
- * check is if a non-super-user has enabled the
- * profile or syscall providers -- providers that
- * allow visibility of all processes. For the
- * profile case, the check above will ensure that
- * we're examining a user context.
- */
- if (ecb->dte_cond & DTRACE_COND_OWNER) {
- cred_t *cr;
- cred_t *s_cr =
- ecb->dte_state->dts_cred.dcr_cred;
- proc_t *proc;
-
- ASSERT(s_cr != NULL);
-
- if ((cr = CRED()) == NULL ||
- s_cr->cr_uid != cr->cr_uid ||
- s_cr->cr_uid != cr->cr_ruid ||
- s_cr->cr_uid != cr->cr_suid ||
- s_cr->cr_gid != cr->cr_gid ||
- s_cr->cr_gid != cr->cr_rgid ||
- s_cr->cr_gid != cr->cr_sgid ||
- (proc = ttoproc(curthread)) == NULL ||
- (proc->p_flag & SNOCD))
- continue;
- }
-
- if (ecb->dte_cond & DTRACE_COND_ZONEOWNER) {
- cred_t *cr;
- cred_t *s_cr =
- ecb->dte_state->dts_cred.dcr_cred;
-
- ASSERT(s_cr != NULL);
-
- if ((cr = CRED()) == NULL ||
- s_cr->cr_zone->zone_id !=
- cr->cr_zone->zone_id)
- continue;
- }
- }
+ if (ecb->dte_cond && !dtrace_priv_probe(state, &mstate, ecb))
+ continue;
if (now - state->dts_alive > dtrace_deadman_timeout) {
/*
@@ -5857,9 +5916,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
mstate.dtms_present |= DTRACE_MSTATE_EPID;
if (state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL)
- mstate.dtms_access = DTRACE_ACCESS_KERNEL;
- else
- mstate.dtms_access = 0;
+ mstate.dtms_access |= DTRACE_ACCESS_KERNEL;
if (pred != NULL) {
dtrace_difo_t *dp = pred->dtp_difo;
@@ -5919,7 +5976,8 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
switch (act->dta_kind) {
case DTRACEACT_STOP:
- if (dtrace_priv_proc_destructive(state))
+ if (dtrace_priv_proc_destructive(state,
+ &mstate))
dtrace_action_stop();
continue;
@@ -5946,7 +6004,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
case DTRACEACT_JSTACK:
case DTRACEACT_USTACK:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, &mstate))
continue;
/*
@@ -6032,7 +6090,8 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
continue;
case DTRACEACT_RAISE:
- if (dtrace_priv_proc_destructive(state))
+ if (dtrace_priv_proc_destructive(state,
+ &mstate))
dtrace_action_raise(val);
continue;
@@ -6072,7 +6131,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
case DTRACEACT_UADDR: {
struct pid *pid = curthread->t_procp->p_pidp;
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, &mstate))
continue;
DTRACE_STORE(uint64_t, tomax,
@@ -7004,9 +7063,9 @@ dtrace_register(const char *name, const dtrace_pattr_t *pap, uint32_t priv,
if ((priv & DTRACE_PRIV_KERNEL) &&
(priv & (DTRACE_PRIV_USER | DTRACE_PRIV_OWNER)) &&
- pops->dtps_usermode == NULL) {
+ pops->dtps_mode == NULL) {
cmn_err(CE_WARN, "failed to register provider '%s': need "
- "dtps_usermode() op for given privilege attributes", name);
+ "dtps_mode() op for given privilege attributes", name);
return (EINVAL);
}
View
25 usr/src/uts/common/dtrace/profile.c
@@ -23,6 +23,9 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ */
#include <sys/errno.h>
#include <sys/stat.h>
@@ -408,9 +411,25 @@ profile_disable(void *arg, dtrace_id_t id, void *parg)
/*ARGSUSED*/
static int
-profile_usermode(void *arg, dtrace_id_t id, void *parg)
+profile_mode(void *arg, dtrace_id_t id, void *parg)
{
- return (CPU->cpu_profile_pc == 0);
+ profile_probe_t *prof = parg;
+ int mode;
+
+ if (CPU->cpu_profile_pc != 0) {
+ mode = DTRACE_MODE_KERNEL;
+ } else {
+ mode = DTRACE_MODE_USER;
+ }
+
+ if (prof->prof_kind == PROF_TICK) {
+ mode |= DTRACE_MODE_NOPRIV_RESTRICT;
+ } else {
+ ASSERT(prof->prof_kind == PROF_PROFILE);
+ mode |= DTRACE_MODE_NOPRIV_DROP;
+ }
+
+ return (mode);
}
static dtrace_pattr_t profile_attr = {
@@ -430,7 +449,7 @@ static dtrace_pops_t profile_pops = {
NULL,
NULL,
NULL,
- profile_usermode,
+ profile_mode,
profile_destroy
};
View
29 usr/src/uts/common/sys/dtrace.h
@@ -1352,7 +1352,7 @@ typedef struct dof_helper {
* dtps_resume() <-- Resume specified probe
* dtps_getargdesc() <-- Get the argument description for args[X]
* dtps_getargval() <-- Get the value for an argX or args[X] variable
- * dtps_usermode() <-- Find out if the probe was fired in user mode
+ * dtps_mode() <-- Return the mode of the fired probe
* dtps_destroy() <-- Destroy all state associated with this probe
*
* 1.2 void dtps_provide(void *arg, const dtrace_probedesc_t *spec)
@@ -1601,24 +1601,32 @@ typedef struct dof_helper {
* This is called from within dtrace_probe() meaning that interrupts
* are disabled. No locks should be taken within this entry point.
*
- * 1.10 int dtps_usermode(void *arg, dtrace_id_t id, void *parg)
+ * 1.10 int dtps_mode(void *arg, dtrace_id_t id, void *parg)
*
* 1.10.1 Overview
*
- * Called to determine if the probe was fired in a user context.
+ * Called to determine the mode of a fired probe.
*
* 1.10.2 Arguments and notes
*
* The first argument is the cookie as passed to dtrace_register(). The
- * second argument is the identifier of the current probe. The third
+ * second argument is the identifier of the current probe. The third
* argument is the probe argument as passed to dtrace_probe_create(). This
* entry point must not be left NULL for providers whose probes allow for
- * mixed mode tracing, that is to say those probes that can fire during
- * kernel- _or_ user-mode execution
+ * mixed mode tracing, that is to say those unanchored probes that can fire
+ * during kernel- or user-mode execution.
*
* 1.10.3 Return value
*
- * A boolean value.
+ * A bitwise OR that encapsulates both the mode (either DTRACE_MODE_KERNEL
+ * or DTRACE_MODE_USER) and the policy when the privilege of the enabling
+ * is insufficient for that mode (either DTRACE_MODE_NOPRIV_DROP or
+ * DTRACE_MODE_NOPRIV_RESTRICT). If the policy is DTRACE_MODE_NOPRIV_DROP,
+ * insufficient privilege will result in the probe firing being silently
+ * ignored for the enabling; if the policy is DTRACE_NODE_NOPRIV_RESTRICT,
+ * insufficient privilege will not prevent probe processing for the
+ * enabling, but restrictions will be in place that induce a UPRIV fault
+ * upon attempt to examine probe arguments or current process state.
*
* 1.10.4 Caller's context
*
@@ -2009,10 +2017,15 @@ typedef struct dtrace_pops {
dtrace_argdesc_t *desc);
uint64_t (*dtps_getargval)(void *arg, dtrace_id_t id, void *parg,
int argno, int aframes);
- int (*dtps_usermode)(void *arg, dtrace_id_t id, void *parg);
+ int (*dtps_mode)(void *arg, dtrace_id_t id, void *parg);
void (*dtps_destroy)(void *arg, dtrace_id_t id, void *parg);
} dtrace_pops_t;
+#define DTRACE_MODE_KERNEL 0x01
+#define DTRACE_MODE_USER 0x02
+#define DTRACE_MODE_NOPRIV_DROP 0x10
+#define DTRACE_MODE_NOPRIV_RESTRICT 0x20
+
typedef uintptr_t dtrace_provider_id_t;
extern int dtrace_register(const char *, const dtrace_pattr_t *, uint32_t,
View
3  usr/src/uts/common/sys/dtrace_impl.h
@@ -929,7 +929,8 @@ typedef struct dtrace_mstate {
* Access flag used by dtrace_mstate.dtms_access.
*/
#define DTRACE_ACCESS_KERNEL 0x1 /* the priv to read kmem */
-
+#define DTRACE_ACCESS_PROC 0x2 /* the priv for proc state */
+#define DTRACE_ACCESS_ARGS 0x4 /* the priv to examine args */
/*
* DTrace Activity
Please sign in to comment.
Something went wrong with that request. Please try again.