From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) by sourceware.org (Postfix) with ESMTPS id 8E3CF3858C2D for ; Tue, 16 Aug 2022 08:55:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8E3CF3858C2D Received: by mail-pj1-x102b.google.com with SMTP id q7-20020a17090a7a8700b001f300db8677so8996067pjf.5 for ; Tue, 16 Aug 2022 01:55:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-disposition:mime-version:message-id:subject:to:from:date :x-gm-message-state:from:to:cc; bh=RLXegDl2zT2DpswvTVdUC1XjIM1cqXblqMFQiudGiyc=; b=G5Y3tIWNGuLwG1r0EuvDYyQ5BHDyxkqbCzZnfMtQKDKloV6vOHb+rRl3rAtZlDCTO3 cCeZciKmPX3GYUtnmzpMt5q9/9z1SQAfDBWmQulpYv/eaR8sgIcDyNjZRVqa6l3iENk5 CW6YKKDHv01m7pgAXMTbVE77Nketdl6cKiHY1Itm1b14lrtP6bDwxJnHKnlOtx4sxE38 D3TTOy29Tdorju6KwOrivHnblrQIM0lbJ/TalD5XBlqjd3mK8slPZcyR94AxXStdbBXZ PHoVgE1g/f3+c4Bi3dSTcGteMGiqfA8siv7tQXtwwhAMqnNUrnJgnigqTzz86TQEacqA 8VTA== X-Gm-Message-State: ACgBeo3QJx9V1Iuy3OYb7G7qYnqsHex6DT/1Wz/r4Kd/nsqMu/7+DY4V n/O8lhX+2sN6fc3tlWzLA7IXrr+nA7E= X-Google-Smtp-Source: AA6agR6gG8+qSn+NvbRWhE5ZLDn9iOOk437AkRmXhvMH2Rkot6WqhE424ZkER4yj4LK19XiiceGW8A== X-Received: by 2002:a17:902:7c03:b0:172:56b1:8152 with SMTP id x3-20020a1709027c0300b0017256b18152mr16949567pll.16.1660640136245; Tue, 16 Aug 2022 01:55:36 -0700 (PDT) Received: from squeak.grove.modra.org (158.106.96.58.static.exetel.com.au. [58.96.106.158]) by smtp.gmail.com with ESMTPSA id a22-20020aa795b6000000b0052dab7afa04sm7875973pfk.47.2022.08.16.01.55.35 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 16 Aug 2022 01:55:35 -0700 (PDT) Received: by squeak.grove.modra.org (Postfix, from userid 1000) id 044741142EC4; Tue, 16 Aug 2022 18:25:33 +0930 (ACST) Date: Tue, 16 Aug 2022 18:25:33 +0930 From: Alan Modra To: binutils@sourceware.org Subject: PR29495, rewrite_elf_program_header looping Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Status: No, score=-3036.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Aug 2022 08:55:41 -0000 This patch, in order of significance: 1) Replaces some macros with inline functions. 2) Those inline functions catch and avoid arithmetic overflows when comparing addresses. 3) When assigning sections to segments (IS_SECTION_IN_INPUT_SEGMENT) use bed->want_p_paddr_set_to_zero to decide whether lma vs p_paddr or vma vs p_vaddr should be tested. When remapping, use the same test, and use is_note rather than the more restrictive IS_COREFILE_NOTE. It's important that the later tests not be more restrictive. If they are it can lead to the situation triggered by the testcases, where a section seemingly didn't fit and thus needed a new mapping. It didn't fit the new mapping either, and this repeated until memory exhausted. PR 29495 * elf.c (SEGMENT_END, SECTION_SIZE, IS_CONTAINED_BY_VMA): Delete. (IS_CONTAINED_BY_LMA, IS_NOTE, IS_COREFILE_NOTE): Delete. (segment_size, segment_end, section_size): New inline function. (is_contained_by, is_note): Likewise. (rewrite_elf_program_header): Use new functions. diff --git a/bfd/elf.c b/bfd/elf.c index 1b9b7fad15a..76877b43f99 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -6886,6 +6886,66 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr) return idx; } +static inline bfd_vma +segment_size (Elf_Internal_Phdr *segment) +{ + return (segment->p_memsz > segment->p_filesz + ? segment->p_memsz : segment->p_filesz); +} + + +/* Returns the end address of the segment + 1. */ +static inline bfd_vma +segment_end (Elf_Internal_Phdr *segment, bfd_vma start) +{ + return start + segment_size (segment); +} + +static inline bfd_size_type +section_size (asection *section, Elf_Internal_Phdr *segment) +{ + if ((section->flags & SEC_HAS_CONTENTS) != 0 + || (section->flags & SEC_THREAD_LOCAL) == 0 + || segment->p_type == PT_TLS) + return section->size; + return 0; +} + +/* Returns TRUE if the given section is contained within the given + segment. LMA addresses are compared against PADDR when + bed->want_p_paddr_set_to_zero is false, VMA against VADDR when true. */ +static bool +is_contained_by (asection *section, Elf_Internal_Phdr *segment, + bfd_vma paddr, bfd_vma vaddr, unsigned int opb, + const struct elf_backend_data *bed) +{ + bfd_vma seg_addr = !bed->want_p_paddr_set_to_zero ? paddr : vaddr; + bfd_vma addr = !bed->want_p_paddr_set_to_zero ? section->lma : section->vma; + bfd_vma octet; + if (_bfd_mul_overflow (addr, opb, &octet)) + return false; + /* The third and fourth lines below are testing that the section end + address is within the segment. It's written this way to avoid + overflow. Add seg_addr + section_size to both sides of the + inequality to make it obvious. */ + return (octet >= seg_addr + && segment_size (segment) >= section_size (section, segment) + && (octet - seg_addr + <= segment_size (segment) - section_size (section, segment))); +} + +/* Handle PT_NOTE segment. */ +static bool +is_note (Elf_Internal_Phdr *p, asection *s) +{ + return (p->p_type == PT_NOTE + && elf_section_type (s) == SHT_NOTE + && (ufile_ptr) s->filepos >= p->p_offset + && p->p_filesz >= s->size + && ((ufile_ptr) s->filepos - p->p_offset + <= p->p_filesz - s->size)); +} + /* Rewrite program header information. */ static bool @@ -6914,47 +6974,6 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) num_segments = elf_elfheader (ibfd)->e_phnum; - /* Returns the end address of the segment + 1. */ -#define SEGMENT_END(segment, start) \ - (start + (segment->p_memsz > segment->p_filesz \ - ? segment->p_memsz : segment->p_filesz)) - -#define SECTION_SIZE(section, segment) \ - (((section->flags & (SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) \ - != SEC_THREAD_LOCAL || segment->p_type == PT_TLS) \ - ? section->size : 0) - - /* Returns TRUE if the given section is contained within - the given segment. VMA addresses are compared. */ -#define IS_CONTAINED_BY_VMA(section, segment, opb) \ - (section->vma * (opb) >= segment->p_vaddr \ - && (section->vma * (opb) + SECTION_SIZE (section, segment) \ - <= (SEGMENT_END (segment, segment->p_vaddr)))) - - /* Returns TRUE if the given section is contained within - the given segment. LMA addresses are compared. */ -#define IS_CONTAINED_BY_LMA(section, segment, base, opb) \ - (section->lma * (opb) >= base \ - && (section->lma + SECTION_SIZE (section, segment) / (opb) >= section->lma) \ - && (section->lma * (opb) + SECTION_SIZE (section, segment) \ - <= SEGMENT_END (segment, base))) - - /* Handle PT_NOTE segment. */ -#define IS_NOTE(p, s) \ - (p->p_type == PT_NOTE \ - && elf_section_type (s) == SHT_NOTE \ - && (bfd_vma) s->filepos >= p->p_offset \ - && ((bfd_vma) s->filepos + s->size \ - <= p->p_offset + p->p_filesz)) - - /* Special case: corefile "NOTE" section containing regs, prpsinfo - etc. */ -#define IS_COREFILE_NOTE(p, s) \ - (IS_NOTE (p, s) \ - && bfd_get_format (ibfd) == bfd_core \ - && s->vma == 0 \ - && s->lma == 0) - /* The complicated case when p_vaddr is 0 is to handle the Solaris linker, which generates a PT_INTERP section with p_vaddr and p_memsz set to 0. */ @@ -6983,11 +7002,10 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) 8. PT_DYNAMIC should not contain empty sections at the beginning (with the possible exception of .dynamic). */ #define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed, opb) \ - ((((segment->p_paddr \ - ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr, opb) \ - : IS_CONTAINED_BY_VMA (section, segment, opb)) \ + (((is_contained_by (section, segment, segment->p_paddr, \ + segment->p_vaddr, opb, bed) \ && (section->flags & SEC_ALLOC) != 0) \ - || IS_NOTE (segment, section)) \ + || is_note (segment, section)) \ && segment->p_type != PT_GNU_STACK \ && (segment->p_type != PT_TLS \ || (section->flags & SEC_THREAD_LOCAL)) \ @@ -6995,7 +7013,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) || segment->p_type == PT_TLS \ || (section->flags & SEC_THREAD_LOCAL) == 0) \ && (segment->p_type != PT_DYNAMIC \ - || SECTION_SIZE (section, segment) > 0 \ + || section_size (section, segment) > 0 \ || (segment->p_paddr \ ? segment->p_paddr != section->lma * (opb) \ : segment->p_vaddr != section->vma * (opb)) \ @@ -7010,7 +7028,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) /* Returns TRUE iff seg1 starts after the end of seg2. */ #define SEGMENT_AFTER_SEGMENT(seg1, seg2, field) \ - (seg1->field >= SEGMENT_END (seg2, seg2->field)) + (seg1->field >= segment_end (seg2, seg2->field)) /* Returns TRUE iff seg1 and seg2 overlap. Segments overlap iff both their VMA address ranges and their LMA address ranges overlap. @@ -7090,8 +7108,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) { /* Extend SEGMENT2 to include SEGMENT and then delete SEGMENT. */ - extra_length = (SEGMENT_END (segment, segment->p_vaddr) - - SEGMENT_END (segment2, segment2->p_vaddr)); + extra_length = (segment_end (segment, segment->p_vaddr) + - segment_end (segment2, segment2->p_vaddr)); if (extra_length > 0) { @@ -7110,8 +7128,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) { /* Extend SEGMENT to include SEGMENT2 and then delete SEGMENT2. */ - extra_length = (SEGMENT_END (segment2, segment2->p_vaddr) - - SEGMENT_END (segment, segment->p_vaddr)); + extra_length = (segment_end (segment2, segment2->p_vaddr) + - segment_end (segment, segment->p_vaddr)); if (extra_length > 0) { @@ -7311,11 +7329,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) /* Match up the physical address of the segment with the LMA address of the output section. */ - if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr, - opb) - || IS_COREFILE_NOTE (segment, section) - || (bed->want_p_paddr_set_to_zero - && IS_CONTAINED_BY_VMA (output_section, segment, opb))) + if (is_contained_by (output_section, segment, map->p_paddr, + map->p_paddr + map->p_vaddr_offset, opb, bed) + || is_note (segment, section)) { if (matching_lma == NULL || output_section->lma < matching_lma->lma) @@ -7431,9 +7447,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) BFD_ASSERT (output_section != NULL); - if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr, - opb) - || IS_COREFILE_NOTE (segment, section)) + if (is_contained_by (output_section, segment, map->p_paddr, + map->p_paddr + map->p_vaddr_offset, opb, bed) + || is_note (segment, section)) { if (map->count == 0) { @@ -7556,12 +7572,6 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) } } -#undef SEGMENT_END -#undef SECTION_SIZE -#undef IS_CONTAINED_BY_VMA -#undef IS_CONTAINED_BY_LMA -#undef IS_NOTE -#undef IS_COREFILE_NOTE #undef IS_SOLARIS_PT_INTERP #undef IS_SECTION_IN_INPUT_SEGMENT #undef INCLUDE_SECTION_IN_SEGMENT -- Alan Modra Australia Development Lab, IBM