[Top][All Lists]
[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))
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Libunwind-devel] Re: [PATCH][x86_64] Make address validation a per thread setting,
Arun Sharma <=