On Thu, Feb 13, 2025 at 12:15:54PM -0500, Rich Felker wrote:
> Vulnerability description:
> 
> A vulnerability has been identified in musl libc's implementation of
> iconv that can result in out-of-bounds memory writes in applications
> which process untrusted input using iconv and where the input charset
> for the conversion is input-controlled.
> 
> In order for the vulnerability to be exposed, an application must call
> iconv_open with an output encoding of UTF-8 and and input encoding of
> EUC-KR, and must subsequently process untrusted input using the
> resulting conversion descriptor. The most common scenario in which
> this occurs is using the declared MIME charset of untrusted input (for
> example, in XML, HTML, or MIME-encoded email) as input to iconv_open
> for converting arbitrary-encoding input to UTF-8.
> 
> This issue was discovered and reported by Nick Wellnhofer. It arose as
> a combination of incorrect input byte validation in the EUC-KR
> decoder, and the fact that the UTF-8 output encoder assumed an
> invariant that the input decoder never produces character codes which
> are not valid Unicode Scalar Values.

Addendum: I also have a test program that will check if your iconv is
affected, attached. It runs over all 65536 byte pairs and looks for
bogus changes to the output buffer pointer/remaining.
#include <iconv.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define T(x) ((x) || (e+=fail(r, errno, i, j, out1, pout, outb, #x)))

int fail(int r, int err, int i, int j, char *start, char *end, size_t rem, char 
*pred)
{
        printf("%.2x %.2x: returned %d (%s), start %p end %p rem %zu: failed 
assertion: %s\n",
                i, j, r, r<0?strerror(err):"", start, end, rem, pred);
        return 1;
}


int main()
{
        iconv_t cd = iconv_open("UTF-8", "EUC-KR");
        int e = 0;
        for (int i=0; i<256; i++)
                for (int j=0; j<256; j++) {
                        char in[3] = { i, j, 'x' };
                        char out[12] = "", *out1=out+4;
                        char *pin = in, *pout = out1;
                        size_t inb = sizeof in;
                        size_t outb = sizeof out - (out1-out);
                        errno = 0;
                        size_t r = iconv(cd, &pin, &inb, &pout, &outb);
                        T(pout>=out1 && pout<out+sizeof out);
                        T(outb <= sizeof out - (out1-out));
                        T(out1[-1]=='\0');
                }
        return !!e;
}

Reply via email to