ACK: [PATCH][V2] fwts-alloc: track memory allocations, cleans up 6 coverity scan warnings
ivanhu
ivan.hu at canonical.com
Wed Feb 8 04:30:10 UTC 2017
On 2017年02月03日 00:39, Colin King wrote:
> From: Colin Ian King <colin.king at canonical.com>
>
> CoverityScan was warning about use of tainted pointers on memory
> re-allocations and frees as well as mistrusted data read from the
> /proc/self/maps. This fix addresses these issues by keeping a
> record of all allocations and sanity checking pointers on re-allocs
> and frees so that we can be sure we can trust the pointers to
> the memory regions. The fix also performs some more robust
> sanity range checks on address ranges read from /proc/self/maps.
>
> Since fwts only makes 50 or so low memory allocations for cached
> ACPI data we don't need a large hash table; 509 slots were used
> as a prime sized hash tables work well with power of two sized
> data to hash, plus we normally end up with direct hashing into
> the table so we get fast lookup.
>
> Signed-off-by: Colin Ian King <colin.king at canonical.com>
> ---
> src/lib/src/fwts_alloc.c | 135 +++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 124 insertions(+), 11 deletions(-)
>
> diff --git a/src/lib/src/fwts_alloc.c b/src/lib/src/fwts_alloc.c
> index 09e7c93..1901a53 100644
> --- a/src/lib/src/fwts_alloc.c
> +++ b/src/lib/src/fwts_alloc.c
> @@ -27,6 +27,92 @@
> #include "fwts.h"
>
> /*
> + * Typically we use around 50 or so low mem allocations in fwts
> + * so 509 is a good large prime size to ensure we get a good
> + * hash table hit rate
> + */
> +#define HASH_ALLOC_SIZE (509)
> +
> +typedef struct hash_alloc {
> + void *addr; /* allocation addr, NULL = not used */
> + struct hash_alloc *next;/* next one in hash chain */
> +} hash_alloc_t;
> +
> +static hash_alloc_t *hash_allocs[HASH_ALLOC_SIZE];
> +
> +/*
> + * hash_addr()
> + * turn a void * address into a hash index
> + */
> +static inline size_t hash_addr(const void *addr)
> +{
> + ptrdiff_t h = (ptrdiff_t)addr;
> +
> + h ^= h >> 17;
> + h %= HASH_ALLOC_SIZE;
> +
> + return (size_t)h;
> +}
> +
> +/*
> + * hash_alloc_add()
> + * add a allocated address into the hash of
> + * known allocations so we can keep track
> + * of valid allocs.
> + */
> +static bool hash_alloc_add(void *addr)
> +{
> + size_t h = hash_addr(addr);
> + hash_alloc_t *new = hash_allocs[h];
> +
> + while (new) {
> + /* re-use old nullified records */
> + if (new->addr == NULL) {
> + /* old and free, so re-use */
> + new->addr = addr;
> + return true;
> + }
> + /* something is wrong, already in use */
> + if (new->addr == addr) {
> + return false;
> + }
> + new = new->next;
> + }
> +
> + /* not found, add a new record */
> + new = malloc(sizeof(*new));
> + if (!new)
> + return false;
> +
> + new->addr = addr;
> + new->next = hash_allocs[h];
> + hash_allocs[h] = new;
> +
> + return true;
> +}
> +
> +/*
> + * hash_alloc_remove()
> + * remove an allocated address from the hash
> + * of know allocations.
> + */
> +static bool hash_alloc_remove(const void *addr)
> +{
> + size_t h = hash_addr(addr);
> + hash_alloc_t *ha = hash_allocs[h];
> +
> + while (ha) {
> + if (ha->addr == addr) {
> + /* Just nullify it */
> + ha->addr = NULL;
> + return true;
> + }
> + ha = ha->next;
> + }
> + return false;
> +}
> +
> +/*
> * We implement a low memory allocator to allow us to allocate
> * memory < 2G limit for the ACPICA table handling. On 64 bit
> * machines we have to ensure that cached copies of ACPI tables
> @@ -111,7 +197,6 @@ static void *fwts_low_mmap_walkdown(const size_t requested_size)
> static void *fwts_low_mmap(const size_t requested_size)
> {
> FILE *fp;
> - char buffer[1024];
> char pathname[1024];
> void *addr_start;
> void *addr_end;
> @@ -129,15 +214,23 @@ static void *fwts_low_mmap(const size_t requested_size)
> if ((fp = fopen("/proc/self/maps", "r")) == NULL)
> return fwts_low_mmap_walkdown(requested_size);
>
> - while (fgets(buffer, sizeof(buffer), fp) != NULL) {
> - if (sscanf(buffer, "%p-%p %*s %*x %*s %*u %1023s",
> + while (!feof(fp)) {
> + if (fscanf(fp, "%p-%p %*s %*x %*s %*u %1023s\n",
> &addr_start, &addr_end, pathname) != 3)
> continue;
> /*
> + * Sanity check data
> + */
> + if ((addr_start <= (void *)LIMIT_START) ||
> + (addr_start >= (void *)LIMIT_2GB) ||
> + (addr_end <= (void *)LIMIT_START) ||
> + (addr_end >= (void *)LIMIT_2GB) ||
> + (addr_end <= addr_start))
> + continue;
> + /*
> * Try and allocate under first mmap'd address space
> */
> - if ((first_addr_start == NULL) &&
> - (addr_start > (void*)LIMIT_START)) {
> + if (first_addr_start == NULL) {
> size_t sz = (requested_size + CHUNK_SIZE) & ~(CHUNK_SIZE - 1);
> uint8_t *addr = (uint8_t *)addr_start - sz;
>
> @@ -241,7 +334,14 @@ void *fwts_low_calloc(const size_t nmemb, const size_t size)
> hdr->size = n;
> hdr->magic = FWTS_ALLOC_MAGIC;
>
> - return (void *)((uint8_t *)ret + sizeof(fwts_mmap_header));
> + ret = (void *)((uint8_t *)ret + sizeof(fwts_mmap_header));
> +
> + if (!hash_alloc_add(ret)) {
> + munmap((void *)hdr, n);
> + return NULL;
> + }
> +
> + return ret;
> }
>
> /*
> @@ -287,10 +387,23 @@ void *fwts_low_realloc(const void *ptr, const size_t size)
> */
> void fwts_low_free(const void *ptr)
> {
> - if (ptr) {
> - fwts_mmap_header *hdr = (fwts_mmap_header *)
> - ((uint8_t *)ptr - sizeof(fwts_mmap_header));
> - if (hdr->magic == FWTS_ALLOC_MAGIC)
> - munmap(hdr, hdr->size);
> + /*
> + * Sanity check the address we are about to
> + * try and free. If it is not known about
> + * the don't free it.
> + */
> + if (!ptr)
> + return;
> + if (!hash_alloc_remove(ptr)) {
> + /* Should never happen... */
> + fprintf(stderr, "double free on %p\n", ptr);
> + return;
> }
> +
> + fwts_mmap_header *hdr = (fwts_mmap_header *)
> + ((uint8_t *)ptr - sizeof(fwts_mmap_header));
> +
> + /* Be doubly sure by checking magic before we munmap */
> + if (hdr->magic == FWTS_ALLOC_MAGIC)
> + munmap(hdr, hdr->size);
> }
>
Acked-by: Ivan Hu <ivan.hu at canonical.com>
More information about the fwts-devel
mailing list