--- /dev/null	Fri Jun 22 23:09:00 2012
+++ new/usr/src/cmd/dtrace/test/tst/common/privs/tst.procpriv.ksh	Fri Jun 22 23:09:00 2012
@@ -0,0 +1,138 @@
+#
+# 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.
+#
+
+ppriv -s A=basic,dtrace_proc,dtrace_user $$
+
+#
+# When we have dtrace_proc (but lack dtrace_kernel), we expect to be able to
+# read certain curpsinfo/curlwpsinfo/curcpu fields even though they require
+# reading in-kernel state.  However, there are other fields in these translated
+# structures that we know we shouldn't be able to read, as they require reading
+# in-kernel state that we cannot read with only dtrace_proc.  Finally, there
+# are a few fields that we may or may not be able to read depending on the
+# specifics of context.  This test therefore asserts that we can read what we
+# think we should be able to, that we can't read what we think we shouldn't be
+# able to, and (for purposes of completeness) that we are indifferent about
+# what we cannot assert one way or the other.
+#
+/usr/sbin/dtrace -q -Cs /dev/stdin <<EOF
+
+#define CANREAD(what, field) \
+    BEGIN { errmsg = "can't read field from what"; printf("field: "); \
+	trace(what->field); printf("\n"); }
+
+#define CANTREAD(what, field) \
+    BEGIN { errmsg = ""; trace(what->field); \
+	printf("\nable to successfully read field from what!"); exit(1); }
+
+#define MIGHTREAD(what, field) \
+    BEGIN { errmsg = ""; printf("field: "); trace(what->field); printf("\n"); }
+
+#define CANREADVAR(vname) \
+    BEGIN { errmsg = "can't read vname"; printf("vname: "); \
+	trace(vname); printf("\n"); }
+
+#define CANTREADVAR(vname) \
+    BEGIN { errmsg = ""; trace(vname); \
+	printf("\nable to successfully read vname!"); exit(1); }
+
+#define MIGHTREADVAR(vname) \
+    BEGIN { errmsg = ""; printf("vname: "); trace(vname); printf("\n"); }
+
+CANREAD(curpsinfo, pr_pid)
+CANREAD(curpsinfo, pr_nlwp)
+CANREAD(curpsinfo, pr_ppid)
+CANREAD(curpsinfo, pr_uid)
+CANREAD(curpsinfo, pr_euid)
+CANREAD(curpsinfo, pr_gid)
+CANREAD(curpsinfo, pr_egid)
+CANREAD(curpsinfo, pr_addr)
+CANREAD(curpsinfo, pr_start)
+CANREAD(curpsinfo, pr_fname)
+CANREAD(curpsinfo, pr_psargs)
+CANREAD(curpsinfo, pr_argc)
+CANREAD(curpsinfo, pr_argv)
+CANREAD(curpsinfo, pr_envp)
+CANREAD(curpsinfo, pr_dmodel)
+
+/*
+ * If our p_pgidp points to the same pid structure as our p_pidp, we will
+ * be able to read pr_pgid -- but we won't if not.
+ */
+MIGHTREAD(curpsinfo, pr_pgid)
+
+CANTREAD(curpsinfo, pr_sid)
+CANTREAD(curpsinfo, pr_ttydev)
+CANTREAD(curpsinfo, pr_projid)
+CANTREAD(curpsinfo, pr_zoneid)
+CANTREAD(curpsinfo, pr_contract)
+
+CANREAD(curlwpsinfo, pr_flag)
+CANREAD(curlwpsinfo, pr_lwpid)
+CANREAD(curlwpsinfo, pr_addr)
+CANREAD(curlwpsinfo, pr_wchan)
+CANREAD(curlwpsinfo, pr_stype)
+CANREAD(curlwpsinfo, pr_state)
+CANREAD(curlwpsinfo, pr_sname)
+CANREAD(curlwpsinfo, pr_syscall)
+CANREAD(curlwpsinfo, pr_pri)
+CANREAD(curlwpsinfo, pr_onpro)
+CANREAD(curlwpsinfo, pr_bindpro)
+CANREAD(curlwpsinfo, pr_bindpset)
+
+CANTREAD(curlwpsinfo, pr_clname)
+CANTREAD(curlwpsinfo, pr_lgrp)
+
+CANREAD(curcpu, cpu_id)
+
+CANTREAD(curcpu, cpu_pset)
+CANTREAD(curcpu, cpu_chip)
+CANTREAD(curcpu, cpu_lgrp)
+CANTREAD(curcpu, cpu_info)
+
+/*
+ * We cannot assert one thing or another about the variable "root":  for those
+ * with only dtrace_proc, it will be readable in the global but not readable in
+ * the non-global.
+ */
+MIGHTREADVAR(root)
+
+CANREADVAR(cpu)
+CANTREADVAR(pset)
+CANTREADVAR(cwd)
+CANTREADVAR(chip)
+CANTREADVAR(lgrp)
+
+BEGIN
+{
+	exit(0);
+}
+
+ERROR
+/errmsg != ""/
+{
+	printf("fatal error: %s", errmsg);
+	exit(1);
+}
--- old/usr/src/uts/common/dtrace/dtrace.c	Fri Jun 22 23:09:00 2012
+++ new/usr/src/uts/common/dtrace/dtrace.c	Fri Jun 22 23:09:00 2012
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  */
 
 /*
@@ -372,8 +372,8 @@
  * disallow all negative sizes.  Ranges of size 0 are allowed.
  */
 #define	DTRACE_INRANGE(testaddr, testsz, baseaddr, basesz) \
