]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Minor] url: fix out-of-bounds read on empty/all-dots host
authorVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 20 May 2026 10:29:49 +0000 (11:29 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 20 May 2026 10:29:49 +0000 (11:29 +0100)
rspamd_url_maybe_regenerate_from_ip could read host[-1]:

* The trailing-dot strip loop tested *(end - 1) before the end > p
  bound, so an all-dots host (http://.../) walked end down to p and
  then dereferenced one byte before the host buffer.
* rspamd_url_parse only rejected an empty host before URL-decoding;
  a host such as "%" decodes to zero bytes, so hostlen could become 0
  and still reach the regen/telephone code with end == p.

Reorder the loop condition, re-check hostlen after the host is
decoded and shifted, and guard rspamd_url_maybe_regenerate_from_ip
against a zero-length host.

src/libserver/url.c

index 9aba86defabf412034de19b7ef094d03d1ae03a4..5ea429395c9afaad03e94dd0f3ae3f4fbadb9f15 100644 (file)
@@ -1849,6 +1849,10 @@ rspamd_url_maybe_regenerate_from_ip(struct rspamd_url *uri, rspamd_mempool_t *po
        gboolean ret = FALSE, check_num = TRUE;
        uint32_t n, dots, t = 0, i = 0, shift, nshift;
 
+       if (uri->hostlen == 0) {
+               return FALSE;
+       }
+
        p = rspamd_url_host_unsafe(uri);
        end = p + uri->hostlen;
 
@@ -1857,7 +1861,8 @@ rspamd_url_maybe_regenerate_from_ip(struct rspamd_url *uri, rspamd_mempool_t *po
                end--;
        }
 
-       while (*(end - 1) == '.' && end > p) {
+       /* Bound check must come first: an all-dots host walks end down to p */
+       while (end > p && *(end - 1) == '.') {
                end--;
        }
 
@@ -2446,6 +2451,16 @@ rspamd_url_parse(struct rspamd_url *uri,
 
        rspamd_url_shift(uri, unquoted_len, UF_HOST);
 
+       /*
+        * URL-decoding the host can collapse it to nothing (e.g. a host that
+        * is just a truncated "%" escape decodes to zero bytes). The hostlen
+        * check above runs before decoding, so re-check here to keep an empty
+        * host out of the downstream host parsing.
+        */
+       if (uri->hostlen == 0) {
+               return URI_ERRNO_HOST_MISSING;
+       }
+
        /*
         * Remove extra slashes between host and path.
         * URLs like https://example.com//path should be normalized to https://example.com/path