diff options
Diffstat (limited to 'usr/src')
-rwxr-xr-x | usr/src/cmd/dtrace/test/tst/common/privs/tst.noprivdrop.ksh | 72 | ||||
-rwxr-xr-x | usr/src/cmd/dtrace/test/tst/common/privs/tst.noprivrestrict.ksh | 61 | ||||
-rwxr-xr-x | usr/src/cmd/dtrace/test/tst/common/privs/tst.tick.ksh | 55 | ||||
-rw-r--r-- | usr/src/pkg/manifests/system-dtrace-tests.mf | 3 | ||||
-rw-r--r-- | usr/src/uts/common/dtrace/dcpc.c | 10 | ||||
-rw-r--r-- | usr/src/uts/common/dtrace/dtrace.c | 239 | ||||
-rw-r--r-- | usr/src/uts/common/dtrace/profile.c | 25 | ||||
-rw-r--r-- | usr/src/uts/common/sys/dtrace.h | 29 | ||||
-rw-r--r-- | usr/src/uts/common/sys/dtrace_impl.h | 3 |
9 files changed, 392 insertions, 105 deletions
diff --git a/usr/src/cmd/dtrace/test/tst/common/privs/tst.noprivdrop.ksh b/usr/src/cmd/dtrace/test/tst/common/privs/tst.noprivdrop.ksh new file mode 100755 index 0000000000..a5cd18386c --- /dev/null +++ b/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 diff --git a/usr/src/cmd/dtrace/test/tst/common/privs/tst.noprivrestrict.ksh b/usr/src/cmd/dtrace/test/tst/common/privs/tst.noprivrestrict.ksh new file mode 100755 index 0000000000..358ed92c6f --- /dev/null +++ b/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 diff --git a/usr/src/cmd/dtrace/test/tst/common/privs/tst.tick.ksh b/usr/src/cmd/dtrace/test/tst/common/privs/tst.tick.ksh new file mode 100755 index 0000000000..eaff59fa94 --- /dev/null +++ b/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 diff --git a/usr/src/pkg/manifests/system-dtrace-tests.mf b/usr/src/pkg/manifests/system-dtrace-tests.mf index d7d8c0e6be..fcb488550c 100644 --- a/usr/src/pkg/manifests/system-dtrace-tests.mf +++ b/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 \ diff --git a/usr/src/uts/common/dtrace/dcpc.c b/usr/src/uts/common/dtrace/dcpc.c index d4ca1d308b..8fd96cc24c 100644 --- a/usr/src/uts/common/dtrace/dcpc.c +++ b/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 }; diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c index c352f66d5d..1a0599ca31 100644 --- a/usr/src/uts/common/dtrace/dtrace.c +++ b/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 @@ bad: } 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); } diff --git a/usr/src/uts/common/dtrace/profile.c b/usr/src/uts/common/dtrace/profile.c index c1a2d1f1c1..fc809d3579 100644 --- a/usr/src/uts/common/dtrace/profile.c +++ b/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 }; diff --git a/usr/src/uts/common/sys/dtrace.h b/usr/src/uts/common/sys/dtrace.h index 834cfd6d55..7977373f7b 100644 --- a/usr/src/uts/common/sys/dtrace.h +++ b/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, diff --git a/usr/src/uts/common/sys/dtrace_impl.h b/usr/src/uts/common/sys/dtrace_impl.h index dc89cb1b0b..3bebd0cb30 100644 --- a/usr/src/uts/common/sys/dtrace_impl.h +++ b/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 |