[DTrace-devel] [PATCH v3] Ensure curcpu values are scalarized when typecast

Kris Van Hees kris.van.hees at oracle.com
Wed Aug 3 17:03:18 UTC 2022


The 'curcpu' built-in variable is special because its value is a
pointer to a map value.  This means that the verifier will impose
strict limitations on what can be done with that pointer value.
By scalarizing it when it is typecast we ensure that the verifier
will treat the value as a regular scalar.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 bpf/get_bvar.c                             | 11 +++++++--
 libdtrace/dt_cg.c                          |  2 +-
 libdtrace/dt_ident.h                       |  1 +
 libdtrace/dt_open.c                        |  4 ++--
 libdtrace/dt_parser.c                      |  9 +++++---
 test/unittest/arithmetic/tst.cast-alloca.d | 27 ++++++++++++++++++++++
 test/unittest/arithmetic/tst.cast-curcpu.d | 26 +++++++++++++++++++++
 7 files changed, 72 insertions(+), 8 deletions(-)
 create mode 100644 test/unittest/arithmetic/tst.cast-alloca.d
 create mode 100644 test/unittest/arithmetic/tst.cast-curcpu.d

diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
index 4ff9b695..ef2e2ca6 100644
--- a/bpf/get_bvar.c
+++ b/bpf/get_bvar.c
@@ -186,8 +186,15 @@ noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx)
 		uint32_t	key = 0;
 		void		*val = bpf_map_lookup_elem(&cpuinfo, &key);
 
-		if (val == NULL)
-			return (uint64_t)NULL;	/* FIXME */
+		if (val == NULL) {
+			/*
+			 * Typically, we would use 'return error(...);' but
+			 * that confuses the verifier because it returns -1.
+			 * So, instead, we explicitly return 0.
+			 */
+			error(dctx, DTRACEFLT_ILLOP, 0);
+			return 0;
+		}
 
 		return (uint64_t)val;
 	}
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 83fbeba9..9ac00585 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -2521,7 +2521,7 @@ dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
 		return;
 
 	if (dt_node_is_arith(dst) && dt_node_is_pointer(src) &&
-	    (src->dn_flags & DT_NF_ALLOCA)) {
+	    (src->dn_flags & (DT_NF_ALLOCA | DT_NF_DPTR))) {
 		int	mst;
 
 		if ((mst = dt_regset_alloc(drp)) == -1)
diff --git a/libdtrace/dt_ident.h b/libdtrace/dt_ident.h
index 7a44613d..c7cb29d1 100644
--- a/libdtrace/dt_ident.h
+++ b/libdtrace/dt_ident.h
@@ -96,6 +96,7 @@ typedef struct dt_ident {
 #define	DT_IDFLG_BPF	0x1000	/* variable is BPF */
 #define	DT_IDFLG_ALLOCA	0x2000	/* variable holds an alloca()ed pointer */
 #define	DT_IDFLG_NONALLOCA 0x4000 /* variable known not to hold an alloca()ed pointer */
+#define DT_IDFLG_DPTR	0x8000	/* variable is ptr to DTrace-managed storage */
 
 #define DT_IDENT_UNDEF	UINT_MAX /* id for (as yet) undefined identifiers */
 
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 4ee506f3..f5cbd499 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -143,8 +143,8 @@ static const dt_ident_t _dtrace_globals[] = {
 	&dt_idops_func, "void(char *, uintptr_t, size_t)" },
 { "count", DT_IDENT_AGGFUNC, 0, DT_AGG_COUNT, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "void()" },
-{ "curcpu", DT_IDENT_SCALAR, 0, DIF_VAR_CURCPU, DT_ATTR_STABCMN, DT_VERS_1_0,
-	&dt_idops_type, "cpuinfo_t *" },
+{ "curcpu", DT_IDENT_SCALAR, DT_IDFLG_DPTR, DIF_VAR_CURCPU, DT_ATTR_STABCMN,
+	DT_VERS_1_0, &dt_idops_type, "cpuinfo_t *" },
 { "curthread", DT_IDENT_SCALAR, 0, DIF_VAR_CURTHREAD,
 	{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE,
 	DTRACE_CLASS_COMMON }, DT_VERS_1_0,
diff --git a/libdtrace/dt_parser.c b/libdtrace/dt_parser.c
index 1625e887..713c4f01 100644
--- a/libdtrace/dt_parser.c
+++ b/libdtrace/dt_parser.c
@@ -2819,10 +2819,13 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
 		dnp->dn_flags |= DT_NF_LVALUE;
 
 		/*
-		 * If the type of the variable is a REF-type, we mark this
-		 * variable node as a pointer to DTrace-managed storage (DPTR).
+		 * If the identifier is marked as a pointer to DTrace-managed
+		 * storage (DPTR), or if the type of the variable is a
+		 * REF-type, we mark this variable node as a pointer to
+		 * DTrace-managed storage (DPTR).
 		 */
-		if (dnp->dn_flags & DT_NF_REF)
+		if ((idp->di_flags & DT_IDFLG_DPTR) ||
+		    (dnp->dn_flags & DT_NF_REF))
 			dnp->dn_flags |= DT_NF_DPTR;
 
 		if (idp->di_flags & DT_IDFLG_WRITE)
diff --git a/test/unittest/arithmetic/tst.cast-alloca.d b/test/unittest/arithmetic/tst.cast-alloca.d
new file mode 100644
index 00000000..4af597d5
--- /dev/null
+++ b/test/unittest/arithmetic/tst.cast-alloca.d
@@ -0,0 +1,27 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, 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.
+ */
+
+/*
+ * ASSERTION: Casting an alloca() pointer to a scalar is allowed.
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	ptr = alloca(10);
+	val = ((int64_t)ptr) >> 8;
+	trace(val);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/arithmetic/tst.cast-curcpu.d b/test/unittest/arithmetic/tst.cast-curcpu.d
new file mode 100644
index 00000000..bc58352d
--- /dev/null
+++ b/test/unittest/arithmetic/tst.cast-curcpu.d
@@ -0,0 +1,26 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2022, 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.
+ */
+
+/*
+ * ASSERTION: Casting a curcpu value to a scalar is allowed.
+ *
+ * SECTION: Types, Operators, and Expressions/Arithmetic Operators
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	val = ((int64_t)curcpu) >> 8;
+	trace(val);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
-- 
2.34.1




More information about the DTrace-devel mailing list