Print this page
2915 DTrace in a zone should see "cpu", "curpsinfo", et al

@@ -19,11 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * 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.
  */
 
 /*
  * DTrace - Dynamic Tracing for Solaris
  *

@@ -370,12 +370,12 @@
  * within the range of memory described by addr, sz.  We take care to avoid
  * problems with overflow and underflow of the unsigned quantities, and
  * 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))
 
 /*
  * Test whether alloc_sz bytes will fit in the scratch region.  We isolate
  * alloc_sz on the righthand side of the comparison in order to avoid overflow

@@ -472,10 +472,11 @@
     dtrace_state_t *, dtrace_mstate_t *);
 static int dtrace_state_option(dtrace_state_t *, dtrace_optid_t,
     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
  *
  * These functions are called from probe context.  Because probe context is

@@ -616,11 +617,11 @@
         /*
          * Now check to see if it's a dynamic variable.  This check will pick
          * 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 +
                     (dstate->dtds_hashsize * sizeof (dtrace_dynhash_t));
                 uintptr_t chunkoffs;

@@ -700,14 +701,58 @@
                 return (1);
 
         /*
          * 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);
 }
 

@@ -2890,11 +2935,11 @@
 
                 return (rval);
         }
 
         case DIF_VAR_CURTHREAD:
-                if (!dtrace_priv_kernel(state))
+                if (!dtrace_priv_proc(state, mstate))
                         return (0);
                 return ((uint64_t)(uintptr_t)curthread);
 
         case DIF_VAR_TIMESTAMP:
                 if (!(mstate->dtms_present & DTRACE_MSTATE_TIMESTAMP)) {

@@ -4905,75 +4950,54 @@
                 case DIF_OP_BLEU:
                         if (cc_c | cc_z)
                                 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]);
                         break;
                 case DIF_OP_ULDSB: