[DTrace-devel] [PATCH v2] cg: fix store/load for struct and union members for alloca pointers

Kris Van Hees kris.van.hees at oracle.com
Thu Aug 31 16:47:43 UTC 2023


Storing to and loading from struct or union members of alloca pointers
was not properly turning the alloca pointer into a real pointer, nor was
it performing boundary checks.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_cg.c                             | 32 ++++++++++-----
 .../funcs/alloca/tst.alloca-array-load.d      | 29 ++++++++++++++
 .../funcs/alloca/tst.alloca-array-store.d     | 28 +++++++++++++
 .../funcs/alloca/tst.alloca-deref-load.d      | 29 ++++++++++++++
 .../funcs/alloca/tst.alloca-deref-store.d     | 28 +++++++++++++
 .../funcs/alloca/tst.alloca-struct-load.d     | 33 +++++++++++++++
 .../funcs/alloca/tst.alloca-struct-store.d    | 32 +++++++++++++++
 .../alloca/tst.alloca-struct-union-load.d     | 40 +++++++++++++++++++
 .../alloca/tst.alloca-struct-union-store.d    | 39 ++++++++++++++++++
 9 files changed, 281 insertions(+), 9 deletions(-)
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-array-load.d
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-array-store.d
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-deref-load.d
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-deref-store.d
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-struct-load.d
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-struct-store.d
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-struct-union-load.d
 create mode 100644 test/unittest/funcs/alloca/tst.alloca-struct-union-store.d

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 5c7e3998..4e163e01 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -3051,7 +3051,7 @@ dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
 	int		dreg = dst->dn_reg;
 
 	/*
-	 * If we're loading a bit-field, the size of our store is found by
+	 * If we're storing into a bit-field, the size of our store is found by
 	 * rounding dst's cte_bits up to a byte boundary and then finding the
 	 * nearest power of two to this value (see clp2(), above).
 	 */
@@ -3062,13 +3062,15 @@ dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
 		size = dt_node_type_size(dst);
 
 	/*
-	 * If we're loading a writable non-alloca lvalue, and it's a
-	 * dereference, and *its* child is an alloca pointer, then this is a
-	 * dereferenced alloca pointer and needs bounds-checking (which could
-	 * not be done at deref time due to not knowing the size of the write).
+	 * If we're storing into a writable lvalue that is a dereference of an
+	 * alloca pointer or if we are storing into a writable alloca lvalue,
+	 * we need to do bounds-checking and turn the offset value into a real
+	 * pointer.
 	 */
-	if (dst->dn_flags & DT_NF_WRITABLE && dst->dn_flags & DT_NF_LVALUE
-	    && dst->dn_op == DT_TOK_DEREF && dst->dn_child->dn_flags & DT_NF_ALLOCA) {
+	if (dst->dn_flags & DT_NF_WRITABLE && dst->dn_flags & DT_NF_LVALUE &&
+	    ((dst->dn_op == DT_TOK_DEREF &&
+	      dst->dn_child->dn_flags & DT_NF_ALLOCA) ||
+	     dst->dn_flags & DT_NF_ALLOCA)) {
 		assert(!(dst->dn_flags & DT_NF_BITFIELD));
 
 		if ((dreg = dt_regset_alloc(drp)) == -1)
@@ -6473,7 +6475,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 		}
 
 		if (m.ctm_offset != 0)
-			emit(dlp, BPF_ALU64_IMM(BPF_ADD, dnp->dn_left->dn_reg, m.ctm_offset / NBBY));
+			emit(dlp, BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, m.ctm_offset / NBBY));
 
 		if (!(dnp->dn_flags & DT_NF_REF)) {
 			uint_t	op;
@@ -6481,8 +6483,20 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 
 			op = dt_cg_ldsize(dnp, ctfp, m.ctm_type, &size);
 
+			/*
+			 * If the left-hand side of PTR or DOT is an alloca
+			 * pointer, bounds-check the pointer reference.
+			 */
+			if (dnp->dn_left->dn_flags & DT_NF_ALLOCA) {
+				assert(dnp->dn_flags & DT_NF_ALLOCA);
+				dt_cg_alloca_access_check(dlp, drp, dnp->dn_reg,
+							  DT_ISIMM, size);
+				dt_cg_alloca_ptr(dlp, drp, dnp->dn_reg,
+						 dnp->dn_reg);
+			}
+
 			if (dnp->dn_left->dn_flags & (DT_NF_ALLOCA | DT_NF_DPTR))
-				emit(dlp, BPF_LOAD(op, dnp->dn_left->dn_reg, dnp->dn_left->dn_reg, 0));
+				emit(dlp, BPF_LOAD(op, dnp->dn_reg, dnp->dn_reg, 0));
 			else
 				dt_cg_load_scalar(dnp->dn_left, op, size, dlp, drp);
 		}
