Commit bb00c898 authored by Andrew Gabbasov's avatar Andrew Gabbasov Committed by Jan Kara

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: default avatarAndrew Gabbasov <andrew_gabbasov@mentor.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent ad402b26
...@@ -177,17 +177,22 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) ...@@ -177,17 +177,22 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
{ {
unsigned c, i, max_val, utf_char; unsigned c, i, max_val, utf_char;
int utf_cnt, u_len; int utf_cnt, u_len, u_ch;
memset(ocu, 0, sizeof(dstring) * length); memset(ocu, 0, sizeof(dstring) * length);
ocu[0] = 8; ocu[0] = 8;
max_val = 0xffU; max_val = 0xffU;
u_ch = 1;
try_again: try_again:
u_len = 0U; u_len = 0U;
utf_char = 0U; utf_char = 0U;
utf_cnt = 0U; utf_cnt = 0U;
for (i = 0U; i < utf->u_len; i++) { for (i = 0U; i < utf->u_len; i++) {
/* Name didn't fit? */
if (u_len + 1 + u_ch >= length)
return 0;
c = (uint8_t)utf->u_name[i]; c = (uint8_t)utf->u_name[i];
/* Complete a multi-byte UTF-8 character */ /* Complete a multi-byte UTF-8 character */
...@@ -229,6 +234,7 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) ...@@ -229,6 +234,7 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
if (max_val == 0xffU) { if (max_val == 0xffU) {
max_val = 0xffffU; max_val = 0xffffU;
ocu[0] = (uint8_t)0x10U; ocu[0] = (uint8_t)0x10U;
u_ch = 2;
goto try_again; goto try_again;
} }
goto error_out; goto error_out;
...@@ -299,15 +305,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, ...@@ -299,15 +305,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
int len; int len;
unsigned i, max_val; unsigned i, max_val;
uint16_t uni_char; uint16_t uni_char;
int u_len; int u_len, u_ch;
memset(ocu, 0, sizeof(dstring) * length); memset(ocu, 0, sizeof(dstring) * length);
ocu[0] = 8; ocu[0] = 8;
max_val = 0xffU; max_val = 0xffU;
u_ch = 1;
try_again: try_again:
u_len = 0U; u_len = 0U;
for (i = 0U; i < uni->u_len; i++) { for (i = 0U; i < uni->u_len; i++) {
/* Name didn't fit? */
if (u_len + 1 + u_ch >= length)
return 0;
len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
if (!len) if (!len)
continue; continue;
...@@ -320,6 +330,7 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, ...@@ -320,6 +330,7 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
if (uni_char > max_val) { if (uni_char > max_val) {
max_val = 0xffffU; max_val = 0xffffU;
ocu[0] = (uint8_t)0x10U; ocu[0] = (uint8_t)0x10U;
u_ch = 2;
goto try_again; goto try_again;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment