From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1062) id 82855384D181; Wed, 14 Sep 2022 07:49:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 82855384D181 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] looping in bfd_mach_o_fat_openr_next_archived_file X-Act-Checkin: binutils-gdb X-Git-Author: Alan Modra X-Git-Refname: refs/heads/master X-Git-Oldrev: faf351b59d95e4bed4d43668498d1ae3d852e0c4 X-Git-Newrev: 8d783d5e1d60ec951368ceaf7f4bb8c241e4d3ee Message-Id: <20220914074903.82855384D181@sourceware.org> Date: Wed, 14 Sep 2022 07:49:03 +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, 14 Sep 2022 07:49:03 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D8d783d5e1d60= ec951368ceaf7f4bb8c241e4d3ee commit 8d783d5e1d60ec951368ceaf7f4bb8c241e4d3ee Author: Alan Modra Date: Wed Sep 14 16:57:42 2022 +0930 looping in bfd_mach_o_fat_openr_next_archived_file =20 mach-o.c doesn't sanity check mach-o-fat archives, making it easy for fuzzers to create an archive with mach_o_fat_archentry headers that point to the same offset. bfd_mach_o_fat_openr_next_archived_file uses the previous element offset to find its header, and thus the next element. If two offsets are the same, any tool reading the archive will get stuck. This patch rejects such archives, and any with overlapping elements. =20 * mach-o.c (overlap_previous): New function. (bfd_mach_o_fat_archive_p): Sanity check that elements do not overlap each other or the file and archive headers. Diff: --- bfd/mach-o.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/bfd/mach-o.c b/bfd/mach-o.c index eb325236454..acb35e7f0c6 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -5497,6 +5497,22 @@ typedef struct mach_o_fat_data_struct mach_o_fat_archentry *archentries; } mach_o_fat_data_struct; =20 +/* Check for overlapping archive elements. Note that we can't allow + multiple elements at the same offset even if one is empty, because + bfd_mach_o_fat_openr_next_archived_file assume distinct offsets. */ +static bool +overlap_previous (const mach_o_fat_archentry *elt, unsigned long i) +{ + unsigned long j =3D i; + while (j-- !=3D 0) + if (elt[i].offset =3D=3D elt[j].offset + || (elt[i].offset > elt[j].offset + ? elt[i].offset - elt[j].offset < elt[j].size + : elt[j].offset - elt[i].offset < elt[i].size)) + return true; + return false; +} + bfd_cleanup bfd_mach_o_fat_archive_p (bfd *abfd) { @@ -5545,10 +5561,13 @@ bfd_mach_o_fat_archive_p (bfd *abfd) adata->archentries[i].offset =3D bfd_getb32 (arch.offset); adata->archentries[i].size =3D bfd_getb32 (arch.size); adata->archentries[i].align =3D bfd_getb32 (arch.align); - if (filesize !=3D 0 - && (adata->archentries[i].offset > filesize - || (adata->archentries[i].size - > filesize - adata->archentries[i].offset))) + if ((filesize !=3D 0 + && (adata->archentries[i].offset > filesize + || (adata->archentries[i].size + > filesize - adata->archentries[i].offset))) + || (adata->archentries[i].offset + < sizeof (hdr) + adata->nfat_arch * sizeof (arch)) + || overlap_previous (adata->archentries, i)) { bfd_release (abfd, adata); bfd_set_error (bfd_error_malformed_archive);