[DTrace-devel] [PATCH v2 3/4] uregs: Fix access to thread members on x86
eugene.loh at oracle.com
eugene.loh at oracle.com
Fri May 19 17:49:46 UTC 2023
From: Eugene Loh <eugene.loh at oracle.com>
The "fix" is simply to account for thread members that are less than
8 bytes wide.
Most of this patch is for refactoring (using functions to determine
offsets with CTF types or to load a scalar safely from memory that
the BPF verifier cannot vet) and adding a test.
Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
libdtrace/dt_cg.c | 62 +++++++------------
test/unittest/arrays/tst.uregsarray-check2.d | 32 ++++++++++
test/unittest/arrays/tst.uregsarray-check2.r | 5 ++
.../unittest/arrays/tst.uregsarray-check2.r.p | 5 ++
test/unittest/arrays/tst.uregsarray-check2.x | 4 ++
5 files changed, 70 insertions(+), 38 deletions(-)
create mode 100644 test/unittest/arrays/tst.uregsarray-check2.d
create mode 100644 test/unittest/arrays/tst.uregsarray-check2.r
create mode 100755 test/unittest/arrays/tst.uregsarray-check2.r.p
create mode 100755 test/unittest/arrays/tst.uregsarray-check2.x
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index e431fb36..74eb4a31 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -4132,57 +4132,43 @@ dt_cg_uregs(unsigned int idx, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp
if (idx >= sizeof(dt_pt_regs) / sizeof(uint64_t)) {
#if defined(__amd64)
+ /* Confirm that we can hardwire for 21 pt_regs[]. */
+ assert(sizeof(dt_pt_regs) == 21 * sizeof(uint64_t));
+
/*
* Even if out-of-bounds, on x86 there are still a few
* indices that are used to access task->thread. members.
*/
if (idx <= 25) {
- ctf_file_t *cfp = dtp->dt_shared_ctf;
- ctf_id_t type;
- ctf_membinfo_t ctm;
- int offset, rc;
-
- /* look up task->thread offset */
- if (!cfp)
- longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
-
- type = ctf_lookup_by_name(cfp, "struct task_struct");
- if (type == CTF_ERR)
- longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
- if (ctf_member_info(cfp, type, "thread", &ctm) == CTF_ERR)
- longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
- offset = ctm.ctm_offset / NBBY;
-
- /* add the thread->member offset */
- type = ctf_lookup_by_name(cfp, "struct thread_struct");
- if (type == CTF_ERR)
- longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
- switch (idx) {
- case 21: rc = ctf_member_info(cfp, type, "ds", &ctm); break;
- case 22: rc = ctf_member_info(cfp, type, "es", &ctm); break;
- case 23: rc = ctf_member_info(cfp, type, "fsbase", &ctm); break;
- case 24: rc = ctf_member_info(cfp, type, "gsbase", &ctm); break;
- case 25: rc = ctf_member_info(cfp, type, "trap_nr", &ctm); break;
- }
- if (rc == -1)
- longjmp(yypcb->pcb_jmpbuf, EDT_NOCTF);
- offset += ctm.ctm_offset / NBBY;
+ int offset;
+ ssize_t size;
+ char *memnames[] = { "ds", "es", "fsbase", "gsbase", "trap_nr" };
+
+ /* Look up task->thread offset. */
+ offset = dt_cg_ctf_offsetof("struct task_struct", "thread", NULL);
- /* copy task->thread.member onto the stack */
+ /* Add the thread->member offset. */
+ offset += dt_cg_ctf_offsetof("struct thread_struct",
+ memnames[idx - 21], &size);
+ if (size < 1 || size > 8 || (size & (size - 1)) != 0)
+ xyerror(D_UNKNOWN, "internal error -- cg cannot load "
+ "size %ld when passed by value\n", (long)size);
+
+ /* Get task. */
if (dt_regset_xalloc_args(drp) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dt_regset_xalloc(drp, BPF_REG_0);
emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_task));
- emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0));
- emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, offset));
- emit(dlp, BPF_MOV_IMM(BPF_REG_2, sizeof(uint64_t)));
- emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_SP));
- emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_kernel]));
dt_regset_free_args(drp);
- emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_FP, DT_STK_SP));
- emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_0, 0));
+ emit(dlp, BPF_MOV_REG(dnp->dn_reg, BPF_REG_0));
dt_regset_free(drp, BPF_REG_0);
+ /* Add the offset to the task pointer. */
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, offset));
+
+ /* Dereference it safely (the BPF verifier has no idea what it is). */
+ dt_cg_load_scalar(dnp, ldstw[size], size, dlp, drp);
+
return;
}
#endif
diff --git a/test/unittest/arrays/tst.uregsarray-check2.d b/test/unittest/arrays/tst.uregsarray-check2.d
new file mode 100644
index 00000000..de65bbfd
--- /dev/null
+++ b/test/unittest/arrays/tst.uregsarray-check2.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: Check the constants used to access uregs[].
+ * On x86, certain high indices are used to access not
+ * pt_regs[] but curthread->thread.xxx. So check them.
+ *
+ * SECTION: User Process Tracing/uregs Array
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ printf("%x %x\n", uregs[R_DS ], curthread->thread.ds);
+ printf("%x %x\n", uregs[R_ES ], curthread->thread.ds);
+ printf("%x %x\n", uregs[R_FS ], curthread->thread.fsbase);
+ printf("%x %x\n", uregs[R_GS ], curthread->thread.gsbase);
+ printf("%x %x\n", uregs[R_TRAPNO], curthread->thread.trap_nr);
+
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/arrays/tst.uregsarray-check2.r b/test/unittest/arrays/tst.uregsarray-check2.r
new file mode 100644
index 00000000..05c0b188
--- /dev/null
+++ b/test/unittest/arrays/tst.uregsarray-check2.r
@@ -0,0 +1,5 @@
+match
+match
+match
+match
+match
diff --git a/test/unittest/arrays/tst.uregsarray-check2.r.p b/test/unittest/arrays/tst.uregsarray-check2.r.p
new file mode 100755
index 00000000..2f53ea95
--- /dev/null
+++ b/test/unittest/arrays/tst.uregsarray-check2.r.p
@@ -0,0 +1,5 @@
+#!/usr/bin/gawk -f
+
+NF == 0 { next }
+$1 == $2 { print "match" }
+$1 != $2 { print "ERROR" }
diff --git a/test/unittest/arrays/tst.uregsarray-check2.x b/test/unittest/arrays/tst.uregsarray-check2.x
new file mode 100755
index 00000000..69e36e70
--- /dev/null
+++ b/test/unittest/arrays/tst.uregsarray-check2.x
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+[ `uname -m` = "x86_64" ] && exit 0
+exit 2
--
2.18.4
More information about the DTrace-devel
mailing list