[DTrace-devel] [PATCH] Ensure string constants that are too long are truncated correctly

Kris Van Hees kris.van.hees at oracle.com
Fri Nov 19 05:38:39 UTC 2021


The string table can contain strings that are longer than the maximum
string size for the program being compiled.  They need to be truncated
before they are used to ensure that string operations work correctly.

We need to treat the probeprov, probemod, probefunc, probename built-in
variable special because they return pointers to a string constant in
the strtab, but we do not know their actual content until runtime.  For
that case, we change the dt_get_bvar() code to return the string
constant strtab offset rather than a pointer to the string, and use that
to copy the string to a tstring (possibly truncating it).

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 bpf/get_bvar.c                               |  6 +-
 libdtrace/dt_cg.c                            | 74 ++++++++++++++++++--
 test/unittest/codegen/tst.str_const_length.d | 21 ++++++
 test/unittest/codegen/tst.str_const_length.r |  4 ++
 4 files changed, 95 insertions(+), 10 deletions(-)
 create mode 100644 test/unittest/codegen/tst.str_const_length.d
 create mode 100644 test/unittest/codegen/tst.str_const_length.r

diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
index 7c98e166..55ba5585 100644
--- a/bpf/get_bvar.c
+++ b/bpf/get_bvar.c
@@ -103,7 +103,7 @@ noinline uint64_t dt_get_bvar(dt_dctx_t *dctx, uint32_t id)
 		key = mst->prid;
 		pinfo = bpf_map_lookup_elem(&probes, &key);
 		if (pinfo == NULL)
-			return (uint64_t)dctx->strtab;
+			return 0;
 
 		switch (id) {
 		case DIF_VAR_PROBEPROV:
@@ -119,9 +119,9 @@ noinline uint64_t dt_get_bvar(dt_dctx_t *dctx, uint32_t id)
 			off = pinfo->prb;
 		}
 		if (off > (uint64_t)&STBSZ)
-			return (uint64_t)dctx->strtab;
+			return 0;
 
-		return (uint64_t)(dctx->strtab + off);
+		return off;
 	}
 	case DIF_VAR_PID: {
 		uint64_t	val = bpf_get_current_pid_tgid();
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index a42005c6..3b13dbdf 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -887,11 +887,50 @@ dt_cg_tstring_free(dt_pcb_t *pcb, dt_node_t *dnp)
 	case DT_NODE_OP2:
 	case DT_NODE_OP3:
 	case DT_NODE_DEXPR:
+	case DT_NODE_STRING:
+	case DT_NODE_VAR:
 		if (dnp->dn_tstring)
 			dt_cg_tstring_xfree(pcb, dnp->dn_tstring->dn_value);
 	}
 }
 
