diff options
author | Dave Brolley <brolley@redhat.com> | 2009-09-03 17:19:05 -0400 |
---|---|---|
committer | Dave Brolley <brolley@redhat.com> | 2009-09-03 17:19:05 -0400 |
commit | d0822e28934cd0387c2af4349cf52c52c368c55a (patch) | |
tree | 183ad07b7c064d885b1a0327d7aae09953dae3dc | |
parent | 5e8a3b7b558273fa06525f642fdf2d678dde85eb (diff) | |
download | systemtap-steved-d0822e28934cd0387c2af4349cf52c52c368c55a.tar.gz systemtap-steved-d0822e28934cd0387c2af4349cf52c52c368c55a.tar.xz systemtap-steved-d0822e28934cd0387c2af4349cf52c52c368c55a.zip |
Disallow kernel space memory access when unprivileged.
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.
-rw-r--r-- | runtime/addr-map.c | 45 | ||||
-rw-r--r-- | runtime/loc2c-runtime.h | 28 |
2 files changed, 49 insertions, 24 deletions
diff --git a/runtime/addr-map.c b/runtime/addr-map.c index e898044f..8c0e84d8 100644 --- a/runtime/addr-map.c +++ b/runtime/addr-map.c @@ -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) diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 620e1615..e9e5a071 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -192,7 +192,7 @@ #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; \ @@ -201,7 +201,7 @@ #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++){ \ |