/* -*- 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
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;
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;
}
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)
#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); \
})
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) \
#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) \
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) \
#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) \
({ \
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){ \
#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){ \
({ \
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) \
#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) \
({ \
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){ \
#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){ \
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) { \
({ \
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++){ \