--- /dev/null	Sat Jun 23 09:31:25 2012
+++ new/usr/src/cmd/dtrace/test/tst/common/privs/tst.providers.ksh	Sat Jun 23 09:31:25 2012
@@ -0,0 +1,126 @@
+#
+# 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) 2012, Joyent, Inc. All rights reserved.
+#
+
+#
+# First, make sure that we can successfully enable the io provider
+#
+if ! dtrace -P io -n BEGIN'{exit(0)}' > /dev/null 2>&1 ; then
+	echo failed to enable io provider with full privs
+	exit 1
+fi
+
+ppriv -s A=basic,dtrace_proc,dtrace_user $$
+
+#
+# Now make sure that we cannot enable the io provider with reduced privs
+#
+if ! dtrace -x errtags -P io -n BEGIN'{exit(1)}' 2>&1 | \
+    grep D_PDESC_ZERO > /dev/null 2>&1 ; then
+	echo successfully enabled the io provider with reduced privs
+	exit 1
+fi
+
+#
+# Keeping our reduced privs, we want to assure that we can see every provider
+# that we think we should be able to see -- and that we can see curpsinfo
+# state but can't otherwise see arguments.
+#
+/usr/sbin/dtrace -wq -Cs /dev/stdin <<EOF
+
+int seen[string];
+int err;
+
+#define CANENABLE(provider) \
+provider:::								\
+/err == 0 && progenyof(\$pid) && !seen["provider"]/			\
+{									\
+	trace(arg0);							\
+	printf("\nsuccessful trace of arg0 in %s:%s:%s:%s\n",		\
+	    probeprov, probemod, probefunc, probename);			\
+	exit(++err);							\
+}									\
+									\
+provider:::								\
+/progenyof(\$pid)/							\
+{									\
+	seen["provider"]++;						\
+}									\
+									\
+provider:::								\
+/progenyof(\$pid)/							\
+{									\
+	errstr = "provider";						\
+	this->ignore = stringof(curpsinfo->pr_psargs);			\
+	errstr = "";							\
+}									\
+									\
+END									\
+/err == 0 && !seen["provider"]/						\
+{									\
+	printf("no probes from provider\n");				\
+	exit(++err);							\
+}									\
+									\
+END									\
+/err == 0/								\
+{									\
+	printf("saw %d probes from provider\n", seen["provider"]);	\
+}
+
+CANENABLE(proc)
+CANENABLE(sched)
+CANENABLE(vminfo)
+CANENABLE(sysinfo)
+
+BEGIN
+{
+	/*
+	 * We'll kick off a system of a do-nothing command -- which should be
+	 * enough to kick proc, sched, vminfo and sysinfo probes.
+	 */
+	system("echo > /dev/null");
+}
+
+ERROR
+/err == 0 && errstr != ""/
+{
+	printf("fatal error: couldn't read curpsinfo->pr_psargs in ");
+	printf("%s-provided probe\n", errstr);
+	exit(++err);
+}
+
+proc:::exit
+/progenyof(\$pid)/
+{
+	exit(0);
+}
+
+tick-10ms
+/i++ > 500/
+{
+	printf("exit probe did not seem to fire\n");
+	exit(++err);
+}
+EOF
--- old/usr/src/uts/common/dtrace/dtrace.c	Sat Jun 23 09:31:25 2012
+++ new/usr/src/uts/common/dtrace/dtrace.c	Sat Jun 23 09:31:26 2012
@@ -1300,19 +1300,17 @@
 		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));
+		ASSERT(mode & (DTRACE_MODE_USER | DTRACE_MODE_KERNEL));
+		ASSERT(mode & (DTRACE_MODE_NOPRIV_RESTRICT |
+		    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.
+	 * see user-mode firings of this probe, 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);
@@ -1379,6 +1377,15 @@
 		}
 	}
 
+	/*
+	 * By merits of being in this code path at all, we have limited
+	 * privileges.  If the provider has indicated that limited privileges
+	 * are to denote restricted operation, strip off the ability to access
+	 * arguments.
+	 */
+	if (mode & DTRACE_MODE_LIMITEDPRIV_RESTRICT)
+		mstate->dtms_access &= ~DTRACE_ACCESS_ARGS;
+
 	return (1);
 }
 
--- old/usr/src/uts/common/dtrace/sdt_subr.c	Sat Jun 23 09:31:27 2012
+++ new/usr/src/uts/common/dtrace/sdt_subr.c	Sat Jun 23 09:31:27 2012
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  */
 
 #include <sys/sdt_impl.h>
