]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/daemon: address sanitizer annotated poisoning
authorMarek Vavruša <marek.vavrusa@nic.cz>
Fri, 13 Nov 2015 12:42:55 +0000 (13:42 +0100)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Fri, 13 Nov 2015 12:42:55 +0000 (13:42 +0100)
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

daemon/worker.c
lib/defines.h

index c3ab8b15c12d7064765beb3fd0c43b24084865bc..0d7f44b7a36a687a2d7e50181d92dc064decfac4 100644 (file)
@@ -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;
 }
index bde4be76f98b5e28192f5290458276214b1f0cef..92c7c6fb9d1c95233c5e4d10f46fc16e26c0527d 100644 (file)
@@ -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