libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] Re: [PATCH][x86_64] Make address validation a per thre


From: Arun Sharma
Subject: [Libunwind-devel] Re: [PATCH][x86_64] Make address validation a per thread setting
Date: Wed, 3 Dec 2008 10:13:02 -0800
User-agent: Mutt/1.5.17+20080114 (2008-01-14)

Attached is the equivalent patch for 32 bit x86.

This corresponds to commit 649f1fb3449a65dd0626a709432d8b02a7c56bbc.

Signed-off-by: Paul Pluzhnikov <address@hidden>
Signed-off-by: Arun Sharma <address@hidden>

diff --git a/include/tdep-x86/libunwind_i.h b/include/tdep-x86/libunwind_i.h
index 43c22f1..e6ee149 100644
--- a/include/tdep-x86/libunwind_i.h
+++ b/include/tdep-x86/libunwind_i.h
@@ -65,8 +65,17 @@ struct cursor
       }
     sigcontext_format;
     unw_word_t sigcontext_addr;
+    int validate;
+    ucontext_t *uc;
   };
 
+static inline ucontext_t *
+dwarf_get_uc(const struct dwarf_cursor *cursor)
+{
+  const struct cursor *c = (struct cursor *) cursor->as_arg;
+  return c->uc;
+}
+
 #define DWARF_GET_LOC(l)       ((l).val)
 
 #ifdef UNW_LOCAL_ONLY
@@ -75,10 +84,10 @@ struct cursor
 # define DWARF_LOC(r, t)       ((dwarf_loc_t) { .val = (r) })
 # define DWARF_IS_REG_LOC(l)   0
 # define DWARF_REG_LOC(c,r)    (DWARF_LOC((unw_word_t)                      \
-                                tdep_uc_addr((c)->as_arg, (r)), 0))
+                                tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
 # define DWARF_MEM_LOC(c,m)    DWARF_LOC ((m), 0)
 # define DWARF_FPREG_LOC(c,r)  (DWARF_LOC((unw_word_t)                      \
-                                tdep_uc_addr((c)->as_arg, (r)), 0))
+                                tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
 
 static inline int
 dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
@@ -103,8 +112,8 @@ dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, 
unw_word_t *val)
 {
   if (!DWARF_GET_LOC (loc))
     return -1;
-  *val = *(unw_word_t *) DWARF_GET_LOC (loc);
-  return 0;
+  return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
+                                  0, c->as_arg);
 }
 
 static inline int
@@ -112,8 +121,8 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, 
unw_word_t val)
 {
   if (!DWARF_GET_LOC (loc))
     return -1;
-  *(unw_word_t *) DWARF_GET_LOC (loc) = val;
-  return 0;
+  return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val,
+                                  1, c->as_arg);
 }
 
 #else /* !UNW_LOCAL_ONLY */
diff --git a/src/x86/Ginit.c b/src/x86/Ginit.c
index abc9e61..e1b1dcf 100644
--- a/src/x86/Ginit.c
+++ b/src/x86/Ginit.c
@@ -102,6 +102,47 @@ get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t 
*dyn_info_list_addr,
   return 0;
 }
 
+#define PAGE_SIZE 4096
+#define PAGE_START(a)  ((a) & ~(PAGE_SIZE-1))
+
+/* Cache of already validated addresses */
+#define NLGA 4
+static unw_word_t last_good_addr[NLGA];
+static int lga_victim;
+
+static int
+validate_mem (unw_word_t addr)
+{
+  int i, victim;
+
+  addr = PAGE_START(addr);
+
+  for (i = 0; i < NLGA; i++)
+    {
+      if (last_good_addr[i] && (addr == last_good_addr[i]))
+       return 0;
+    }
+
+  if (msync ((void *) addr, 1, MS_SYNC) == -1)
+    return -1;
+
+  victim = lga_victim;
+  for (i = 0; i < NLGA; i++) {
+    if (!last_good_addr[victim]) {
+      last_good_addr[victim++] = addr;
+      return 0;
+    }
+    victim = (victim + 1) % NLGA;
+  }
+
+  /* All slots full. Evict the victim. */
+  last_good_addr[victim] = addr;
+  victim = (victim + 1) % NLGA;
+  lga_victim = victim;
+
+  return 0;
+}
+
 static int
 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
            void *arg)