diff --git a/test/unittest/funcs/alloca/tst.alloca-array-load.d b/test/unittest/funcs/alloca/tst.alloca-array-load.d
new file mode 100644
index 00000000..3db98049
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-array-load.d
@@ -0,0 +1,29 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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: Loading from array elements works for alloca pointers.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+int *arr;
+
+BEGIN
+{
+	arr = alloca(5 * sizeof(int));
+	arr[3] = 0x42;
+	trace(arr[3]);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-array-store.d b/test/unittest/funcs/alloca/tst.alloca-array-store.d
new file mode 100644
index 00000000..17edb584
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-array-store.d
@@ -0,0 +1,28 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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: Storing to array elements works for alloca pointers.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+int *arr;
+
+BEGIN
+{
+	arr = alloca(5 * sizeof(int));
+	arr[3] = 0x42;
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-deref-load.d b/test/unittest/funcs/alloca/tst.alloca-deref-load.d
new file mode 100644
index 00000000..2d23cdd3
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-deref-load.d
@@ -0,0 +1,29 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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: Loading from dereferenced alloca pointers works.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+int *val;
+
+BEGIN
+{
+	val = alloca(sizeof(int));
+	*val = 0x42;
+	trace(*val);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-deref-store.d b/test/unittest/funcs/alloca/tst.alloca-deref-store.d
new file mode 100644
index 00000000..e7d36e53
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-deref-store.d
@@ -0,0 +1,28 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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: Storing to dereferenced alloca pointers works.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+int *val;
+
+BEGIN
+{
+	val = alloca(sizeof(int));
+	*val = 0x42;
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-struct-load.d b/test/unittest/funcs/alloca/tst.alloca-struct-load.d
new file mode 100644
index 00000000..5f022985
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-struct-load.d
@@ -0,0 +1,33 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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: Loading from struct members works for alloca pointers.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+struct foo {
+	int	a;
+	char	b;
+	int	c;
+} *ptr;
+
+BEGIN
+{
+	ptr = alloca(sizeof(struct foo));
+	ptr->c = 0x42;
+	trace(ptr->c);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-struct-store.d b/test/unittest/funcs/alloca/tst.alloca-struct-store.d
new file mode 100644
index 00000000..4f55f958
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-struct-store.d
@@ -0,0 +1,32 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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: Storing to struct members works for alloca pointers.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+struct foo {
+	int	a;
+	char	b;
+	int	c;
+} *ptr;
+
+BEGIN
+{
+	ptr = alloca(sizeof(struct foo));
+	ptr->c = 0x42;
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-struct-union-load.d b/test/unittest/funcs/alloca/tst.alloca-struct-union-load.d
new file mode 100644
index 00000000..7361b494
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-struct-union-load.d
@@ -0,0 +1,40 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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: Loading from nested members works for alloca pointers.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+struct st {
+    struct {
+	union {
+	    struct {
+		int	a;
+		char	b;
+		int	c;
+	    } apa;
+	    uint64_t	val;
+	} u;
+    } s;
+} *ptr;
+
+BEGIN
+{
+	ptr = alloca(sizeof(struct st));
+	ptr->s.u.apa.c = 0x42;
+	trace(ptr->s.u.apa.c);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/alloca/tst.alloca-struct-union-store.d b/test/unittest/funcs/alloca/tst.alloca-struct-union-store.d
new file mode 100644
index 00000000..c0cbd787
--- /dev/null
+++ b/test/unittest/funcs/alloca/tst.alloca-struct-union-store.d
@@ -0,0 +1,39 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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: Storing to nested members works for alloca pointers.
+ *
+ * SECTION: Actions and Subroutines/alloca()
+ */
+
+#pragma D option quiet
+
+struct st {
+    struct {
+	union {
+	    struct {
+		int	a;
+		char	b;
+		int	c;
+	    } apa;
+	    uint64_t	val;
+	} u;
+    } s;
+} *ptr;
+
+BEGIN
+{
+	ptr = alloca(sizeof(struct st));
+	ptr->s.u.apa.c = 0x42;
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
-- 
2.40.1




More information about the DTrace-devel mailing list