]> sourceware.org Git - systemtap.git/commitdiff
Disallow kernel space memory access when unprivileged.
authorDave Brolley <brolley@redhat.com>
Thu, 3 Sep 2009 21:19:05 +0000 (17:19 -0400)
committerDave Brolley <brolley@redhat.com>
Thu, 3 Sep 2009 21:19:05 +0000 (17:19 -0400)
2009-09-03  Dave Brolley  <brolley@redhat.com>

        * runtime/addr-map.c (lookup_addr_aux): Now takes size argument.
        Consider the size when looking for overlapping range with the map
        entries.
        (lookup_bad_addr): Now takes size argument. Disallow kernel space access
        when STP_PRIVILEGED is not defined. Pass size to lookup_addr_aux.
        <asm/processor.h>: #include it when STP_PRIVILEGED is not defined.
        (add_bad_addr_entry): Supply a size of 1 to calls to lookup_addr_aux.
        * runtime/loc2c-runtime.h (kread): Pass sizeof (*(ptr)) to
        lookup_bad_addr.
        (kwrite): Likewise.
        (deref): Pass size to lookup_bad_addr.
        (store_deref): Likewise.

runtime/addr-map.c
runtime/loc2c-runtime.h

index e898044f81addf13405f97a17abe9c06953beede..8c0e84d8c7df448f01d599854b5798fd530606c3 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- linux-c -*- 
  * Map of addresses to disallow.
- * Copyright (C) 2005-2008 Red Hat Inc.
+ * Copyright (C) 2005-2009 Red Hat Inc.
  *
  * This file is part of systemtap, and is free software.  You can
  * redistribute it and/or modify it under the terms of the GNU General
@@ -59,28 +59,41 @@ upper_bound(unsigned long addr, struct addr_map* map)
   return entry - &map->entries[0];
 }
 
+/* Search for an entry in the given map which overlaps the range specified by
+   addr and size.  */
 static struct addr_map_entry*
