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: