The branch main has been updated by markj:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=a9d3259c4e50da8aac100da23aa37c43055f8be2

commit a9d3259c4e50da8aac100da23aa37c43055f8be2
Author:     Taylor R Campbell <[email protected]>
AuthorDate: 2026-06-22 21:15:25 +0000
Commit:     Mark Johnston <[email protected]>
CommitDate: 2026-06-30 17:00:23 +0000

    iconv(3): Fix problems in various encodings
    
    Fix null pointer dereference with HZ8 encoding.
    
    Fix output buffer overrun in UTF-7, VIQR, ZW encodings.
    
    Approved by:    so
    Security:       FreeBSD-SA-26:49.iconv
    Security:       CVE-2026-58081
    Reviewed by:    markj, kevans
    Differential Revision:  https://reviews.freebsd.org/D57947
---
 lib/libiconv_modules/HZ/citrus_hz.c     |  2 ++
 lib/libiconv_modules/UTF7/citrus_utf7.c | 20 +++++++++++++++-----
 lib/libiconv_modules/VIQR/citrus_viqr.c |  6 +++++-
 lib/libiconv_modules/ZW/citrus_zw.c     |  7 +++++--
 4 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/lib/libiconv_modules/HZ/citrus_hz.c 
b/lib/libiconv_modules/HZ/citrus_hz.c
index f12938a7dab8..db738b8f812e 100644
--- a/lib/libiconv_modules/HZ/citrus_hz.c
+++ b/lib/libiconv_modules/HZ/citrus_hz.c
@@ -262,6 +262,8 @@ _citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei,
                                tail = psenc->chlen = 0;
                                continue;
                        }
+                       if (graphic == NULL)
+                               break;
                } else if (ch & 0x80) {
                        if (graphic != GR(psenc->inuse))
                                break;
diff --git a/lib/libiconv_modules/UTF7/citrus_utf7.c 
b/lib/libiconv_modules/UTF7/citrus_utf7.c
index f924366551f1..e7c6a0862c54 100644
--- a/lib/libiconv_modules/UTF7/citrus_utf7.c
+++ b/lib/libiconv_modules/UTF7/citrus_utf7.c
@@ -296,7 +296,7 @@ done:
 
 static int
 _citrus_UTF7_utf16tomb(_UTF7EncodingInfo * __restrict ei,
-    char * __restrict s, size_t n __unused, uint16_t u16,
+    char * __restrict s, size_t n, uint16_t u16,
     _UTF7State * __restrict psenc, size_t * __restrict nresult)
 {
        int bits, i;
@@ -336,6 +336,8 @@ _citrus_UTF7_utf16tomb(_UTF7EncodingInfo * __restrict ei,
                        psenc->ch[psenc->chlen++] = base64[i];
                }
        }
+       if (n < (size_t)psenc->chlen)
+               return (E2BIG);
        memcpy(s, psenc->ch, psenc->chlen);
        *nresult = psenc->chlen;
        psenc->chlen = 0;
@@ -352,6 +354,8 @@ _citrus_UTF7_wcrtomb_priv(_UTF7EncodingInfo * __restrict ei,
        uint16_t u16[2];
        int err, i, len;
        size_t nr, siz;
+       char buf[8], *bufp = buf;
+       _UTF7State psenc_save = *psenc;
 
        u32 = (uint32_t)wchar;
        if (u32 <= UTF16_MAX) {
@@ -367,14 +371,20 @@ _citrus_UTF7_wcrtomb_priv(_UTF7EncodingInfo * __restrict 
ei,
                return (EILSEQ);
        }
        siz = 0;
+       if (n > sizeof(buf))
+               n = sizeof(buf);
        for (i = 0; i < len; ++i) {
-               err = _citrus_UTF7_utf16tomb(ei, s, n, u16[i], psenc, &nr);
-               if (err != 0)
-                       return (err); /* XXX: state has been modified */
-               s += nr;
+               err = _citrus_UTF7_utf16tomb(ei, bufp, n, u16[i], psenc, &nr);
+               if (err != 0) {
+                       *nresult = (size_t)-1;
+                       *psenc = psenc_save; /* restore state */
+                       return (err);
+               }
+               bufp += nr;
                n -= nr;
                siz += nr;
        }
+       memcpy(s, buf, siz);
        *nresult = siz;
 
        return (0);
diff --git a/lib/libiconv_modules/VIQR/citrus_viqr.c 
b/lib/libiconv_modules/VIQR/citrus_viqr.c
index 1747c0a1705e..c1e88f188aab 100644
--- a/lib/libiconv_modules/VIQR/citrus_viqr.c
+++ b/lib/libiconv_modules/VIQR/citrus_viqr.c
@@ -323,7 +323,11 @@ _citrus_VIQR_wcrtomb_priv(_VIQREncodingInfo * __restrict 
ei,
        int ch = 0;
 
        switch (psenc->chlen) {
-       case 0: case 1:
+       case 0:
+               break;
+       case 1:
+               if (n-- < 1)
+                       goto e2big;
                break;
        default:
                return (EINVAL);
diff --git a/lib/libiconv_modules/ZW/citrus_zw.c 
b/lib/libiconv_modules/ZW/citrus_zw.c
index 3c650c46d0f4..cf66581c3336 100644
--- a/lib/libiconv_modules/ZW/citrus_zw.c
+++ b/lib/libiconv_modules/ZW/citrus_zw.c
@@ -263,9 +263,12 @@ _citrus_ZW_wcrtomb_priv(_ZWEncodingInfo * __restrict ei 
__unused,
                ch = (unsigned char)wc;
                switch (psenc->charset) {
                case NONE:
-                       if (ch == '\0' || ch == '\n')
+                       if (ch == '\0' || ch == '\n') {
+                               if (n < 1)
+                                       return (E2BIG);
+                               n -= 1;
                                psenc->ch[psenc->chlen++] = ch;
-                       else {
+                       } else {
                                if (n < 4)
                                        return (E2BIG);
                                n -= 4;

Reply via email to