Skip to content

Commit

Permalink
alloca: allow passing alloca pointers to actions and subrs
Browse files Browse the repository at this point in the history
A great many subrs and a good few actions allow the passing-in of
pointers (mostly, but not entirely, char *) which may be in alloca()ed
space.  Since they then usually go on to dereference these pointers,
the pointers must be bounds-checked.  We already handled actions
earlier (they don't do formal dereferences except insofar as it
is already done via the deref operator, so we only needed to check
them for nullity); but subrs remain unhandled.

For non-alloca pointers we can just keep on doing null checking; for
alloca pointers, we need to do the usual access_check/ptr dance, with a
length derived from the parser's idea of the length (which is passed
through identifiers accurately).

In addition to subrs, we also need to handle alloca'ed pointers in
codegen for stringof(), since the arg to stringof() might be in
alloca()ed space too.

A new test that tests more or less all of this is added: it has no
expected results because all we actually care about is that there are no
verifier failures.

Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@oracle.com>
  • Loading branch information
nickalcock committed Apr 19, 2022
1 parent 91c2062 commit a24181d
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 19 deletions.
60 changes: 41 additions & 19 deletions libdtrace/dt_cg.c
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,27 @@ dt_cg_alloca_ptr(dt_irlist_t *dlp, dt_regset_t *drp, int dreg, int sreg)
}
}

/*
* Convert an alloca pointer value into an actual scratchmem pointer.
* Generate code to check a pointer argument (specifically for subroutine
* arguments) to ensure that it is not NULL. If the arguent pointer is an
* alloca pointer, we also need to perform an access check and convert the
* alloca pointer value into a real pointer.
*/
static void
dt_cg_check_ptr_arg(dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dnp)
{
if (dnp->dn_flags & DT_NF_ALLOCA) {
dtrace_diftype_t vtype;

dt_node_diftype(yypcb->pcb_hdl, dnp, &vtype);
dt_cg_alloca_access_check(dlp, drp, dnp->dn_reg,
DT_ISIMM, vtype.dtdt_size);
dt_cg_alloca_ptr(dlp, drp, dnp->dn_reg, dnp->dn_reg);
} else
dt_cg_check_notnull(dlp, drp, dnp->dn_reg);
}

