From 0676ec3c22f096bdf98b145b720feeef9493b5bb Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 24 Feb 2023 12:37:22 +0000 Subject: [PATCH] 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 --- gdb/value.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/gdb/value.c b/gdb/value.c index d2c2a2d7859..9d5e694e574 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -1168,6 +1168,11 @@ value::contents_copy_raw (struct value *dst, LONGEST dst_offset, mean we'd be copying garbage. */ 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 replaced. Make sure to remember to implement replacing if it turns out actually necessary. */ @@ -1178,10 +1183,10 @@ value::contents_copy_raw (struct value *dst, LONGEST dst_offset, /* Copy the data. */ gdb::array_view dst_contents = dst->contents_all_raw ().slice (dst_offset * unit_size, - length * unit_size); + copy_length * unit_size); gdb::array_view src_contents = contents_all_raw ().slice (src_offset * unit_size, - length * unit_size); + copy_length * unit_size); gdb::copy (src_contents, dst_contents); /* 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. */ 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 replaced. Make sure to remember to implement replacing if it turns out actually necessary. */ @@ -1220,7 +1231,7 @@ value::contents_copy_raw_bitwise (struct value *dst, LONGEST dst_bit_offset, gdb::array_view src_contents = contents_all_raw (); copy_bitwise (dst_contents.data (), dst_bit_offset, src_contents.data (), src_bit_offset, - bit_length, + copy_bit_length, type_byte_order (type ()) == BFD_ENDIAN_BIG); /* Copy the meta-data. */ -- 2.30.2