From 8e2f54bcee7e3e8315d4a39a302eaf8e4389e07d Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Tue, 30 May 2017 06:34:05 -0700 Subject: [PATCH] Add bfd_get_file_size to get archive element size We can't use stat() to get archive element size. Add bfd_get_file_size to get size for both normal files and archive elements. bfd/ PR binutils/21519 * bfdio.c (bfd_get_file_size): New function. * bfd-in2.h: Regenerated. binutils/ PR binutils/21519 * objdump.c (dump_relocs_in_section): Replace get_file_size with bfd_get_file_size to get archive element size. * testsuite/binutils-all/objdump.exp (test_objdump_f): New proc. (test_objdump_h): Likewise. (test_objdump_t): Likewise. (test_objdump_r): Likewise. (test_objdump_s): Likewise. Add objdump tests on archive. Upstream-Status: Backport CVE: CVE-2017-9955 Signed-off-by: Armin Kuster --- bfd/ChangeLog | 6 + bfd/bfd-in2.h | 2 + bfd/bfdio.c | 23 ++++ binutils/ChangeLog | 13 ++ binutils/objdump.c | 2 +- binutils/testsuite/binutils-all/objdump.exp | 178 +++++++++++++++++++--------- 6 files changed, 170 insertions(+), 54 deletions(-) Index: git/bfd/bfd-in2.h =================================================================== --- git.orig/bfd/bfd-in2.h +++ git/bfd/bfd-in2.h @@ -1241,6 +1241,8 @@ long bfd_get_mtime (bfd *abfd); file_ptr bfd_get_size (bfd *abfd); +file_ptr bfd_get_file_size (bfd *abfd); + void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, int prot, int flags, file_ptr offset, void **map_addr, bfd_size_type *map_len); Index: git/bfd/bfdio.c =================================================================== --- git.orig/bfd/bfdio.c +++ git/bfd/bfdio.c @@ -434,6 +434,29 @@ bfd_get_size (bfd *abfd) return buf.st_size; } +/* +FUNCTION + bfd_get_file_size + +SYNOPSIS + file_ptr bfd_get_file_size (bfd *abfd); + +DESCRIPTION + Return the file size (as read from file system) for the file + associated with BFD @var{abfd}. It supports both normal files + and archive elements. + +*/ + +file_ptr +bfd_get_file_size (bfd *abfd) +{ + if (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + return arelt_size (abfd); + + return bfd_get_size (abfd); +} /* FUNCTION Index: git/binutils/objdump.c =================================================================== --- git.orig/binutils/objdump.c +++ git/binutils/objdump.c @@ -3310,7 +3310,7 @@ dump_relocs_in_section (bfd *abfd, } if ((bfd_get_file_flags (abfd) & (BFD_IN_MEMORY | BFD_LINKER_CREATED)) == 0 - && relsize > get_file_size (bfd_get_filename (abfd))) + && relsize > bfd_get_file_size (abfd)) { printf (" (too many: 0x%x)\n", section->reloc_count); bfd_set_error (bfd_error_file_truncated); Index: git/binutils/testsuite/binutils-all/objdump.exp =================================================================== --- git.orig/binutils/testsuite/binutils-all/objdump.exp +++ git/binutils/testsuite/binutils-all/objdump.exp @@ -64,96 +64,168 @@ if [regexp $want $got] then { if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then { return } +if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest2.o]} then { + return +} if [is_remote host] { set testfile [remote_download host tmpdir/bintest.o] + set testfile2 [remote_download host tmpdir/bintest2.o] } else { set testfile tmpdir/bintest.o + set testfile2 tmpdir/bintest2.o +} + +if { ![istarget "alpha-*-*"] || [is_elf_format] } then { + remote_file host file delete tmpdir/bintest.a + set got [binutils_run $AR "rc tmpdir/bintest.a $testfile2"] + if ![string match "" $got] then { + fail "bintest.a" + remote_file host delete tmpdir/bintest.a + } else { + if [is_remote host] { + set testarchive [remote_download host tmpdir/bintest.a] + } else { + set testarchive tmpdir/bintest.a + } + } + remote_file host delete tmpdir/bintest2.o } # Test objdump -f -set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -f $testfile"] +proc test_objdump_f { testfile dumpfile } { + global OBJDUMP + global OBJDUMPFLAGS + global cpus_regex -set want "$testfile:\[ \]*file format.*architecture:\[ \]*${cpus_regex}.*HAS_RELOC.*HAS_SYMS" + set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -f $testfile"] -if ![regexp $want $got] then { - fail "objdump -f" -} else { - pass "objdump -f" + set want "$dumpfile:\[ \]*file format.*architecture:\[ \]*${cpus_regex}.*HAS_RELOC.*HAS_SYMS" + + if ![regexp $want $got] then { + fail "objdump -f ($testfile, $dumpfile)" + } else { + pass "objdump -f ($testfile, $dumpfile)" + } +} + +test_objdump_f $testfile $testfile +if { [ remote_file host exists $testarchive ] } then { + test_objdump_f $testarchive bintest2.o } # Test objdump -h -set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -h $testfile"] +proc test_objdump_h { testfile dumpfile } { + global OBJDUMP + global OBJDUMPFLAGS -set want "$testfile:\[ \]*file format.*Sections.*\[0-9\]+\[ \]+\[^ \]*(text|TEXT|P|\\\$CODE\\\$)\[^ \]*\[ \]*(\[0-9a-fA-F\]+).*\[0-9\]+\[ \]+\[^ \]*(\\.data|DATA|D_1)\[^ \]*\[ \]*(\[0-9a-fA-F\]+)" + set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -h $testfile"] -if ![regexp $want $got all text_name text_size data_name data_size] then { - fail "objdump -h" -} else { - verbose "text name is $text_name size is $text_size" - verbose "data name is $data_name size is $data_size" - set ets 8 - set eds 4 - # The [ti]c4x target has the property sizeof(char)=sizeof(long)=1 - if [istarget *c4x*-*-*] then { - set ets 2 - set eds 1 - } - # c54x section sizes are in bytes, not octets; adjust accordingly - if [istarget *c54x*-*-*] then { - set ets 4 - set eds 2 - } - if {[expr "0x$text_size"] < $ets || [expr "0x$data_size"] < $eds} then { - send_log "sizes too small\n" - fail "objdump -h" + set want "$dumpfile:\[ \]*file format.*Sections.*\[0-9\]+\[ \]+\[^ \]*(text|TEXT|P|\\\$CODE\\\$)\[^ \]*\[ \]*(\[0-9a-fA-F\]+).*\[0-9\]+\[ \]+\[^ \]*(\\.data|DATA|D_1)\[^ \]*\[ \]*(\[0-9a-fA-F\]+)" + + if ![regexp $want $got all text_name text_size data_name data_size] then { + fail "objdump -h ($testfile, $dumpfile)" } else { - pass "objdump -h" + verbose "text name is $text_name size is $text_size" + verbose "data name is $data_name size is $data_size" + set ets 8 + set eds 4 + # The [ti]c4x target has the property sizeof(char)=sizeof(long)=1 + if [istarget *c4x*-*-*] then { + set ets 2 + set eds 1 + } + # c54x section sizes are in bytes, not octets; adjust accordingly + if [istarget *c54x*-*-*] then { + set ets 4 + set eds 2 + } + if {[expr "0x$text_size"] < $ets || [expr "0x$data_size"] < $eds} then { + send_log "sizes too small\n" + fail "objdump -h ($testfile, $dumpfile)" + } else { + pass "objdump -h ($testfile, $dumpfile)" + } } } +test_objdump_h $testfile $testfile +if { [ remote_file host exists $testarchive ] } then { + test_objdump_h $testarchive bintest2.o +} + # Test objdump -t -set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -t $testfile"] +proc test_objdump_t { testfile} { + global OBJDUMP + global OBJDUMPFLAGS + + set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -t $testfile"] + + if [info exists vars] then { unset vars } + while {[regexp "(\[a-z\]*_symbol)(.*)" $got all symbol rest]} { + set vars($symbol) 1 + set got $rest + } -if [info exists vars] then { unset vars } -while {[regexp "(\[a-z\]*_symbol)(.*)" $got all symbol rest]} { - set vars($symbol) 1 - set got $rest + if {![info exists vars(text_symbol)] \ + || ![info exists vars(data_symbol)] \ + || ![info exists vars(common_symbol)] \ + || ![info exists vars(external_symbol)]} then { + fail "objdump -t ($testfile)" + } else { + pass "objdump -t ($testfile)" + } } -if {![info exists vars(text_symbol)] \ - || ![info exists vars(data_symbol)] \ - || ![info exists vars(common_symbol)] \ - || ![info exists vars(external_symbol)]} then { - fail "objdump -t" -} else { - pass "objdump -t" +test_objdump_t $testfile +if { [ remote_file host exists $testarchive ] } then { + test_objdump_t $testarchive } # Test objdump -r -set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -r $testfile"] +proc test_objdump_r { testfile dumpfile } { + global OBJDUMP + global OBJDUMPFLAGS -set want "$testfile:\[ \]*file format.*RELOCATION RECORDS FOR \\\[\[^\]\]*(text|TEXT|P|\\\$CODE\\\$)\[^\]\]*\\\].*external_symbol" + set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -r $testfile"] -if [regexp $want $got] then { - pass "objdump -r" -} else { - fail "objdump -r" + set want "$dumpfile:\[ \]*file format.*RELOCATION RECORDS FOR \\\[\[^\]\]*(text|TEXT|P|\\\$CODE\\\$)\[^\]\]*\\\].*external_symbol" + + if [regexp $want $got] then { + pass "objdump -r ($testfile, $dumpfile)" + } else { + fail "objdump -r ($testfile, $dumpfile)" + } +} + +test_objdump_r $testfile $testfile +if { [ remote_file host exists $testarchive ] } then { + test_objdump_r $testarchive bintest2.o } # Test objdump -s -set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -s $testfile"] +proc test_objdump_s { testfile dumpfile } { + global OBJDUMP + global OBJDUMPFLAGS -set want "$testfile:\[ \]*file format.*Contents.*(text|TEXT|P|\\\$CODE\\\$)\[^0-9\]*\[ \]*\[0-9a-fA-F\]*\[ \]*(00000001|01000000|00000100).*Contents.*(data|DATA|D_1)\[^0-9\]*\[ \]*\[0-9a-fA-F\]*\[ \]*(00000002|02000000|00000200)" + set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -s $testfile"] -if [regexp $want $got] then { - pass "objdump -s" -} else { - fail "objdump -s" + set want "$dumpfile:\[ \]*file format.*Contents.*(text|TEXT|P|\\\$CODE\\\$)\[^0-9\]*\[ \]*\[0-9a-fA-F\]*\[ \]*(00000001|01000000|00000100).*Contents.*(data|DATA|D_1)\[^0-9\]*\[ \]*\[0-9a-fA-F\]*\[ \]*(00000002|02000000|00000200)" + + if [regexp $want $got] then { + pass "objdump -s ($testfile, $dumpfile)" + } else { + fail "objdump -s ($testfile, $dumpfile)" + } +} + +test_objdump_s $testfile $testfile +if { [ remote_file host exists $testarchive ] } then { + test_objdump_s $testarchive bintest2.o } # Test objdump -s on a file that contains a compressed .debug section Index: git/bfd/ChangeLog =================================================================== --- git.orig/bfd/ChangeLog +++ git/bfd/ChangeLog @@ -1,3 +1,9 @@ +2017-05-30 H.J. Lu + + PR binutils/21519 + * bfdio.c (bfd_get_file_size): New function. + * bfd-in2.h: Regenerated. + 2017-06-27 Alan Modra PR binutils/21665 Index: git/binutils/ChangeLog =================================================================== --- git.orig/binutils/ChangeLog +++ git/binutils/ChangeLog @@ -1,3 +1,16 @@ +2017-05-30 H.J. Lu + + PR binutils/21519 + * objdump.c (dump_relocs_in_section): Replace get_file_size + with bfd_get_file_size to get archive element size. + * testsuite/binutils-all/objdump.exp (test_objdump_f): New + proc. + (test_objdump_h): Likewise. + (test_objdump_t): Likewise. + (test_objdump_r): Likewise. + (test_objdump_s): Likewise. + Add objdump tests on archive. + 2017-07-01 Alan Modra PR binutils/21665