[DTrace-devel] [PATCH v3 12/19] alloca: fix verifier failure checking the bounds of scalars

Nick Alcock nick.alcock at oracle.com
Thu Mar 24 18:24:38 UTC 2022


dt_check_scratch_bounds works for all genuine pointer inputs... but the
nature of the beast that the caller might pass it *anything*.  What if
the caller passes it a random integer, or a random kernel address?
The first thing we do is turn it into an offset by subtracting the
baseptr from it, and oops that is now maths between a scalar and a
map_value and the verifier fails.

So don't rely on the offset reduction to turn the reg into a scalar,
since it can fail if it already *is* one; instead, scalarize it
explicitly like we do for out-of-bounds checking.  That means we
have to scalarize the baseptr too, since if we already scalarized the
reg, subtracting the baseptr from it is now maths between a map_value
and a scalar again!

(We work on a copy of the baseptr, since we need a real map_value
baseptr at the end to turn the scalar reg offset back into a map_value.)

Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
 libdtrace/dt_cg.c | 31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 210aee4248b2..0f2fc02a316b 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -2143,13 +2143,36 @@ dt_cg_check_bounds(dt_irlist_t *dlp, dt_regset_t *drp, int regptr, int basereg,
 
 	/*
 	 * Check for below/above scratch space by reduction to offsets and
-	 * comparision, to allow the verifier to bounds-check.  Satisfy
-	 * the verifier after reduction via masking.
+	 * comparision, to allow the verifier to bounds-check.  Satisfy the
+	 * verifier after reduction via masking.  (This also catches null
+	 * pointers of both sorts, which are outside scratch space by
+	 * definition).  Annoyingly we need to take a copy of the basereg and
+	 * scalarize it first, or we might find an out-of-bounds address
+	 * yielding a verifier failure: this means we need to scalarize the reg
+	 * too, even though the subtraction would scalarize it in any case!
+	 * Round and round we go...
 	 */
 
 	if (regptr && basereg > -1) {
-		emit(dlp,  BPF_BRANCH_REG(BPF_JLT, reg, basereg, lbl_err));
-		emit(dlp, BPF_ALU64_REG(BPF_SUB, reg, basereg));
+		int mst, scalarbase;
+
+		if ((scalarbase = dt_regset_alloc(drp)) == -1 ||
+		    (mst = dt_regset_alloc(drp)) == 1)
+			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+		emit(dlp,  BPF_LOAD(BPF_DW, mst, BPF_REG_FP, DT_STK_DCTX));
+		emit(dlp,  BPF_LOAD(BPF_DW, mst, mst, DCTX_MST));
+
+		emit(dlp,  BPF_STORE(BPF_DW, mst, DMST_SCALARIZER, basereg));
+		emit(dlp,  BPF_LOAD(BPF_DW, scalarbase, mst, DMST_SCALARIZER));
+		emit(dlp,  BPF_STORE(BPF_DW, mst, DMST_SCALARIZER, reg));
+		emit(dlp,  BPF_LOAD(BPF_DW, reg, mst, DMST_SCALARIZER));
+
+		emit(dlp, BPF_BRANCH_REG(BPF_JLT, reg, scalarbase, lbl_err));
+		emit(dlp, BPF_ALU64_REG(BPF_SUB, reg, scalarbase));
+
+		dt_regset_free(drp, scalarbase);
+		dt_regset_free(drp, mst);
 	}
 
 	emit(dlp,  BPF_BRANCH_IMM(BPF_JSLT, reg, 0, lbl_err));
-- 
2.35.1.261.g8402f930ba.dirty




More information about the DTrace-devel mailing list