static const uint_t ldstw[] = {
0,
BPF_B, BPF_H, 0, BPF_W,
Expand Down Expand Up @@ -3686,10 +3707,10 @@ dt_cg_subr_path_helper(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,

TRACE_REGSET(" subr-path_helper:Begin");
dt_cg_node(str, dlp, drp);
dt_cg_check_notnull(dlp, drp, str->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, str);

/*
* The result needs be be a temporary string, so we request one.
* The result needs to be a temporary string, so we request one.
*/
dnp->dn_reg = dt_regset_alloc(drp);
if (dnp->dn_reg == -1)
Expand Down Expand Up @@ -3745,9 +3766,9 @@ dt_cg_subr_index(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
TRACE_REGSET(" subr-index:Begin");

dt_cg_node(s, dlp, drp);
dt_cg_check_notnull(dlp, drp, s->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, s);
dt_cg_node(t, dlp, drp);
dt_cg_check_notnull(dlp, drp, t->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, t);
if (start != NULL)
dt_cg_node(start, dlp, drp);

Expand Down Expand Up @@ -3861,9 +3882,9 @@ dt_cg_subr_rindex(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)

/* evaluate arguments to D subroutine rindex() */
dt_cg_node(s, dlp, drp);
dt_cg_check_notnull(dlp, drp, s->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, s);
dt_cg_node(t, dlp, drp);
dt_cg_check_notnull(dlp, drp, t->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, t);
if (start != NULL)
dt_cg_node(start, dlp, drp);

Expand Down Expand Up @@ -4106,7 +4127,7 @@ dt_cg_subr_strchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)

TRACE_REGSET(" subr-strchr:Begin");
dt_cg_node(str, dlp, drp);
dt_cg_check_notnull(dlp, drp, str->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, str);
dt_cg_node(chr, dlp, drp);

if (dt_regset_xalloc_args(drp) == -1)
Expand All @@ -4119,7 +4140,7 @@ dt_cg_subr_strchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_regset_free(drp, chr->dn_reg);

/*
* The result needs be be a temporary string, so we request one.
* The result needs to be a temporary string, so we request one.
*/
dnp->dn_reg = dt_regset_alloc(drp);
if (dnp->dn_reg == -1)
Expand Down Expand Up @@ -4162,7 +4183,7 @@ dt_cg_subr_strrchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)

TRACE_REGSET(" subr-strrchr:Begin");
dt_cg_node(str, dlp, drp);
dt_cg_check_notnull(dlp, drp, str->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, str);
dt_cg_node(chr, dlp, drp);

if (dt_regset_xalloc_args(drp) == -1)
Expand All @@ -4175,7 +4196,7 @@ dt_cg_subr_strrchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_regset_free(drp, chr->dn_reg);

/*
* The result needs be be a temporary string, so we request one.
* The result needs to be a temporary string, so we request one.
*/
dnp->dn_reg = dt_regset_alloc(drp);
if (dnp->dn_reg == -1)
Expand Down Expand Up @@ -4213,7 +4234,7 @@ dt_cg_subr_strlen(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
TRACE_REGSET(" subr-strlen:Begin");

dt_cg_node(str, dlp, drp);
dt_cg_check_notnull(dlp, drp, str->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, str);
dnp->dn_reg = str->dn_reg; /* re-use register */

if (dt_regset_xalloc_args(drp) == -1)
Expand Down Expand Up @@ -4248,12 +4269,12 @@ dt_cg_subr_strjoin(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
TRACE_REGSET(" subr-strjoin:Begin");

dt_cg_node(s1, dlp, drp);
dt_cg_check_notnull(dlp, drp, s1->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, s1);
dt_cg_node(s2, dlp, drp);
dt_cg_check_notnull(dlp, drp, s2->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, s2);

/*
* The result needs be be a temporary string, so we request one.
* The result needs to be a temporary string, so we request one.
*/
dnp->dn_reg = dt_regset_alloc(drp);
if (dnp->dn_reg == -1)
Expand Down Expand Up @@ -4295,9 +4316,9 @@ dt_cg_subr_strstr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)

/* get args */
dt_cg_node(s, dlp, drp);
dt_cg_check_notnull(dlp, drp, s->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, s);
dt_cg_node(t, dlp, drp);
dt_cg_check_notnull(dlp, drp, t->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, t);

/* call dt_index() call */
if (dt_regset_xalloc_args(drp) == -1)
Expand Down Expand Up @@ -4398,7 +4419,7 @@ dt_cg_subr_strtok(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
if (str->dn_op != DT_TOK_INT || str->dn_value != 0) {
/* string is present: copy it to internal state */
dt_cg_node(str, dlp, drp);
dt_cg_check_notnull(dlp, drp, str->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, str);

if (dt_regset_xalloc_args(drp) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
Expand Down Expand Up @@ -4427,7 +4448,7 @@ dt_cg_subr_strtok(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)

/* get delimiters */
dt_cg_node(del, dlp, drp);
dt_cg_check_notnull(dlp, drp, del->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, del);

/* allocate temporary string for result */
dnp->dn_reg = dt_regset_alloc(drp);
Expand Down Expand Up @@ -4478,7 +4499,7 @@ dt_cg_subr_substr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
TRACE_REGSET(" subr-substr:Begin");

dt_cg_node(str, dlp, drp);
dt_cg_check_notnull(dlp, drp, str->dn_reg);
dt_cg_check_ptr_arg(dlp, drp, str);
dt_cg_node(idx, dlp, drp);
if (cnt != NULL)
dt_cg_node(cnt, dlp, drp);
Expand Down Expand Up @@ -4933,6 +4954,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)

case DT_TOK_STRINGOF:
dt_cg_node(dnp->dn_child, dlp, drp);
dt_cg_check_ptr_arg(dlp, drp, dnp->dn_child);
dnp->dn_reg = dnp->dn_child->dn_reg;
break;

Expand Down
164 changes: 164 additions & 0 deletions test/unittest/funcs/alloca/tst.alloca-funcs.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* 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: Function calls to alloca()ed space work.
*
* SECTION: Actions and Subroutines/alloca()
*/

#pragma D option quiet

/*
* Everything is in an independent clause with its own alloca(),
* to try to make sure that the verifier's bound proofs don't leak
* from one test to the next.
*/

BEGIN
{
x = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
printf("%s\n", stringof(x));
trace(x);
}

BEGIN
{
x = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
trace(basename(x));
}

BEGIN
{
x = (char *) alloca(8);
y = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
y[0] = '/';
y[1] = 0;
trace(index(x, y));
}

BEGIN
{
x = (char *) alloca(8);
y = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
y[0] = '/';
y[1] = 0;
trace(rindex(x, y));
}

BEGIN
{
x = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
trace(strchr(x, '/'));
}

BEGIN
{
x = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
trace(strrchr(x, '/'));
}

BEGIN
{
x = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
trace(strlen(x));
}

BEGIN
{
x = (char *) alloca(8);
y = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
y[0] = '/';
y[1] = 0;
trace(strjoin(x, y));
}

BEGIN
{
x = (char *) alloca(8);
y = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
y[0] = '/';
y[1] = 0;
trace(strstr(x, y));
}

BEGIN
{
x = (char *) alloca(8);
y = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
y[0] = '/';
y[1] = 0;
trace(strtok(x, y));
}

BEGIN
{
x = (char *) alloca(8);
x[0] = '/';
x[1] = 0;
trace(strtok(NULL, x));
}

BEGIN
{
x = (char *) alloca(8);
x[0] = 'a';
x[1] = '/';
x[2] = 'b';
x[3] = 0;
trace(substr(x, 0, 1));
}

BEGIN
{
exit(0);
}

ERROR
{
exit(0);
}
2 changes: 2 additions & 0 deletions test/unittest/funcs/alloca/tst.alloca-funcs.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a/b
8b11/b/b3a/b//baba
29 changes: 29 additions & 0 deletions test/unittest/funcs/alloca/tst.string-alloca.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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: You can copy a string into an alloca'ed region and read
* it out again.
*
* SECTION: Actions and Subroutines/alloca()
*/

#pragma D option quiet
#pragma D option scratchsize=512

BEGIN
{
x = (string *)alloca(sizeof(string) + 1);
*x = "abc";
trace(*x);
exit(0);
}

ERROR
{
exit(1);
}
1 change: 1 addition & 0 deletions test/unittest/funcs/alloca/tst.string-alloca.r
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
abc

0 comments on commit a24181d

Please sign in to comment.