Skip to content

Commit

Permalink
alloca: track alloca()ed allocations
Browse files Browse the repository at this point in the history
This introduces a DT_IDFLG_ALLOCA flag which, when set, will (in future
commits) cause dereferences to bounds-check alloca scratch-space offsets
against the scratch top and boost the offsets into actual pointers into
scratch memory.  There is a matching parse tree node flag DT_NF_ALLOCA
which indicates that a parse tree node has been influenced by an
alloca'ed value.  There is also a DT_IDFLG_NONALLOCA flag which
indicates that an assignment happened that did *not* involve an
alloca()ed value: this will be used to prevent reuse of the same
variable for both alloca() and non-alloca() purposes.  The node flag
propagates across most operations (but not dereferences, because
dereferencing a pointer yields a value, which should not have its offset
adjusted).  One function's identifier has this flag set by default:
obviously enough, alloca().  (Other functions that always return
alloca()ed pointers, or pointers into alloca()ed space, should do the
same.)

Propagating this is fairly amusing, because not only do we have to
handle propagation of these flags both to and from parse tree nodes and
identifiers (because you can do things like "foo = alloca(10); bar =
foo;") and across casts, but we have to handle cases like identifiers
with alloca'ed vars in their arglists (which will become relevant when
indexed associative arrays appear), ternaries in which one side is
allocaed and the other side isn't (which flips on a similarly-propagated
DT_NF_NONASSIGN flag to stop you using such things in assignments), and
the same possibility of changes sweeping backwards and forwards between
the predicate and the clause that already has to be handled for ++,
which can require the two to be cooked in either order and to be cooked
repeatedly (yes, you can alloca in a predicate, and you can use
alloca'ed memory in a predicate).

A few things are newly banned that were allowed before: in particular,
you can't say bar : -alloca(10). It makes little sense to negate a
pointer anyway, but this pointer's eventual representation as a
bounds-checked offset from the scratchmem array makes it even less
sensible.  You also cannot add or subtract pointers where one is
allocaed and the other is not, nor (as noted above) assign the results
of a partly-allocaed ternary to a variable.

The parser dn_flags is boosted to a ushort because we have run out of
flags :(

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 9489c3b commit a37f2d0
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 10 deletions.
4 changes: 3 additions & 1 deletion libdtrace/dt_errtags.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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.
*/
Expand Down Expand Up @@ -174,6 +174,8 @@ typedef enum {
D_USTACK_FRAMES, /* ustack() frames arg bad type */
D_USTACK_STRSIZE, /* ustack() strsize arg bad type */
D_USTACK_PROTO, /* ustack() prototype mismatch */
D_ALLOCA_SIZE, /* allocation too large */
D_ALLOCA_INCOMPAT, /* pointer reused for alloca and non-alloca */
D_LQUANT_BASETYPE, /* lquantize() bad base type */
D_LQUANT_BASEVAL, /* lquantize() bad base value */
D_LQUANT_LIMTYPE, /* lquantize() bad limit type */
Expand Down
18 changes: 17 additions & 1 deletion libdtrace/dt_ident.c
Original file line number Diff line number Diff line change
Expand Up @@ -979,18 +979,34 @@ dt_ident_cook(dt_node_t *dnp, dt_ident_t *idp, dt_node_t **pargp)
dtrace_attribute_t attr;
dt_node_t *args, *argp;
int argc = 0;
int alloca_args = 0;

attr = dt_node_list_cook(pargp, DT_IDFLG_REF);
args = pargp ? *pargp : NULL;

for (argp = args; argp != NULL; argp = argp->dn_list)
for (argp = args; argp != NULL; argp = argp->dn_list) {
argc++;
if (argp->dn_flags & DT_NF_ALLOCA)
alloca_args = 1;
}

idp->di_ops->di_cook(dnp, idp, argc, args);

if (idp->di_flags & DT_IDFLG_USER)
dnp->dn_flags |= DT_NF_USERLAND;

/*
* Propagate alloca flags in both directions. No need to propagate it
* down into the arglist, but if the alloca flag is on in the arglist it
* should also be on in both the identifer and the node. (If this is
* a node of the sort we propagate alloca taint into at all.)
*/

if (idp->di_flags & DT_IDFLG_ALLOCA ||
dnp->dn_flags & DT_NF_ALLOCA ||
alloca_args)
dt_cook_taint_alloca(dnp, idp, NULL);

return dt_attr_min(attr, idp->di_attr);
}

Expand Down
4 changes: 3 additions & 1 deletion libdtrace/dt_ident.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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.
*/
Expand Down Expand Up @@ -94,6 +94,8 @@ typedef struct dt_ident {
#define DT_IDFLG_DECL 0x0400 /* variable is associated with explicit decl */
#define DT_IDFLG_ORPHAN 0x0800 /* variable is in a dt_node and not dt_idhash */
#define DT_IDFLG_BPF 0x1000 /* variable is BPF */
#define DT_IDFLG_ALLOCA 0x2000 /* variable holds an alloca()ed pointer */
#define DT_IDFLG_NONALLOCA 0x4000 /* variable known not to hold an alloca()ed pointer */

#define DT_IDENT_UNDEF UINT_MAX /* id for (as yet) undefined identifiers */

Expand Down
4 changes: 2 additions & 2 deletions libdtrace/dt_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ static const dt_provimpl_t *dt_providers[] = {
* argument.
*/
static const dt_ident_t _dtrace_globals[] = {
{ "alloca", DT_IDENT_FUNC, 0, DIF_SUBR_ALLOCA, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void *(size_t)" },
{ "alloca", DT_IDENT_FUNC, DT_IDFLG_ALLOCA, DIF_SUBR_ALLOCA, DT_ATTR_STABCMN,
DT_VERS_1_0, &dt_idops_func, "void *(size_t)" },
{ "arg0", DT_IDENT_SCALAR, 0, DIF_VAR_ARG0, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "int64_t" },
{ "arg1", DT_IDENT_SCALAR, 0, DIF_VAR_ARG1, DT_ATTR_STABCMN, DT_VERS_1_0,
Expand Down

0 comments on commit a37f2d0

Please sign in to comment.