⬢ DragonFlyBSD Kernel Audit
DF-5756 / fix.diff
← back to finding ↓ download raw
--- 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);
 }