aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Gabbasov <andrew_gabbasov@mentor.com>2015-12-24 11:25:33 -0500
committerJan Kara <jack@suse.cz>2016-01-04 09:57:49 -0500
commitbb00c898ad1ce40c4bb422a8207ae562e9aea7ae (patch)
treedca567eb137f212cab63c725599aafdd62e84129
parentad402b265ecf6fa22d04043b41444cdfcdf4f52d (diff)
udf: Check output buffer length when converting name to CS0
If a name contains at least some characters with Unicode values exceeding single byte, the CS0 output should have 2 bytes per character. And if other input characters have single byte Unicode values, then the single input byte is converted to 2 output bytes, and the length of output becomes larger than the length of input. And if the input name is long enough, the output length may exceed the allocated buffer length. All this means that conversion from UTF8 or NLS to CS0 requires checking of output length in order to stop when it exceeds the given output buffer size. [JK: Make code return -ENAMETOOLONG instead of silently truncating the name] CC: stable@vger.kernel.org Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/udf/unicode.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 95a224b26048..e788a05aab83 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -177,17 +177,22 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
177static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) 177static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
178{ 178{
179 unsigned c, i, max_val, utf_char; 179 unsigned c, i, max_val, utf_char;
180 int utf_cnt, u_len; 180 int utf_cnt, u_len, u_ch;
181 181
182 memset(ocu, 0, sizeof(dstring) * length); 182 memset(ocu, 0, sizeof(dstring) * length);
183 ocu[0] = 8; 183 ocu[0] = 8;
184 max_val = 0xffU; 184 max_val = 0xffU;
185 u_ch = 1;
185 186
186try_again: 187try_again:
187 u_len = 0U; 188 u_len = 0U;
188 utf_char = 0U; 189 utf_char = 0U;
189 utf_cnt = 0U; 190 utf_cnt = 0U;
190 for (i = 0U; i < utf->u_len; i++) { 191 for (i = 0U; i < utf->u_len; i++) {
192 /* Name didn't fit? */
193 if (u_len + 1 + u_ch >= length)
194 return 0;
195
191 c = (uint8_t)utf->u_name[i]; 196 c = (uint8_t)utf->u_name[i];
192 197
193 /* Complete a multi-byte UTF-8 character */ 198 /* Complete a multi-byte UTF-8 character */
@@ -229,6 +234,7 @@ try_again:
229 if (max_val == 0xffU) { 234 if (max_val == 0xffU) {
230 max_val = 0xffffU; 235 max_val = 0xffffU;
231 ocu[0] = (uint8_t)0x10U; 236 ocu[0] = (uint8_t)0x10U;
237 u_ch = 2;
232 goto try_again; 238 goto try_again;
233 } 239 }
234 goto error_out; 240 goto error_out;
@@ -299,15 +305,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
299 int len; 305 int len;
300 unsigned i, max_val; 306 unsigned i, max_val;
301 uint16_t uni_char; 307 uint16_t uni_char;
302 int u_len; 308 int u_len, u_ch;
303 309
304 memset(ocu, 0, sizeof(dstring) * length); 310 memset(ocu, 0, sizeof(dstring) * length);
305 ocu[0] = 8; 311 ocu[0] = 8;
306 max_val = 0xffU; 312 max_val = 0xffU;
313 u_ch = 1;
307 314
308try_again: 315try_again:
309 u_len = 0U; 316 u_len = 0U;
310 for (i = 0U; i < uni->u_len; i++) { 317 for (i = 0U; i < uni->u_len; i++) {
318 /* Name didn't fit? */
319 if (u_len + 1 + u_ch >= length)
320 return 0;
311 len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); 321 len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
312 if (!len) 322 if (!len)
313 continue; 323 continue;
@@ -320,6 +330,7 @@ try_again:
320 if (uni_char > max_val) { 330 if (uni_char > max_val) {
321 max_val = 0xffffU; 331 max_val = 0xffffU;
322 ocu[0] = (uint8_t)0x10U; 332 ocu[0] = (uint8_t)0x10U;
333 u_ch = 2;
323 goto try_again; 334 goto try_again;
324 } 335 }
325 336