-	((testaddr) - (baseaddr) < (basesz) && \
-	(testaddr) + (testsz) - (baseaddr) <= (basesz) && \
+	((testaddr) - (uintptr_t)(baseaddr) < (basesz) && \
+	(testaddr) + (testsz) - (uintptr_t)(baseaddr) <= (basesz) && \
 	(testaddr) + (testsz) >= (testaddr))
 
 /*
@@ -474,6 +474,7 @@
     dtrace_optval_t);
 static int dtrace_ecb_create_enable(dtrace_probe_t *, void *);
 static void dtrace_helper_provider_destroy(dtrace_helper_provider_t *);
+static int dtrace_priv_proc(dtrace_state_t *, dtrace_mstate_t *);
 
 /*
  * DTrace Probe Context Functions
@@ -618,7 +619,7 @@
 	 * up both thread-local variables and any global dynamically-allocated
 	 * variables.
 	 */
-	if (DTRACE_INRANGE(addr, sz, (uintptr_t)vstate->dtvs_dynvars.dtds_base,
+	if (DTRACE_INRANGE(addr, sz, vstate->dtvs_dynvars.dtds_base,
 	    vstate->dtvs_dynvars.dtds_size)) {
 		dtrace_dstate_t *dstate = &vstate->dtvs_dynvars;
 		uintptr_t base = (uintptr_t)dstate->dtds_base +
@@ -702,10 +703,54 @@
 	/*
 	 * We're allowed to read from our own string table.
 	 */
-	if (DTRACE_INRANGE(addr, sz, (uintptr_t)mstate->dtms_difo->dtdo_strtab,
+	if (DTRACE_INRANGE(addr, sz, mstate->dtms_difo->dtdo_strtab,
 	    mstate->dtms_difo->dtdo_strlen))
 		return (1);
 
+	if (vstate->dtvs_state != NULL &&
+	    dtrace_priv_proc(vstate->dtvs_state, mstate)) {
+		proc_t *p;
+
+		/*
+		 * When we have privileges to the current process, there are
+		 * several context-related kernel structures that are safe to
+		 * read, even absent the privilege to read from kernel memory.
+		 * These reads are safe because these structures contain only
+		 * state that (1) we're permitted to read, (2) is harmless or
+		 * (3) contains pointers to additional kernel state that we're
+		 * not permitted to read (and as such, do not present an
+		 * opportunity for privilege escalation).  Finally (and
+		 * critically), because of the nature of their relation with
+		 * the current thread context, the memory associated with these
+		 * structures cannot change over the duration of probe context,
+		 * and it is therefore impossible for this memory to be
+		 * deallocated and reallocated as something else while it's
+		 * being operated upon.
+		 */
+		if (DTRACE_INRANGE(addr, sz, curthread, sizeof (kthread_t)))
+			return (1);
+
+		if ((p = curthread->t_procp) != NULL && DTRACE_INRANGE(addr,
+		    sz, curthread->t_procp, sizeof (proc_t))) {
+			return (1);
+		}
+
+		if (curthread->t_cred != NULL && DTRACE_INRANGE(addr, sz,
+		    curthread->t_cred, sizeof (cred_t))) {
+			return (1);
+		}
+
+		if (p != NULL && p->p_pidp != NULL && DTRACE_INRANGE(addr, sz,
+		    &(p->p_pidp->pid_id), sizeof (pid_t))) {
+			return (1);
+		}
+
+		if (curthread->t_cpu != NULL && DTRACE_INRANGE(addr, sz,
+		    curthread->t_cpu, offsetof(cpu_t, cpu_pause_thread))) {
+			return (1);
+		}
+	}
+
 	DTRACE_CPUFLAG_SET(CPU_DTRACE_KPRIV);
 	*illval = addr;
 	return (0);
@@ -2892,7 +2937,7 @@
 	}
 
 	case DIF_VAR_CURTHREAD:
-		if (!dtrace_priv_kernel(state))
+		if (!dtrace_priv_proc(state, mstate))
 			return (0);
 		return ((uint64_t)(uintptr_t)curthread);
 
@@ -4907,71 +4952,50 @@
 				pc = DIF_INSTR_LABEL(instr);
 			break;
 		case DIF_OP_RLDSB:
-			if (!dtrace_canstore(regs[r1], 1, mstate, vstate)) {
-				*flags |= CPU_DTRACE_KPRIV;
-				*illval = regs[r1];
+			if (!dtrace_canload(regs[r1], 1, mstate, vstate))
 				break;
-			}
 			/*FALLTHROUGH*/
 		case DIF_OP_LDSB:
 			regs[rd] = (int8_t)dtrace_load8(regs[r1]);
 			break;
 		case DIF_OP_RLDSH:
-			if (!dtrace_canstore(regs[r1], 2, mstate, vstate)) {
-				*flags |= CPU_DTRACE_KPRIV;
-				*illval = regs[r1];
+			if (!dtrace_canload(regs[r1], 2, mstate, vstate))
 				break;
-			}
 			/*FALLTHROUGH*/
 		case DIF_OP_LDSH:
 			regs[rd] = (int16_t)dtrace_load16(regs[r1]);
 			break;
 		case DIF_OP_RLDSW:
-			if (!dtrace_canstore(regs[r1], 4, mstate, vstate)) {
-				*flags |= CPU_DTRACE_KPRIV;
-				*illval = regs[r1];
+			if (!dtrace_canload(regs[r1], 4, mstate, vstate))
 				break;
-			}
 			/*FALLTHROUGH*/
 		case DIF_OP_LDSW:
 			regs[rd] = (int32_t)dtrace_load32(regs[r1]);
 			break;
 		case DIF_OP_RLDUB:
-			if (!dtrace_canstore(regs[r1], 1, mstate, vstate)) {
-				*flags |= CPU_DTRACE_KPRIV;
-				*illval = regs[r1];
+			if (!dtrace_canload(regs[r1], 1, mstate, vstate))
 				break;
-			}
 			/*FALLTHROUGH*/
 		case DIF_OP_LDUB:
 			regs[rd] = dtrace_load8(regs[r1]);
 			break;
 		case DIF_OP_RLDUH:
-			if (!dtrace_canstore(regs[r1], 2, mstate, vstate)) {
-				*flags |= CPU_DTRACE_KPRIV;
-				*illval = regs[r1];
+			if (!dtrace_canload(regs[r1], 2, mstate, vstate))
 				break;
-			}
 			/*FALLTHROUGH*/
 		case DIF_OP_LDUH:
 			regs[rd] = dtrace_load16(regs[r1]);
 			break;
 		case DIF_OP_RLDUW:
-			if (!dtrace_canstore(regs[r1], 4, mstate, vstate)) {
-				*flags |= CPU_DTRACE_KPRIV;
-				*illval = regs[r1];
+			if (!dtrace_canload(regs[r1], 4, mstate, vstate))
 				break;
-			}
 			/*FALLTHROUGH*/
 		case DIF_OP_LDUW:
 			regs[rd] = dtrace_load32(regs[r1]);
 			break;
 		case DIF_OP_RLDX:
-			if (!dtrace_canstore(regs[r1], 8, mstate, vstate)) {
-				*flags |= CPU_DTRACE_KPRIV;
-				*illval = regs[r1];
+			if (!dtrace_canload(regs[r1], 8, mstate, vstate))
 				break;
-			}
 			/*FALLTHROUGH*/
 		case DIF_OP_LDX:
 			regs[rd] = dtrace_load64(regs[r1]);
