From: Marek VavruĊĦa Date: Fri, 13 Nov 2015 12:42:55 +0000 (+0100) Subject: lib/daemon: address sanitizer annotated poisoning X-Git-Tag: v1.0.0-beta2~25 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f3b32a2f185fa1739adb7ca8fe849183f476a01c;p=thirdparty%2Fknot-resolver.git lib/daemon: address sanitizer annotated poisoning if the library or daemon is compiled with address sanitizer, objects in freelists are poisoned to detect use-after-recycle errors it is not currently used in the library, as there are no freelists --- diff --git a/daemon/worker.c b/daemon/worker.c index c3ab8b15c..0d7f44b7a 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -48,11 +48,13 @@ static inline struct ioreq *ioreq_take(struct worker_ctx *worker) } else { req = malloc(sizeof(*req)); } + kr_asan_unpoison(req, sizeof(*req)); return req; } static inline void ioreq_release(struct worker_ctx *worker, struct ioreq *req) { + kr_asan_poison(req, sizeof(*req)); if (!req || worker->ioreqs.len < 4 * MP_FREELIST_SIZE) { array_push(worker->ioreqs, req); } else { @@ -60,6 +62,32 @@ static inline void ioreq_release(struct worker_ctx *worker, struct ioreq *req) } } +static inline struct mempool *pool_take(struct worker_ctx *worker) +{ + /* Recycle available mempool if possible */ + struct mempool *mp = NULL; + if (worker->pools.len > 0) { + mp = array_tail(worker->pools); + array_pop(worker->pools); + } else { /* No mempool on the freelist, create new one */ + mp = mp_new (4 * CPU_PAGE_SIZE); + } + kr_asan_unpoison(mp, sizeof(*mp)); + return mp; +} + +static inline void pool_release(struct worker_ctx *worker, struct mempool *mp) +{ + /* Return mempool to ring or free it if it's full */ + if (worker->pools.len < MP_FREELIST_SIZE) { + mp_flush(mp); + array_push(worker->pools, mp); + kr_asan_poison(mp, sizeof(*mp)); + } else { + mp_delete(mp); + } +} + /** @internal Query resolution task. */ struct qr_task { @@ -117,15 +145,9 @@ static struct qr_task *qr_task_create(struct worker_ctx *worker, uv_handle_t *ha /* Recycle available mempool if possible */ mm_ctx_t pool = { - .ctx = NULL, + .ctx = pool_take(worker), .alloc = (mm_alloc_t) mp_alloc }; - if (worker->pools.len > 0) { - pool.ctx = array_tail(worker->pools); - array_pop(worker->pools); - } else { /* No mempool on the freelist, create new one */ - pool.ctx = mp_new (4 * CPU_PAGE_SIZE); - } /* Create resolution task */ struct qr_task *task = mm_alloc(&pool, sizeof(*task)); @@ -174,13 +196,8 @@ static void qr_task_free(struct qr_task *task) { /* Return mempool to ring or free it if it's full */ struct worker_ctx *worker = task->worker; - void *mp_context = task->req.pool.ctx; - if (worker->pools.len < MP_FREELIST_SIZE) { - mp_flush(mp_context); - array_push(worker->pools, mp_context); - } else { - mp_delete(mp_context); - } + pool_release(worker, task->req.pool.ctx); + /* @note The 'task' is invalidated from now on. */ /* Decommit memory every once in a while */ static int mp_delete_count = 0; if (++mp_delete_count == 100000) { @@ -528,16 +545,18 @@ int worker_reserve(struct worker_ctx *worker, size_t ring_maxlen) return kr_ok(); } -#define reclaim_freelist(list, cb) \ +#define reclaim_freelist(list, type, cb) \ for (unsigned i = 0; i < list.len; ++i) { \ - cb(list.at[i]); \ + type *elm = list.at[i]; \ + kr_asan_unpoison(elm, sizeof(type)); \ + cb(elm); \ } \ array_clear(list) void worker_reclaim(struct worker_ctx *worker) { - reclaim_freelist(worker->pools, mp_delete); - reclaim_freelist(worker->ioreqs, free); + reclaim_freelist(worker->pools, struct mempool, mp_delete); + reclaim_freelist(worker->ioreqs, struct ioreq, free); mp_delete(worker->pkt_pool.ctx); worker->pkt_pool.ctx = NULL; } diff --git a/lib/defines.h b/lib/defines.h index bde4be76f..92c7c6fb9 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -44,4 +44,22 @@ static inline int __attribute__((__cold__)) kr_error(int x) { #define KR_DNS_PORT 53 #define KR_EDNS_VERSION 0 #define KR_EDNS_PAYLOAD 4096 /* Default UDP payload (max unfragmented UDP is 1452B) */ -/* @endcond */ + +/* + * Address sanitizer hints. + */ +#if !defined(__SANITIZE_ADDRESS__) && defined(__has_feature) +# if __has_feature(address_sanitizer) +# define __SANITIZE_ADDRESS__ 1 +# endif +#endif +#if defined(__SANITIZE_ADDRESS__) +void __asan_poison_memory_region(void const volatile *addr, size_t size); +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#define kr_asan_poison(addr, size) __asan_poison_memory_region((addr), (size)) +#define kr_asan_unpoison(addr, size) __asan_unpoison_memory_region((addr), (size)) +#else +#define kr_asan_poison(addr, size) +#define kr_asan_unpoison(addr, size) +#endif +/* @endcond */ \ No newline at end of file