From 35a3d9507374b5377868593a13bf38eaa4dd42c3 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Thu, 1 Nov 2012 18:11:04 +0000 Subject: [PATCH] mm: implement support to guarded address space areas Guarded address space areas will have at least one unmapped page at both its ends. This should prevent overflows from being undetected. --- abi/include/mm/as.h | 9 +++--- kernel/generic/src/mm/as.c | 81 +++++++++++++++++++++++++++++++++------------- 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/abi/include/mm/as.h b/abi/include/mm/as.h index 5f55c1523..f83658210 100644 --- a/abi/include/mm/as.h +++ b/abi/include/mm/as.h @@ -36,10 +36,11 @@ #define ABI_AS_H_ /** Address space area flags. */ -#define AS_AREA_READ 1 -#define AS_AREA_WRITE 2 -#define AS_AREA_EXEC 4 -#define AS_AREA_CACHEABLE 8 +#define AS_AREA_READ 0x01 +#define AS_AREA_WRITE 0x02 +#define AS_AREA_EXEC 0x04 +#define AS_AREA_CACHEABLE 0x08 +#define AS_AREA_GUARD 0x10 /** Address space area info exported to uspace. */ typedef struct { diff --git a/kernel/generic/src/mm/as.c b/kernel/generic/src/mm/as.c index 36435c05d..76d8f8cd5 100644 --- a/kernel/generic/src/mm/as.c +++ b/kernel/generic/src/mm/as.c @@ -284,16 +284,17 @@ NO_TRACE void as_release(as_t *as) /** Check area conflicts with other areas. * - * @param as Address space. - * @param addr Starting virtual address of the area being tested. - * @param count Number of pages in the area being tested. - * @param avoid Do not touch this area. + * @param as Address space. + * @param addr Starting virtual address of the area being tested. + * @param count Number of pages in the area being tested. + * @param guarded True if the area being tested is protected by guard pages. + * @param avoid Do not touch this area. * * @return True if there is no conflict, false otherwise. * */ NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr, - size_t count, as_area_t *avoid) + size_t count, bool guarded, as_area_t *avoid) { ASSERT((addr % PAGE_SIZE) == 0); ASSERT(mutex_locked(&as->lock)); @@ -303,7 +304,7 @@ NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr, */ if (overlaps(addr, P2SZ(count), (uintptr_t) NULL, PAGE_SIZE)) return false; - + /* * The leaf node is found in O(log n), where n is proportional to * the number of address space areas belonging to as. @@ -327,9 +328,17 @@ NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr, if (area != avoid) { mutex_lock(&area->lock); + + /* If at least one of the two areas are protected + * by the AS_AREA_GUARD flag then we must be sure + * that they are separated by at least one unmapped + * page. + */ + int const gp = (guarded || + (area->flags & AS_AREA_GUARD)) ? 1 : 0; if (overlaps(addr, P2SZ(count), area->base, - P2SZ(area->pages))) { + P2SZ(area->pages + gp))) { mutex_unlock(&area->lock); return false; } @@ -344,8 +353,11 @@ NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr, if (area != avoid) { mutex_lock(&area->lock); + + int const gp = (guarded || + (area->flags & AS_AREA_GUARD)) ? 1 : 0; - if (overlaps(addr, P2SZ(count), area->base, + if (overlaps(addr, P2SZ(count + gp), area->base, P2SZ(area->pages))) { mutex_unlock(&area->lock); return false; @@ -364,9 +376,12 @@ NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr, continue; mutex_lock(&area->lock); - - if (overlaps(addr, P2SZ(count), area->base, - P2SZ(area->pages))) { + + int const gp = (guarded || + (area->flags & AS_AREA_GUARD)) ? 1 : 0; + + if (overlaps(addr, P2SZ(count + gp), area->base, + P2SZ(area->pages + gp))) { mutex_unlock(&area->lock); return false; } @@ -391,16 +406,17 @@ NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr, * The address space must be already locked when calling * this function. * - * @param as Address space. - * @param bound Lowest address bound. - * @param size Requested size of the allocation. + * @param as Address space. + * @param bound Lowest address bound. + * @param size Requested size of the allocation. + * @param guarded True if the allocation must be protected by guard pages. * * @return Address of the beginning of unmapped address space area. * @return -1 if no suitable address space area was found. * */ NO_TRACE static uintptr_t as_get_unmapped_area(as_t *as, uintptr_t bound, - size_t size) + size_t size, bool guarded) { ASSERT(mutex_locked(&as->lock)); @@ -422,9 +438,17 @@ NO_TRACE static uintptr_t as_get_unmapped_area(as_t *as, uintptr_t bound, /* First check the bound address itself */ uintptr_t addr = ALIGN_UP(bound, PAGE_SIZE); - if ((addr >= bound) && - (check_area_conflicts(as, addr, pages, NULL))) - return addr; + if (addr >= bound) { + if (guarded) { + /* Leave an unmapped page between the lower + * bound and the area's start address. + */ + addr += P2SZ(1); + } + + if (check_area_conflicts(as, addr, pages, guarded, NULL)) + return addr; + } /* Eventually check the addresses behind each area */ list_foreach(as->as_area_btree.leaf_list, cur) { @@ -438,9 +462,17 @@ NO_TRACE static uintptr_t as_get_unmapped_area(as_t *as, uintptr_t bound, addr = ALIGN_UP(area->base + P2SZ(area->pages), PAGE_SIZE); + + if (guarded || area->flags & AS_AREA_GUARD) { + /* We must leave an unmapped page + * between the two areas. + */ + addr += P2SZ(1); + } + bool avail = ((addr >= bound) && (addr >= area->base) && - (check_area_conflicts(as, addr, pages, area))); + (check_area_conflicts(as, addr, pages, guarded, area))); mutex_unlock(&area->lock); @@ -486,18 +518,20 @@ as_area_t *as_area_create(as_t *as, unsigned int flags, size_t size, /* Writeable executable areas are not supported. */ if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE)) return NULL; + + bool const guarded = flags & AS_AREA_GUARD; mutex_lock(&as->lock); if (*base == (uintptr_t) -1) { - *base = as_get_unmapped_area(as, bound, size); + *base = as_get_unmapped_area(as, bound, size, guarded); if (*base == (uintptr_t) -1) { mutex_unlock(&as->lock); return NULL; } } - - if (!check_area_conflicts(as, *base, pages, NULL)) { + + if (!check_area_conflicts(as, *base, pages, guarded, NULL)) { mutex_unlock(&as->lock); return NULL; } @@ -777,7 +811,8 @@ int as_area_resize(as_t *as, uintptr_t address, size_t size, unsigned int flags) * Growing the area. * Check for overlaps with other address space areas. */ - if (!check_area_conflicts(as, address, pages, area)) { + bool const guarded = area->flags & AS_AREA_GUARD; + if (!check_area_conflicts(as, address, pages, guarded, area)) { mutex_unlock(&area->lock); mutex_unlock(&as->lock); return EADDRNOTAVAIL; -- 2.11.4.GIT