[binutils-gdb] PR23881, pdp11 binutils fails if too much debug data
Alan Modra
amodra@sourceware.org
Wed Feb 28 10:55:52 GMT 2024
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4b72a278f46245635ca03ffc8179570c07e3531a
commit 4b72a278f46245635ca03ffc8179570c07e3531a
Author: Alan Modra <amodra@gmail.com>
Date: Wed Feb 28 18:53:52 2024 +1030
PR23881, pdp11 binutils fails if too much debug data
The PR testcase overflows one of the exec header fields, e_syms (the
size of the symbol table), leading to the string table offset being
wrong. Things go downhill from there. Fixed by checking for
overflow. This happens to trigger in the ld testsuite, so xfail that
test.
PR 23881
bfd/
* libaout.h (swap_exec_header_out): Return a bool.
* aoutx.h (swap_exec_header_out): Check for overflow in exec
header.
* pdp11.c (swap_exec_header_out): Likewise.
* i386lynx.c (WRITE_HEADERS): Adjust.
ld/
* testsuite/ld-scripts/map-address.exp: xfail pdp11.
Diff:
---
bfd/aoutx.h | 31 +++++++++++++++++++++++++++++--
bfd/i386lynx.c | 3 ++-
bfd/libaout.h | 5 +++--
bfd/pdp11.c | 28 ++++++++++++++++++++++++++--
ld/testsuite/ld-scripts/map-address.exp | 1 +
5 files changed, 61 insertions(+), 7 deletions(-)
diff --git a/bfd/aoutx.h b/bfd/aoutx.h
index 545285c823c..c8aaa14baeb 100644
--- a/bfd/aoutx.h
+++ b/bfd/aoutx.h
@@ -407,7 +407,7 @@ FUNCTION
aout_@var{size}_swap_exec_header_out
SYNOPSIS
- void aout_@var{size}_swap_exec_header_out
+ bool aout_@var{size}_swap_exec_header_out
(bfd *abfd,
struct internal_exec *execp,
struct external_exec *raw_bytes);
@@ -416,11 +416,37 @@ DESCRIPTION
Swap the information in an internal exec header structure
@var{execp} into the buffer @var{raw_bytes} ready for writing to disk.
*/
-void
+bool
NAME (aout, swap_exec_header_out) (bfd *abfd,
struct internal_exec *execp,
struct external_exec *bytes)
{
+ const char *err = NULL;
+ uint64_t val;
+#define MAXVAL(x) ((UINT64_C (1) << (8 * sizeof (x) - 1) << 1) - 1)
+ if ((val = execp->a_text) > MAXVAL (bytes->e_text))
+ err = "e_text";
+ else if ((val = execp->a_data) > MAXVAL (bytes->e_data))
+ err = "e_data";
+ else if ((val = execp->a_bss) > MAXVAL (bytes->e_bss))
+ err = "e_bss";
+ else if ((val = execp->a_syms) > MAXVAL (bytes->e_syms))
+ err = "e_syms";
+ else if ((val = execp->a_entry) > MAXVAL (bytes->e_entry))
+ err = "e_entry";
+ else if ((val = execp->a_trsize) > MAXVAL (bytes->e_trsize))
+ err = "e_trsize";
+ else if ((val = execp->a_drsize) > MAXVAL (bytes->e_drsize))
+ err = "e_drsize";
+#undef MAXVAL
+ if (err)
+ {
+ _bfd_error_handler (_("%pB: %#" PRIx64 " overflows header %s field"),
+ abfd, val, err);
+ bfd_set_error (bfd_error_file_too_big);
+ return false;
+ }
+
/* Now fill in fields in the raw data, from the fields in the exec struct. */
H_PUT_32 (abfd, execp->a_info , bytes->e_info);
PUT_WORD (abfd, execp->a_text , bytes->e_text);
@@ -430,6 +456,7 @@ NAME (aout, swap_exec_header_out) (bfd *abfd,
PUT_WORD (abfd, execp->a_entry , bytes->e_entry);
PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize);
PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize);
+ return true;
}
/* Make all the section for an a.out file. */
diff --git a/bfd/i386lynx.c b/bfd/i386lynx.c
index cd06a6447d1..1d4c411a6ed 100644
--- a/bfd/i386lynx.c
+++ b/bfd/i386lynx.c
@@ -46,7 +46,8 @@
* obj_reloc_entry_size (abfd)); \
execp->a_drsize = ((obj_datasec (abfd)->reloc_count) \
* obj_reloc_entry_size (abfd)); \
- NAME (aout, swap_exec_header_out) (abfd, execp, &exec_bytes); \
+ if (!NAME (aout, swap_exec_header_out) (abfd, execp, &exec_bytes)) \
+ return false; \
\
if (bfd_seek (abfd, 0, SEEK_SET) != 0 \
|| bfd_write (&exec_bytes, EXEC_BYTES_SIZE, \
diff --git a/bfd/libaout.h b/bfd/libaout.h
index 11a6f701526..91033d4649f 100644
--- a/bfd/libaout.h
+++ b/bfd/libaout.h
@@ -570,7 +570,7 @@ extern bool NAME (aout, adjust_sizes_and_vmas)
extern void NAME (aout, swap_exec_header_in)
(bfd *, struct external_exec *, struct internal_exec *);
-extern void NAME (aout, swap_exec_header_out)
+extern bool NAME (aout, swap_exec_header_out)
(bfd *, struct internal_exec *, struct external_exec *);
extern struct bfd_hash_entry * NAME (aout, link_hash_newfunc)
@@ -631,7 +631,8 @@ extern bool NAME (aout, bfd_free_cached_info)
* obj_reloc_entry_size (abfd)); \
execp->a_drsize = ((obj_datasec (abfd)->reloc_count) \
* obj_reloc_entry_size (abfd)); \
- NAME (aout, swap_exec_header_out) (abfd, execp, &exec_bytes); \
+ if (!NAME (aout, swap_exec_header_out) (abfd, execp, &exec_bytes)) \
+ return false; \
\
if (bfd_seek (abfd, 0, SEEK_SET) != 0 \
|| bfd_write (&exec_bytes, EXEC_BYTES_SIZE, \
diff --git a/bfd/pdp11.c b/bfd/pdp11.c
index 7d93904e63c..e83a4854aa5 100644
--- a/bfd/pdp11.c
+++ b/bfd/pdp11.c
@@ -365,7 +365,8 @@ pdp11_aout_write_headers (bfd *abfd, struct internal_exec *execp)
execp->a_drsize = 0;
}
- NAME (aout, swap_exec_header_out) (abfd, execp, & exec_bytes);
+ if (!NAME (aout, swap_exec_header_out) (abfd, execp, & exec_bytes))
+ return false;
if (bfd_seek (abfd, 0, SEEK_SET) != 0)
return false;
@@ -456,11 +457,33 @@ NAME (aout, swap_exec_header_in) (bfd *abfd,
/* Swap the information in an internal exec header structure
"execp" into the buffer "bytes" ready for writing to disk. */
-void
+bool
NAME (aout, swap_exec_header_out) (bfd *abfd,
struct internal_exec *execp,
struct external_exec *bytes)
{
+ const char *err = NULL;
+ uint64_t val;
+#define MAXVAL(x) ((UINT64_C (1) << (8 * sizeof (x) - 1) << 1) - 1)
+ if ((val = execp->a_text) > MAXVAL (bytes->e_text))
+ err = "e_text";
+ else if ((val = execp->a_data) > MAXVAL (bytes->e_data))
+ err = "e_data";
+ else if ((val = execp->a_bss) > MAXVAL (bytes->e_bss))
+ err = "e_bss";
+ else if ((val = execp->a_syms) > MAXVAL (bytes->e_syms))
+ err = "e_syms";
+ else if ((val = execp->a_entry) > MAXVAL (bytes->e_entry))
+ err = "e_entry";
+#undef MAXVAL
+ if (err)
+ {
+ _bfd_error_handler (_("%pB: %#" PRIx64 " overflows header %s field"),
+ abfd, val, err);
+ bfd_set_error (bfd_error_file_too_big);
+ return false;
+ }
+
/* Now fill in fields in the raw data, from the fields in the exec struct. */
PUT_MAGIC (abfd, execp->a_info, bytes->e_info);
PUT_WORD (abfd, execp->a_text, bytes->e_text);
@@ -482,6 +505,7 @@ NAME (aout, swap_exec_header_out) (bfd *abfd,
fprintf (stderr, "BFD:%s:%d: internal error\n", __FILE__, __LINE__);
PUT_WORD (abfd, 0, bytes->e_flag);
}
+ return true;
}
/* Make all the section for an a.out file. */
diff --git a/ld/testsuite/ld-scripts/map-address.exp b/ld/testsuite/ld-scripts/map-address.exp
index 3944ec16910..bc1f5a6a87d 100644
--- a/ld/testsuite/ld-scripts/map-address.exp
+++ b/ld/testsuite/ld-scripts/map-address.exp
@@ -32,6 +32,7 @@ if { [is_pecoff_format] } then {
set IMAGE_BASE ""
}
+setup_xfail "pdp11-*-*"
if {![ld_link $ld tmpdir/map-address \
"$LDFLAGS -T $srcdir/$subdir/map-address.t \
$IMAGE_BASE tmpdir/map-address.o \
More information about the Binutils-cvs
mailing list