From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 34874 invoked by alias); 11 May 2018 10:49:29 -0000 Mailing-List: contact elfutils-devel-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: elfutils-devel-owner@sourceware.org Received: (qmail 34860 invoked by uid 89); 11 May 2018 10:49:28 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.4 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=H*Ad:U*mark, Got, have_config_h, HAVE_CONFIG_H X-Spam-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 11 May 2018 10:49:26 +0000 Received: from tarox.wildebeest.org (tarox.wildebeest.org [172.31.17.39]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id EA762310E0BC; Fri, 11 May 2018 12:49:22 +0200 (CEST) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id 9E23E413CB3E; Fri, 11 May 2018 12:49:22 +0200 (CEST) From: Mark Wielaard To: elfutils-devel@sourceware.org Cc: Mark Wielaard Subject: [PATCH] libdw: Fix crashing on illegal/zero Dwarf_Die. Date: Fri, 11 May 2018 10:49:00 -0000 Message-Id: <1526035758-27844-1-git-send-email-mark@klomp.org> X-Mailer: git-send-email 1.8.3.1 X-Spam-Flag: NO X-IsSubscribed: yes X-SW-Source: 2018-q2/txt/msg00029.txt.bz2 In some cases we create an illegal Dwarf_Die by clearing all fields. The idea is that dwarf_tag () on such a Dwarf_Die will return DW_TAG_invalid, to indicate that the Dwarf_Die is unusable (and other functions will also return errors). But when "reconstructing" the Dwarf_Die addr we might use the cu before realizing the Dwarf_Die is invalid. Fix this with an explicit NULL check and add a testcase. Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 6 +++ libdw/dwarf_siblingof.c | 5 ++- libdw/libdwP.h | 2 + tests/ChangeLog | 9 ++++ tests/Makefile.am | 10 +++-- tests/get-units-invalid.c | 96 ++++++++++++++++++++++++++++++++++++++++++ tests/run-get-units-invalid.sh | 44 +++++++++++++++++++ 7 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 tests/get-units-invalid.c create mode 100755 tests/run-get-units-invalid.sh diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 5e2c0d8..86d2b78 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,9 @@ +2018-05-11 Mark Wielaard + + * dwarf_siblingof.c (dwarf_siblingof): Don't reference cu till it is + known the Dwarf_Die is came from is valid. + * libdwP.h (__libdw_dieabbrev): Check cu is not NULL. + 2018-05-08 Mark Wielaard * dwarf_formref.c (__libdw_formref): Explicitly don't handle diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c index df39c1c..613d209 100644 --- a/libdw/dwarf_siblingof.c +++ b/libdw/dwarf_siblingof.c @@ -58,8 +58,6 @@ dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result) sibattr.cu = this_die.cu; /* That's the address we start looking. */ unsigned char *addr = this_die.addr; - /* End of the buffer. */ - unsigned char *endp = sibattr.cu->endp; /* Search for the beginning of the next die on this level. We must not return the dies for children of the given die. */ @@ -96,6 +94,8 @@ dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result) /* This abbreviation has children. */ ++level; + /* End of the buffer. */ + unsigned char *endp = sibattr.cu->endp; while (1) { @@ -125,6 +125,7 @@ dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result) while (level > 0); /* Maybe we reached the end of the CU. */ + unsigned char *endp = sibattr.cu->endp; if (addr >= endp) return 1; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 751206d..7aa290e 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -615,6 +615,8 @@ __libdw_dieabbrev (Dwarf_Die *die, const unsigned char **readp) /* Get the abbreviation code. */ unsigned int code; const unsigned char *addr = die->addr; + if (die->cu == NULL) + return DWARF_END_ABBREV; get_uleb128 (code, addr, die->cu->endp); if (readp != NULL) *readp = addr; diff --git a/tests/ChangeLog b/tests/ChangeLog index 8a098b4..b236ee7 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,12 @@ +2018-05-11 Mark Wielaard + + * Makefile.am (check_PROGRAMS): Add get-units-invalid. + (TESTS): Add run-get-units-invalid.sh. + (EXTRA_DIST): Likewise. + (get_units_invalid_LDADD): New variable. + * get-units-invalid.c: New test program. + * run-get-units-invalid.sh: New test program runner. + 2018-05-05 Mark Wielaard * testfile-dwarf-45.source: New file. diff --git a/tests/Makefile.am b/tests/Makefile.am index 2f9ae23..ac16a5e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -55,7 +55,8 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ getsrc_die strptr newdata elfstrtab dwfl-proc-attach \ elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr \ elfgetzdata elfputzdata zstrptr emptyfile vendorelf \ - fillfile dwarf_default_lower_bound dwarf-die-addr-die + fillfile dwarf_default_lower_bound dwarf-die-addr-die \ + get-units-invalid asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ asm-tst6 asm-tst7 asm-tst8 asm-tst9 @@ -138,7 +139,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-compress-test.sh \ run-readelf-zdebug.sh run-readelf-zdebug-rel.sh \ emptyfile vendorelf fillfile dwarf_default_lower_bound \ - run-dwarf-die-addr-die.sh + run-dwarf-die-addr-die.sh \ + run-get-units-invalid.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -358,7 +360,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-disasm-bpf.sh \ testfile-bpf-dis1.expect.bz2 testfile-bpf-dis1.o.bz2 \ testfile-m68k-core.bz2 testfile-m68k.bz2 testfile-m68k-s.bz2 \ - run-dwarf-die-addr-die.sh + run-dwarf-die-addr-die.sh \ + run-get-units-invalid.sh if USE_VALGRIND valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1' @@ -517,6 +520,7 @@ vendorelf_LDADD = $(libelf) fillfile_LDADD = $(libelf) dwarf_default_lower_bound_LDADD = $(libdw) dwarf_die_addr_die_LDADD = $(libdw) +get_units_invalid_LDADD = $(libdw) # We want to test the libelf header against the system elf.h header. # Don't include any -I CPPFLAGS. diff --git a/tests/get-units-invalid.c b/tests/get-units-invalid.c new file mode 100644 index 0000000..9ec16ee --- /dev/null +++ b/tests/get-units-invalid.c @@ -0,0 +1,96 @@ +/* Test cudie and subdie properties. + Copyright (C) 2018 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include ELFUTILS_HEADER(dw) +#include +#include +#include +#include +#include +#include + + +int +main (int argc, char *argv[]) +{ + for (int i = 1; i < argc; i++) + { + printf ("file: %s\n", argv[i]); + int fd = open (argv[i], O_RDONLY); + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable: %s\n", argv[i], dwarf_errmsg (-1)); + return -1; + } + + Dwarf_CU *cu = NULL; + Dwarf_Die cudie, subdie; + uint8_t unit_type; + while (dwarf_get_units (dbg, cu, &cu, NULL, + &unit_type, &cudie, &subdie) == 0) + { + printf ("Got cudie: %s, unit_type: %" PRIx8 "\n", + dwarf_diename (&cudie), unit_type); + + int tag = dwarf_tag (&subdie); + if (unit_type == DW_UT_compile) + { + if (tag != DW_TAG_invalid) + { + printf ("Not invalid: %x\n", dwarf_tag (&subdie)); + return -1; + } + if (dwarf_diename (&subdie) != NULL) + { + printf ("Should have NULL name: %s\n", + dwarf_diename (&subdie)); + return -1; + } + Dwarf_Die result; + if (dwarf_siblingof (&subdie, &result) != -1) + { + printf ("Should NOT have a valid sibling: %s\n", + dwarf_diename (&result)); + return -1; + } + if (dwarf_child (&subdie, &result) != -1) + { + printf ("Should NOT have a valid child: %s\n", + dwarf_diename (&result)); + return -1; + } + } + else if (unit_type == DW_UT_type) + printf ("subdie: %s\n", dwarf_diename (&subdie)); + else + printf ("subdie tag: %x\n", dwarf_tag (&subdie)); + } + + dwarf_end (dbg); + close (fd); + + printf ("\n"); + } + + return 0; +} diff --git a/tests/run-get-units-invalid.sh b/tests/run-get-units-invalid.sh new file mode 100755 index 0000000..66ef944 --- /dev/null +++ b/tests/run-get-units-invalid.sh @@ -0,0 +1,44 @@ +#! /bin/sh +# Copyright (C) 2018 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/test-subr.sh + +# See run-typeiter.sh +testfiles testfile-debug-types + +testrun ${abs_builddir}/get-units-invalid testfile-debug-types + +# see run-readelf-dwz-multi.sh +testfiles testfile_multi_main testfile_multi.dwz + +testrun ${abs_builddir}/get-units-invalid testfile_multi_main + +# see tests/run-dwflsyms.sh +testfiles testfilebazdbgppc64.debug + +testrun ${abs_builddir}/get-units-invalid testfilebazdbgppc64.debug + +# see tests/testfile-dwarf-45.source +testfiles testfile-dwarf-4 testfile-dwarf-5 + +testrun ${abs_builddir}/get-units-invalid testfile-dwarf-4 +testrun ${abs_builddir}/get-units-invalid testfile-dwarf-5 + +# Self test +testrun_on_self ${abs_builddir}/get-units-invalid + +exit 0 -- 1.8.3.1