[DTrace-devel] [PATCH 12/12] Add support for copyinstr() subroutine

Kris Van Hees kris.van.hees at oracle.com
Wed Jul 13 19:18:03 UTC 2022


The copyinstr() subroutine is almost identical to the copyin() subroutine.
The differences are:
 - the 2nd argument (max size) is optional (default is strsize)
 - if a size is given, it is capped at strsize
 - data is copied using bpf_probe_read_user_str (or bpf_probe_read_str)

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_cg.c                             | 58 ++++++++++++++++++-
 .../funcs/copyinstr/err.D_ALLOCA_SIZE.d       | 26 +++++++++
 .../err.D_PROTO_ARG.non_scalar_arg1.d         | 24 ++++++++
 .../err.D_PROTO_ARG.non_scalar_arg2.d         | 24 ++++++++
 .../copyinstr/err.D_PROTO_LEN.missing_arg.d   | 24 ++++++++
 .../copyinstr/err.D_PROTO_LEN.too_many_args.d | 24 ++++++++
 test/unittest/funcs/copyinstr/err.badaddr.d   | 24 ++++++++
 test/unittest/funcs/copyinstr/err.badaddr.r   |  6 ++
 test/unittest/funcs/copyinstr/err.badsize.d   | 27 +++++++++
 test/unittest/funcs/copyinstr/err.null_arg1.d | 24 ++++++++
 test/unittest/funcs/copyinstr/err.null_arg1.r |  6 ++
 .../copyinstr/tst.copyinstr-no-maxsize.d      | 24 ++++++++
 test/unittest/funcs/copyinstr/tst.copyinstr.d | 24 ++++++++
 13 files changed, 314 insertions(+), 1 deletion(-)
 create mode 100644 test/unittest/funcs/copyinstr/err.D_ALLOCA_SIZE.d
 create mode 100644 test/unittest/funcs/copyinstr/err.D_PROTO_ARG.non_scalar_arg1.d
 create mode 100644 test/unittest/funcs/copyinstr/err.D_PROTO_ARG.non_scalar_arg2.d
 create mode 100644 test/unittest/funcs/copyinstr/err.D_PROTO_LEN.missing_arg.d
 create mode 100644 test/unittest/funcs/copyinstr/err.D_PROTO_LEN.too_many_args.d
 create mode 100644 test/unittest/funcs/copyinstr/err.badaddr.d
 create mode 100644 test/unittest/funcs/copyinstr/err.badaddr.r
 create mode 100644 test/unittest/funcs/copyinstr/err.badsize.d
 create mode 100644 test/unittest/funcs/copyinstr/err.null_arg1.d
 create mode 100644 test/unittest/funcs/copyinstr/err.null_arg1.r
 create mode 100644 test/unittest/funcs/copyinstr/tst.copyinstr-no-maxsize.d
 create mode 100644 test/unittest/funcs/copyinstr/tst.copyinstr.d

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 265a6408..6c55f048 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -4325,6 +4325,62 @@ dt_cg_subr_copyin(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	TRACE_REGSET("    subr-copyin:End  ");
 }
 
