]> dgit.raspbian.org Git - dovecot.git/log
dovecot.git
8 days agoMerge version 1:2.4.1+dfsg1-6+rpi1+deb13u6 and 1:2.4.1+dfsg1-6+deb13u7 to produce... trixie-staging archive/raspbian/1%2.4.1+dfsg1-6+rpi1+deb13u7 raspbian/1%2.4.1+dfsg1-6+rpi1+deb13u7
Raspbian automatic forward porter [Fri, 2 Oct 2026 09:09:32 +0000 (10:09 +0100)]
Merge version 1:2.4.1+dfsg1-6+rpi1+deb13u6 and 1:2.4.1+dfsg1-6+deb13u7 to produce 1:2.4.1+dfsg1-6+rpi1+deb13u7

3 weeks agoMerge dovecot (1:2.4.1+dfsg1-6+deb13u7) import into refs/heads/workingbranch
Noah Meyerhans [Wed, 16 Sep 2026 19:06:35 +0000 (15:06 -0400)]
Merge dovecot (1:2.4.1+dfsg1-6+deb13u7) import into refs/heads/workingbranch

3 weeks ago[PATCH 2/2] login-common: Avoid array_front() panic on empty forward_fields array
Timo Sirainen [Sun, 3 May 2026 16:24:38 +0000 (16:24 +0000)]
[PATCH 2/2] login-common: Avoid array_front() panic on empty forward_fields array

sasl_server_auth_request_info_fill() and proxy_redirect_reauth()
NUL-terminate the forward_fields array via array_append_zero() +
array_pop_back() and then call array_front() to hand the C array to
the auth client. array_front() asserts when the array is empty, so a
created-but-empty forward_fields array crashes login.

The empty-array case is no longer reachable from
client_forward_decode_base64() after the previous commit, but guard
defensively here as well: any future caller that creates the array
without populating it should not be able to panic the process.

Gbp-Pq: Name 0002-login-common-Avoid-array_front-panic-on-empty-forwar.patch

3 weeks ago[PATCH 1/2] login-common: Fix crash when XCLIENT FORWARD= base64 contains NUL byte
Timo Sirainen [Sun, 3 May 2026 16:20:00 +0000 (16:20 +0000)]
[PATCH 1/2] login-common: Fix crash when XCLIENT FORWARD= base64 contains NUL byte

Sending "XCLIENT FORWARD=AA==" (base64 for a single NUL byte) followed
by a regular login crashed pop3-login (and other login services) with:

  Panic: file ../../src/lib/array.h: line 275 (array_idx_i):
  assertion failed: (idx < array->buffer->used / array->element_size)

p_strsplit_tabescaped() truncates at the first NUL, so an all-NUL
payload produced an empty fields list. forward_fields was still
created (but empty), and the later array_front() call in
sasl_server_auth_begin() then panicked on the empty array.

Reject empty payloads and payloads containing NUL bytes during base64
decode, so the array is never created in this case.

Gbp-Pq: Name 0001-login-common-Fix-crash-when-XCLIENT-FORWARD-base64-c.patch

3 weeks ago[PATCH 2/2] doveadm: Avoid leaking doveadm_password or doveadm_api_key lengths
Timo Sirainen [Mon, 27 Apr 2026 22:51:01 +0000 (01:51 +0300)]
[PATCH 2/2] doveadm: Avoid leaking doveadm_password or doveadm_api_key lengths

Gbp-Pq: Name 0002-doveadm-Avoid-leaking-doveadm_password-or-doveadm_ap.patch

3 weeks ago[PATCH 1/2] lib: Add str_equals_timing_safe()
Timo Sirainen [Mon, 27 Apr 2026 22:50:56 +0000 (01:50 +0300)]
[PATCH 1/2] lib: Add str_equals_timing_safe()

Constant-time string comparison that avoids the length leak in
str_equals_timing_almost_safe(). Compares HMAC-SHA256 digests of the
inputs (keyed with hash_iv) rather than the strings themselves, so
neither the contents nor the length of either input affects timing in
a way an attacker can exploit.

Gbp-Pq: Name 0001-lib-Add-str_equals_timing_safe.patch

3 weeks ago[PATCH] lib-imap-urlauth: Fix leaking uninitialized memory into client error message
Timo Sirainen [Wed, 6 May 2026 14:53:41 +0000 (14:53 +0000)]
[PATCH] lib-imap-urlauth: Fix leaking uninitialized memory into client error message

imap_urlauth_fetch_parsed() called imap_msgpart_url_open_mailbox() with
client_error_r and then, on the ret==0 (mailbox-not-found) branch,
formatted a separate uninitialized local "error" pointer with
t_strdup_printf("Invalid URLAUTH: %s", error). The %s read process
stack memory until a NUL byte and sent it to the authenticated IMAP
client inside the "* NO Failed to fetch URLAUTH ..." response.

Broken by bb193c273e63ffa42c5c0b51ecd8860398e3beab

Gbp-Pq: Name 0001-lib-imap-urlauth-Fix-leaking-uninitialized-memory-in.patch

3 weeks ago[PATCH 2/2] auth: Fix prefixing forward_fields without a value from client
Markus Valentin [Thu, 23 Apr 2026 11:07:08 +0000 (13:07 +0200)]
[PATCH 2/2] auth: Fix prefixing forward_fields without a value from client

Bare tokens (without '=') were not prefixed, only key=value pairs were.
In practice this affected forward_fields, where a bare token such as
'nopassword' would land in extra_fields unprefixed instead of as
'forward_nopassword', allowing injection of internal auth control fields.

Gbp-Pq: Name 0002-auth-Fix-prefixing-forward_fields-without-a-value-fr.patch

3 weeks ago[PATCH 1/2] submission: Fix settings leak on error paths in client_create_from_input()
Markus Valentin [Thu, 23 Apr 2026 10:53:07 +0000 (12:53 +0200)]
[PATCH 1/2] submission: Fix settings leak on error paths in client_create_from_input()

Gbp-Pq: Name 0001-submission-Fix-settings-leak-on-error-paths-in-clien.patch

3 weeks ago[PATCH 6/6] imap: Reset DEFLATE dictionary after every tagged reply
Timo Sirainen [Thu, 16 Apr 2026 15:38:53 +0000 (17:38 +0200)]
[PATCH 6/6] imap: Reset DEFLATE dictionary after every tagged reply

Prevents CRIME-style cross-command compression oracle attacks
(CVE-class: compression side-channel).  Without this fix an observer
who can inject chosen plaintext into one IMAP command's response can
measure the compressed size of a subsequent command's response and
determine whether the secret content matches the injected plaintext.

After each tagged response line is sent, the DEFLATE compression
dictionary is reset via Z_FULL_FLUSH so that the compression history
from one command cannot influence the compressed size of the next.

For direct compression (imap_compress_on_proxy=no) the reset is applied
to the local ostream.  For proxy-mode compression
(imap_compress_on_proxy=yes) a "dict_reset" command is sent over the
multiplex side channel to the imap-login process.

Gbp-Pq: Name 0006-imap-Reset-DEFLATE-dictionary-after-every-tagged-rep.patch

3 weeks ago[PATCH 5/6] imap: Add imap_compress_on_proxy hidden setting
Timo Sirainen [Wed, 4 Jun 2025 14:05:36 +0000 (17:05 +0300)]
[PATCH 5/6] imap: Add imap_compress_on_proxy hidden setting

Keep it disabled by default for now. Once we're sure COMPRESS on proxy
works properly we'll enable it again.

Gbp-Pq: Name 0005-imap-Add-imap_compress_on_proxy-hidden-setting.patch

3 weeks ago[PATCH 4/5] imap-login: Add dict_reset side-channel command to imap-proxy
Timo Sirainen [Thu, 16 Apr 2026 15:38:45 +0000 (17:38 +0200)]
[PATCH 4/5] imap-login: Add dict_reset side-channel command to imap-proxy

When imap_compress_on_proxy is enabled, DEFLATE compression runs inside
the imap-login process.  The imap backend process cannot call
o_stream_deflate_reset_dict() directly on a remote stream, so this adds
a new side-channel command "dict_reset" that the backend can send to
trigger the dictionary reset on the proxy side.

Gbp-Pq: Name 0004-imap-login-Add-dict_reset-side-channel-command-to-im.patch