-lookup_addr_aux(unsigned long addr, struct addr_map* map)
+lookup_addr_aux(unsigned long addr, size_t size, struct addr_map* map)
 {
   size_t start = 0;
   size_t end;
+
+  /* No map? No matching entry. */
   if (!map)
     return 0;
-  end = map->size;
+  /* Empty map? No matching entry.  */
   if (map->size == 0)
     return 0;
 
+  /* Use binary search on the sorted map entries.  */
+  end = map->size;
   do
     {
       int entry_idx;
       struct addr_map_entry *entry = 0;
-      if (addr < map->entries[start].min || addr >= map->entries[end - 1].max)
+      /* If the target range is beyond those of the remaining entries in the
+        map, then a matching entry will not be found  */
+      if (addr + size <= map->entries[start].min ||
+         addr >= map->entries[end - 1].max)
         return 0;
+      /* Choose the map entry at the mid point of the remaining entries.  */
       entry_idx = (end + start) / 2;
       entry = &map->entries[entry_idx];
-      if (entry->min <= addr && entry->max > addr)
+      /* If our range overlaps the range of this entry, then we have a match. */
+      if (addr + size > entry->min && addr < entry->max)
         return entry;
-      if (addr < entry->min)
+      /* If our range is below the range of this entry, then cull the entries
+        above this entry, otherwise cull the entries below it.  */
+      if (addr + size <= entry->min)
         end = entry_idx;
       else
         start = entry_idx + 1;
@@ -88,12 +101,24 @@ lookup_addr_aux(unsigned long addr, struct addr_map* map)
   return 0;
 }
 
+#ifndef STP_PRIVILEGED
+#include <asm/processor.h> /* For TASK_SIZE */
+#endif
+
 static int
-lookup_bad_addr(unsigned long addr)
+lookup_bad_addr(unsigned long addr, size_t size)
 {
   struct addr_map_entry* result = 0;
+
+#ifndef STP_PRIVILEGED
+  /* Unprivileged users must not access kernel space memory.  */
+  if (addr + size > TASK_SIZE)
+    return 1;
+#endif
+
+  /* Search for the given range in the black-listed map.  */
   spin_lock(&addr_map_lock);
-  result = lookup_addr_aux(addr, blackmap);
+  result = lookup_addr_aux(addr, size, blackmap);
   spin_unlock(&addr_map_lock);
   if (result)
     return 1;
@@ -149,8 +174,8 @@ add_bad_addr_entry(unsigned long min_addr, unsigned long max_addr,
     }
   else
     {
-      min_entry = lookup_addr_aux(min_addr, blackmap);
-      max_entry = lookup_addr_aux(max_addr, blackmap);
+      min_entry = lookup_addr_aux(min_addr, 1, blackmap);
+      max_entry = lookup_addr_aux(max_addr, 1, blackmap);
       if (min_entry || max_entry)
         {
           if (existing_min)
index 620e161590195c2f2ba75289d54bd4b74ea41943..e9e5a0716c24ecedf7fa1ebbabee32b16a53ee3b 100644 (file)
 
 #define kread(ptr) ({ \
         typeof(*(ptr)) _v = 0; \
-        if (lookup_bad_addr((unsigned long)(ptr)) || \
+        if (lookup_bad_addr((unsigned long)(ptr), sizeof (*(ptr))) ||  \
             probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \
           DEREF_FAULT(ptr); \
         _v; \
 #define kwrite(ptr, value) ({ \
         typeof(*(ptr)) _v; \
         _v = (typeof(*(ptr)))(value); \
-        if (lookup_bad_addr((unsigned long)addr) || \
+        if (lookup_bad_addr((unsigned long)addr, sizeof (*(ptr))) ||   \
             probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \
           STORE_DEREF_FAULT(ptr); \
     })
@@ -240,7 +240,7 @@ extern void __store_deref_bad(void);
     int _bad = 0;                                                            \
     u8 _b; u16 _w; u32 _l;                                                   \
     intptr_t _v = 0;                                                         \
-    if (lookup_bad_addr((unsigned long)addr))                                 \
+    if (lookup_bad_addr((unsigned long)addr, size))                          \
       _bad = 1;                                                               \
     else                                                                      \
       switch (size)                                                           \
@@ -258,7 +258,7 @@ extern void __store_deref_bad(void);
 #define store_deref(size, addr, value)                                       \
   ({                                                                         \
     int _bad = 0;                                                            \
-    if (lookup_bad_addr((unsigned long)addr))                                 \
+    if (lookup_bad_addr((unsigned long)addr, size))                          \
       _bad = 1;                                                               \
     else                                                                      \
       switch (size)                                                           \
@@ -280,7 +280,7 @@ extern void __store_deref_bad(void);
     int _bad = 0;                                                            \
     u8 _b; u16 _w; u32 _l; u64 _q;                                           \
     intptr_t _v = 0;                                                         \
-    if (lookup_bad_addr((unsigned long)addr))                                 \
+    if (lookup_bad_addr((unsigned long)addr, size))                          \
       _bad = 1;                                                               \
     else                                                                      \
       switch (size)                                                           \
@@ -299,7 +299,7 @@ extern void __store_deref_bad(void);
 #define store_deref(size, addr, value)                                       \
   ({                                                                         \
     int _bad = 0;                                                            \
-    if (lookup_bad_addr((unsigned long)addr))                                 \
+    if (lookup_bad_addr((unsigned long)addr, size))                          \
       _bad = 1;                                                               \
     else                                                                      \
       switch (size)                                                           \
@@ -319,7 +319,7 @@ extern void __store_deref_bad(void);
   ({                                                                   \
      int _bad = 0;                                                     \
      intptr_t _v=0;                                                    \
-     if (lookup_bad_addr((unsigned long)addr))                          \
+     if (lookup_bad_addr((unsigned long)addr, size))                   \
        _bad = 1;                                                        \
      else                                                               \
        switch (size){                                                  \
@@ -337,7 +337,7 @@ extern void __store_deref_bad(void);
 #define store_deref(size, addr, value)                                 \
   ({                                                                   \
     int _bad=0;                                                                \
-    if (lookup_bad_addr((unsigned long)addr))                           \
+    if (lookup_bad_addr((unsigned long)addr, size))                    \
       _bad = 1;                                                         \
     else                                                                \
       switch (size){                                                   \
@@ -397,7 +397,7 @@ extern void __store_deref_bad(void);
   ({                                                                         \
     int _bad = 0;                                                            \
     intptr_t _v = 0;                                                         \
-    if (lookup_bad_addr((unsigned long)addr))                                 \
+    if (lookup_bad_addr((unsigned long)addr, size))                          \
       _bad = 1;                                                               \
     else                                                                      \
       switch (size)                                                           \
@@ -416,7 +416,7 @@ extern void __store_deref_bad(void);
 #define store_deref(size, addr, value)                                       \
   ({                                                                         \
     int _bad = 0;                                                            \
-    if (lookup_bad_addr((unsigned long)addr))                                 \
+    if (lookup_bad_addr((unsigned long)addr, size))                          \
       _bad = 1;                                                               \
     else                                                                      \
       switch (size)                                                           \
@@ -571,7 +571,7 @@ extern void __store_deref_bad(void);
   ({                                                                   \
      int _bad = 0;                                                     \
      intptr_t _v=0;                                                    \
-     if (lookup_bad_addr((unsigned long)addr))                          \
+     if (lookup_bad_addr((unsigned long)addr, size))                   \
       _bad = 1;                                                         \
     else                                                                \
       switch (size){                                                   \
@@ -588,7 +588,7 @@ extern void __store_deref_bad(void);
 #define store_deref(size, addr, value)                                 \
   ({                                                                   \
     int _bad=0;                                                                \
-    if (lookup_bad_addr((unsigned long)addr))                           \
+    if (lookup_bad_addr((unsigned long)addr, size))                    \
       _bad = 1;                                                         \
     else                                                                \
       switch (size){                                                   \
@@ -660,7 +660,7 @@ extern void __store_deref_bad(void);
        u8 _b; u16 _w; u32 _l; u64 _q;                          \
        int _bad = 0;                                           \
        intptr_t _v = 0;                                        \
-        if (lookup_bad_addr((unsigned long)addr))               \
+        if (lookup_bad_addr((unsigned long)addr, size))                \
           _bad = 1;                                             \
         else                                                    \
           switch (size) {                                      \
@@ -696,7 +696,7 @@ extern void __store_deref_bad(void);
 ({                                                              \
         int _bad = 0;                                           \
        int i;                                                  \
-        if (lookup_bad_addr((unsigned long)addr))               \
+        if (lookup_bad_addr((unsigned long)addr, size))                \
           _bad = 1;                                             \
         else                                                    \
           for(i=0;i<size;i++){                                  \
This page took 0.039567 seconds and 5 git commands to generate.