Skip to content

Commit

Permalink
Add support for copyinto() subroutine
Browse files Browse the repository at this point in the history
The copyinto() subroutine is a near-identical copy of bcopy() other
than that the arguments are ordered differently, and it reads from
userspace addresses rather than kernel addresses.  A new function is
added to implement the shared functionality (dt_cg_subr_bcopy_impl).

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Reviewed-by: Eugene Loh <eugene.loh@oracle.com>
  • Loading branch information
kvanhees committed Jul 28, 2022
1 parent d97c8fa commit c26e2e5
Show file tree
Hide file tree
Showing 18 changed files with 370 additions and 52 deletions.
68 changes: 52 additions & 16 deletions libdtrace/dt_cg.c
Original file line number Diff line number Diff line change
Expand Up @@ -4223,37 +4223,43 @@ dt_cg_subr_alloca(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
}

static void
dt_cg_subr_bcopy(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_cg_subr_bcopy_impl(dt_node_t *dnp, dt_node_t *dst, dt_node_t *src,
dt_node_t *size, dt_irlist_t *dlp, dt_regset_t *drp)
{
dt_node_t *src = dnp->dn_args;
dt_node_t *dst = src->dn_list;
dt_node_t *size = dst->dn_list;
int maxsize = yypcb->pcb_hdl->dt_options[DTRACEOPT_SCRATCHSIZE] - 8;
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
int maxsize = dtp->dt_options[DTRACEOPT_SCRATCHSIZE] - 8;
uint_t lbl_badsize = dt_irlist_label(dlp);
uint_t lbl_ok = dt_irlist_label(dlp);
int is_bcopy = dnp->dn_ident->di_id == DIF_SUBR_BCOPY;

TRACE_REGSET(" subr-bcopy:Begin");
TRACE_REGSET(" subr-bcopy-impl:Begin");

/* Validate the size for the copy operation. */
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));

/* Validate the source pointer. */
dt_cg_node(src, dlp, drp);
if (src->dn_flags & DT_NF_ALLOCA)
dnerror(src, D_PROTO_ARG,
"bcopy( ) argument #1 is incompatible with prototype:\n"
"%s( ) argument #1 is incompatible with prototype:\n"
"\tprototype: non-alloca pointer\n"
"\t argument: alloca pointer\n");
"\t argument: alloca pointer\n",
is_bcopy ? "bcopy" : "copyinto");
dt_cg_check_notnull(dlp, drp, src->dn_reg);

/* Validate the destination pointer. */
dt_cg_node(dst, dlp, drp);
if (!(dst->dn_flags & DT_NF_ALLOCA))
dnerror(dst, D_PROTO_ARG,
"bcopy( ) argument #2 is incompatible with prototype:\n"
"%s( ) argument #%d is incompatible with prototype:\n"
"\tprototype: alloca pointer\n"
"\t argument: non-alloca pointer\n");
"\t argument: non-alloca pointer\n",
is_bcopy ? "bcopy" : "copyinto", is_bcopy ? 2 : 3);
/* The dst will be NULL-checked in the alloca access check below. */

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));

dt_cg_alloca_access_check(dlp, drp, dst->dn_reg,
DT_ISREG, size->dn_reg);
dt_cg_alloca_ptr(dlp, drp, dst->dn_reg, dst->dn_reg);
Expand All @@ -4265,7 +4271,9 @@ dt_cg_subr_bcopy(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
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(BPF_FUNC_probe_read));
emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[
is_bcopy ? BPF_FUNC_probe_read_kernel
: BPF_FUNC_probe_read_user]));

