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; }