From: Fangrui Song <i@maskray.me>
To: Alan Modra <amodra@gmail.com>
Cc: "H.J. Lu" <hjl.tools@gmail.com>, Binutils <binutils@sourceware.org>
Subject: Re: [PATCH v4] ld: Rewrite lang_size_relro_segment_1
Date: Sat, 29 Jan 2022 01:06:47 -0800 [thread overview]
Message-ID: <20220129090647.rizizoj6muegtttg@gmail.com> (raw)
In-Reply-To: <YfSR31z2gRZnoh5l@squeak.grove.modra.org>
On 2022-01-29, Alan Modra via Binutils wrote:
>On Wed, Jan 26, 2022 at 06:10:28PM -0800, H.J. Lu wrote:
>> On Wed, Jan 26, 2022 at 4:48 PM Alan Modra <amodra@gmail.com> wrote:
>> >
>> > On Wed, Jan 26, 2022 at 10:55:35AM +0000, Nick Clifton via Binutils wrote:
>> > > Hi H.J.
>> > >
>> > > > Here is the v4 patch to align the PT_GNU_RELRO segment first and subtract
>> > > > the maximum page size if therer is still a 1-page gap. This fixes:
>> > > >
>> > > > https://sourceware.org/bugzilla/show_bug.cgi?id=28819
>> > >
>> > > Looks good to me. Please apply. Branch and mainline.
>> >
>> > How was this patch tested? If it has not been tested on targets other
>> > than x86 then it is not appropriate for the branch. Instead, I
>>
>> What kinds of tests are you looking for? Do you have a testcase to show
>> there is still an issue?
>
>Can you answer my question?
>
>> > believe commit 2f83249c13d ought to be reverted on the branch. A
>> > wasted page in memory layout is not an important problem. We have
>> > more serious relro issues on targets other than x86. See pr28824.
>> >
>> > I'm speaking up because I raised concerns over the design of the
>> > previous patch, not just the implementation, and had those concerns
>> > overridden by Nick. Or possibly Nick didn't see my email before the
>> > previous patch was approved. Regardless of how it happened, I fear
>> > we might have even worse relro support in 2.38.
>> >
>> > FWIW, I also think that any fix I might develop for pr28824 will
>> > likely not be release branch quality until is has been tested for some
>> > time on mainline.
>
>This is the patch I'm playing with. It reverts your changes to
>lang_size_relro_segment_1 and fixes PR2844.
>
>The end of the PT_GNU_RELRO segment must be aligned to maxpagesize in
>order for the last page in the segment to be write protected after
>relocation. Unfortunately we currently only align to commonpagesize,
>which works for x86 but no other architecture that actually uses
>maxpagesize memory pages. I've kept the commonpage alignment for x86,
>other targets get maxpagesize.
Wouldn't aligning to maxpagesize punish the architectures with 64KiB
maxpagesize? These binaries will incur size bloat due the PT_GNU_RELRO
end alignment.
I think my idea of two PF_R|PF_W PT_LOAD will be worth implementing at
some point :) There is no alignment.
The glibc strict check
https://sourceware.org/bugzilla/show_bug.cgi?id=28688 affects glibc<2.35
so I don't think ld making p_align smaller than maxpagesize is
reasonable in the near term, at least before objcopy/strip supporting
the small p_align becomes widespread.
(I need to confess I am not closely subscribed to the sudden p_align
movement in glibc)
>There are of course testsuite changes that are needed, multiple x86
>and one s390x test. The only fail of any significance is pr18176, but
>there is a fundamental tension between pr18176 and pr28743. You
>either create holes or you waste disk space, both conditions can't be
>met. Worse IMO, the pr18176 testcase not only has a hole but also a
>gap in memory layout after the last section in the relro segment.
>That's not ideal for powerpc where sections after .got (the last relro
>section) are in some cases accessed via the got/toc pointer reg. On
>x86 you'd see a gap between .got and .got.plt when SEPARATE_GOTPLT.
>
>diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
>index da8a488db36..c9b3e7c4d9f 100644
>--- a/bfd/elfxx-x86.c
>+++ b/bfd/elfxx-x86.c
>@@ -4205,4 +4205,5 @@ _bfd_elf_linker_x86_set_options (struct bfd_link_info * info,
> = elf_x86_hash_table (info, bed->target_id);
> if (htab != NULL)
> htab->params = params;
>+ info->relro_use_commonpagesize = true;
> }
>diff --git a/include/bfdlink.h b/include/bfdlink.h
>index 69fc9d33ff4..8d5561b0b28 100644
>--- a/include/bfdlink.h
>+++ b/include/bfdlink.h
>@@ -413,6 +413,10 @@ struct bfd_link_info
> /* TRUE if PT_GNU_RELRO segment should be created. */
> unsigned int relro: 1;
>
>+ /* TRUE if the relro segment should be aligned to commonpagesize
>+ rather than maxpagesize. */
>+ unsigned int relro_use_commonpagesize : 1;
>+
> /* TRUE if DT_RELR should be enabled for compact relative
> relocations. */
> unsigned int enable_dt_relr: 1;
>diff --git a/ld/ldexp.c b/ld/ldexp.c
>index 5f904aaf8ae..65618912043 100644
>--- a/ld/ldexp.c
>+++ b/ld/ldexp.c
>@@ -469,7 +469,8 @@ fold_segment_align (seg_align_type *seg, etree_value_type *lhs)
> }
> else
> {
>- expld.result.value += expld.dot & (maxpage - 1);
>+ if (!link_info.relro)
>+ expld.result.value += expld.dot & (maxpage - 1);
> if (seg->phase == exp_seg_done)
> {
> /* OK. */
>@@ -480,6 +481,10 @@ fold_segment_align (seg_align_type *seg, etree_value_type *lhs)
> seg->base = expld.result.value;
> seg->pagesize = commonpage;
> seg->maxpagesize = maxpage;
>+ if (link_info.relro_use_commonpagesize)
>+ seg->relropagesize = commonpage;
>+ else
>+ seg->relropagesize = maxpage;
> seg->relro_end = 0;
> }
> else
>@@ -508,10 +513,10 @@ fold_segment_relro_end (seg_align_type *seg, etree_value_type *lhs)
> seg->relro_end = lhs->value + expld.result.value;
>
> if (seg->phase == exp_seg_relro_adjust
>- && (seg->relro_end & (seg->pagesize - 1)))
>+ && (seg->relro_end & (seg->relropagesize - 1)))
> {
>- seg->relro_end += seg->pagesize - 1;
>- seg->relro_end &= ~(seg->pagesize - 1);
>+ seg->relro_end += seg->relropagesize - 1;
>+ seg->relro_end &= ~(seg->relropagesize - 1);
> expld.result.value = seg->relro_end - expld.result.value;
> }
> else
>diff --git a/ld/ldexp.h b/ld/ldexp.h
>index ac4fa7e82b0..f1701b66330 100644
>--- a/ld/ldexp.h
>+++ b/ld/ldexp.h
>@@ -136,7 +136,8 @@ enum relro_enum {
> typedef struct {
> enum phase_enum phase;
>
>- bfd_vma base, relro_offset, relro_end, end, pagesize, maxpagesize;
>+ bfd_vma base, relro_offset, relro_end, end;
>+ bfd_vma pagesize, maxpagesize, relropagesize;
>
> enum relro_enum relro;
>
>diff --git a/ld/ldlang.c b/ld/ldlang.c
>index 5dd3df12a0f..1a09b988fbe 100644
>--- a/ld/ldlang.c
>+++ b/ld/ldlang.c
>@@ -6370,101 +6370,40 @@ lang_size_segment (seg_align_type *seg)
> static bfd_vma
> lang_size_relro_segment_1 (seg_align_type *seg)
> {
>- bfd_vma relro_end, desired_relro_base;
>- asection *sec, *relro_sec = NULL;
>- unsigned int max_alignment_power = 0;
>- bool seen_reloc_section = false;
>- bool desired_relro_base_reduced = false;
>+ bfd_vma relro_end, desired_end;
>+ asection *sec;
>
> /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end. */
>- relro_end = ((seg->relro_end + seg->pagesize - 1)
>- & ~(seg->pagesize - 1));
>+ relro_end = (seg->relro_end + seg->relropagesize - 1) & -seg->relropagesize;
>
> /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END. */
>- desired_relro_base = relro_end - seg->relro_offset;
>+ desired_end = relro_end - seg->relro_offset;
>
>- /* For sections in the relro segment. */
>+ /* For sections in the relro segment.. */
> for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
>- if ((sec->flags & SEC_ALLOC) != 0)
>+ if ((sec->flags & SEC_ALLOC) != 0
>+ && sec->vma >= seg->base
>+ && sec->vma < seg->relro_end - seg->relro_offset)
> {
>- /* Record the maximum alignment for all sections starting from
>- the relro segment. */
>- if (sec->alignment_power > max_alignment_power)
>- max_alignment_power = sec->alignment_power;
>-
>- if (sec->vma >= seg->base
>- && sec->vma < seg->relro_end - seg->relro_offset)
>- {
>- /* Where do we want to put the relro section so that the
>- relro segment ends on the page bounary? */
>- bfd_vma start, end, bump;
>-
>- end = start = sec->vma;
>- if (!IS_TBSS (sec))
>- end += TO_ADDR (sec->size);
>- bump = desired_relro_base - end;
>- /* We'd like to increase START by BUMP, but we must heed
>- alignment so the increase might be less than optimum. */
>- start += bump;
>- start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
>- /* This is now the desired end for the previous section. */
>- desired_relro_base = start;
>- relro_sec = sec;
>- seen_reloc_section = true;
>- }
>- else if (seen_reloc_section)
>- {
>- /* Stop searching if we see a non-relro section after seeing
>- relro sections. */
>- break;
>- }
>+ /* Where do we want to put this section so that it ends as
>+ desired? */
>+ bfd_vma start, end, bump;
>+
>+ end = start = sec->vma;
>+ if (!IS_TBSS (sec))
>+ end += TO_ADDR (sec->size);
>+ bump = desired_end - end;
>+ /* We'd like to increase START by BUMP, but we must heed
>+ alignment so the increase might be less than optimum. */
>+ start += bump;
>+ start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
>+ /* This is now the desired end for the previous section. */
>+ desired_end = start;
> }
>
>- if (relro_sec != NULL
>- && seg->maxpagesize >= (1U << max_alignment_power))
>- {
>- asection *prev_sec;
>- bfd_vma prev_sec_end_plus_1_page;
>-
>- /* Find the first preceding load section. */
>- for (prev_sec = relro_sec->prev;
>- prev_sec != NULL;
>- prev_sec = prev_sec->prev)
>- if ((prev_sec->flags & SEC_ALLOC) != 0)
>- break;
>-
>- prev_sec_end_plus_1_page = (prev_sec->vma + prev_sec->size
>- + seg->maxpagesize);
>- if (prev_sec_end_plus_1_page < desired_relro_base)
>- {
>- bfd_vma aligned_relro_base;
>-
>- desired_relro_base_reduced = true;
>-
>- /* Don't add the 1-page gap before the relro segment. Align
>- the relro segment first. */
>- aligned_relro_base = (desired_relro_base
>- & ~(seg->maxpagesize - 1));
>- if (prev_sec_end_plus_1_page < aligned_relro_base)
>- {
>- /* Subtract the maximum page size if therer is still a
>- 1-page gap. */
>- desired_relro_base -= seg->maxpagesize;
>- relro_end -= seg->maxpagesize;
>- }
>- else
>- {
>- /* Align the relro segment. */
>- desired_relro_base = aligned_relro_base;
>- relro_end &= ~(seg->maxpagesize - 1);
>- }
>- }
>- }
>-
> seg->phase = exp_seg_relro_adjust;
>- ASSERT (desired_relro_base_reduced
>- || desired_relro_base >= seg->base);
>- seg->base = desired_relro_base;
>+ ASSERT (desired_end >= seg->base);
>+ seg->base = desired_end;
> return relro_end;
> }
>
>
>--
>Alan Modra
>Australia Development Lab, IBM
next prev parent reply other threads:[~2022-01-29 9:06 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-11 2:12 [PATCH] elf: Remove the 1-page gap before the RELRO segment H.J. Lu
2022-01-11 5:26 ` Fangrui Song
2022-01-13 12:44 ` Nick Clifton
2022-01-13 12:52 ` Alan Modra
2022-01-13 13:19 ` H.J. Lu
2022-01-14 8:12 ` Alan Modra
2022-01-14 9:37 ` Fangrui Song
2022-01-14 14:58 ` H.J. Lu
2022-01-14 21:55 ` [PATCH] ld: Rewrite lang_size_relro_segment_1 H.J. Lu
2022-01-17 4:08 ` Alan Modra
2022-01-18 4:16 ` [PATCH v2] " H.J. Lu
[not found] ` <CAMe9rOpdkYZDigz8r_oPbweLnaCJUjx3-L-v-vp-70c0MGOHQw@mail.gmail.com>
2022-01-24 16:24 ` Fwd: " Nick Clifton
2022-01-24 21:17 ` [PATCH v3] " H.J. Lu
2022-01-25 15:05 ` [PATCH v4] " H.J. Lu
2022-01-26 10:55 ` Nick Clifton
2022-01-27 0:48 ` Alan Modra
2022-01-27 2:10 ` H.J. Lu
2022-01-29 1:01 ` Alan Modra
2022-01-29 9:06 ` Fangrui Song [this message]
2022-01-29 16:45 ` H.J. Lu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220129090647.rizizoj6muegtttg@gmail.com \
--to=i@maskray.me \
--cc=amodra@gmail.com \
--cc=binutils@sourceware.org \
--cc=hjl.tools@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).