3 weeks ago[PATCH 3/5] lib-compression: Add o_stream_deflate_reset_dict()
Timo Sirainen [Thu, 16 Apr 2026 15:38:41 +0000 (17:38 +0200)]
[PATCH 3/5] lib-compression: Add o_stream_deflate_reset_dict()

New public function that locates the deflate ostream in the parent chain
(transparently handles rawlog wrappers) and schedules a Z_FULL_FLUSH on
the next uncork/flush.  Z_FULL_FLUSH emits all buffered data and then
resets the deflate dictionary, so subsequent compressed output cannot
reference data from before the call.

Adds a pending_dict_reset flag to struct zlib_ostream.  The flag persists
through partial flush retries and is cleared only once the full flush
loop completes.

Gbp-Pq: Name 0003-lib-compression-Add-o_stream_deflate_reset_dict.patch

3 weeks ago[PATCH 2/5] imap: Recreate multiplex ostream side channel after unhibernation
Timo Sirainen [Fri, 1 May 2026 17:40:17 +0000 (17:40 +0000)]
[PATCH 2/5] imap: Recreate multiplex ostream side channel after unhibernation

This will be needed by the following changes to send dict_reset commands via
the side channel.

Gbp-Pq: Name 0002-imap-Recreate-multiplex-ostream-side-channel-after-u.patch

3 weeks ago[PATCH 1/5] imap: Extract side-channel ostream creation into helper
Timo Sirainen [Fri, 1 May 2026 17:40:08 +0000 (17:40 +0000)]
[PATCH 1/5] imap: Extract side-channel ostream creation into helper

Add client_create_side_channel_output() and use it in cmd_compress()
in place of the inline channel-creation code. The helper will also be
used by the imap state import path to recreate the side channel after
unhibernation. No functional change.

Gbp-Pq: Name 0001-imap-Extract-side-channel-ostream-creation-into-help.patch

3 weeks ago[PATCH 2/2] dsync: Fix escaping mail or attribute value that begins with a "." line
Timo Sirainen [Tue, 24 Mar 2026 10:03:08 +0000 (12:03 +0200)]
[PATCH 2/2] dsync: Fix escaping mail or attribute value that begins with a "." line

Such a mail or attribute would have escaped the value parameter and the rest
of the value would have been processed as dsync stream commands.

Gbp-Pq: Name 0002-dsync-Fix-escaping-mail-or-attribute-value-that-begi.patch

3 weeks ago[PATCH 1/2] dsync: Avoid potentially excessive data stack growth for mailbox attribut...
Timo Sirainen [Tue, 24 Mar 2026 10:02:00 +0000 (12:02 +0200)]
[PATCH 1/2] dsync: Avoid potentially excessive data stack growth for mailbox attribute sending

The attribute value can be large.

Gbp-Pq: Name 0001-dsync-Avoid-potentially-excessive-data-stack-growth-.patch

3 weeks ago[PATCH] *-login: Add LOGIN_PROXY_FAILURE_TYPE_AUTH_NOT_REPLIED
Timo Sirainen [Fri, 18 Jul 2025 11:28:47 +0000 (14:28 +0300)]
[PATCH] *-login: Add LOGIN_PROXY_FAILURE_TYPE_AUTH_NOT_REPLIED

Gbp-Pq: Name 0001-login-Add-LOGIN_PROXY_FAILURE_TYPE_AUTH_NOT_REPLIED.patch

3 weeks agomanagesieve-login-Support-LOGIN_PROXY_FAILURE_TYPE_A
Dovecot Maintainers [Wed, 16 Sep 2026 19:06:35 +0000 (15:06 -0400)]
managesieve-login-Support-LOGIN_PROXY_FAILURE_TYPE_A

===================================================================

Gbp-Pq: Name 0001-managesieve-login-Support-LOGIN_PROXY_FAILURE_TYPE_A.patch

3 weeks ago[PATCH 5/5] submission-login: submission-proxy - Recognize 421 4.7.0 as connection...
Timo Sirainen [Thu, 7 May 2026 10:58:24 +0000 (10:58 +0000)]
[PATCH 5/5] submission-login: submission-proxy - Recognize 421 4.7.0 as connection-limit reply

When the backend signals that the user's connection limit has been
reached, do not classify the response as a generic temporary
authentication failure (which causes the proxy to reconnect). Map it
instead to LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED, which
suppresses retries and reports the failure as proxy_dest_connection_limit
in the login_aborted event/log line. This mirrors what imap-login does
for the [LIMIT] response code and pop3-login for [IN-USE].

Other 421 replies (typically server shutdown / fatal error) are mapped
to LOGIN_PROXY_FAILURE_TYPE_AUTH_REPLIED rather than AUTH_TEMPFAIL: 421
means "closing transmission channel" (RFC 5321 Section 4.2.1), so a
reconnect on the same destination is unlikely to help and should not
happen automatically.

Gbp-Pq: Name 0005-submission-login-submission-proxy-Recognize-421-4.7..patch

3 weeks ago[PATCH] login-common, *-login: Add proxy_dest_connection_limit error_code to proxy_se...
Timo Sirainen [Wed, 3 Dec 2025 10:06:42 +0000 (12:06 +0200)]
[PATCH] login-common, *-login: Add proxy_dest_connection_limit error_code to proxy_session_finished

If IMAP backend returns with [LIMIT] or POP3 backend returns with [IN-USE],
use this error code rather than the generic proxy_dest_auth_failed.
Error messages are also updated.

Gbp-Pq: Name 0001-login-common-login-Add-proxy_dest_connection_limit-e.patch

3 weeks agomanagesieve-login-Adjust-to-core-s-login_proxy_failu
Dovecot Maintainers [Wed, 16 Sep 2026 19:06:35 +0000 (15:06 -0400)]
managesieve-login-Adjust-to-core-s-login_proxy_failu

===================================================================

Gbp-Pq: Name 0001-managesieve-login-Adjust-to-core-s-login_proxy_failu.patch

3 weeks ago[PATCH] *-commin: Rename LOGIN_PROXY_FAILURE_TYPE_AUTH to LOGIN_PROXY_FAILURE_TYPE_AU...
Timo Sirainen [Fri, 18 Jul 2025 11:26:21 +0000 (14:26 +0300)]
[PATCH] *-commin: Rename LOGIN_PROXY_FAILURE_TYPE_AUTH to LOGIN_PROXY_FAILURE_TYPE_AUTH_REPLIED

Gbp-Pq: Name 0001-commin-Rename-LOGIN_PROXY_FAILURE_TYPE_AUTH-to-LOGIN.patch

3 weeks ago[PATCH 4/5] submission-login: client-authenticate - Reply 421 4.7.0 on mail_max_useri...
Timo Sirainen [Thu, 7 May 2026 10:58:12 +0000 (10:58 +0000)]
[PATCH 4/5] submission-login: client-authenticate - Reply 421 4.7.0 on mail_max_userip_connections

