x86: Avoid loading the second PT_NOTE segment
Commit Message
On x86-64, there may be 2 PT_NOTE segments:
NOTE 0x0000000000000350 0x0000000000000350 0x0000000000000350
0x0000000000000040 0x0000000000000040 R 0x8
NOTE 0x0000000000000390 0x0000000000000390 0x0000000000000390
0x0000000000000044 0x0000000000000044 R 0x4
...
07 .note.gnu.property
08 .note.gnu.build-id .note.ABI-tag
When loading a shared library, _dl_process_pt_note is called on each
PT_NOTE segment. It will seek and load its content from disk. This
patch avoids loading the second PT_NOTE segment when the GNU property
note has been processed. For loading libc.so.6, before:
lseek(3, 848, SEEK_SET) = 848
read(3, "\4\0\0\0000\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 64) = 64
lseek(3, 912, SEEK_SET) = 912
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0Q,\254S$\377\225\242\324\372\253\303J\267\301D"..., 68) = 68
after:
lseek(3, 848, SEEK_SET) = 848
read(3, "\4\0\0\0000\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 64) = 64
We avoid the extra:
lseek(3, 912, SEEK_SET) = 912
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0Q,\254S$\377\225\242\324\372\253\303J\267\301D"..., 68) = 68
* sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Don't
check l_cet here.
(_dl_process_pt_note): Skip if the GNU property note has been
processed.
(_rtld_process_pt_note): Likewise.
---
sysdeps/x86/dl-prop.h | 59 +++++++++++++++++++++++--------------------
1 file changed, 31 insertions(+), 28 deletions(-)
@@ -49,10 +49,6 @@ _dl_process_cet_property_note (struct link_map *l,
const ElfW(Addr) align)
{
#if CET_ENABLED
- /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */
- if (l->l_cet != lc_unknown)
- return;
-
/* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in
32-bit objects and to 8 bytes in 64-bit objects. Skip notes
with incorrect alignment. */
@@ -152,33 +148,36 @@ _dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
int fd, struct filebuf *fbp)
{
# if CET_ENABLED
- const ElfW(Nhdr) *note;
- ElfW(Nhdr) *note_malloced = NULL;
- ElfW(Addr) size = ph->p_filesz;
-
- if (ph->p_offset + size <= (size_t) fbp->len)
- note = (const void *) (fbp->buf + ph->p_offset);
- else
+ if (l->l_cet == lc_unknown)
{
- if (size < __MAX_ALLOCA_CUTOFF)
- note = alloca (size);
+ const ElfW(Nhdr) *note;
+ ElfW(Nhdr) *note_malloced = NULL;
+ ElfW(Addr) size = ph->p_filesz;
+
+ if (ph->p_offset + size <= (size_t) fbp->len)
+ note = (const void *) (fbp->buf + ph->p_offset);
else
{
- note_malloced = malloc (size);
- note = note_malloced;
- }
- __lseek (fd, ph->p_offset, SEEK_SET);
- if (__read_nocancel (fd, (void *) note, size) != size)
- {
- if (note_malloced)
- free (note_malloced);
- return -1;
+ if (size < __MAX_ALLOCA_CUTOFF)
+ note = alloca (size);
+ else
+ {
+ note_malloced = malloc (size);
+ note = note_malloced;
+ }
+ __lseek (fd, ph->p_offset, SEEK_SET);
+ if (__read_nocancel (fd, (void *) note, size) != size)
+ {
+ if (note_malloced)
+ free (note_malloced);
+ return -1;
+ }
}
- }
- _dl_process_cet_property_note (l, note, size, ph->p_align);
- if (note_malloced)
- free (note_malloced);
+ _dl_process_cet_property_note (l, note, size, ph->p_align);
+ if (note_malloced)
+ free (note_malloced);
+ }
# endif
return 0;
}
@@ -187,8 +186,12 @@ _dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
static inline int __attribute__ ((unused))
_rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
{
- const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
- _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align);
+ /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */
+ if (l->l_cet == lc_unknown)
+ {
+ const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
+ _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align);
+ }
return 0;
}