+static void
+dt_cg_subr_copyinstr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dtrace_hdl_t	*dtp = yypcb->pcb_hdl;
+	dt_node_t	*src = dnp->dn_args;
+	dt_node_t	*size = src->dn_list;
+	int		maxsize = dtp->dt_options[DTRACEOPT_STRSIZE];
+	uint_t		lbl_ok = dt_irlist_label(dlp);
+	uint_t		lbl_badsize = dt_irlist_label(dlp);
+
+	TRACE_REGSET("    subr-copyin:Begin");
+
+	/* Validate the size for the copy operation (if provided). */
+	if (size == NULL) {
+		size = dt_node_int(maxsize);
+		src->dn_list = size;
+	}
+
+	dt_cg_node(size, dlp, drp);
+
+	emit(dlp,  BPF_BRANCH_IMM(BPF_JSLT, size->dn_reg, 0, lbl_badsize));
+	emit(dlp,  BPF_BRANCH_IMM(BPF_JGT, size->dn_reg, maxsize, lbl_badsize));
+
+	if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	/* Allocate scratch space. */
+	dt_cg_subr_alloca_impl(dnp, size, dlp, drp);
+	dt_cg_alloca_ptr(dlp, drp, dnp->dn_reg, dnp->dn_reg);
+
+	dt_cg_node(src, dlp, drp);
+
+	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_REG(BPF_REG_2, size->dn_reg));
+	emit(dlp, BPF_MOV_REG(BPF_REG_3, src->dn_reg));
+	dt_regset_xalloc(drp, BPF_REG_0);
+	emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user_str]));
+	dt_regset_free_args(drp);
+	emit(dlp,  BPF_BRANCH_IMM(BPF_JSGT, BPF_REG_0, 0, lbl_ok));
+	dt_cg_probe_error(yypcb, DTRACEFLT_BADADDR, DT_ISREG, src->dn_reg);
+	emitl(dlp, lbl_badsize,
+		   BPF_NOP());
+	dt_cg_probe_error(yypcb, DTRACEFLT_BADSIZE, DT_ISREG, size->dn_reg);
+	emitl(dlp, lbl_ok,
+		   BPF_NOP());
+	dt_regset_free(drp, BPF_REG_0);
+
+	dt_regset_free(drp, src->dn_reg);
+	dt_regset_free(drp, size->dn_reg);
+
+	TRACE_REGSET("    subr-copyin:End  ");
+}
+
 static void
 dt_cg_subr_copyinto(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 {
@@ -4868,7 +4924,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
 	[DIF_SUBR_RW_WRITE_HELD]	= &dt_cg_subr_rw_write_held,
 	[DIF_SUBR_RW_ISWRITER]		= &dt_cg_subr_rw_iswriter,
 	[DIF_SUBR_COPYIN]		= &dt_cg_subr_copyin,
-	[DIF_SUBR_COPYINSTR]		= NULL,
+	[DIF_SUBR_COPYINSTR]		= &dt_cg_subr_copyinstr,
 	[DIF_SUBR_SPECULATION]		= &dt_cg_subr_speculation,
 	[DIF_SUBR_PROGENYOF]		= &dt_cg_subr_progenyof,
 	[DIF_SUBR_STRLEN]		= &dt_cg_subr_strlen,
diff --git a/test/unittest/funcs/copyinstr/err.D_ALLOCA_SIZE.d b/test/unittest/funcs/copyinstr/err.D_ALLOCA_SIZE.d
new file mode 100644
index 00000000..c9f25721
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.D_ALLOCA_SIZE.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: The copyinstr() size must not exceed the (adjusted) scratchsize.
+ *
+ * SECTION: Actions and Subroutines/copyinstr()
+ *	    User Process Tracing/copyin() and copyinstr()
+ */
+
+#pragma D option scratchsize=64
+
+BEGIN
+{
+	copyinstr(0, 65);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/copyinstr/err.D_PROTO_ARG.non_scalar_arg1.d b/test/unittest/funcs/copyinstr/err.D_PROTO_ARG.non_scalar_arg1.d
new file mode 100644
index 00000000..98b0a29b
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.D_PROTO_ARG.non_scalar_arg1.d
@@ -0,0 +1,24 @@
+/*
+ * 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: Argument 1 for copyinstr() must be a scalar.
+ *
+ * SECTION: Actions and Subroutines/copyinstr()
+ *	    User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+{
+	copyinstr("1", 2);
+	exit(1);
+}
+
+ERROR
+{
+	exit(0);
+}
diff --git a/test/unittest/funcs/copyinstr/err.D_PROTO_ARG.non_scalar_arg2.d b/test/unittest/funcs/copyinstr/err.D_PROTO_ARG.non_scalar_arg2.d
new file mode 100644
index 00000000..6db8e059
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.D_PROTO_ARG.non_scalar_arg2.d
@@ -0,0 +1,24 @@
+/*
+ * 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: Argument 2 for copyinstr() must be a scalar.
+ *
+ * SECTION: Actions and Subroutines/copyinstr()
+ *	    User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+{
+	copyinstr(1, "2");
+	exit(1);
+}
+
+ERROR
+{
+	exit(0);
+}
diff --git a/test/unittest/funcs/copyinstr/err.D_PROTO_LEN.missing_arg.d b/test/unittest/funcs/copyinstr/err.D_PROTO_LEN.missing_arg.d
new file mode 100644
index 00000000..47a6eb4b
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.D_PROTO_LEN.missing_arg.d
@@ -0,0 +1,24 @@
+/*
+ * 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: Arguments are required for copyinstr().
+ *
+ * SECTION: Actions and Subroutines/copyinstr()
+ *	    User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+{
+	copyinstr();
+	exit(1);
+}
+
+ERROR
+{
+	exit(0);
+}
diff --git a/test/unittest/funcs/copyinstr/err.D_PROTO_LEN.too_many_args.d b/test/unittest/funcs/copyinstr/err.D_PROTO_LEN.too_many_args.d
new file mode 100644
index 00000000..ee3e9ed9
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.D_PROTO_LEN.too_many_args.d
@@ -0,0 +1,24 @@
+/*
+ * 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: No more than two arguments can be passed for copyinstr().
+ *
+ * SECTION: Actions and Subroutines/copyinstr()
+ *	    User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+{
+	copyinstr(1, 2, 3);
+	exit(1);
+}
+
+ERROR
+{
+	exit(0);
+}
diff --git a/test/unittest/funcs/copyinstr/err.badaddr.d b/test/unittest/funcs/copyinstr/err.badaddr.d
new file mode 100644
index 00000000..3e8078c4
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.badaddr.d
@@ -0,0 +1,24 @@
+/*
+ * 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: Using copyinstr() with an invalid source address reports a fault.
+ *
+ * SECTION: Actions and Subroutines/copyinstr()
+ *	    User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+{
+	copyinstr(0x1234, 8);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/copyinstr/err.badaddr.r b/test/unittest/funcs/copyinstr/err.badaddr.r
new file mode 100644
index 00000000..0f566d6e
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.badaddr.r
@@ -0,0 +1,6 @@
+                   FUNCTION:NAME
+                          :ERROR 
+
+-- @@stderr --
+dtrace: script 'test/unittest/funcs/copyinstr/err.badaddr.d' matched 2 probes
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyinstr/err.badsize.d b/test/unittest/funcs/copyinstr/err.badsize.d
new file mode 100644
index 00000000..2e476238
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.badsize.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: The copyinstr() size must not exceed the (adjusted) scratchsize.
+ *
+ * SECTION: Actions and Subroutines/copyinstr()
+ *	    User Process Tracing/copyin() and copyinstr()
+ */
+
+#pragma D option scratchsize=64
+
+BEGIN
+{
+	sz = 65;
+	copyinstr(0, sz);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/copyinstr/err.null_arg1.d b/test/unittest/funcs/copyinstr/err.null_arg1.d
new file mode 100644
index 00000000..7733efe8
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.null_arg1.d
@@ -0,0 +1,24 @@
+/*
+ * 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: Using copyinstr() with a NULL source address reports a fault.
+ *
+ * SECTION: Actions and Subroutines/copyinstr()
+ *	    User Process Tracing/copyin() and copyinstr()
+ */
+
+BEGIN
+{
+	copyinstr(0, 8);
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/copyinstr/err.null_arg1.r b/test/unittest/funcs/copyinstr/err.null_arg1.r
new file mode 100644
index 00000000..cdd7c22c
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/err.null_arg1.r
@@ -0,0 +1,6 @@
+                   FUNCTION:NAME
+                          :ERROR 
+
+-- @@stderr --
+dtrace: script 'test/unittest/funcs/copyinstr/err.null_arg1.d' matched 2 probes
+dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyinstr/tst.copyinstr-no-maxsize.d b/test/unittest/funcs/copyinstr/tst.copyinstr-no-maxsize.d
new file mode 100644
index 00000000..900115f5
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/tst.copyinstr-no-maxsize.d
@@ -0,0 +1,24 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2006, 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: It is possible to read a string from the envp[] userspace area.
+ *
+ * SECTION: Actions and Subroutines/copyin()
+ *	    User Process Tracing/copyin() and copyinstr() Subroutines
+ */
+
+BEGIN
+{
+	printf("envp[0] = \"%s\"", copyinstr(curthread->mm->env_start));
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/copyinstr/tst.copyinstr.d b/test/unittest/funcs/copyinstr/tst.copyinstr.d
new file mode 100644
index 00000000..0b011878
--- /dev/null
+++ b/test/unittest/funcs/copyinstr/tst.copyinstr.d
@@ -0,0 +1,24 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2006, 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: It is possible to read a string from the envp[] userspace area.
+ *
+ * SECTION: Actions and Subroutines/copyin()
+ *	    User Process Tracing/copyin() and copyinstr() Subroutines
+ */
+
+BEGIN
+{
+	printf("envp[0] = \"%s\"", copyinstr(curthread->mm->env_start, 256));
+	exit(0);
+}
+
+ERROR
+{
+	exit(1);
+}
-- 
2.34.1




More information about the DTrace-devel mailing list