@@ -97,26 +98,26 @@
 };
 
 sdt_provider_t sdt_providers[] = {
-	{ "vtrace", "__vtrace_", &vtrace_attr, 0 },
-	{ "sysinfo", "__cpu_sysinfo_", &info_attr, 0 },
-	{ "vminfo", "__cpu_vminfo_", &info_attr, 0 },
-	{ "fpuinfo", "__fpuinfo_", &fpu_attr, 0 },
-	{ "sched", "__sched_", &stab_attr, 0 },
-	{ "proc", "__proc_", &stab_attr, 0 },
-	{ "io", "__io_", &stab_attr, 0 },
-	{ "ip", "__ip_", &stab_attr, 0 },
-	{ "tcp", "__tcp_", &stab_attr, 0 },
-	{ "udp", "__udp_", &stab_attr, 0 },
-	{ "mib", "__mib_", &stab_attr, 0 },
-	{ "fsinfo", "__fsinfo_", &fsinfo_attr, 0 },
-	{ "iscsi", "__iscsi_", &iscsi_attr, 0 },
-	{ "nfsv3", "__nfsv3_", &stab_attr, 0 },
-	{ "nfsv4", "__nfsv4_", &stab_attr, 0 },
-	{ "xpv", "__xpv_", &xpv_attr, 0 },
-	{ "fc", "__fc_", &fc_attr, 0 },
-	{ "srp", "__srp_", &fc_attr, 0 },
-	{ "sysevent", "__sysevent_", &stab_attr, 0 },
-	{ "sdt", NULL, &sdt_attr, 0 },
+	{ "vtrace", "__vtrace_", &vtrace_attr },
+	{ "sysinfo", "__cpu_sysinfo_", &info_attr, DTRACE_PRIV_USER },
+	{ "vminfo", "__cpu_vminfo_", &info_attr, DTRACE_PRIV_USER },
+	{ "fpuinfo", "__fpuinfo_", &fpu_attr },
+	{ "sched", "__sched_", &stab_attr, DTRACE_PRIV_USER },
+	{ "proc", "__proc_", &stab_attr, DTRACE_PRIV_USER },
+	{ "io", "__io_", &stab_attr },
+	{ "ip", "__ip_", &stab_attr },
+	{ "tcp", "__tcp_", &stab_attr },
+	{ "udp", "__udp_", &stab_attr },
+	{ "mib", "__mib_", &stab_attr },
+	{ "fsinfo", "__fsinfo_", &fsinfo_attr },
+	{ "iscsi", "__iscsi_", &iscsi_attr },
+	{ "nfsv3", "__nfsv3_", &stab_attr },
+	{ "nfsv4", "__nfsv4_", &stab_attr },
+	{ "xpv", "__xpv_", &xpv_attr },
+	{ "fc", "__fc_", &fc_attr },
+	{ "srp", "__srp_", &fc_attr },
+	{ "sysevent", "__sysevent_", &stab_attr },
+	{ "sdt", NULL, &sdt_attr },
 	{ NULL }
 };
 
@@ -1155,6 +1156,20 @@
 };
 
 /*ARGSUSED*/
