summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2015-01-11 15:00:52 +0100
committerMark Wielaard <mjw@redhat.com>2015-01-12 09:35:59 +0100
commitdaf278fda6d9bd329b517757f9ba2d74619f3be7 (patch)
treef4f4b56945a0c354e8ad54f6d338f995e1020aa6
parent147018e729e7c22eeabf15b82d26e4bf68a0d18e (diff)
downloadelfutils-daf278fda6d9bd329b517757f9ba2d74619f3be7.tar.gz
libdw: Prevent infinite recursion when processing DW_TAG_imported_unit.
Invalid DWARF could create cycles with DW_TAG_imported_unit, which would lead to infinite recursion and stack overflow in libdw_visit_scopes. Keep track of imported units and error out when a cycle is detected. Found by afl-fuzz. Signed-off-by: Mark Wielaard <mjw@redhat.com>
-rw-r--r--libdw/ChangeLog13
-rw-r--r--libdw/dwarf_func_inline.c4
-rw-r--r--libdw/dwarf_getfuncs.c4
-rw-r--r--libdw/dwarf_getscopes.c8
-rw-r--r--libdw/dwarf_getscopes_die.c4
-rw-r--r--libdw/libdwP.h5
-rw-r--r--libdw/libdw_visit_scopes.c28
7 files changed, 51 insertions, 15 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index abc2d71a..edafe974 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,16 @@
+2015-01-11 Mark Wielaard <mjw@redhat.com>
+
+ * dwarf_func_inline.c (dwarf_func_inline_instances): Call
+ __libdw_visit_scopes with NULL imports.
+ * dwarf_getfuncs.c (dwarf_getfuncs): Likewise.
+ * dwarf_getscopes.c (pc_record): Likewise.
+ (dwarf_getscopes): Likewise.
+ * dwarf_getscopes_die.c (dwarf_getscopes_die): Likewise.
+ * libdwP.h (__libdw_visit_scopes): Add imports argument.
+ * libdw_visit_scopes.c (__libdw_visit_scopes): Likewise. Add new
+ function imports_contains. Push and pop imports around walk_children
+ when processing DW_TAG_imported_unit.
+
2014-12-18 Ulrich Drepper <drepper@gmail.com>
* Makefile.am: Suppress output of textrel_check command.
diff --git a/libdw/dwarf_func_inline.c b/libdw/dwarf_func_inline.c
index bc9db1cf..1f04adfa 100644
--- a/libdw/dwarf_func_inline.c
+++ b/libdw/dwarf_func_inline.c
@@ -1,5 +1,5 @@
/* Convenience functions for handling DWARF descriptions of inline functions.
- Copyright (C) 2005,2006 Red Hat, Inc.
+ Copyright (C) 2005,2006,2015 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -97,5 +97,5 @@ dwarf_func_inline_instances (Dwarf_Die *func,
{
struct visitor_info v = { func->addr, callback, arg };
struct Dwarf_Die_Chain cu = { .die = CUDIE (func->cu), .parent = NULL };
- return __libdw_visit_scopes (0, &cu, &scope_visitor, NULL, &v);
+ return __libdw_visit_scopes (0, &cu, NULL, &scope_visitor, NULL, &v);
}
diff --git a/libdw/dwarf_getfuncs.c b/libdw/dwarf_getfuncs.c
index f79b0a79..b95f06f4 100644
--- a/libdw/dwarf_getfuncs.c
+++ b/libdw/dwarf_getfuncs.c
@@ -1,5 +1,5 @@
/* Get function information.
- Copyright (C) 2005, 2013 Red Hat, Inc.
+ Copyright (C) 2005, 2013, 2015 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2005.
@@ -109,7 +109,7 @@ dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
.parent = NULL };
- int res = __libdw_visit_scopes (0, &chain, &tree_visitor, NULL, &v);
+ int res = __libdw_visit_scopes (0, &chain, NULL, &tree_visitor, NULL, &v);
if (res == DWARF_CB_ABORT)
return (ptrdiff_t) v.last_addr;
diff --git a/libdw/dwarf_getscopes.c b/libdw/dwarf_getscopes.c
index 0ca6da0b..df480d33 100644
--- a/libdw/dwarf_getscopes.c
+++ b/libdw/dwarf_getscopes.c
@@ -1,5 +1,5 @@
/* Return scope DIEs containing PC address.
- Copyright (C) 2005, 2007 Red Hat, Inc.
+ Copyright (C) 2005, 2007, 2015 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -176,7 +176,7 @@ pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
If we don't find it, return to search the containing scope.
If we do find it, the nonzero return value will bail us out
of the postorder traversal. */
- return __libdw_visit_scopes (depth, die, &origin_match, NULL, a);
+ return __libdw_visit_scopes (depth, die, NULL, &origin_match, NULL, a);
}
@@ -189,10 +189,10 @@ dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
struct args a = { .pc = pc };
- int result = __libdw_visit_scopes (0, &cu, &pc_match, &pc_record, &a);
+ int result = __libdw_visit_scopes (0, &cu, NULL, &pc_match, &pc_record, &a);
if (result == 0 && a.scopes != NULL)
- result = __libdw_visit_scopes (0, &cu, &origin_match, NULL, &a);
+ result = __libdw_visit_scopes (0, &cu, NULL, &origin_match, NULL, &a);
if (result > 0)
*scopes = a.scopes;
diff --git a/libdw/dwarf_getscopes_die.c b/libdw/dwarf_getscopes_die.c
index d3615852..8e2e41db 100644
--- a/libdw/dwarf_getscopes_die.c
+++ b/libdw/dwarf_getscopes_die.c
@@ -1,5 +1,5 @@
/* Return scope DIEs containing given DIE.
- Copyright (C) 2005 Red Hat, Inc.
+ Copyright (C) 2005, 2015 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -67,7 +67,7 @@ dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes)
struct Dwarf_Die_Chain cu = { .die = CUDIE (die->cu), .parent = NULL };
void *info = die->addr;
- int result = __libdw_visit_scopes (1, &cu, &scope_visitor, NULL, &info);
+ int result = __libdw_visit_scopes (1, &cu, NULL, &scope_visitor, NULL, &info);
if (result > 0)
*scopes = info;
return result;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 5ab72194..e38e0c9b 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -1,5 +1,5 @@
/* Internal definitions for libdwarf.
- Copyright (C) 2002-2011, 2013, 2014 Red Hat, Inc.
+ Copyright (C) 2002-2011, 2013-2015 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -555,6 +555,7 @@ struct Dwarf_Die_Chain
};
extern int __libdw_visit_scopes (unsigned int depth,
struct Dwarf_Die_Chain *root,
+ struct Dwarf_Die_Chain *imports,
int (*previsit) (unsigned int depth,
struct Dwarf_Die_Chain *,
void *arg),
@@ -562,7 +563,7 @@ extern int __libdw_visit_scopes (unsigned int depth,
struct Dwarf_Die_Chain *,
void *arg),
void *arg)
- __nonnull_attribute__ (2, 3) internal_function;
+ __nonnull_attribute__ (2, 4) internal_function;
/* Parse a DWARF Dwarf_Block into an array of Dwarf_Op's,
and cache the result (via tsearch). */
diff --git a/libdw/libdw_visit_scopes.c b/libdw/libdw_visit_scopes.c
index 487375dc..ac7e8532 100644
--- a/libdw/libdw_visit_scopes.c
+++ b/libdw/libdw_visit_scopes.c
@@ -1,5 +1,5 @@
/* Helper functions to descend DWARF scope trees.
- Copyright (C) 2005,2006,2007 Red Hat, Inc.
+ Copyright (C) 2005,2006,2007,2015 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -65,9 +65,10 @@ may_have_scopes (Dwarf_Die *die)
}
int
-__libdw_visit_scopes (depth, root, previsit, postvisit, arg)
+__libdw_visit_scopes (depth, root, imports, previsit, postvisit, arg)
unsigned int depth;
struct Dwarf_Die_Chain *root;
+ struct Dwarf_Die_Chain *imports;
int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
void *arg;
@@ -81,10 +82,21 @@ __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
inline int recurse (void)
{
- return __libdw_visit_scopes (depth + 1, &child,
+ return __libdw_visit_scopes (depth + 1, &child, imports,
previsit, postvisit, arg);
}
+ /* Checks the given DIE hasn't been imported yet to prevent cycles. */
+ inline bool imports_contains (Dwarf_Die *die)
+ {
+ for (struct Dwarf_Die_Chain *import = imports; import != NULL;
+ import = import->parent)
+ if (import->die.addr == die->addr)
+ return true;
+
+ return false;
+ }
+
inline int walk_children ()
{
do
@@ -103,7 +115,17 @@ __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
if (INTUSE(dwarf_formref_die) (attr, &child.die) != NULL
&& INTUSE(dwarf_child) (&child.die, &child.die) == 0)
{
+ if (imports_contains (&orig_child_die))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ struct Dwarf_Die_Chain *orig_imports = imports;
+ struct Dwarf_Die_Chain import = { .die = orig_child_die,
+ .parent = orig_imports };
+ imports = &import;
int result = walk_children ();
+ imports = orig_imports;
if (result != DWARF_CB_OK)
return result;
}