[DTrace-devel] [PATCH] cg, sdt: copy userspace string arguments to kernelspace
Eugene Loh
eugene.loh at oracle.com
Tue Feb 28 16:41:18 UTC 2023
Reviewed-by: Eugene Loh <eugene.loh at oracle.com>
minor comments...
On 2/28/23 03:20, Kris Van Hees via DTrace-devel wrote:
> 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);
Why %r0? How about xalloc_args() here and put the "src" value directly
into %r3, where it is eventually needed? That would save the later
%r3=%r0 instruction.
> +
> + 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 *", } },
I haven't been following proc, but signal-clear is documented as having
only one arg?
> #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", },
> };
>
>
More information about the DTrace-devel
mailing list