--- a/sys/libiconv/iconv_ucs.c +++ b/sys/libiconv/iconv_ucs.c @@ -252,6 +252,13 @@ *q = *p++; *(q + 1) = *p++; } + if ((*q & 0xfc) == 0xdc) { + /* leading low surrogate: invalid unicode. + * (A leading high surrogate is checked for + * below and requires a valid pair.) */ + ret = -1; + break; + } if ((*q & 0xfc) == 0xd8) { if (dp->convtype & KICONV_UCS_UCS4 && dp->convtype & KICONV_UCS_FROM_UTF16) { @@ -298,6 +305,13 @@ } else { code = (ucs[0] << 8) | ucs[1]; } + if (code >= 0xd800 && code < 0xe000) { + /* unpaired UTF-16 surrogate reaching the + * UTF-8 output stage: never valid Unicode; + * must not be emitted (CESU-8). */ + ret = -1; + break; + } if (casetype == KICONV_LOWER && dp->ctype) { code = towlower(code, dp->ctype); @@ -473,6 +487,17 @@ ucs4 |= *(src + i) & 0x3f; } + /* + * Reject overlong (non-shortest) encodings: the decoded value must + * not be representable in fewer bytes than the width actually used. + * Without this, e.g. "\xC0\xAF" decodes to U+002F ('/') and is + * written into converted filenames, and 4-byte encodings of BMP + * values make encode_surrogate() wrap below 0x10000. + */ + if ((w == 2 && ucs4 < 0x80) || (w == 3 && ucs4 < 0x800) || + (w == 4 && ucs4 < 0x10000)) + return (0); + *utf8width = w; return (ucs4); }