From: Brad Smith Subject: Re: dovecot, cherry-pick fixes from release-2.3 branch To: ports , sthen@openbsd.org Date: Fri, 31 Oct 2025 13:31:37 -0400 OK. On 2025-10-31 12:37 p.m., Stuart Henderson wrote: > There are a few crash fixes, etc, in Dovecot's release-2.3 branch, > https://github.com/dovecot/core/tree/release-2.3 > > According to https://marc.info/?l=dovecot&m=176191803628624&w=2 they > won't be making another 'community edition' release from there unless > there's a security issue (I guess these were mostly done for commercial > users) so this cherry-picks them as patches to the port. I skipped the > "add variables holding local/remote port numbers for mail_log_prefix" > commits. Also adds commit info for the existing replicator-queue.c fix. > > ok? > > Index: Makefile > =================================================================== > RCS file: /cvs/ports/mail/dovecot/Makefile,v > diff -u -p -r1.321 Makefile > --- Makefile 21 Jul 2025 16:51:21 -0000 1.321 > +++ Makefile 31 Oct 2025 16:21:33 -0000 > @@ -11,8 +11,7 @@ COMMENT-postgresql= PostgreSQL authentic > V_MAJOR= 2.3 > V_DOVECOT= 2.3.21.1 > EPOCH= 0 > -REVISION= 1 > -REVISION-postgresql= 2 > +REVISION= 3 > > DISTNAME= dovecot-${V_DOVECOT} > PKGNAME= dovecot-${V_DOVECOT} > Index: patches/patch-src_doveadm_doveadm-mail-save_c > =================================================================== > RCS file: patches/patch-src_doveadm_doveadm-mail-save_c > diff -N patches/patch-src_doveadm_doveadm-mail-save_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-src_doveadm_doveadm-mail-save_c 31 Oct 2025 16:21:33 -0000 > @@ -0,0 +1,22 @@ > +From 97791e1ea53fdff64bafef6ff572b237b41dbe3b Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 3 Jun 2024 22:46:51 +0300 > +Subject: [PATCH] doveadm save: Fix potential assert-crash if saving failed > + > +The input stream may not have been fully read at failure time. > + > +Fixes: > +Panic: file doveadm-mail-save.c: line 91 (cmd_save_to_mailbox): assertion failed: (input->eof) > + > +Index: src/doveadm/doveadm-mail-save.c > +--- src/doveadm/doveadm-mail-save.c.orig > ++++ src/doveadm/doveadm-mail-save.c > +@@ -77,7 +77,7 @@ cmd_save_to_mailbox(struct save_cmd_context *ctx, stru > + mailbox_save_cancel(&save_ctx); > + if (trans != NULL) > + mailbox_transaction_rollback(&trans); > +- i_assert(input->eof); > ++ i_assert(ret < 0 || input->eof); > + return ret < 0 ? -1 : 0; > + } > + > Index: patches/patch-src_imap-login_imap-login-cmd-id_c > =================================================================== > RCS file: patches/patch-src_imap-login_imap-login-cmd-id_c > diff -N patches/patch-src_imap-login_imap-login-cmd-id_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-src_imap-login_imap-login-cmd-id_c 31 Oct 2025 16:21:33 -0000 > @@ -0,0 +1,37 @@ > +From 1fd4fcc00335a0560e5686e17aceece7933f214d Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Fri, 6 Sep 2024 14:42:55 +0300 > +Subject: [PATCH] imap-login: Don't forward x-multiplex ID parameter when > + proxying > + > +If a connecting v2.4 proxy sends this parameter, it should be ignored rather > +than forwarded to the next hop, which again might be v2.4. This would end > +up enabling multiplex iostreams, even though this v2.3 proxy doesn't > +understand it. > + > +Index: src/imap-login/imap-login-cmd-id.c > +--- src/imap-login/imap-login-cmd-id.c.orig > ++++ src/imap-login/imap-login-cmd-id.c > +@@ -70,6 +70,14 @@ cmd_id_x_forward_(struct imap_client *client, > + client_add_forward_field(&client->common, key+10, value); > + } > + > ++static void > ++cmd_id_x_multiplex(struct imap_client *client ATTR_UNUSED, > ++ const char *key ATTR_UNUSED, const char *value ATTR_UNUSED) > ++{ > ++ /* ignore - registered here only so that it's not automatically > ++ forwarded by imap_id_retain=yes handling */ > ++} > ++ > + static const struct imap_id_param_handler imap_login_id_params[] = { > + { "x-originating-ip", FALSE, cmd_id_x_originating_ip }, > + { "x-originating-port", FALSE, cmd_id_x_originating_port }, > +@@ -79,6 +87,7 @@ static const struct imap_id_param_handler imap_login_i > + { "x-session-id", FALSE, cmd_id_x_session_id }, > + { "x-session-ext-id", FALSE, cmd_id_x_session_id }, > + { "x-forward-", TRUE, cmd_id_x_forward_ }, > ++ { "x-multiplex", FALSE, cmd_id_x_multiplex }, > + > + { NULL, FALSE, NULL } > + }; > Index: patches/patch-src_imap_cmd-idle_c > =================================================================== > RCS file: patches/patch-src_imap_cmd-idle_c > diff -N patches/patch-src_imap_cmd-idle_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-src_imap_cmd-idle_c 31 Oct 2025 16:21:33 -0000 > @@ -0,0 +1,32 @@ > +From 9a00369c8a09ccb2799dd6b3a4767947f5ace55a Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 14 Oct 2024 12:53:33 +0300 > +Subject: [PATCH] imap: Fix potential hang/crash when unhibernating > + > +This fixes two potential bugs: > + > +a) Unhibernation is triggered by new mailbox changes. While sending these > +to IMAP client, Dovecot notices that the client has disconnected. The > +process will stay IDLEing for 30 minutes until it gets disconnected with > +"Disconnected: Inactivity - no input for 1800 secs" > + > +b) Unhibernation is triggered by DONE command with some further pipelined > +commands. During unhibernation new mailbox changes are noticed, and > +again IMAP client is found to be disconnected while sending the changes. > +This causes a segfault. > + > +Index: src/imap/cmd-idle.c > +--- src/imap/cmd-idle.c.orig > ++++ src/imap/cmd-idle.c > +@@ -302,7 +302,9 @@ bool cmd_idle(struct client_command_context *cmd) > + > + /* check immediately if there are changes. if they came before we > + added mailbox-notifier, we wouldn't see them otherwise. */ > +- if (client->mailbox != NULL) > +- idle_sync_now(client->mailbox, ctx); > ++ if (client->mailbox != NULL) { > ++ if (idle_sync_now(client->mailbox, ctx)) > ++ return TRUE; > ++ } > + return idle_client_handle_input(ctx, FALSE); > + } > Index: patches/patch-src_lib-storage_index_dbox-multi_mdbox-map_c > =================================================================== > RCS file: patches/patch-src_lib-storage_index_dbox-multi_mdbox-map_c > diff -N patches/patch-src_lib-storage_index_dbox-multi_mdbox-map_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-src_lib-storage_index_dbox-multi_mdbox-map_c 31 Oct 2025 16:21:33 -0000 > @@ -0,0 +1,21 @@ > +From efdceaab8aa8c2443264b5cc2239e19c72904227 Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Wed, 20 Nov 2024 15:16:00 +0200 > +Subject: [PATCH] mdbox: Fix crash if resync fails because of an early failure > + > +This mainly happened if dovecot.map.index.log was locked and resync timed > +out waiting for it. > + > +Index: src/lib-storage/index/dbox-multi/mdbox-map.c > +--- src/lib-storage/index/dbox-multi/mdbox-map.c.orig > ++++ src/lib-storage/index/dbox-multi/mdbox-map.c > +@@ -537,7 +537,8 @@ void mdbox_map_atomic_set_success(struct mdbox_map_ato > + > + void mdbox_map_atomic_unset_fscked(struct mdbox_map_atomic_context *atomic) > + { > +- mail_index_unset_fscked(atomic->sync_trans); > ++ if (atomic->sync_trans != NULL) > ++ mail_index_unset_fscked(atomic->sync_trans); > + } > + > + int mdbox_map_atomic_finish(struct mdbox_map_atomic_context **_atomic) > Index: patches/patch-src_lib_istream-seekable_c > =================================================================== > RCS file: patches/patch-src_lib_istream-seekable_c > diff -N patches/patch-src_lib_istream-seekable_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-src_lib_istream-seekable_c 31 Oct 2025 16:21:33 -0000 > @@ -0,0 +1,157 @@ > +From 30b7e3cb5c7037a5a2d31096a75696d70c9c9f94 Mon Sep 17 00:00:00 2001 > +From: Markus Valentin > +Date: Tue, 3 Dec 2024 14:30:27 +0100 > +Subject: [PATCH] lib: istream-seekable - Remove unused define BUF_INITIAL_SIZE > + > +From 97791e1ea53fdff64bafef6ff572b237b41dbe3b Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 3 Jun 2024 22:46:51 +0300 > +Subject: [PATCH] doveadm save: Fix potential assert-crash if saving failed > + > +The input stream may not have been fully read at failure time. > + > +From 53c7113720fbf4768f6413fdfbb2e55bc778716d Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 3 Jun 2024 23:05:22 +0300 > +Subject: [PATCH] lib: istream-seekable - Fix moving stream to memory on > + write() failure > + > +Fixes: > +Panic: file istream-seekable.c: line 238 (read_from_buffer): assertion failed: (*ret_r > 0) > + > +From 6afc5b06a543c936aa428d758d7f8bad3f13fb66 Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 3 Jun 2024 23:23:40 +0300 > +Subject: [PATCH] lib: istream-seekable - Assert that write() won't return 0 > + > +From bc94afb46ad201af6c4a0e145ac07f8730973b01 Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 3 Jun 2024 23:28:23 +0300 > +Subject: [PATCH] lib: istream-seekable - Improve logging after write() errors > + > +Also don't silently handle out of disk space errors - log a warning instead. > + > +From 7fe2c39271b8e993632fd1b9a3ec95e031360f24 Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 3 Jun 2024 23:42:25 +0300 > +Subject: [PATCH] lib: istream-seekable - Allow in-memory fallback only for up > + to 10 MB streams > + > + > +Index: src/lib/istream-seekable.c > +--- src/lib/istream-seekable.c.orig > ++++ src/lib/istream-seekable.c > +@@ -13,13 +13,14 @@ > + > + #include > + > +-#define BUF_INITIAL_SIZE (1024*32) > ++#define MAX_MEMORY_FALLBACK_SIZE (1024*1024*10) > + > + struct seekable_istream { > + struct istream_private istream; > + > +- char *temp_path; > ++ char *temp_path, *write_failed_temp_path; > + uoff_t write_peak; > ++ int write_failed_errno; > + uoff_t size; > + size_t buffer_peak; > + > +@@ -63,6 +64,7 @@ static void i_stream_seekable_destroy(struct iostream_ > + if (sstream->free_context) > + i_free(sstream->context); > + i_free(sstream->temp_path); > ++ i_free(sstream->write_failed_temp_path); > + i_free(sstream->input); > + } > + > +@@ -194,6 +196,7 @@ static bool read_from_buffer(struct seekable_istream * > + /* This could be the first read() or we could have already > + seeked backwards. */ > + i_assert(stream->pos == 0 && stream->skip == 0); > ++ i_assert(sstream->buffer_peak >= stream->istream.v_offset); > + stream->skip = stream->istream.v_offset; > + stream->pos = sstream->buffer_peak; > + size = stream->pos - stream->skip; > +@@ -244,11 +247,12 @@ static int i_stream_seekable_write_failed(struct seeka > + struct istream_private *stream = &sstream->istream; > + void *data; > + size_t old_pos = stream->pos; > ++ int write_errno = errno; > + > + i_assert(sstream->fd != -1); > + i_assert(stream->skip == 0); > + > +- stream->max_buffer_size = SIZE_MAX; > ++ stream->max_buffer_size = MAX_MEMORY_FALLBACK_SIZE; > + stream->pos = 0; > + data = i_stream_alloc(stream, sstream->write_peak); > + stream->pos = old_pos; > +@@ -257,10 +261,11 @@ static int i_stream_seekable_write_failed(struct seeka > + sstream->istream.istream.stream_errno = errno; > + sstream->istream.istream.eof = TRUE; > + io_stream_set_error(&sstream->istream.iostream, > +- "istream-seekable: read(%s) failed: %m", > +- sstream->temp_path); > ++ "istream-seekable: write(%s) failed: %s, and attempt to read() it back failed: %m", > ++ sstream->temp_path, strerror(write_errno)); > + return -1; > + } > ++ sstream->buffer_peak = sstream->write_peak; > + i_stream_destroy(&sstream->fd_input); > + sstream->fd = -1; /* autoclosed by fd_input */ > + > +@@ -280,6 +285,17 @@ static ssize_t i_stream_seekable_read(struct istream_p > + if (read_from_buffer(sstream, &ret)) > + return ret; > + > ++ if (sstream->write_failed_errno != 0) { > ++ errno = sstream->write_failed_errno; > ++ sstream->istream.istream.stream_errno = errno; > ++ sstream->istream.istream.eof = TRUE; > ++ io_stream_set_error(&sstream->istream.iostream, > ++ "istream-seekable: write(%s) failed: %m - " > ++ "stream is too large for memory", > ++ sstream->write_failed_temp_path); > ++ return -1; > ++ } > ++ > + /* copy everything to temp file and use it as the stream */ > + if (copy_to_temp_file(sstream) < 0) { > + stream->max_buffer_size = SIZE_MAX; > +@@ -306,16 +322,31 @@ static ssize_t i_stream_seekable_read(struct istream_p > + > + /* save to our file */ > + data = i_stream_get_data(sstream->cur_input, &size); > ++ i_assert(size > 0); > + ret = write(sstream->fd, data, size); > +- if (ret <= 0) { > +- if (ret < 0 && !ENOSPACE(errno)) { > +- i_error("istream-seekable: write_full(%s) failed: %m", > ++ i_assert(ret != 0); > ++ if (ret < 0) { > ++ if (sstream->write_peak + size >= MAX_MEMORY_FALLBACK_SIZE) { > ++ sstream->istream.istream.stream_errno = errno; > ++ sstream->istream.istream.eof = TRUE; > ++ io_stream_set_error(&sstream->istream.iostream, > ++ "istream-seekable: write(%s) failed: %m", > + sstream->temp_path); > ++ return -1; > + } > ++ > ++ sstream->write_failed_errno = errno; > ++ sstream->write_failed_temp_path = > ++ i_strdup(sstream->temp_path); > + if (i_stream_seekable_write_failed(sstream) < 0) > + return -1; > + if (!read_from_buffer(sstream, &ret)) > + i_unreached(); > ++ > ++ errno = sstream->write_failed_errno; > ++ i_warning("istream-seekable: write_full(%s) failed: %m - " > ++ "fallback to using only memory", > ++ sstream->write_failed_temp_path); > + return ret; > + } > + i_stream_sync(sstream->fd_input); > Index: patches/patch-src_plugins_fts_fts-storage_c > =================================================================== > RCS file: patches/patch-src_plugins_fts_fts-storage_c > diff -N patches/patch-src_plugins_fts_fts-storage_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-src_plugins_fts_fts-storage_c 31 Oct 2025 16:21:33 -0000 > @@ -0,0 +1,18 @@ > +From 13061d620c1dd6952bbb7b0d4a7ae4f5e665b8d9 Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 9 Sep 2024 18:45:59 +0300 > +Subject: [PATCH] fts: Don't ignore parent mail_precache() failure > + > +Index: src/plugins/fts/fts-storage.c > +--- src/plugins/fts/fts-storage.c.orig > ++++ src/plugins/fts/fts-storage.c > +@@ -558,7 +558,8 @@ static int fts_mail_precache(struct mail *_mail) > + struct fts_transaction_context *ft = FTS_CONTEXT_REQUIRE(_mail->transaction); > + int ret = 0; > + > +- fmail->module_ctx.super.precache(_mail); > ++ if (fmail->module_ctx.super.precache(_mail) < 0) > ++ return -1; > + if (fmail->virtual_mail) { > + if (ft->highest_virtual_uid < _mail->uid) > + ft->highest_virtual_uid = _mail->uid; > Index: patches/patch-src_plugins_virtual_virtual-mail_c > =================================================================== > RCS file: patches/patch-src_plugins_virtual_virtual-mail_c > diff -N patches/patch-src_plugins_virtual_virtual-mail_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-src_plugins_virtual_virtual-mail_c 31 Oct 2025 16:21:33 -0000 > @@ -0,0 +1,21 @@ > +From 4eb23fdf2d285d710dc1f70b5158dbc6ffef48aa Mon Sep 17 00:00:00 2001 > +From: Timo Sirainen > +Date: Mon, 9 Sep 2024 18:46:56 +0300 > +Subject: [PATCH] virtual: Fix copying storage error on mail_precache() failure > + > +Index: src/plugins/virtual/virtual-mail.c > +--- src/plugins/virtual/virtual-mail.c.orig > ++++ src/plugins/virtual/virtual-mail.c > +@@ -240,7 +240,11 @@ static int virtual_mail_precache(struct mail *mail) > + if (backend_mail_get(vmail, &backend_mail) < 0) > + return -1; > + p = (struct mail_private *)backend_mail; > +- return p->v.precache(backend_mail); > ++ if (p->v.precache(backend_mail) < 0) { > ++ virtual_box_copy_error(mail->box, backend_mail->box); > ++ return -1; > ++ } > ++ return 0; > + } > + > + static void > Index: patches/patch-src_replication_replicator_replicator-queue_c > =================================================================== > RCS file: /cvs/ports/mail/dovecot/patches/patch-src_replication_replicator_replicator-queue_c,v > diff -u -p -r1.1 patch-src_replication_replicator_replicator-queue_c > --- patches/patch-src_replication_replicator_replicator-queue_c 5 Oct 2024 07:35:54 -0000 1.1 > +++ patches/patch-src_replication_replicator_replicator-queue_c 31 Oct 2025 16:21:33 -0000 > @@ -1,5 +1,10 @@ > -replicator: fixed infinity loop on sync replication > -https://github.com/dovecot/core/pull/223 > +From d3a097075afb7b5d8955978ed4a2ae99add11f88 Mon Sep 17 00:00:00 2001 > +From: "Kirill A. Korinsky" > +Date: Wed, 25 Sep 2024 18:30:52 +0200 > +Subject: [PATCH] replicator: fixed infinity loop on sync replication > + > +Before this fix, replicator adds the same lookup into callbacks over and > +over, until it reaches out of memory, and crashes. > > Index: src/replication/replicator/replicator-queue.c > --- src/replication/replicator/replicator-queue.c.orig >