libunwind-devel
[Top][All Lists]
Advanced

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

[Libunwind-devel] (no subject)


From: v . barinov
Subject: [Libunwind-devel] (no subject)
Date: Wed, 15 Apr 2015 12:34:27 +0100

>From 20355c6dd143ea295256da17d6edd334ba754120 Mon Sep 17 00: 00:00 2001
From: Vyacheslav Barinov <address@hidden>
Date: Wed, 15 Apr 2015 14:08:06 +0300
Subject: [PATCH] arm: Validate memory before access

Prevent SIGSEGV due to accessing addresses now mapped to current process

Signed-off-by: Vyacheslav Barinov <address@hidden>
---

Notes:
    In certain cases a signal frame generated on arm has wrong "ip" in DWARF 
frame.
    During access to addresses like 0x00000000 or 0xffffffff from
    _ULarm_is_signal_frame libunwind catches internal SIGSEGV.
    
    The address check is copied from x86 code and fixes the problem

 src/arm/Ginit.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/src/arm/Ginit.c b/src/arm/Ginit.c
index 3484cb5..67050ce 100644
--- a/src/arm/Ginit.c
+++ b/src/arm/Ginit.c
@@ -72,6 +72,56 @@ 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;
+  size_t len;
+
+  if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
+    len = PAGE_SIZE;
+  else
+    len = PAGE_SIZE * 2;
+
+  addr = PAGE_START(addr);
+
+  if (addr == 0)
+    return -1;
+
+  for (i = 0; i < NLGA; i++)
+    {
+      if (last_good_addr[i] && (addr == last_good_addr[i]))
+       return 0;
+    }
+
+  if (msync ((void *) addr, len, MS_ASYNC) == -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)
@@ -83,6 +133,11 @@ 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 && validate_mem(addr))
+       return -1;
+
       *val = *(unw_word_t *) addr;
       Debug (16, "mem[%x] -> %x\n", addr, *val);
     }
-- 
2.3.5




reply via email to

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