x86: Avoid loading the second PT_NOTE segment

Message ID 20190410222054.1584-1-hjl.tools@gmail.com
State Dropped
Headers

Commit Message

H.J. Lu April 10, 2019, 10:20 p.m. UTC
  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(-)
  

Patch

diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
index 1b335ccbb3..5e21ad5fec 100644
--- a/sysdeps/x86/dl-prop.h
+++ b/sysdeps/x86/dl-prop.h
@@ -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;
 }