From: H.J. Lu Date: Wed, 29 Jul 2015 18:57:54 +0000 (-0700) Subject: Extend local PLT reference check X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1b248392fbadaa5a81ed220fdf2f7ec3b9939b9e;p=thirdparty%2Fglibc.git Extend local PLT reference check On x86, linker in binutils 2.26 and newer consolidates R_*_JUMP_SLOT with R_*_GLOB_DAT relocation against the same symbol. This patch extends local PLT reference check to support alternate relocations. [BZ #18078] * scripts/check-localplt.awk: Support alternate relocations. * scripts/localplt.awk: Also check relocations in DT_RELA/DT_REL sections. * sysdeps/unix/sysv/linux/i386/localplt.data: Mark free and malloc entries with + REL R_386_GLOB_DAT. * sysdeps/x86_64/localplt.data: New file. --- diff --git a/ChangeLog b/ChangeLog index b31754382b5..907cc1dd90c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2015-07-29 H.J. Lu + + [BZ #18078] + * scripts/check-localplt.awk: Support alternate relocations. + * scripts/localplt.awk: Also check relocations in DT_RELA/DT_REL + sections. + * sysdeps/unix/sysv/linux/i386/localplt.data: Mark free and + malloc entries with + REL R_386_GLOB_DAT. + * sysdeps/x86_64/localplt.data: New file. + 2015-03-03 Alan Modra [BZ #16512] diff --git a/NEWS b/NEWS index e0ed68d90f3..f6c26504691 100644 --- a/NEWS +++ b/NEWS @@ -10,7 +10,7 @@ Version 2.21.1 * The following bugs are resolved with this release: 16512, 17090, 17269, 17620, 17621, 17628, 17905, 17949, 18007, 18032, - 18080, 18240, 18287, 18508, 18694, 18887, 18985, 19048, 19682. + 18078, 18080, 18240, 18287, 18508, 18694, 18887, 18985, 19048, 19682. * A stack-based buffer overflow was found in libresolv when invoked from libnss_dns, allowing specially crafted DNS responses to seize control diff --git a/scripts/check-localplt.awk b/scripts/check-localplt.awk index bb1b9121319..39652928883 100644 --- a/scripts/check-localplt.awk +++ b/scripts/check-localplt.awk @@ -3,9 +3,14 @@ # Each line is either a comment starting with # or it looks like: # libfoo.so: function # or +# libfoo.so: function + {RELA|REL} RELOC +# or # libfoo.so: function ? -# The latter means that a PLT entry for function is optional in libfoo.so. -# The former means one is required. +# The first entry means that one is required. +# The second entry means that one is required and relocation may also be +# {RELA|REL} RELOC. +# The third entry means that a PLT entry for function is optional in +# libfoo.so. # The second file argument is - and this (stdin) receives the output # of the check-localplt program. @@ -14,7 +19,10 @@ BEGIN { result = 0 } FILENAME != "-" && /^#/ { next } FILENAME != "-" { - if (NF != 2 && !(NF == 3 && $3 == "?")) { + if (NF == 5 && $3 == "+" && ($4 == "RELA" || $4 == "REL")) { + accept_type[$1 " " $2] = $4; + accept_reloc[$1 " " $2] = $5; + } else if (NF != 2 && !(NF == 3 && $3 == "?")) { printf "%s:%d: bad data line: %s\n", FILENAME, FNR, $0 > "/dev/stderr"; result = 2; } else { @@ -23,7 +31,7 @@ FILENAME != "-" { next; } -NF != 2 { +NF != 2 && !(NF == 4 && ($3 == "RELA" || $3 == "REL")) { print "Unexpected output from check-localplt:", $0 > "/dev/stderr"; result = 2; next @@ -31,7 +39,23 @@ NF != 2 { { key = $1 " " $2 - if (key in accept) { + if ($3 == "RELA" || $3 == "REL") { + # Entries like: + # libc.so: free + RELA R_X86_64_GLOB_DAT + # may be ignored. + if (key in accept_type && accept_type[key] == $3 && accept_reloc[key] == $4) { + # Match + # libc.so: free + RELA R_X86_64_GLOB_DAT + delete accept_type[key] + } + } else if (NF == 2 && key in accept_reloc) { + # Match + # libc.so: free + # against + # libc.so: free + RELA R_X86_64_GLOB_DAT + if (key in accept_type) + delete accept_type[key] + } else if (key in accept) { delete accept[key] } else { print "Extra PLT reference:", $0; @@ -49,5 +73,11 @@ END { } } + for (key in accept_type) { + # It's mandatory. + print "Missing required PLT or " accept_reloc[key] " reference:", key; + result = 1; + } + exit(result); } diff --git a/scripts/localplt.awk b/scripts/localplt.awk index 84c94d10241..f75b3b427b1 100644 --- a/scripts/localplt.awk +++ b/scripts/localplt.awk @@ -13,6 +13,8 @@ FILENAME != lastfile { } lastfile = FILENAME; jmprel_offset = 0; + rela_offset = 0; + rel_offset = 0; delete section_offset_by_address; } @@ -43,6 +45,30 @@ in_relocs && relocs_offset == jmprel_offset && NF >= 5 { } } +in_relocs && relocs_offset == rela_offset && NF >= 5 { + # Relocations against GNU_IFUNC symbols are not shown as an hexadecimal + # value, but rather as the resolver symbol followed by (). + if ($4 ~ /\(\)/) { + print whatfile, gensub(/@.*/, "", "g", $5), "RELA", $3 + } else { + symval = strtonum("0x" $4); + if (symval != 0) + print whatfile, gensub(/@.*/, "", "g", $5), "RELA", $3 + } +} + +in_relocs && relocs_offset == rel_offset && NF >= 5 { + # Relocations against GNU_IFUNC symbols are not shown as an hexadecimal + # value, but rather as the resolver symbol followed by (). + if ($4 ~ /\(\)/) { + print whatfile, gensub(/@.*/, "", "g", $5), "REL", $3 + } else { + symval = strtonum("0x" $4); + if (symval != 0) + print whatfile, gensub(/@.*/, "", "g", $5), "REL", $3 + } +} + in_relocs { next } $1 == "Relocation" && $2 == "section" && $5 == "offset" { @@ -62,4 +88,25 @@ $2 == "(JMPREL)" { next } +$2 == "(RELA)" { + rela_addr = strtonum($3); + if (rela_addr in section_offset_by_address) { + rela_offset = section_offset_by_address[rela_addr]; + } else { + print FILENAME ": *** DT_RELA does not match any section's address"; + result = 2; + } + next +} + +$2 == "(REL)" { + rel_addr = strtonum($3); + if (rel_addr in section_offset_by_address) { + rel_offset = section_offset_by_address[rel_addr]; + } else { + print FILENAME ": *** DT_REL does not match any section's address"; + result = 2; + } + next +} END { exit(result) } diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data index b25abf80065..2e03821dfdc 100644 --- a/sysdeps/unix/sysv/linux/i386/localplt.data +++ b/sysdeps/unix/sysv/linux/i386/localplt.data @@ -1,7 +1,9 @@ +# Linker in binutils 2.26 and newer consolidates R_X86_64_JUMP_SLOT +# relocation with R_386_GLOB_DAT relocation against the same symbol. libc.so: _Unwind_Find_FDE libc.so: calloc -libc.so: free -libc.so: malloc +libc.so: free + REL R_386_GLOB_DAT +libc.so: malloc + REL R_386_GLOB_DAT libc.so: memalign libc.so: realloc libm.so: matherr @@ -12,4 +14,4 @@ ld.so: __libc_memalign ld.so: malloc ld.so: calloc ld.so: realloc -ld.so: free +ld.so: free + REL R_386_GLOB_DAT diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data new file mode 100644 index 00000000000..d140476dfef --- /dev/null +++ b/sysdeps/x86_64/localplt.data @@ -0,0 +1,19 @@ +# See scripts/check-localplt.awk for how this file is processed. +# PLT use is required for the malloc family and for matherr because +# users can define their own functions and have library internals call them. +# Linker in binutils 2.26 and newer consolidates R_X86_64_JUMP_SLOT +# relocation with R_X86_64_GLOB_DAT relocation against the same symbol. +libc.so: calloc +libc.so: free + RELA R_X86_64_GLOB_DAT +libc.so: malloc + RELA R_X86_64_GLOB_DAT +libc.so: memalign +libc.so: realloc +libm.so: matherr +# The dynamic loader uses __libc_memalign internally to allocate aligned +# TLS storage. The other malloc family of functions are expected to allow +# user symbol interposition. +ld.so: __libc_memalign +ld.so: malloc +ld.so: calloc +ld.so: realloc +ld.so: free + RELA R_X86_64_GLOB_DAT