]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Use refcounting for mail_storage_service_user
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 22 Feb 2017 11:28:43 +0000 (13:28 +0200)
committerGitLab <gitlab@git.dovecot.net>
Wed, 22 Feb 2017 11:42:12 +0000 (13:42 +0200)
doveadm import was freeing the user too early, which resulted
mail_user._service_user pointing to freed memory. More importantly,
after 34512eaad8b1b2f929e6d6e3a2f7252c29fba97b user->set was pointing
to already freed memory.

src/lib-storage/mail-storage-service.c
src/lib-storage/mail-storage-service.h
src/lib-storage/mail-user.c

index 601f22fed55da7c750bfc724bab1f91a3013908d..815e89b914fb13d0d17e418f9de5311ed04b49e6 100644 (file)
@@ -70,6 +70,8 @@ struct mail_storage_service_ctx {
 
 struct mail_storage_service_user {
        pool_t pool;
+       int refcount;
+
        struct mail_storage_service_ctx *service_ctx;
        struct mail_storage_service_input input;
        enum mail_storage_service_flags flags;
@@ -661,6 +663,7 @@ mail_storage_service_init_post(struct mail_storage_service_ctx *ctx,
        mail_user = mail_user_alloc_nodup_set(user->input.username,
                                              user->user_info, user->user_set);
        mail_user->_service_user = user;
+       mail_storage_service_user_ref(user);
        mail_user_set_home(mail_user, *home == '\0' ? NULL : home);
        mail_user_set_vars(mail_user, ctx->service->name,
                           &user->input.local_ip, &user->input.remote_ip);
@@ -1242,6 +1245,7 @@ mail_storage_service_lookup_real(struct mail_storage_service_ctx *ctx,
        }
 
        user = p_new(user_pool, struct mail_storage_service_user, 1);
+       user->refcount = 1;
        user->service_ctx = ctx;
        user->pool = user_pool;
        user->input = *input;
@@ -1487,19 +1491,29 @@ int mail_storage_service_lookup_next(struct mail_storage_service_ctx *ctx,
 
        ret = mail_storage_service_next(ctx, user, mail_user_r, error_r);
        if (ret < 0) {
-               mail_storage_service_user_free(&user);
+               mail_storage_service_user_unref(&user);
                return ret;
        }
        *user_r = user;
        return 1;
 }
 
-void mail_storage_service_user_free(struct mail_storage_service_user **_user)
+void mail_storage_service_user_ref(struct mail_storage_service_user *user)
+{
+       i_assert(user->refcount > 0);
+       user->refcount++;
+}
+
+void mail_storage_service_user_unref(struct mail_storage_service_user **_user)
 {
        struct mail_storage_service_user *user = *_user;
 
        *_user = NULL;
 
+       i_assert(user->refcount > 0);
+       if (--user->refcount > 0)
+               return;
+
        if (user->ioloop_ctx != NULL) {
                if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0) {
                        io_loop_context_remove_callbacks(user->ioloop_ctx,
index 8bc992cd56a435402e6edf81ea16584652a71a05..d5309e56ad4a25e0c3b86044ef4f310c293ca0f0 100644 (file)
@@ -112,7 +112,11 @@ int mail_storage_service_lookup_next(struct mail_storage_service_ctx *ctx,
                                     struct mail_storage_service_user **user_r,
                                     struct mail_user **mail_user_r,
                                     const char **error_r);
-void mail_storage_service_user_free(struct mail_storage_service_user **user);
+void mail_storage_service_user_ref(struct mail_storage_service_user *user);
+void mail_storage_service_user_unref(struct mail_storage_service_user **user);
+/* FIXME: for backwards compatibility - remove */
+#define mail_storage_service_user_free(user) \
+       mail_storage_service_user_unref(user)
 /* Initialize iterating through all users. */
 void mail_storage_service_all_init(struct mail_storage_service_ctx *ctx);
 /* Initialize iterating through all users with a user mask hint to the
index 507b49a85070c1db9d5c08468335fd451376278a..7221c79ccabd906136db98ef07746495951ab40b 100644 (file)
@@ -36,6 +36,8 @@ static void mail_user_deinit_base(struct mail_user *user)
                dict_deinit(&user->_attr_dict);
        }
        mail_namespaces_deinit(&user->namespaces);
+       if (user->_service_user != NULL)
+               mail_storage_service_user_unref(&user->_service_user);
 }
 
 static void mail_user_stats_fill_base(struct mail_user *user ATTR_UNUSED,
@@ -599,7 +601,10 @@ struct mail_user *mail_user_dup(struct mail_user *user)
 
        user2 = mail_user_alloc(user->username, user->set_info,
                                user->unexpanded_set);
-       user2->_service_user = user->_service_user;
+       if (user2->_service_user != NULL) {
+               user2->_service_user = user->_service_user;
+               mail_storage_service_user_ref(user2->_service_user);
+       }
        if (user->_home != NULL)
                mail_user_set_home(user2, user->_home);
        mail_user_set_vars(user2, user->service,