GDB: Fix out of bounds accesses with limited-length values

Fix accesses to limited-length values in `contents_copy_raw' and
`contents_copy_raw_bitwise' so that they observe the limit of the
original allocation.

Reported by Simon Marchi as a heap-buffer-overflow AddressSanitizer
issue triggered with gdb.ada/limited-length.exp.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
This commit is contained in:
Maciej W. Rozycki
2023-02-24 12:37:22 +00:00
parent 7b1792f543
commit 0676ec3c22

View File

@ -1168,6 +1168,11 @@ value::contents_copy_raw (struct value *dst, LONGEST dst_offset,
mean we'd be copying garbage. */ mean we'd be copying garbage. */
gdb_assert (!dst->m_lazy && !m_lazy); gdb_assert (!dst->m_lazy && !m_lazy);
ULONGEST copy_length = length;
ULONGEST limit = m_limited_length;
if (limit > 0 && src_offset + length > limit)
copy_length = src_offset > limit ? 0 : limit - src_offset;
/* The overwritten DST range gets unavailability ORed in, not /* The overwritten DST range gets unavailability ORed in, not
replaced. Make sure to remember to implement replacing if it replaced. Make sure to remember to implement replacing if it
turns out actually necessary. */ turns out actually necessary. */
@ -1178,10 +1183,10 @@ value::contents_copy_raw (struct value *dst, LONGEST dst_offset,
/* Copy the data. */ /* Copy the data. */
gdb::array_view<gdb_byte> dst_contents gdb::array_view<gdb_byte> dst_contents
= dst->contents_all_raw ().slice (dst_offset * unit_size, = dst->contents_all_raw ().slice (dst_offset * unit_size,
length * unit_size); copy_length * unit_size);
gdb::array_view<const gdb_byte> src_contents gdb::array_view<const gdb_byte> src_contents
= contents_all_raw ().slice (src_offset * unit_size, = contents_all_raw ().slice (src_offset * unit_size,
length * unit_size); copy_length * unit_size);
gdb::copy (src_contents, dst_contents); gdb::copy (src_contents, dst_contents);
/* Copy the meta-data, adjusted. */ /* Copy the meta-data, adjusted. */
@ -1206,6 +1211,12 @@ value::contents_copy_raw_bitwise (struct value *dst, LONGEST dst_bit_offset,
mean we'd be copying garbage. */ mean we'd be copying garbage. */
gdb_assert (!dst->m_lazy && !m_lazy); gdb_assert (!dst->m_lazy && !m_lazy);
ULONGEST copy_bit_length = bit_length;
ULONGEST bit_limit = m_limited_length * TARGET_CHAR_BIT;
if (bit_limit > 0 && src_bit_offset + bit_length > bit_limit)
copy_bit_length = (src_bit_offset > bit_limit ? 0
: bit_limit - src_bit_offset);
/* The overwritten DST range gets unavailability ORed in, not /* The overwritten DST range gets unavailability ORed in, not
replaced. Make sure to remember to implement replacing if it replaced. Make sure to remember to implement replacing if it
turns out actually necessary. */ turns out actually necessary. */
@ -1220,7 +1231,7 @@ value::contents_copy_raw_bitwise (struct value *dst, LONGEST dst_bit_offset,
gdb::array_view<const gdb_byte> src_contents = contents_all_raw (); gdb::array_view<const gdb_byte> src_contents = contents_all_raw ();
copy_bitwise (dst_contents.data (), dst_bit_offset, copy_bitwise (dst_contents.data (), dst_bit_offset,
src_contents.data (), src_bit_offset, src_contents.data (), src_bit_offset,
bit_length, copy_bit_length,
type_byte_order (type ()) == BFD_ENDIAN_BIG); type_byte_order (type ()) == BFD_ENDIAN_BIG);
/* Copy the meta-data. */ /* Copy the meta-data. */