[DTrace-devel] [PATCH] cg, sdt: copy userspace string arguments to kernelspace
Kris Van Hees
kris.van.hees at oracle.com
Tue Feb 28 08:20:11 UTC 2023
When an SDT probe argument is provided by a userspace string, it must be
copied to kernelspace because SDT probe pointer arguments are expected
to be kernel addresses.
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
libdtrace/dt_cg.c | 31 +++++++++++++++++++++++++++++++
libdtrace/dt_probe.c | 1 +
libdtrace/dt_prov_proc.c | 38 +++++++++++++++++++-------------------
libdtrace/dt_provider.h | 1 +
libdtrace/dt_provider_tp.c | 1 +
5 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 2c4648df..be0215d7 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -4132,6 +4132,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar");
size_t size;
int n;
+ int ustr = 0;
assert(dnp->dn_kind == DT_NODE_VAR);
assert(!(idp->di_flags & (DT_IDFLG_TLS | DT_IDFLG_LOCAL)));
@@ -4155,6 +4156,12 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dnp->dn_reg = -1;
return;
}
+
+ /*
+ * If the argument node is mark DT_NF_USERLAND, it is a string
+ * in userspace. Set a flag to indicate we need to copy it.
+ */
+ ustr = prp->xargv[saved]->dn_flags & DT_NF_USERLAND;
dnp->dn_args->dn_value = prp->mapping[saved];
}
@@ -4201,6 +4208,30 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
emit(dlp, BPF_MOV_REG(dnp->dn_reg, BPF_REG_0));
dt_regset_free(drp, BPF_REG_0);
+ if (dt_node_is_string(dnp) && ustr) {
+ dtrace_hdl_t *dtp = yypcb->pcb_hdl;
+
+ dt_regset_xalloc(drp, BPF_REG_0);
+
+ 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_MOV_IMM(BPF_REG_2, dtp->dt_options[DTRACEOPT_STRSIZE]));
+ emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0));
+ emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user_str]));
+
+ dt_regset_free_args(drp);
+ dt_regset_free(drp, BPF_REG_0);
+ return;
+ }
+
/*
* If this is a reference to the args[] array, we need to take the
* additional step of explicitly eliminating any bits larger than the
diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
index dfcd28a8..5cf5fe27 100644
--- a/libdtrace/dt_probe.c
+++ b/libdtrace/dt_probe.c
@@ -951,6 +951,7 @@ dt_probe_args_info(dtrace_hdl_t *dtp, dt_probe_t *prp)
prp->mapping[i] = argv[i].mapping;
prp->argv[i] = dtt;
+ prp->xargv[i]->dn_flags |= argv[i].flags;
}
dt_free(dtp, argv);
diff --git a/libdtrace/dt_prov_proc.c b/libdtrace/dt_prov_proc.c
index 57753b94..4544f594 100644
--- a/libdtrace/dt_prov_proc.c
+++ b/libdtrace/dt_prov_proc.c
@@ -82,32 +82,32 @@ typedef struct probe_arg {
* that provides no arguments.
*/
static probe_arg_t probe_args[] = {
- { "create", 0, { 0, "struct task_struct *", "psinfo_t *" } },
- { "exec", 0, { 0, "string", } },
- { "exec-failure", 0, { 0, "int", } },
+ { "create", 0, { 0, 0, "struct task_struct *", "psinfo_t *" } },
+ { "exec", 0, { 0, DT_NF_USERLAND, "string", } },
+ { "exec-failure", 0, { 0, 0, "int", } },
{ "exec-success", },
- { "exit", 0, { 0, "int", } },
+ { "exit", 0, { 0, 0, "int", } },
#if 0
- { "fault", 0, { 0, "int", } },
- { "fault", 1, { 1, "siginfo_t *", } },
+ { "fault", 0, { 0, 0, "int", } },
+ { "fault", 1, { 1, 0, "siginfo_t *", } },
#endif
- { "lwp-create", 0, { 0, "struct task_struct *", "lwpsinfo_t *" } },
- { "lwp-create", 1, { 0, "struct task_struct *", "psinfo_t *" } },
+ { "lwp-create", 0, { 0, 0, "struct task_struct *", "lwpsinfo_t *" } },
+ { "lwp-create", 1, { 0, 0, "struct task_struct *", "psinfo_t *" } },
{ "lwp-exit", },
{ "lwp-start", },
#if 0
- { "signal-clear", 0, { 0, "int", } },
- { "signal-clear", 1, { 1, "siginfo_t *", } },
+ { "signal-clear", 0, { 0, 0, "int", } },
+ { "signal-clear", 1, { 1, 0, "siginfo_t *", } },
#endif
- { "signal-discard", 0, { 0, "struct task_struct *", "lwpsinfo_t *" } },
- { "signal-discard", 1, { 0, "struct task_struct *", "psinfo_t *" } },
- { "signal-discard", 2, { 1, "int", } },
- { "signal-handle", 0, { 0, "int", } },
- { "signal-handle", 1, { 1, "siginfo_t *", } },
- { "signal-handle", 2, { 2, "void (*)(void)", } },
- { "signal-send", 0, { 0, "struct task_struct *", "lwpsinfo_t *" } },
- { "signal-send", 1, { 0, "struct task_struct *", "psinfo_t *" } },
- { "signal-send", 2, { 1, "int", } },
+ { "signal-discard", 0, { 0, 0, "struct task_struct *", "lwpsinfo_t *" } },
+ { "signal-discard", 1, { 0, 0, "struct task_struct *", "psinfo_t *" } },
+ { "signal-discard", 2, { 1, 0, "int", } },
+ { "signal-handle", 0, { 0, 0, "int", } },
+ { "signal-handle", 1, { 1, 0, "siginfo_t *", } },
+ { "signal-handle", 2, { 2, 0, "void (*)(void)", } },
+ { "signal-send", 0, { 0, 0, "struct task_struct *", "lwpsinfo_t *" } },
+ { "signal-send", 1, { 0, 0, "struct task_struct *", "psinfo_t *" } },
+ { "signal-send", 2, { 1, 0, "int", } },
{ "start", },
};
diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h
index 0986f4f8..da1b4e57 100644
--- a/libdtrace/dt_provider.h
+++ b/libdtrace/dt_provider.h
@@ -48,6 +48,7 @@ struct dt_probe;
*/
typedef struct dt_argdesc {
int mapping;
+ int flags; /* see DT_NF_* */
const char *native;
const char *xlate;
} dt_argdesc_t;
diff --git a/libdtrace/dt_provider_tp.c b/libdtrace/dt_provider_tp.c
index 07ba5e4e..a08550ab 100644
--- a/libdtrace/dt_provider_tp.c
+++ b/libdtrace/dt_provider_tp.c
@@ -248,6 +248,7 @@ dt_tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip, tp_probe_t *tpp,
}
argv[argc].mapping = argc;
+ argv[argc].flags = 0;
argv[argc].native = strp;
argv[argc].xlate = NULL;
--
2.39.1
More information about the DTrace-devel
mailing list