From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1062) id 0F3893857413; Wed, 17 Aug 2022 07:08:47 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0F3893857413 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Alan Modra To: bfd-cvs@sourceware.org Subject: [binutils-gdb] asan: heap buffer overflow in mmo_scan X-Act-Checkin: binutils-gdb X-Git-Author: Alan Modra X-Git-Refname: refs/heads/master X-Git-Oldrev: 11c6a7c6232c2fcd23058dcb9ac7909e491e02bc X-Git-Newrev: 2bda15d73cb1d6c4e3db402682d4c11a94d96b7b Message-Id: <20220817070847.0F3893857413@sourceware.org> Date: Wed, 17 Aug 2022 07:08:47 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Aug 2022 07:08:47 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D2bda15d73cb1= d6c4e3db402682d4c11a94d96b7b commit 2bda15d73cb1d6c4e3db402682d4c11a94d96b7b Author: Alan Modra Date: Wed Aug 17 15:43:25 2022 +0930 asan: heap buffer overflow in mmo_scan =20 mmo_get_loc needs to handle arbitrary vma and size chunks. Fuzzers found that it wasn't working so well when the end of chunks were getting close to address wrap-around. =20 * mmo.c (mmo_get_loc): Make "size" unsigned. Avoid arithmetic overflow when calculating whether range hits an existing chunk. Diff: --- bfd/mmo.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/bfd/mmo.c b/bfd/mmo.c index 9c177d8d0b0..1c901ae5c20 100644 --- a/bfd/mmo.c +++ b/bfd/mmo.c @@ -382,7 +382,7 @@ static bool mmo_scan (bfd *); static asection *mmo_decide_section (bfd *, bfd_vma); static asection *mmo_get_generic_spec_data_section (bfd *, int); static asection *mmo_get_spec_section (bfd *, int); -static bfd_byte *mmo_get_loc (asection *, bfd_vma, int); +static bfd_byte *mmo_get_loc (asection *, bfd_vma, unsigned int); static bfd_cleanup mmo_object_p (bfd *); static void mmo_map_set_sizes (bfd *, asection *, void *); static bool mmo_get_symbols (bfd *); @@ -1492,7 +1492,7 @@ SUBSECTION MMO_SEC_CONTENTS_CHUNK_SIZE. */ =20 static bfd_byte * -mmo_get_loc (asection *sec, bfd_vma vma, int size) +mmo_get_loc (asection *sec, bfd_vma vma, unsigned int size) { bfd_size_type allocated_size; struct mmo_section_data_struct *sdatap =3D mmo_section_data (sec); @@ -1504,27 +1504,29 @@ mmo_get_loc (asection *sec, bfd_vma vma, int size) for (; datap !=3D NULL; datap =3D datap->next) { if (datap->where <=3D vma - && datap->where + datap->size >=3D vma + size) - return datap->data + vma - datap->where; + && datap->size >=3D size + && datap->size - size >=3D vma - datap->where) + return datap->data + (vma - datap->where); else if (datap->where <=3D vma - && datap->where + datap->allocated_size >=3D vma + size + && datap->allocated_size >=3D size + && datap->allocated_size - size >=3D vma - datap->where /* Only munch on the "allocated size" if it does not overlap the next chunk. */ && (datap->next =3D=3D NULL || datap->next->where >=3D vma + size)) { /* There was room allocated, but the size wasn't set to include it. Do that now. */ - datap->size +=3D (vma + size) - (datap->where + datap->size); + datap->size =3D vma - datap->where + size; =20 /* Update the section size. This happens only if we update the 32-bit-aligned chunk size. Callers that have non-32-bit-aligned sections should do all allocation and size-setting by themselves or at least set the section size after the last allocating call to this function. */ - if (vma + size > sec->vma + sec->size) - sec->size +=3D (vma + size) - (sec->vma + sec->size); + if (vma - sec->vma + size > sec->size) + sec->size =3D vma - sec->vma + size; =20 - return datap->data + vma - datap->where; + return datap->data + (vma - datap->where); } } =20 @@ -1535,7 +1537,7 @@ mmo_get_loc (asection *sec, bfd_vma vma, int size) for no more than MMO_SEC_CONTENTS_CHUNK_SIZE will always get resolved= . */ =20 for (datap =3D sdatap->head; datap !=3D NULL; datap =3D datap->next) - if ((datap->where <=3D vma && datap->where + datap->size > vma) + if ((datap->where <=3D vma && datap->size > vma - datap->where) || (datap->where < vma + size && datap->where + datap->size >=3D vma + size)) return NULL; @@ -1583,8 +1585,8 @@ mmo_get_loc (asection *sec, bfd_vma vma, int size) =20 /* Update the section size. This happens only when we add contents and re-size as we go. The section size will then be aligned to 32 bits. = */ - if (vma + size > sec->vma + sec->size) - sec->size +=3D (vma + size) - (sec->vma + sec->size); + if (vma - sec->vma + size > sec->size) + sec->size =3D vma - sec->vma + size; return entry->data; }