/*
* At this point the dst is validated, so any problem must be with
Expand All @@ -4285,6 +4293,20 @@ dt_cg_subr_bcopy(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_regset_free(drp, dst->dn_reg);
dt_regset_free(drp, size->dn_reg);

TRACE_REGSET(" subr-bcopy-impl:End ");
}

static void
dt_cg_subr_bcopy(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
{
dt_node_t *src = dnp->dn_args;
dt_node_t *dst = src->dn_list;
dt_node_t *size = dst->dn_list;

TRACE_REGSET(" subr-bcopy:Begin");

dt_cg_subr_bcopy_impl(dnp, dst, src, size, dlp, drp);

TRACE_REGSET(" subr-bcopy:End ");
}

Expand Down Expand Up @@ -4339,6 +4361,20 @@ 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_copyinto(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
{
dt_node_t *src = dnp->dn_args;
dt_node_t *size = src->dn_list;
dt_node_t *dst = size->dn_list;

TRACE_REGSET(" subr-copyinto:Begin");

dt_cg_subr_bcopy_impl(dnp, dst, src, size, dlp, drp);

TRACE_REGSET(" subr-copyinto:End ");
}

static void
dt_cg_subr_strchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
{
Expand Down Expand Up @@ -4819,7 +4855,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
[DIF_SUBR_COPYOUTSTR] = NULL,
[DIF_SUBR_ALLOCA] = &dt_cg_subr_alloca,
[DIF_SUBR_BCOPY] = &dt_cg_subr_bcopy,
[DIF_SUBR_COPYINTO] = NULL,
[DIF_SUBR_COPYINTO] = &dt_cg_subr_copyinto,
[DIF_SUBR_MSGDSIZE] = NULL,
[DIF_SUBR_MSGSIZE] = NULL,
[DIF_SUBR_GETMAJOR] = &dt_cg_subr_getmajor,
Expand Down
23 changes: 23 additions & 0 deletions test/unittest/funcs/copyinto/err.D_PROTO_ARG.non_alloca_arg3-2.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 3 for copyinto() must be an alloca() pointer.
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
copyinto(1, 2, &`max_pfn);
exit(1);
}

ERROR
{
exit(0);
}
23 changes: 23 additions & 0 deletions test/unittest/funcs/copyinto/err.D_PROTO_ARG.non_alloca_arg3.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 3 for copyinto() must be an alloca() pointer.
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
copyinto(1, 2, "");
exit(1);
}

ERROR
{
exit(0);
}
23 changes: 23 additions & 0 deletions test/unittest/funcs/copyinto/err.D_PROTO_ARG.non_ptr_arg3.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 3 for copyinto() must be a pointer.
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
copyinto(1, 2, 3);
exit(1);
}

ERROR
{
exit(0);
}
23 changes: 23 additions & 0 deletions test/unittest/funcs/copyinto/err.D_PROTO_ARG.non_scalar_arg1.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 copyinto() must be a scalar.
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
copyinto("1", 2, 3);
exit(1);
}

ERROR
{
exit(0);
}
23 changes: 23 additions & 0 deletions test/unittest/funcs/copyinto/err.D_PROTO_ARG.non_scalar_arg2.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 copyinto() must be a scalar.
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
copyinto(1, "2", 3);
exit(1);
}

ERROR
{
exit(0);
}
23 changes: 23 additions & 0 deletions test/unittest/funcs/copyinto/err.D_PROTO_LEN.missing_arg.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 copyinto().
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
copyinto();
exit(1);
}

ERROR
{
exit(0);
}
23 changes: 23 additions & 0 deletions test/unittest/funcs/copyinto/err.D_PROTO_LEN.too_few_args.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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: Three arguments are required for copyinto().
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
copyinto(1, 2);
exit(1);
}

ERROR
{
exit(0);
}
23 changes: 23 additions & 0 deletions test/unittest/funcs/copyinto/err.D_PROTO_LEN.too_many_args.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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: Exactly three Arguments are required for copyinto().
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
copyin(1, 2, 3, 4);
exit(1);
}

ERROR
{
exit(0);
}
24 changes: 24 additions & 0 deletions test/unittest/funcs/copyinto/err.badaddr.d
Original file line number Diff line number Diff line change
@@ -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 copyinto() with an invalid source address reports a fault.
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
ptr = (char *)alloca(256);
copyinto(0x1234, 8, ptr);
exit(0);
}

ERROR
{
exit(1);
}
6 changes: 6 additions & 0 deletions test/unittest/funcs/copyinto/err.badaddr.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FUNCTION:NAME
:ERROR

-- @@stderr --
dtrace: script 'test/unittest/funcs/copyinto/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
24 changes: 24 additions & 0 deletions test/unittest/funcs/copyinto/err.badsize.d
Original file line number Diff line number Diff line change
@@ -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: The copyinto() size must not exceed the allocated space.
*
* SECTION: Actions and Subroutines/copyinto()
*/

BEGIN
{
ptr = (char *)alloca(64);
copyinto(curthread->mm->env_start, 65, ptr);
exit(0);
}

ERROR
{
exit(1);
}
6 changes: 6 additions & 0 deletions test/unittest/funcs/copyinto/err.badsize.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FUNCTION:NAME
:ERROR

-- @@stderr --
dtrace: script 'test/unittest/funcs/copyinto/err.badsize.d' matched 2 probes
dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN

0 comments on commit c26e2e5

Please sign in to comment.