]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: lib-event - Support re-initialization
authorStephan Bosch <stephan.bosch@open-xchange.com>
Thu, 4 Dec 2025 22:21:15 +0000 (23:21 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Mon, 2 Feb 2026 18:54:43 +0000 (18:54 +0000)
Make sure global state is reset properly through deinit->init cycle.
This is needed for fuzzing with address sanitizer.

src/lib/lib-event.c

index 1d5220222eeeaa97fdbad6dd1bc5ff676b8d4875..1876d690c7714a683063651ca48b3d5ee3a21cc6 100644 (file)
@@ -78,6 +78,9 @@ static struct event *event_last_passthrough = NULL;
 static ARRAY(event_callback_t *) event_handlers;
 static ARRAY(event_category_callback_t *) event_category_callbacks;
 static ARRAY(struct event_internal_category *) event_registered_categories_internal;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+static ARRAY(struct event_category *) event_registered_categories;
+#endif
 static ARRAY(struct event_category *) event_registered_categories_representative;
 static ARRAY(struct event *) global_event_stack;
 static uint64_t event_id_counter = 0;
@@ -892,6 +895,22 @@ event_category_register(struct event_category *category)
        }
 
        category->internal = internal;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+       /* Record the registered category for later cleanup upon lib_deinit().
+          For normal operation, calling lib_init() a second time never occurs,
+          so this cleanup (clearing state) is not necessary normally. However,
+          some fuzzers rely on fuzzing some sub-system from the very inception
+          of the Dovecot library, so cycling lib_init() and lib_deinit()
+          becomes a concern. Sadly, clearing event category state will only
+          work when that is not located in some loaded plugin module, which
+          would be unloaded long before lib_deinit(). Since Dovecot supports
+          loading modules at many subsystems, this would cause crashes during
+          normal operation. Therefore, the cleanup of category state is omitted
+          entirely for normal operation and is only compiled in for the benefit
+          of fuzzing where loading such modules is either omitted or handled
+          specially. */
+       array_push_back(&event_registered_categories, &category);
+#endif
 
        if (!allocated) {
                /* not the first registration of this category */
@@ -1867,15 +1886,27 @@ void event_enable_user_cpu_usecs(struct event *event)
 
 void lib_event_init(void)
 {
+       events = NULL;
+       current_global_event = NULL;
+       event_last_passthrough = NULL;
+       event_id_counter = 0;
+
        i_array_init(&event_handlers, 4);
        i_array_init(&event_category_callbacks, 4);
        i_array_init(&event_registered_categories_internal, 16);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+       /* Refer to earlier commment in event_category_register(). */
+       i_array_init(&event_registered_categories, 32);
+#endif
        i_array_init(&event_registered_categories_representative, 16);
 }
 
 void lib_event_deinit(void)
 {
        struct event_internal_category *internal;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+       struct event_category *category;
+#endif
 
        event_unset_global_debug_log_filter();
        event_unset_global_debug_send_filter();
@@ -1890,6 +1921,12 @@ void lib_event_deinit(void)
                i_free(internal->name);
                i_free(internal);
        }
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+       /* Refer to earlier commment in event_category_register(). */
+       array_foreach_elem(&event_registered_categories, category)
+               category->internal = NULL;
+       array_free(&event_registered_categories);
+#endif
        array_free(&event_handlers);
        array_free(&event_category_callbacks);
        array_free(&event_registered_categories_internal);