+/*
+ * Copy a string constant (referenced by the strtab offset value stored in
+ * dnp->dn_reg) into a newly allocated tstring.  The tstring will be associated
+ * with dnp.
+ */
+static void
+dt_cg_strconst_to_tstring(dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dnp)
+{
+	size_t	size = yypcb->pcb_hdl->dt_options[DTRACEOPT_STRSIZE];
+
+	emit(dlp,  BPF_MOV_REG(BPF_REG_0, dnp->dn_reg));
+
+	dt_cg_tstring_alloc(yypcb, dnp);
+	emit(dlp,  BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_FP, DT_STK_DCTX));
+	emit(dlp,  BPF_LOAD(BPF_DW, dnp->dn_reg, dnp->dn_reg, DCTX_MEM));
+	emit(dlp,  BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, dnp->dn_tstring->dn_value));
+
+	if (dt_regset_xalloc_args(drp) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	emit(dlp, BPF_MOV_REG(BPF_REG_1, dnp->dn_reg));
+	emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STRLEN_BYTES));
+	emit(dlp, BPF_MOV_IMM(BPF_REG_2, size + 1));
+	emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_FP, DT_STK_DCTX));
+	emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_3, DCTX_STRTAB));
+	emit(dlp, BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_0));
+	emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, DT_STRLEN_BYTES));
+	dt_regset_xalloc(drp, BPF_REG_0);
+	emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read_str));
+	dt_regset_free_args(drp);
+	emit(dlp, BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 1));
+	emit(dlp, BPF_STORE(BPF_B, dnp->dn_reg, 1, BPF_REG_0));
+	emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 8));
+	emit(dlp, BPF_STORE(BPF_B, dnp->dn_reg, 0, BPF_REG_0));
+	dt_regset_free(drp, BPF_REG_0);
+}
+
 static const uint_t	ldstw[] = {
 					0,
 					BPF_B,	BPF_H,	0, BPF_W,
@@ -2076,8 +2115,16 @@ dt_cg_load_var(dt_node_t *dst, dt_irlist_t *dlp, dt_regset_t *drp)
 
 	if ((dst->dn_reg = dt_regset_alloc(drp)) == -1)
 		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-	emit(dlp,  BPF_MOV_REG(dst->dn_reg, BPF_REG_0));
+	emit(dlp, BPF_MOV_REG(dst->dn_reg, BPF_REG_0));
 	dt_regset_free(drp, BPF_REG_0);
+
+	/*
+	 * If the variable is a string value, we need to ensure that it is not
+	 * exceed the maximum string length.  The easiest way to do that is to
+	 * just make a copy in a tstring, and use the copy.
+	 */
+	if (dt_node_is_string(dst))
+		dt_cg_strconst_to_tstring(dlp, drp, dst);
 }
 
 static void
@@ -4305,7 +4352,9 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 		break;
 	}
 
-	case DT_TOK_STRING:
+	case DT_TOK_STRING: {
+		size_t	size = yypcb->pcb_hdl->dt_options[DTRACEOPT_STRSIZE];
+
 		if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
 			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
 
@@ -4319,13 +4368,24 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 			longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG);
 
 		/*
-		 * Calculate the address of the string data in the 'strtab' BPF
-		 * map.
+		 * If the string constant is longer than the maximum string
+		 * size, we create a truncated copy in a tstring and use the
+		 * adress of the tstring.
+		 *
+		 * If the string constant is not longer than the maximum string
+		 * size, we can just use the address of the string constant in
+		 * the 'strtab' BPF  map.
 		 */
-		emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_FP, DT_STK_DCTX));
-		emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, dnp->dn_reg, DCTX_STRTAB));
-		emit(dlp, BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, stroff));
+		if (dt_node_type_size(dnp) > size) {
+			emit(dlp, BPF_MOV_IMM(dnp->dn_reg, stroff));
+			dt_cg_strconst_to_tstring(dlp, drp, dnp);
+		} else {
+			emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_FP, DT_STK_DCTX));
+			emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, dnp->dn_reg, DCTX_STRTAB));
+			emit(dlp, BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, stroff));
+		}
 		break;
+	}
 
 	case DT_TOK_IDENT:
 		/*
diff --git a/test/unittest/codegen/tst.str_const_length.d b/test/unittest/codegen/tst.str_const_length.d
new file mode 100644
index 00000000..1c58ba13
--- /dev/null
+++ b/test/unittest/codegen/tst.str_const_length.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+#pragma D option rawbytes
+#pragma D option strsize=5
+#pragma D option quiet
+
+BEGIN
+{
+	trace("abcdefgh");
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/codegen/tst.str_const_length.r b/test/unittest/codegen/tst.str_const_length.r
new file mode 100644
index 00000000..b6991a71
--- /dev/null
+++ b/test/unittest/codegen/tst.str_const_length.r
@@ -0,0 +1,4 @@
+
+             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
+         0: 00 05 61 62 63 64 65 00                          ..abcde.
+
-- 
2.33.0




More information about the DTrace-devel mailing list