+int
+sdt_mode(void *arg, dtrace_id_t id, void *parg)
+{
+	/*
+	 * We tell DTrace that we're in kernel mode, that the firing needs to
+	 * be dropped for anything that doesn't have necessary privileges, and
+	 * that it needs to be restricted for anything that has restricted
+	 * (i.e., not all-zone) privileges.
+	 */
+	return (DTRACE_MODE_KERNEL | DTRACE_MODE_NOPRIV_DROP |
+	    DTRACE_MODE_LIMITEDPRIV_RESTRICT);
+}
+
+/*ARGSUSED*/
 void
 sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
 {
--- old/usr/src/uts/common/sys/dtrace.h	Sat Jun 23 09:31:28 2012
+++ new/usr/src/uts/common/sys/dtrace.h	Sat Jun 23 09:31:28 2012
@@ -25,7 +25,7 @@
  */
 
 /*
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  */
 
 #ifndef _SYS_DTRACE_H
@@ -1625,13 +1625,20 @@
  *
  *   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.
+ *   is insufficient for that mode (a combination of DTRACE_MODE_NOPRIV_DROP,
+ *   DTRACE_MODE_NOPRIV_RESTRICT, and DTRACE_MODE_LIMITEDPRIV_RESTRICT).  If
+ *   DTRACE_MODE_NOPRIV_DROP bit is set, insufficient privilege will result
+ *   in the probe firing being silently ignored for the enabling; if the
+ *   DTRACE_NODE_NOPRIV_RESTRICT bit is set, 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.  If the DTRACE_MODE_LIMITEDPRIV_RESTRICT bit
+ *   is set, similar restrictions will be placed upon operation if the
+ *   privilege is sufficient to process the enabling, but does not otherwise
+ *   entitle the enabling to all zones.  The DTRACE_MODE_NOPRIV_DROP and
+ *   DTRACE_MODE_NOPRIV_RESTRICT are mutually exclusive (and one of these
+ *   two policies must be specified), but either may be combined (or not)
+ *   with DTRACE_MODE_LIMITEDPRIV_RESTRICT.
  *
  * 1.10.4  Caller's context
  *
@@ -2030,6 +2037,7 @@
 #define	DTRACE_MODE_USER			0x02
 #define	DTRACE_MODE_NOPRIV_DROP			0x10
 #define	DTRACE_MODE_NOPRIV_RESTRICT		0x20
+#define	DTRACE_MODE_LIMITEDPRIV_RESTRICT	0x40
 
 typedef uintptr_t	dtrace_provider_id_t;
 
--- old/usr/src/uts/common/sys/sdt_impl.h	Sat Jun 23 09:31:29 2012
+++ new/usr/src/uts/common/sys/sdt_impl.h	Sat Jun 23 09:31:29 2012
@@ -24,11 +24,13 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
 #ifndef _SYS_SDT_IMPL_H
 #define	_SYS_SDT_IMPL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -45,6 +47,7 @@
 	char			*sdtp_name;	/* name of provider */
 	char			*sdtp_prefix;	/* prefix for probe names */
 	dtrace_pattr_t		*sdtp_attr;	/* stability attributes */
+	uint32_t		sdtp_priv;	/* privilege, if any */
 	dtrace_provider_id_t	sdtp_id;	/* provider ID */
 } sdt_provider_t;
 
@@ -75,6 +78,7 @@
 } sdt_argdesc_t;
 
 extern void sdt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
+extern int sdt_mode(void *, dtrace_id_t, void *);
 
 #ifdef	__cplusplus
 }
--- old/usr/src/uts/intel/dtrace/sdt.c	Sat Jun 23 09:31:29 2012
+++ new/usr/src/uts/intel/dtrace/sdt.c	Sat Jun 23 09:31:29 2012
@@ -23,6 +23,9 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
 
 #include <sys/modctl.h>
 #include <sys/sunddi.h>
@@ -419,9 +422,19 @@
 	dtrace_invop_add(sdt_invop);
 
 	for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) {
+		uint32_t priv;
+
+		if (prov->sdtp_priv == DTRACE_PRIV_NONE) {
+			priv = DTRACE_PRIV_KERNEL;
+			sdt_pops.dtps_mode = NULL;
+		} else {
+			priv = prov->sdtp_priv;
+			ASSERT(priv == DTRACE_PRIV_USER);
+			sdt_pops.dtps_mode = sdt_mode;
+		}
+
 		if (dtrace_register(prov->sdtp_name, prov->sdtp_attr,
-		    DTRACE_PRIV_KERNEL, NULL,
-		    &sdt_pops, prov, &prov->sdtp_id) != 0) {
+		    priv, NULL, &sdt_pops, prov, &prov->sdtp_id) != 0) {
 			cmn_err(CE_WARN, "failed to register sdt provider %s",
 			    prov->sdtp_name);
 		}
--- old/usr/src/uts/sparc/dtrace/sdt.c	Sat Jun 23 09:31:29 2012
+++ new/usr/src/uts/sparc/dtrace/sdt.c	Sat Jun 23 09:31:29 2012
@@ -23,6 +23,9 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
 
 #include <sys/modctl.h>
 #include <sys/sunddi.h>
@@ -373,9 +376,19 @@
 	sdt_devi = devi;
 
 	for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) {
+		uint32_t priv;
+
+		if (prov->sdtp_priv == DTRACE_PRIV_NONE) {
+			priv = DTRACE_PRIV_KERNEL;
+			sdt_pops.dtps_mode = NULL;
+		} else {
+			priv = prov->sdtp_priv;
+			ASSERT(priv == DTRACE_PRIV_USER);
+			sdt_pops.dtps_mode = sdt_mode;
+		}
+
 		if (dtrace_register(prov->sdtp_name, prov->sdtp_attr,
-		    DTRACE_PRIV_KERNEL, NULL,
-		    &sdt_pops, prov, &prov->sdtp_id) != 0) {
+		    priv, NULL, &sdt_pops, prov, &prov->sdtp_id) != 0) {
 			cmn_err(CE_WARN, "failed to register sdt provider %s",
 			    prov->sdtp_name);
 		}
