public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] Update the dl_iterate_phdr implementation
@ 2022-05-05 12:09 Matthew Malcomson
  0 siblings, 0 replies; only message in thread
From: Matthew Malcomson @ 2022-05-05 12:09 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:524938a9bd4761ec4d782f932c2729f1b778375c

commit 524938a9bd4761ec4d782f932c2729f1b778375c
Author: Matthew Malcomson <matthew.malcomson@arm.com>
Date:   Thu Apr 28 09:53:59 2022 +0100

    Update the dl_iterate_phdr implementation
    
    A hosted unwinder uses dl_iterate_phdr in order to find the location of
    exception handling information.  The structure that this callback
    receives for Morello now contains a capability.  A local internal
    structure needs to be updated to accomodate this.
    
    The existing code works for most cases.  This is because the pointer to
    the exception handling frame section which is found during this
    iteration has been given metadata to span the entire executable by the
    kernel and libc.
    
    There is one exceptional case.  When the load_base of the executable is
    zero (i.e. for a PDE or statically linked executable) it is not always
    possible for the kernel and libc to provide a capability with zero as
    the value and tight bounds spanning the relevant binary.  For this case
    we derive a pointer to the frame using a found address and metadata from
    the dl_phdr_info->dlpi_phdr member, which is set up to span the
    executable.
    
    In order to improve robustness we also add some extra assertions that
    metadata is valid and spans relevant addresses.  The placement of these
    assertions are taken from Morello-LLVM's libunwind in order to catch the
    same sort of problems that Morello LLVM has been adjusted to look for.

Diff:
---
 libgcc/unwind-dw2-fde-dip.c | 58 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
index 31fb1548005..9faf5e1dbc3 100644
--- a/libgcc/unwind-dw2-fde-dip.c
+++ b/libgcc/unwind-dw2-fde-dip.c
@@ -161,6 +161,21 @@ base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
     }
 }
 
+#ifdef __CHERI_PURE_CAPABILITY__
+static int
+valid_cheri_capability (void *x, uintptr_t *base, uintptr_t *top)
+{
+  int is_valid = __builtin_cheri_tag_get (x);
+  if (! is_valid)
+    return 0;
+  if (!base || !top)
+    return 1;
+  *base = __builtin_cheri_base_get (x);
+  *top = *base + __builtin_cheri_length_get (x);
+  return 1;
+}
+#endif
+
 static int
 _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
 {
@@ -178,10 +193,13 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
   struct object ob;
   _Unwind_Ptr pc_low = 0, pc_high = 0;
 
-  /* MORELLO TODO Update types here dlpi_addr should hold uintptr_t.  */
   struct ext_dl_phdr_info
     {
+#ifdef __CHERI_PURE_CAPABILITY__
+      uintptr_t dlpi_addr;
+#else
       ElfW(Addr) dlpi_addr;
+#endif
       const char *dlpi_name;
       const ElfW(Phdr) *dlpi_phdr;
       ElfW(Half) dlpi_phnum;
@@ -195,6 +213,14 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
   p_eh_frame_hdr = NULL;
   p_dynamic = NULL;
 
+#ifdef __CHERI_PURE_CAPABILITY__
+  /* Check on every object we iterate over that we are provided valid
+     capabilities by the libc.  */
+  gcc_assert (valid_cheri_capability (phdr, NULL, NULL));
+  gcc_assert (load_base == 0
+	      || valid_cheri_capability (load_base, NULL, NULL));
+#endif
+
   struct frame_hdr_cache_element *prev_cache_entry = NULL,
     *last_cache_entry = NULL;
 
@@ -323,9 +349,32 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
   if (!p_eh_frame_hdr)
     return 0;
 
+#ifdef __CHERI_PURE_CAPABILITY__
+  /* If we found the FDE we're looking for in a static and position dependent
+     object, then the `load_base` is zero and does not have associated bounds.
+     It does not have relevant bounds because restrictions on the cheri bounds
+     encoding mean that a zero valued capability can not have large bounds.  In
+     this case the kernel and libc ensure that dlpi_phdr spans the executable
+     mapping (while its value is not interesting here).
+
+     The dlpi_phdr pointer would have provided the provenance for the
+     `p_eh_frame_hdr` pointer.  Hence in this case we want to use the *address*
+     stored in p_eh_frame_hdr->p_vaddr with the metadata of the capability
+     pointing to p_eh_frame_hdr.  */
+  if (load_base == 0)
+    hdr = __builtin_cheri_address_set (p_eh_frame_hdr, p_eh_frame_hdr->p_vaddr);
+  else
+#endif
   /* Read .eh_frame_hdr header.  */
   hdr = (const struct unw_eh_frame_hdr *)
     __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base);
+
+#ifdef __CHERI_PURE_CAPABILITY__
+  uintptr_t base, top;
+  gcc_assert (valid_cheri_capability (hdr, &base, &top));
+  gcc_assert (base <= data->pc && top > data->pc);
+#endif
+
   if (hdr->version != 1)
     return 1;
 
@@ -427,6 +476,13 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
 	}
     }
 
+#ifdef __CHERI_PURE_CAPABILITY__
+  /* Any encoding other than DW_EH_PE_pcrel would mean that our eh_frame
+     pointer would not be a valid capability.  Here we're reading from eh_frame
+     and hence would need provenance.  */
+  gcc_assert (valid_cheri_capability (eh_frame, NULL, NULL));
+#endif
+
   /* We have no sorted search table, so need to go the slow way.
      As soon as GLIBC will provide API so to notify that a library has been
      removed, we could cache this (and thus use search_object).  */


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-05-05 12:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-05 12:09 [gcc(refs/vendors/ARM/heads/morello)] Update the dl_iterate_phdr implementation Matthew Malcomson

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).