@@ -113,6 +154,10 @@ access_mem (unw_addr_space_t as, unw_word_t addr, 
unw_word_t *val, int write,
     }
   else
     {
+      /* validate address */
+      const struct cursor *c = (const struct cursor *)arg;
+      if (c && c->validate && validate_mem(addr))
+        return -1;
       *val = *(unw_word_t *) addr;
       Debug (16, "mem[%x] -> %x\n", addr, *val);
     }
@@ -124,7 +169,7 @@ access_reg (unw_addr_space_t as, unw_regnum_t reg, 
unw_word_t *val, int write,
            void *arg)
 {
   unw_word_t *addr;
-  ucontext_t *uc = arg;
+  ucontext_t *uc = ((struct cursor *)arg)->uc;
 
   if (unw_is_fpreg (reg))
     goto badreg;
@@ -153,7 +198,7 @@ static int
 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
              int write, void *arg)
 {
-  ucontext_t *uc = arg;
+  ucontext_t *uc = ((struct cursor *)arg)->uc;
   unw_fpreg_t *addr;
 
   if (!unw_is_fpreg (reg))
diff --git a/src/x86/Ginit_local.c b/src/x86/Ginit_local.c
index 7b86d6e..55ab749 100644
--- a/src/x86/Ginit_local.c
+++ b/src/x86/Ginit_local.c
@@ -47,7 +47,9 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
   Debug (1, "(cursor=%p)\n", c);
 
   c->dwarf.as = unw_local_addr_space;
-  c->dwarf.as_arg = uc;
+  c->dwarf.as_arg = c;
+  c->uc = uc;
+  c->validate = 0;
   return common_init (c);
 }
 
diff --git a/src/x86/Ginit_remote.c b/src/x86/Ginit_remote.c
index 5d3827d..6949a73 100644
--- a/src/x86/Ginit_remote.c
+++ b/src/x86/Ginit_remote.c
@@ -41,6 +41,16 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, 
void *as_arg)
 
   c->dwarf.as = as;
   c->dwarf.as_arg = as_arg;
+  if (as == unw_local_addr_space)
+    {
+      c->dwarf.as_arg = c;
+      c->uc = as_arg;
+    }
+  else
+    {
+      c->dwarf.as_arg = as_arg;
+      c->uc = 0;
+    }
   return common_init (c);
 #endif /* !UNW_LOCAL_ONLY */
 }
diff --git a/src/x86/Gresume.c b/src/x86/Gresume.c
index 6ea9346..cf91478 100644
--- a/src/x86/Gresume.c
+++ b/src/x86/Gresume.c
@@ -34,7 +34,7 @@ x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, 
void *arg)
 {
 #if defined(__linux)
   struct cursor *c = (struct cursor *) cursor;
-  ucontext_t *uc = c->dwarf.as_arg;
+  ucontext_t *uc = c->uc;
 
   /* Ensure c->pi is up-to-date.  On x86, it's relatively common to be
      missing DWARF unwind info.  We don't want to fail in that case,
diff --git a/src/x86/Gstep.c b/src/x86/Gstep.c
index e0e681d..266f89f 100644
--- a/src/x86/Gstep.c
+++ b/src/x86/Gstep.c
@@ -49,6 +49,10 @@ unw_step (unw_cursor_t *cursor)
         or skip over the signal trampoline.  */
       struct dwarf_loc ebp_loc, eip_loc;
 
+      /* We could get here because of missing/bad unwind information.
+         Validate all addresses before dereferencing. */
+      c->validate = 1;
+
       Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
 
       if (unw_is_signal_frame (cursor))




reply via email to

[Prev in Thread] Current Thread [Next in Thread]