Until now the connection limit was reported via the same 454 4.7.0 reply
that is used for generic temporary authentication failures. That makes
proxies (including Dovecot's own submission proxy) treat the rejection as
a transient auth error and retry, which is futile when the limit is hit
and only obscures the actual cause in the proxy log.

Reply with 421 4.7.0 instead. RFC 5321 Section 4.2.1 specifies 421 as
"service shutting down, closing transmission channel", which is the
right signal for "do not retry on this connection". The 421 + 4.7.0
combination is unique among the 421 replies emitted by submission and is
used by the submission proxy to recognize this specifically as a
connection-limit reply rather than a generic 421 internal/shutdown.

Gbp-Pq: Name 0004-submission-login-client-authenticate-Reply-421-4.7.0.patch

3 weeks ago[PATCH 3/5] lib-smtp: smtp-server - Expose smtp_server_connection_reply_immediate
Timo Sirainen [Thu, 7 May 2026 10:57:59 +0000 (10:57 +0000)]
[PATCH 3/5] lib-smtp: smtp-server - Expose smtp_server_connection_reply_immediate

The function already existed internally as a way to write a reply directly
to the output stream, bypassing the per-command reply queue. Make it part
of the public API so callers that need a reply on the wire before tearing
the connection down (where queued replies would otherwise be aborted) can
use it.

Gbp-Pq: Name 0003-lib-smtp-smtp-server-Expose-smtp_server_connection_r.patch

3 weeks ago[PATCH 2/5] submission-login: client - Fix panic occurring at mail_max_userip_connect...
Stephan Bosch [Fri, 28 Nov 2025 03:12:10 +0000 (04:12 +0100)]
[PATCH 2/5] submission-login: client - Fix panic occurring at mail_max_userip_connections limit transgression

Panic was:
Panic: epoll_ctl(del, 8) failed: Bad file descriptor

Fixed by making sure the underlying smtp-server connection is always closed before the connection FD is closed.

Gbp-Pq: Name 0002-submission-login-client-Fix-panic-occurring-at-mail_.patch

3 weeks ago[PATCH 1/5] login-common: client-common - Add client_disconnect() vfunc
Stephan Bosch [Fri, 28 Nov 2025 02:32:36 +0000 (03:32 +0100)]
[PATCH 1/5] login-common: client-common - Add client_disconnect() vfunc

Gbp-Pq: Name 0001-login-common-client-common-Add-client_disconnect-vfu.patch

3 weeks ago[PATCH 3/3] lib-sieve: edit_mail_headers_parse() - Fix info leak via NUL-truncated...
Timo Sirainen [Fri, 1 May 2026 06:28:33 +0000 (06:28 +0000)]
[PATCH 3/3] lib-sieve: edit_mail_headers_parse() - Fix info leak via NUL-truncated header copy

i_strndup() stops at the first NUL byte, so embedded NULs caused field->data
to be shorter than field->size. This left stale heap data readable past the
copied content when callers treat data+body_offset as a string.

Adds a test-edit-mail unit test and a sieve testsuite case that both
exercise edit_mail_headers_parse() with a NUL byte embedded in a header
value. The unit test memcmp-verifies that the bytes after the NUL are
preserved; the sieve test triggers an invalid heap read detectable by
valgrind under the old code.

Gbp-Pq: Name 0003-lib-sieve-edit_mail_headers_parse-Fix-info-leak-via-.patch

3 weeks ago[PATCH 2/3] lib-sieve: util: test-edit-mail - Adjust to changes in dovecot core lib...
Stephan Bosch [Wed, 29 Oct 2025 16:49:10 +0000 (17:49 +0100)]
[PATCH 2/3] lib-sieve: util: test-edit-mail - Adjust to changes in dovecot core lib-test

Gbp-Pq: Name 0002-lib-sieve-util-test-edit-mail-Adjust-to-changes-in-d.patch

3 weeks ago[PATCH 1/3] lib-sieve: util: edit-mail - Fix writing to freed memory
Timo Sirainen [Tue, 14 Apr 2026 10:58:08 +0000 (12:58 +0200)]
[PATCH 1/3] lib-sieve: util: edit-mail - Fix writing to freed memory

Gbp-Pq: Name 0001-lib-sieve-util-edit-mail-Fix-writing-to-freed-memory.patch

3 weeks ago[PATCH 12/12] config: doveconf -dF - Add dovecot_storage_version
Timo Sirainen [Wed, 9 Apr 2025 11:11:42 +0000 (14:11 +0300)]
[PATCH 12/12] config: doveconf -dF - Add dovecot_storage_version

Gbp-Pq: Name 0012-config-doveconf-dF-Add-dovecot_storage_version.patch

3 weeks ago[PATCH 11/12] lib, lib-master: Move version_*() to lib/version.[ch]
Timo Sirainen [Sun, 5 Oct 2025 15:49:13 +0000 (18:49 +0300)]
[PATCH 11/12] lib, lib-master: Move version_*() to lib/version.[ch]

Gbp-Pq: Name 0011-lib-lib-master-Move-version_-to-lib-version.-ch.patch

3 weeks ago[PATCH 10/12] lib-master: Move config_version_find() from src/config/config-parser.c
Timo Sirainen [Fri, 1 May 2026 16:56:21 +0000 (16:56 +0000)]
[PATCH 10/12] lib-master: Move config_version_find() from src/config/config-parser.c

Rename to dovecot_config_version_find() and expose it via
master-service-settings.h so non-config callers (e.g. the upcoming
dovecot_storage_version validation in master_service_settings_check())
can share the same supported-versions list. No behaviour change.

Gbp-Pq: Name 0010-lib-master-Move-config_version_find-from-src-config-.patch

3 weeks ago[PATCH 09/12] config: Assume dovecot_config_version=0.0.0 is the same as the latest...
Timo Sirainen [Mon, 29 Sep 2025 11:09:42 +0000 (14:09 +0300)]
[PATCH 09/12] config: Assume dovecot_config_version=0.0.0 is the same as the latest version

It's used for git builds.

Gbp-Pq: Name 0009-config-Assume-dovecot_config_version-0.0.0-is-the-sa.patch

3 weeks ago[PATCH 08/12] doveadm: Fix ubsan unsigned integer overflow error
Timo Sirainen [Thu, 16 Apr 2026 11:27:42 +0000 (13:27 +0200)]
[PATCH 08/12] doveadm: Fix ubsan unsigned integer overflow error

Gbp-Pq: Name 0008-doveadm-Fix-ubsan-unsigned-integer-overflow-error.patch

3 weeks ago[PATCH 07/12] lib-index: Add keyed xxh64 strmap format v2, gated by config version
Timo Sirainen [Thu, 30 Apr 2026 12:11:57 +0000 (12:11 +0000)]
[PATCH 07/12] lib-index: Add keyed xxh64 strmap format v2, gated by config version

The on-disk hash stored in the strmap file is now optionally a keyed
xxh64_to_32() with a per-file random 64-bit IV stored in the file
header.  This replaces the previous plain crc32_str_nonzero() output
and hardens the strmap against deliberately-collided message-id
hashes.  The v1 (crc32) format remains fully readable and writable
so older configurations keep working without forced rebuilds.

On-disk:
 - v1 header is 8 bytes: version, 3 unused, uid_validity (unchanged).
 - v2 header is 16 bytes: version, compat_flags, 2 unused, uid_validity,
   hash_iv.  The first 8 bytes of v2 align with v1 byte-for-byte, so
   the open path reads 8 bytes, dispatches on version, and reads the
   trailing 8 bytes only for v2.

Runtime:
 - strmap->enable_xxh64 selects the format used when creating a new
   file (or recreating one whose uid_validity has changed).
 - view->format_version follows the on-disk file when one exists; for
   fresh files it follows the strmap-wide preference.
 - Renumber recreate_write() preserves view->format_version, so we
   never silently migrate an existing file across the threshold while
   it is still in use - the migration only happens at open time.
 - When enable_xxh64 is TRUE and the on-disk file is v1, open treats
   it as a version mismatch: the file is unlinked and the next sync's
   recreate_write() produces a v2 file.  Below the threshold v1 stays
   v1 indefinitely.
 - strmap_hash_str() dispatches per-view, so v1 files keep using
   crc32 hashes and v2 files use keyed xxh64 even in mixed setups.

Gbp-Pq: Name 0007-lib-index-Add-keyed-xxh64-strmap-format-v2-gated-by-.patch

3 weeks ago[PATCH 06/12] lib-index: Rename crc32 variables/parameters to hash in strmap
Timo Sirainen [Mon, 13 Apr 2026 10:52:15 +0000 (12:52 +0200)]
[PATCH 06/12] lib-index: Rename crc32 variables/parameters to hash in strmap

Pure rename - no functional change. The stored 32-bit value is still
produced by crc32_str_nonzero(); only the identifiers change to prepare
for swapping the hash algorithm in the next commit.

recs_crc32 -> recs_hash, hash_key.crc32 -> hash_key.hash,
crc32_r -> hash_r, local crc32 -> hash, *crc32 -> *hashes.

Gbp-Pq: Name 0006-lib-index-Rename-crc32-variables-parameters-to-hash-.patch

3 weeks ago[PATCH 05/12] lib-index: mail-index-strmap - Fix OOB read from truncated record size
Aki Tuomi [Mon, 17 Aug 2026 08:13:18 +0000 (11:13 +0300)]
[PATCH 05/12] lib-index: mail-index-strmap - Fix OOB read from truncated record size

Gbp-Pq: Name 0005-lib-index-mail-index-strmap-Fix-OOB-read-from-trunca.patch

3 weeks ago[PATCH 04/12] lib: Key str_hash/strcase_hash with a random seed to prevent HashDoS
Timo Sirainen [Mon, 13 Apr 2026 10:38:50 +0000 (12:38 +0200)]
[PATCH 04/12] lib: Key str_hash/strcase_hash with a random seed to prevent HashDoS

hash_init() fills a process-wide uint64_t hash_iv via random_fill()
at lib_init() time (after random_init()). str_hash() and strcase_hash()
pass hash_iv as the xxh64 seed so an attacker cannot predict bucket
placement and manufacture collision chains.

Gbp-Pq: Name 0004-lib-Key-str_hash-strcase_hash-with-a-random-seed-to-.patch

3 weeks ago[PATCH 03/12] lib: Add str_stable_hash()
Timo Sirainen [Mon, 13 Apr 2026 15:20:46 +0000 (17:20 +0200)]
[PATCH 03/12] lib: Add str_stable_hash()

For now this is the same as str_hash(), but this is changed in a following
commit.

Gbp-Pq: Name 0003-lib-Add-str_stable_hash.patch

3 weeks ago[PATCH 02/12] lib: Replace str_hash/strcase_hash with xxh64
Timo Sirainen [Mon, 13 Apr 2026 10:33:51 +0000 (12:33 +0200)]
[PATCH 02/12] lib: Replace str_hash/strcase_hash with xxh64

Replaces the old ASU-derived shift-and-XOR hash with xxh64_to_32(),
which provides better distribution and avalanche properties.
strcase_hash feeds each i_toupper()'d byte through the streaming API.

Gbp-Pq: Name 0002-lib-Replace-str_hash-strcase_hash-with-xxh64.patch

3 weeks ago[PATCH] lib: xxh64: fix byte ordering bug on big-endian systems
Noah Meyerhans [Wed, 2 Sep 2026 01:12:51 +0000 (21:12 -0400)]
[PATCH] lib: xxh64: fix byte ordering bug on big-endian systems

Convert from little-endian to host byte order where necessary.

Background at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1146449

Gbp-Pq: Name 0001-lib-xxh64-fix-byte-ordering-bug-on-big-endian-system.patch

3 weeks ago[PATCH 01/12] lib: Add XXH64 hash implementation
Timo Sirainen [Mon, 13 Apr 2026 10:30:03 +0000 (12:30 +0200)]
[PATCH 01/12] lib: Add XXH64 hash implementation

Adds a streaming XXH64 (non-cryptographic) hash with init/loop/result
API, a one-shot xxh64_data(), and an xxh64_to_32() XOR-fold inline.
Registered in hash_methods[] for use via the generic hash_method API.

Gbp-Pq: Name 0001-lib-Add-XXH64-hash-implementation.patch

3 weeks ago[PATCH 2/2] imap-hibernate: Use imap-parser API for parsing DONE command
Timo Sirainen [Wed, 22 Apr 2026 09:58:56 +0000 (12:58 +0300)]
[PATCH 2/2] imap-hibernate: Use imap-parser API for parsing DONE command

Replace the ad-hoc DONE/IDLE tokenizer with imap-parser.h: use
imap_parser_read_tag() to read the tag and imap_parser_read_word() to
read the DONE and IDLE keywords. This delegates bounds checks and
character validation to the shared parser.

Gbp-Pq: Name 0002-imap-hibernate-Use-imap-parser-API-for-parsing-DONE-.patch

3 weeks ago[PATCH 1/2] imap-hibernate: Fix out-of-bounds read when parsing DONE command tag
Timo Sirainen [Thu, 16 Apr 2026 21:12:13 +0000 (23:12 +0200)]
[PATCH 1/2] imap-hibernate: Fix out-of-bounds read when parsing DONE command tag

The tag-skipping loop was missing a size>0 guard, so a malformed
DONE command with no space/CR/tab terminator after the tag would
read one byte past the end of the buffer. Also add a \0 check to
stop on embedded null bytes, which are not valid tag characters.

Gbp-Pq: Name 0001-imap-hibernate-Fix-out-of-bounds-read-when-parsing-D.patch

3 weeks ago[PATCH 2/2] managesieve-login: client_skip_line() - Discard data when newline is...
Aki Tuomi [Mon, 25 May 2026 10:38:13 +0000 (10:38 +0000)]
[PATCH 2/2] managesieve-login: client_skip_line() - Discard data when newline is not found

Without this, data without a newline (e.g., from a lone CR protocol violation
detected by the parser) stays in the buffer indefinitely. This prevents the
server from ever detecting client disconnect, causing a deadlock where both
sides wait for the other.

The post-login server-side client_skip_line() in managesieve-client.c already
handles this correctly by always calling i_stream_skip().

Gbp-Pq: Name 0002-managesieve-login-client_skip_line-Discard-data-when.patch

3 weeks ago[PATCH 1/2] lib-managesieve: managesieve-parser - Fix handling of lone CR character
Stephan Bosch [Sat, 11 Apr 2026 12:12:08 +0000 (14:12 +0200)]
[PATCH 1/2] lib-managesieve: managesieve-parser - Fix handling of lone CR character

Gbp-Pq: Name 0001-lib-managesieve-managesieve-parser-Fix-handling-of-l.patch

3 weeks ago[PATCH] lib-sieve: sieve-binary-code - Fix single byte oob stack buffer write in...
Stephan Bosch [Fri, 10 Apr 2026 00:27:17 +0000 (02:27 +0200)]
[PATCH] lib-sieve: sieve-binary-code - Fix single byte oob stack buffer write in sieve_binary_emit_integer()

Gbp-Pq: Name 0001-lib-sieve-sieve-binary-code-Fix-single-byte-oob-stac.patch

3 weeks ago[PATCH 3/3] lib-storage: thread - Limit ancestor chain traversal depth to prevent...
Timo Sirainen [Fri, 17 Apr 2026 13:15:54 +0000 (13:15 +0000)]
[PATCH 3/3] lib-storage: thread - Limit ancestor chain traversal depth to prevent O(N^2) CPU usage

The per-message References limit (MAIL_THREAD_REFERENCES_MAX) prevents a
single crafted message from causing O(N^2) traversals in
thread_node_has_ancestor(). However, multiple crafted messages each
containing 1000 References entries can build an arbitrarily deep ancestor
chain across the mailbox, causing the same quadratic blowup spread over
many messages: processing email k costs O(k * MAIL_THREAD_REFERENCES_MAX)
steps, giving O(M^2 * MAIL_THREAD_REFERENCES_MAX) total for M emails.

Fix this by limiting the traversal depth in thread_node_has_ancestor() to
MAIL_THREAD_REFERENCES_MAX steps. When the limit is reached the link is
dropped, bounding per-email work to O(MAIL_THREAD_REFERENCES_MAX^2)
regardless of how deep the chain was built by prior messages.

Gbp-Pq: Name 0003-lib-storage-thread-Limit-ancestor-chain-traversal-de.patch

3 weeks ago[PATCH 2/3] lib-storage: thread - Limit References: header msgid count to prevent...
Timo Sirainen [Thu, 16 Apr 2026 16:26:47 +0000 (16:26 +0000)]
[PATCH 2/3] lib-storage: thread - Limit References: header msgid count to prevent O(N^2) CPU usage

Cap per-message References ingestion at MAIL_THREAD_REFERENCES_MAX (1000)
in mail_thread_map_add_mail(). Without this limit a single crafted email
with N unique Message-IDs triggers N(N-1)/2 ancestor traversals in
thread_node_has_ancestor(), allowing unauthenticated DoS via mail delivery.

Gbp-Pq: Name 0002-lib-storage-thread-Limit-References-header-msgid-cou.patch

3 weeks ago[PATCH 1/3] lib-storage: thread - Avoid excessive data stack growth with many Referen...
Timo Sirainen [Mon, 13 Apr 2026 15:28:43 +0000 (17:28 +0200)]
[PATCH 1/3] lib-storage: thread - Avoid excessive data stack growth with many References msgids

Gbp-Pq: Name 0001-lib-storage-thread-Avoid-excessive-data-stack-growth.patch

3 weeks ago[PATCH 14/14] lib-mail: Limit total MIME parameter count per message to 200 000
Timo Sirainen [Fri, 17 Apr 2026 13:57:24 +0000 (15:57 +0200)]
[PATCH 14/14] lib-mail: Limit total MIME parameter count per message to 200 000

Content-Type and Content-Disposition parameters are both parsed through
parse_mime_parameters().  A message with many MIME parts each having many
parameters can accumulate millions of struct message_part_param entries.

Add remaining_mime_params to struct message_part_data_limits (combined
budget for both Content-Type and Content-Disposition), initialised to
MESSAGE_PART_DATA_MAX_TOTAL_MIME_PARAMS (200 000).  Cap params_count to the
remaining budget before allocating and deduct accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gbp-Pq: Name 0014-lib-mail-Limit-total-MIME-parameter-count-per-messag.patch

3 weeks ago[PATCH 13/14] lib-mail: Limit total Content-Language tag count per message to 100 000
Timo Sirainen [Fri, 17 Apr 2026 13:56:37 +0000 (15:56 +0200)]
[PATCH 13/14] lib-mail: Limit total Content-Language tag count per message to 100 000

A multipart message with many MIME parts each containing many language tags
can exhaust memory: the per-part RFC 2231 parser had no cumulative limit.

Add remaining_language_tags to struct message_part_data_limits, initialised
to MESSAGE_PART_DATA_MAX_TOTAL_LANGUAGE_TAGS (100 000).  Break out of the
tag-parsing loop in parse_content_language() once the budget reaches zero.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gbp-Pq: Name 0013-lib-mail-Limit-total-Content-Language-tag-count-per-.patch

3 weeks ago[PATCH 12/14] lib-mail: Limit total address count per message to 100 000
Timo Sirainen [Fri, 17 Apr 2026 13:55:48 +0000 (15:55 +0200)]
[PATCH 12/14] lib-mail: Limit total address count per message to 100 000

A message with millions of addresses across all its envelope headers can
exhaust memory when parsed (each struct message_address is ~100 bytes
regardless of whether the raw address is only a few bytes long).

Add remaining_addresses to struct message_part_data_limits, initialised to
MESSAGE_PART_DATA_MAX_TOTAL_ADDRESSES (100 000).  Pass the remaining budget
as max_addresses to message_address_parse_full() so parsing stops at the
limit, then deduct the actual count parsed from the budget.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gbp-Pq: Name 0012-lib-mail-Limit-total-address-count-per-message-to-10.patch

3 weeks ago[PATCH 11/14] lib-mail: Introduce struct message_part_data_limits and thread it throu...
Timo Sirainen [Fri, 17 Apr 2026 13:54:48 +0000 (15:54 +0200)]
[PATCH 11/14] lib-mail: Introduce struct message_part_data_limits and thread it through parsers

Add an empty struct message_part_data_limits and pass it by pointer through
message_part_data_parse_from_header() and message_part_envelope_parse_from_header().

No behaviour change: the struct has no fields yet and no limits are applied.
Subsequent commits add the individual limit fields and enforcement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gbp-Pq: Name 0011-lib-mail-Introduce-struct-message_part_data_limits-a.patch

3 weeks ago[PATCH 10/14] lib-mail: Clamp hdr->value cumulatively against header_block_max_size
Timo Sirainen [Sun, 19 Apr 2026 21:16:14 +0000 (00:16 +0300)]
[PATCH 10/14] lib-mail: Clamp hdr->value cumulatively against header_block_max_size

Until now header_block_max_size only bounded hdr->full_value via
value_buf.  Continued chunks returned to the caller via hdr->value were
left at the raw chunk size, so a caller that consumed hdr->value per
chunk without ever requesting use_full_value (e.g. the header-cache
path in index_mail_parse_header()) could accumulate the full raw header
size.  A pathological To: with millions of addresses could grow
mail->header_data and the cache write buffer to tens of megabytes each,
driving the imap process over vsz_limit on FETCH ENVELOPE.

Reinterpret header_block_total_size as the running sum of line_value_size
across all chunks of all headers, and clamp each new chunk against the
remaining header_block_max_size budget. Propagate the clamped size to
line->value_len in the two continued-line branches that previously left
it untouched. value_buf is bounded implicitly since every append uses
line_value_size. The up-front per-chunk clamp
(line->value_len = MIN(value_len, max_size)) is now subsumed by the
cumulative clamp and has been removed.

Update the truncation tests that were documenting the old
"value_len stays at raw chunk size" behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gbp-Pq: Name 0010-lib-mail-Clamp-hdr-value-cumulatively-against-header.patch

3 weeks ago[PATCH 09/14] lib-storage: Cap per-header size in index_mail_get_header_stream()
Timo Sirainen [Sun, 19 Apr 2026 15:28:16 +0000 (18:28 +0300)]
[PATCH 09/14] lib-storage: Cap per-header size in index_mail_get_header_stream()

Apply MESSAGE_HEADER_BLOCK_DEFAULT_MAX_SIZE (10 MB) to the header-filter
istream used for populating the header cache. A pathological single
header (for example a To: with millions of addresses) otherwise grows
mail->header_data and the cache write buffer in lockstep with the raw
header size, which can push the imap process over vsz_limit on FETCH
ENVELOPE / BODYSTRUCTURE.

On its own this change does not yet bound hdr->value delivery; that
requires the upcoming change to message_parse_header_next() to clamp
per-chunk value_len cumulatively. Setting the limit here now lets that
follow-up take effect without further touching this file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gbp-Pq: Name 0009-lib-storage-Cap-per-header-size-in-index_mail_get_he.patch

3 weeks ago[PATCH 08/14] lib-mail: Make istream-header-filter's per-header size limit configurable
Timo Sirainen [Sun, 19 Apr 2026 15:15:49 +0000 (18:15 +0300)]
[PATCH 08/14] lib-mail: Make istream-header-filter's per-header size limit configurable

Until now the internal message_header_parser_ctx used the default
MESSAGE_HEADER_BLOCK_DEFAULT_MAX_SIZE (10 MB) cap. In practice that cap
only bounded hdr->full_value; per-chunk hdr->value was delivered in full
regardless. A subsequent change to message_parse_header_next() will
clamp hdr->value cumulatively as well, and at that point the 10 MB
default would silently truncate data for callers like mbox-save that
stream raw header bytes to storage.

Default the filter to SIZE_MAX (unlimited) to preserve the effective
behavior and add i_stream_header_filter_set_max_header_block_size() so
callers that genuinely want a cap (index_mail_get_header_stream()) can
opt in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gbp-Pq: Name 0008-lib-mail-Make-istream-header-filter-s-per-header-siz.patch

3 weeks ago[PATCH 07/14] lib-mail: istream-header-filter - Use container_of() for struct casts
Timo Sirainen [Sun, 19 Apr 2026 22:14:02 +0000 (01:14 +0300)]
[PATCH 07/14] lib-mail: istream-header-filter - Use container_of() for struct casts

Replace the C-style downcasts from struct istream_private/iostream_private
to struct header_filter_istream with container_of(), matching the
convention used by other istream implementations in tree.

Gbp-Pq: Name 0007-lib-mail-istream-header-filter-Use-container_of-for-.patch

3 weeks ago[PATCH 06/14] lib-storage/mbox: Explicitly disable the header block size limit
Timo Sirainen [Sun, 19 Apr 2026 12:57:08 +0000 (15:57 +0300)]
[PATCH 06/14] lib-storage/mbox: Explicitly disable the header block size limit

mbox_sync_parse_next_mail() appends each header's raw bytes into
ctx->header and writes them back when rewriting the mbox file. The
default MESSAGE_HEADER_BLOCK_DEFAULT_MAX_SIZE limit (10 MB) must not
apply here: any truncation would corrupt the mbox on rewrite.
Similarly, mbox_sync_parse_match_mail() feeds full raw header bytes
into the MD5 verifier.

Today the per-chunk hdr->value delivered by message_parse_header_next()
is not clamped cumulatively, so the limit only bites on full_value and
unknown headers pass through intact. That is about to change - a
subsequent commit will clamp hdr->value cumulatively. Explicitly
setting SIZE_MAX here locks in the intent and prevents a regression.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gbp-Pq: Name 0006-lib-storage-mbox-Explicitly-disable-the-header-block.patch

3 weeks ago[PATCH 05/14] lib-mail: Add count field to struct message_address_list
Timo Sirainen [Fri, 17 Apr 2026 13:46:10 +0000 (15:46 +0200)]
[PATCH 05/14] lib-mail: Add count field to struct message_address_list

Add a count field and increment it in add_address() so callers can read
the number of parsed addresses directly from the list struct without
walking the linked list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gbp-Pq: Name 0005-lib-mail-Add-count-field-to-struct-message_address_l.patch

3 weeks ago[PATCH 04/14] lib-mail: message-parser-from-parts: Enforce 50 MB all-headers-max...
Timo Sirainen [Thu, 16 Apr 2026 20:38:02 +0000 (22:38 +0200)]
[PATCH 04/14] lib-mail: message-parser-from-parts: Enforce 50 MB all-headers-max-size limit

The preparsed (from-parts) header parser was not tracking
all_headers_total_size and never called message_parse_header_lower_limit(),
so the cumulative 50 MB header size limit was never applied when re-parsing
a message using cached part structure.

Fix by mirroring the same tracking that message-parser.c does in its
parse_next_header_block(): update all_headers_total_size for each parsed
header line, and call message_parse_header_lower_limit() with the remaining
budget when initialising the per-part header parser.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gbp-Pq: Name 0004-lib-mail-message-parser-from-parts-Enforce-50-MB-all.patch

3 weeks ago[PATCH 03/14] imap: Stream ENVELOPE to client without ostream memory duplication
Timo Sirainen [Fri, 17 Apr 2026 14:55:34 +0000 (16:55 +0200)]
[PATCH 03/14] imap: Stream ENVELOPE to client without ostream memory duplication

Same fix as for BODYSTRUCTURE: avoid copying the envelope string into
the ostream ring buffer by using o_stream_set_max_buffer_size(0) +
o_stream_send_istream() with a continuation handler.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gbp-Pq: Name 0003-imap-Stream-ENVELOPE-to-client-without-ostream-memor.patch

3 weeks ago[PATCH 02/14] imap: Stream BODYSTRUCTURE to client without ostream memory duplication
Timo Sirainen [Fri, 17 Apr 2026 14:55:05 +0000 (16:55 +0200)]
[PATCH 02/14] imap: Stream BODYSTRUCTURE to client without ostream memory duplication

For huge BODYSTRUCTURE responses (messages with many MIME parts),
o_stream_send_str() caused the ostream to copy the entire string into
its ring buffer when the stream was corked, doubling memory usage.

Use the same o_stream_set_max_buffer_size(0) + o_stream_send_istream()
pattern as fetch_stream_continue() so the ostream buffer stays at 0
bytes and the I/O loop handles flow control via WAIT_OUTPUT.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gbp-Pq: Name 0002-imap-Stream-BODYSTRUCTURE-to-client-without-ostream-.patch

3 weeks ago[PATCH 01/14] lib-mail: Reset charset translation buffer between MIME parts
Timo Sirainen [Sat, 28 Feb 2026 08:27:19 +0000 (10:27 +0200)]
[PATCH 01/14] lib-mail: Reset charset translation buffer between MIME parts

If MIME part ended with an incomplete charset translation, the buffer was
kept for the next MIME part. This could have produced garbage in the next
MIME part, or a crash.

Fixes:
Panic: file message-decoder.c: line 232 (translation_buf_decode): assertion failed: (orig_size < CHARSET_MAX_PENDING_BUF_SIZE)

Gbp-Pq: Name 0001-lib-mail-Reset-charset-translation-buffer-between-MI.patch

3 weeks ago[PATCH] lib-imap: imap-match - Fix excessive CPU usage caused by backtracking
Noah Meyerhans [Thu, 10 Sep 2026 13:59:18 +0000 (09:59 -0400)]
[PATCH] lib-imap: imap-match - Fix excessive CPU usage caused by backtracking

Backport the NFA/non-backtracking algorithm from 2684624… while retaining the
byte-oriented matcher semantics of 2.4.1.

Original commit message:

Replace the recursive backtracking matcher with a Thompson-style NFA
simulation over grapheme clusters.

Each grapheme cluster of the compressed pattern becomes one state:
LITERAL, PERCENT (consume any number of non-separator clusters) or STAR
(consume any number of clusters including separators).  A virtual
ACCEPT position sits at index n_states.  Simulation tracks the set of
active positions in a bitmap.  Epsilon-closure (skipping a PERCENT or
STAR without consuming) is a single forward pass because the NFA is
linear: each state can only epsilon-skip to i+1.

The resulting match is O(n_data * n_pattern) regardless of pattern
shape, with no recursion and no backtracking, so there is no way for
a malicious pattern or mailbox name to trigger exponential CPU,
excessive stack depth, or unbounded memory.

IMAP_MATCH_YES / NO / CHILDREN / PARENT semantics are preserved:

- YES:      ACCEPT reachable after consuming all data.
- PARENT:   ACCEPT was active at some point while the next data
         grapheme cluster was the separator.
- CHILDREN: some active non-ACCEPT state remains after consuming all
         data, and either the data ends with a separator or an
         active state can still consume a separator (precomputed
         as sep_accept[]).

Inboxcase handling (case-insensitive comparison for the INBOX prefix
of data) and grapheme-cluster comparison are unchanged - the existing
match_gc logic is reused inline as literal_matches().
pattern_compress() and pattern_is_inboxcase() are unchanged.

Gbp-Pq: Name 0001-lib-imap-imap-match-Fix-excessive-CPU-usage-caused-b.patch

3 weeks ago[PATCH 4/4] lib-mail: o_stream_dot_sendv() - Do not send unguarded '.' after bare...
Marco Bettini [Wed, 8 Apr 2026 10:14:08 +0000 (10:14 +0000)]
[PATCH 4/4] lib-mail: o_stream_dot_sendv() - Do not send unguarded '.' after bare '\r'

Gbp-Pq: Name 0004-lib-mail-o_stream_dot_sendv-Do-not-send-unguarded-.-.patch

3 weeks ago[PATCH] lib-test: Require both lengths in test_assert_memcmp()
Aki Tuomi [Tue, 27 Jan 2026 17:02:30 +0000 (19:02 +0200)]
[PATCH] lib-test: Require both lengths in test_assert_memcmp()

Gbp-Pq: Name 0001-lib-test-Require-both-lengths-in-test_assert_memcmp.patch

3 weeks ago[PATCH] lib-test: Add test_assert_memcmp*()
Stephan Bosch [Fri, 25 Jul 2025 01:31:44 +0000 (03:31 +0200)]
[PATCH] lib-test: Add test_assert_memcmp*()

Gbp-Pq: Name 0001-lib-test-Add-test_assert_memcmp.patch

3 weeks ago[PATCH 3/4] lib-mail: o_stream_dot_sendv() - Use enumeration to define the items...
Marco Bettini [Fri, 10 Apr 2026 08:49:49 +0000 (08:49 +0000)]
[PATCH 3/4] lib-mail: o_stream_dot_sendv() - Use enumeration to define the items to inject

Gbp-Pq: Name 0003-lib-mail-o_stream_dot_sendv-Use-enumeration-to-defin.patch

3 weeks ago[PATCH 2/4] lib-mail: o_stream_dot_sendv() - Fix boundary off by one
Marco Bettini [Mon, 20 Apr 2026 09:50:54 +0000 (09:50 +0000)]
[PATCH 2/4] lib-mail: o_stream_dot_sendv() - Fix boundary off by one

Gbp-Pq: Name 0002-lib-mail-o_stream_dot_sendv-Fix-boundary-off-by-one.patch

3 weeks ago[PATCH 1/4] lib-mail: o_stream_dot_sendv() - Use I_MIN()
Marco Bettini [Fri, 10 Apr 2026 08:53:36 +0000 (08:53 +0000)]
[PATCH 1/4] lib-mail: o_stream_dot_sendv() - Use I_MIN()

Gbp-Pq: Name 0001-lib-mail-o_stream_dot_sendv-Use-I_MIN.patch

3 weeks ago[PATCH] lib-mail: ostream-dot - Optimize stream writing
Aki Tuomi [Mon, 26 Jan 2026 12:55:08 +0000 (14:55 +0200)]
[PATCH] lib-mail: ostream-dot - Optimize stream writing

Use i_memcspn() to figure out how much we can skip.

Gbp-Pq: Name 0001-lib-mail-ostream-dot-Optimize-stream-writing.patch

3 weeks ago[PATCH 3/4] auth: db-oauth2: Add oauth2_audience setting, deprecate aud-as-scope...
Aki Tuomi [Fri, 29 May 2026 07:31:50 +0000 (07:31 +0000)]
[PATCH 3/4] auth: db-oauth2: Add oauth2_audience setting, deprecate aud-as-scope fallback

Add a dedicated oauth2_audience setting checked against the token's aud
claim (RFC 7519 section 4.1.3) using the same tab-split AND-semantics as
oauth2_scope. Emit a deprecation warning when the existing aud fallback
in db_oauth2_token_in_scope() is triggered so operators know to migrate.

Gbp-Pq: Name 0003-auth-db-oauth2-Add-oauth2_audience-setting-deprecate.patch

3 weeks ago[PATCH 2/4] auth: db-oauth2: Fix scope check to require all configured scopes
Aki Tuomi [Wed, 3 Jun 2026 12:56:20 +0000 (12:56 +0000)]
[PATCH 2/4] auth: db-oauth2: Fix scope check to require all configured scopes

Switch token-in-scope check to AND semantics: all configured scopes
must be present in the token. Behaviour now matches the JWT path.

Gbp-Pq: Name 0002-auth-db-oauth2-Fix-scope-check-to-require-all-config.patch

3 weeks ago[PATCH 1/4] auth: db-oauth2: Reduce nesting in token_in_scope via early return
Aki Tuomi [Wed, 3 Jun 2026 12:56:13 +0000 (12:56 +0000)]
[PATCH 1/4] auth: db-oauth2: Reduce nesting in token_in_scope via early return

Gbp-Pq: Name 0001-auth-db-oauth2-Reduce-nesting-in-token_in_scope-via-.patch

3 weeks ago[PATCH] lib-sql: Run sql statement queries in their own data stack frame
Timo Sirainen [Thu, 11 Jun 2026 20:02:15 +0000 (20:02 +0000)]
[PATCH] lib-sql: Run sql statement queries in their own data stack frame

Gbp-Pq: Name 0007-lib-sql-Run-sql-statement-queries-in-their-own-data-.patch

3 weeks ago[PATCH 6/6] auth: passdb_sql: connect before expanding query variables
Aki Tuomi [Fri, 29 May 2026 06:28:40 +0000 (09:28 +0300)]
[PATCH 6/6] auth: passdb_sql: connect before expanding query variables

sql_lookup_pass() calls settings_get_params() with an SQL escape func that
requires a live connection. If the DB is disconnected, the error propagated
as "Failed to parse configuration" instead of a DB connectivity error.

Call sql_connect() first; fail with "Not connected to database" directly
if it returns -1.

Gbp-Pq: Name 0006-auth-passdb_sql-connect-before-expanding-query-varia.patch

3 weeks ago[PATCH 5/6] lib-sql: Make escape_string return int with error_r, fail instead of...
Aki Tuomi [Fri, 29 May 2026 11:22:57 +0000 (11:22 +0000)]
[PATCH 5/6] lib-sql: Make escape_string return int with error_r, fail instead of unsafe fallback

Change escape_string driver vfunc and sql_escape_string() to return int
with separate error_r output parameter. On failure (e.g. not connected),
return -1 instead of falling back to unsafe escaping.

Move escaping from sql_statement_bind_str() to sql_statement_get_query()
so errors can be propagated to callers. Add failed_error field to
sql_transaction_context for deferred error reporting at commit time.

Gbp-Pq: Name 0005-lib-sql-Make-escape_string-return-int-with-error_r-f.patch

3 weeks ago[PATCH] lib-sql: Use strchr() based while loop to fill template
Aki Tuomi [Mon, 18 Aug 2025 05:30:42 +0000 (08:30 +0300)]
[PATCH] lib-sql: Use strchr() based while loop to fill template

This is much faster than going one byte at a time.

Gbp-Pq: Name 0001-lib-sql-Use-strchr-based-while-loop-to-fill-template.patch

3 weeks ago[PATCH] lib-sql: driver-sqlite - Use sqlite3_snprintf() to quote values
Aki Tuomi [Fri, 7 Nov 2025 07:21:01 +0000 (09:21 +0200)]
[PATCH] lib-sql: driver-sqlite - Use sqlite3_snprintf() to quote values

This does it the sqlite3 way.

Gbp-Pq: Name 0001-lib-sql-driver-sqlite-Use-sqlite3_snprintf-to-quote-.patch

3 weeks ago[PATCH 4/6] lib-var-expand: Change escape func signature to return int with error_r
Aki Tuomi [Thu, 21 May 2026 08:00:56 +0000 (11:00 +0300)]
[PATCH 4/6] lib-var-expand: Change escape func signature to return int with error_r

Wire error propagation in var_expand_program_execute_one_real() so a
failing escape function causes the expansion to return -1.

Update all implementations (passdb-sql, userdb-sql, db-ldap, dict-ldap,
auth-request-var-expand) and replace the unsafe auth_request_escape_func_t
cast in auth-request-var-expand.c with a proper bridge wrapper.

Gbp-Pq: Name 0004-lib-var-expand-Change-escape-func-signature-to-retur.patch

3 weeks ago[PATCH 3/6] lib-sql: Add sql_commit_schedule_delayed() helper
Aki Tuomi [Tue, 2 Jun 2026 09:54:41 +0000 (09:54 +0000)]
[PATCH 3/6] lib-sql: Add sql_commit_schedule_delayed() helper

Gbp-Pq: Name 0003-lib-sql-Add-sql_commit_schedule_delayed-helper.patch

3 weeks ago[PATCH 2/6] lib-sql: Extract sql_query_callback_delayed() helper
Aki Tuomi [Fri, 29 May 2026 11:21:26 +0000 (11:21 +0000)]
[PATCH 2/6] lib-sql: Extract sql_query_callback_delayed() helper

Gbp-Pq: Name 0002-lib-sql-Extract-sql_query_callback_delayed-helper.patch

3 weeks ago[PATCH] lib-sql: Add sql_result_new_error() helper
Aki Tuomi [Fri, 29 May 2026 11:21:00 +0000 (11:21 +0000)]
[PATCH] lib-sql: Add sql_result_new_error() helper

Gbp-Pq: Name 0001-lib-sql-Add-sql_result_new_error-helper.patch

3 weeks ago[PATCH] lib-sql: sql-api - Implement async calls for drivers that can't
Aki Tuomi [Mon, 6 Oct 2025 09:39:50 +0000 (12:39 +0300)]
[PATCH] lib-sql: sql-api - Implement async calls for drivers that can't

Changes the behaviour of asynchronous functions to be truly asynchronous
even if the underlying driver isn't capable of doing this. Implemented
by adding immediate timeouts to call the callbacks after returning from the
synchronous function and ending up back to ioloop.

Gbp-Pq: Name 0001-lib-sql-sql-api-Implement-async-calls-for-drivers-th.patch

3 weeks ago[PATCH 2/4] lib-compression: Iterate instead of recursing on zero-output decompress...
Aki Tuomi [Wed, 10 Jun 2026 11:54:00 +0000 (11:54 +0000)]
[PATCH 2/4] lib-compression: Iterate instead of recursing on zero-output decompress chunks

istream-lz4, istream-zlib and istream-bzlib each retried a read that
produced no output by tail-calling their own read function. A crafted
compressed stream can contain an unbounded number of chunks/steps that
each decompress to zero bytes - e.g. an lz4 stream of single-byte chunks
that each decode to nothing - so an attacker controlling the compressed
data can drive recursion depth proportional to the chunk count. Tail-call
optimization is not guaranteed, so this can exhaust the stack and crash
the process reading the stream.

Replace the recursive calls with continue inside the for(;;) loop
introduced in the previous commit, keeping stack usage O(1). Add a
regression test that feeds istream-lz4 a stream of 100000 empty chunks
and reads it in a single call.

Gbp-Pq: Name 0002-lib-compression-Iterate-instead-of-recursing-on-zero.patch

3 weeks ago[PATCH 1/4] lib-compression: wrap *_read() in for(;;) loop (reindent only)
Aki Tuomi [Wed, 10 Jun 2026 11:53:39 +0000 (11:53 +0000)]
[PATCH 1/4] lib-compression: wrap *_read() in for(;;) loop (reindent only)

Prepare for the next commit: wrap the body of i_stream_lz4_read(),
i_stream_bzlib_read(), and i_stream_zlib_read() in a for(;;) loop.
No logic change; all paths still return on the first iteration.
Separating the indent churn makes the actual fix easier to review.

Gbp-Pq: Name 0001-lib-compression-wrap-_read-in-for-loop-reindent-only.patch

3 weeks agoglobal-Fix-spelling
Dovecot Maintainers [Wed, 16 Sep 2026 19:06:35 +0000 (15:06 -0400)]
global-Fix-spelling

===================================================================

Gbp-Pq: Name 0001-global-Fix-spelling.patch

3 weeks ago[PATCH] lib-compression: istream-zlib - Use container_of() macro
Stephan Bosch [Tue, 14 Nov 2023 15:57:45 +0000 (16:57 +0100)]
[PATCH] lib-compression: istream-zlib - Use container_of() macro

Gbp-Pq: Name 0001-lib-compression-istream-zlib-Use-container_of-macro.patch

3 weeks ago[PATCH] lib-compression: Don't calculate crc32 if using zlib in deflate mode
Michael M Slusarz [Sat, 4 Oct 2025 18:04:31 +0000 (12:04 -0600)]
[PATCH] lib-compression: Don't calculate crc32 if using zlib in deflate mode

Gbp-Pq: Name 0001-lib-compression-Don-t-calculate-crc32-if-using-zlib-.patch

3 weeks ago[PATCH] lib-compression: istream-lz4 - Try again if no data was decompressed
Aki Tuomi [Mon, 23 Feb 2026 12:09:02 +0000 (14:09 +0200)]
[PATCH] lib-compression: istream-lz4 - Try again if no data was decompressed

Gbp-Pq: Name 0001-lib-compression-istream-lz4-Try-again-if-no-data-was.patch

3 weeks ago[PATCH] lib-compression: istream-lz4 - Ensure uncompressed chunk size is not 0
Aki Tuomi [Mon, 23 Feb 2026 11:52:36 +0000 (13:52 +0200)]
[PATCH] lib-compression: istream-lz4 - Ensure uncompressed chunk size is not 0

Gbp-Pq: Name 0001-lib-compression-istream-lz4-Ensure-uncompressed-chun.patch

3 weeks ago[PATCH 3/4] lib-compression: istream-zstd - Guard against no-progress loop in read
Aki Tuomi [Fri, 12 Jun 2026 11:19:42 +0000 (11:19 +0000)]
[PATCH 3/4] lib-compression: istream-zstd - Guard against no-progress loop in read

If ZSTD_decompressStream() returns with neither input consumed nor
output produced, the read loop would spin indefinitely. Add a check
after each call: if input.pos is unchanged and output.pos is zero,
treat it as a corrupt stream (EIO).

Gbp-Pq: Name 0003-lib-compression-istream-zstd-Guard-against-no-progre.patch

3 weeks ago[PATCH 4/4] lib-compression: test - Add zero-len frame test for all handlers
Aki Tuomi [Fri, 12 Jun 2026 11:19:42 +0000 (11:19 +0000)]
[PATCH 4/4] lib-compression: test - Add zero-len frame test for all handlers

Verify that successive empty compressed frames produce a clean EOF
across all compression algorithms. lz4 is limited to one frame as it
uses a custom single-stream format without concatenation support.

Gbp-Pq: Name 0004-lib-compression-test-Add-zero-len-frame-test-for-all.patch

3 weeks ago[PATCH 2/2] lib-sieve: storage: file - Validate script stat path through dir_fd
Timo Sirainen [Mon, 4 May 2026 13:10:13 +0000 (13:10 +0000)]
[PATCH 2/2] lib-sieve: storage: file - Validate script stat path through dir_fd

Extend the symlink-escape protection added in the previous commit to the
stat performed by sieve_file_script_open(): an "include :personal" lookup
or any other indirect path that triggers sieve_file_script_stat() also
needs to refuse a symlink whose target leaves the personal storage
directory, otherwise the existence check succeeds and the file is opened
later via the safe path with an unhelpful "permission denied".

Add sieve_file_script_stat_safe(), which uses fstatat(AT_SYMLINK_NOFOLLOW)
to obtain the entry's own stat (lnk_st) and then, only if the entry is a
symlink, opens it through sieve_file_storage_open_safe() to validate the
target stays inside dir_fd and to fetch the resolved target's stat (st)
via fstat(). Non-symlink entries skip the open entirely.

Use the new helper in sieve_file_script_open() whenever fstorage->dir_fd
is available, falling back to the unsafe lstat+stat variant for
non-personal or single-file storages.

Gbp-Pq: Name 0002-lib-sieve-storage-file-Validate-script-stat-path-thr.patch

3 weeks ago[PATCH 1/2] lib-sieve: storage: file - Refuse symlinks escaping personal storage...
Timo Sirainen [Mon, 4 May 2026 13:09:37 +0000 (13:09 +0000)]
[PATCH 1/2] lib-sieve: storage: file - Refuse symlinks escaping personal storage directory

Pigeonhole's file storage followed any symlink encountered while resolving a
script path, including symlinks in personal (user-writable) storage whose
target lay outside the storage directory. In some non-recommended
configurations a user could exploit this through the include extension:
an "include :personal name;" lookup of ~/sieve/name.sieve transparently
followed a user-placed to e.g. another user's file readable by the mail
process, leaking its contents (or causing it to be parsed as Sieve).
Normally this shouldn't be possible, because sieve processes shouldn't
have any more privileges to read files than the local system user creating
the symlink.

Open the canonical (realpath'd) personal storage directory at storage init
time and keep an O_DIRECTORY|O_CLOEXEC fd to it. Resolve script content
reads through this fd by routing sieve_file_script_get_stream() via a new
sieve_file_storage_open_safe() wrapper around t_openat_safe(), which:

 - opens each path component with O_NOFOLLOW so symlinks are detected
   explicitly rather than transparently followed;
 - follows symlinks only when their (recursively resolved) target stays
   beneath dir_fd, refusing absolute targets and `..` past the storage
   root with ELOOP;
 - caps the symlink-hop count to bound resolution time.

Anchoring at dir_fd makes the lookup TOCTOU-safe even when intermediate
path components are mutated on disk concurrently: resolution stays
relative to the original directory inode and the safe walker still rejects
any target that leaves it.

Apply the protection only when storage->is_personal is set; admin-managed
global storage is trusted and may legitimately use cross-boundary symlinks.
Single-file storages (is_file=TRUE) keep dir_fd at -1 and fall back to the
existing open path. Also guard the dir_fd open with S_ISDIR() to handle the
autodetect quirk where storage_path can refer to a regular file even when
is_file is FALSE.

Gbp-Pq: Name 0001-lib-sieve-storage-file-Refuse-symlinks-escaping-pers.patch

3 weeks ago[PATCH 5/5] lib: Add comments about memory allocations and string functions preservin...
Timo Sirainen [Wed, 3 Jun 2026 21:14:51 +0000 (21:14 +0000)]
[PATCH 5/5] lib: Add comments about memory allocations and string functions preserving errno

Gbp-Pq: Name 0005-lib-Add-comments-about-memory-allocations-and-string.patch

3 weeks ago[PATCH 4/5] acl: dovecot-acl-list is never supposed to be a symlink - use O_NOFOLLOW...
Timo Sirainen [Wed, 3 Jun 2026 15:16:38 +0000 (18:16 +0300)]
[PATCH 4/5] acl: dovecot-acl-list is never supposed to be a symlink - use O_NOFOLLOW flag

Gbp-Pq: Name 0004-acl-dovecot-acl-list-is-never-supposed-to-be-a-symli.patch

3 weeks ago[PATCH 3/5] lib: Add t_openat_safe_dir()
Timo Sirainen [Wed, 3 Jun 2026 15:10:36 +0000 (18:10 +0300)]
[PATCH 3/5] lib: Add t_openat_safe_dir()

Gbp-Pq: Name 0003-lib-Add-t_openat_safe_dir.patch