diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fat/dir.c | 44 | ||||
-rw-r--r-- | fs/vfat/namei.c | 25 |
2 files changed, 39 insertions, 30 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 72cbcd61bd95..7b62ffb663f6 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -124,8 +124,8 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, | |||
124 | * but ignore that right now. | 124 | * but ignore that right now. |
125 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. | 125 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. |
126 | */ | 126 | */ |
127 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | 127 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, |
128 | struct nls_table *nls) | 128 | int uni_xlate, struct nls_table *nls) |
129 | { | 129 | { |
130 | wchar_t *ip, ec; | 130 | wchar_t *ip, ec; |
131 | unsigned char *op, nc; | 131 | unsigned char *op, nc; |
@@ -135,10 +135,11 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | |||
135 | ip = uni; | 135 | ip = uni; |
136 | op = ascii; | 136 | op = ascii; |
137 | 137 | ||
138 | while (*ip) { | 138 | while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) { |
139 | ec = *ip++; | 139 | ec = *ip++; |
140 | if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { | 140 | if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { |
141 | op += charlen; | 141 | op += charlen; |
142 | len -= charlen; | ||
142 | } else { | 143 | } else { |
143 | if (uni_xlate == 1) { | 144 | if (uni_xlate == 1) { |
144 | *op = ':'; | 145 | *op = ':'; |
@@ -149,16 +150,19 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate, | |||
149 | ec >>= 4; | 150 | ec >>= 4; |
150 | } | 151 | } |
151 | op += 5; | 152 | op += 5; |
153 | len -= 5; | ||
152 | } else { | 154 | } else { |
153 | *op++ = '?'; | 155 | *op++ = '?'; |
156 | len--; | ||
154 | } | 157 | } |
155 | } | 158 | } |
156 | /* We have some slack there, so it's OK */ | ||
157 | if (op>ascii+256) { | ||
158 | op = ascii + 256; | ||
159 | break; | ||
160 | } | ||
161 | } | 159 | } |
160 | |||
161 | if (unlikely(*ip)) { | ||
162 | printk(KERN_WARNING "FAT: filename was truncated while " | ||
163 | "converting."); | ||
164 | } | ||
165 | |||
162 | *op = 0; | 166 | *op = 0; |
163 | return (op - ascii); | 167 | return (op - ascii); |
164 | } | 168 | } |
@@ -311,9 +315,11 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
311 | struct nls_table *nls_io = sbi->nls_io; | 315 | struct nls_table *nls_io = sbi->nls_io; |
312 | struct nls_table *nls_disk = sbi->nls_disk; | 316 | struct nls_table *nls_disk = sbi->nls_disk; |
313 | wchar_t bufuname[14]; | 317 | wchar_t bufuname[14]; |
314 | unsigned char xlate_len, nr_slots; | 318 | unsigned char nr_slots; |
319 | int xlate_len; | ||
315 | wchar_t *unicode = NULL; | 320 | wchar_t *unicode = NULL; |
316 | unsigned char work[MSDOS_NAME], bufname[260]; /* 256 + 4 */ | 321 | unsigned char work[MSDOS_NAME]; |
322 | unsigned char *bufname = NULL; | ||
317 | int uni_xlate = sbi->options.unicode_xlate; | 323 | int uni_xlate = sbi->options.unicode_xlate; |
318 | int utf8 = sbi->options.utf8; | 324 | int utf8 = sbi->options.utf8; |
319 | int anycase = (sbi->options.name_check != 's'); | 325 | int anycase = (sbi->options.name_check != 's'); |
@@ -321,6 +327,10 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
321 | loff_t cpos = 0; | 327 | loff_t cpos = 0; |
322 | int chl, i, j, last_u, err; | 328 | int chl, i, j, last_u, err; |
323 | 329 | ||
330 | bufname = (unsigned char*)__get_free_page(GFP_KERNEL); | ||
331 | if (!bufname) | ||
332 | return -ENOMEM; | ||
333 | |||
324 | err = -ENOENT; | 334 | err = -ENOENT; |
325 | while(1) { | 335 | while(1) { |
326 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | 336 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) |
@@ -386,8 +396,8 @@ parse_record: | |||
386 | 396 | ||
387 | bufuname[last_u] = 0x0000; | 397 | bufuname[last_u] = 0x0000; |
388 | xlate_len = utf8 | 398 | xlate_len = utf8 |
389 | ?utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | 399 | ?utf8_wcstombs(bufname, bufuname, PAGE_SIZE) |
390 | :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | 400 | :uni16_to_x8(bufname, bufuname, PAGE_SIZE, uni_xlate, nls_io); |
391 | if (xlate_len == name_len) | 401 | if (xlate_len == name_len) |
392 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | 402 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || |
393 | (anycase && !nls_strnicmp(nls_io, name, bufname, | 403 | (anycase && !nls_strnicmp(nls_io, name, bufname, |
@@ -396,8 +406,8 @@ parse_record: | |||
396 | 406 | ||
397 | if (nr_slots) { | 407 | if (nr_slots) { |
398 | xlate_len = utf8 | 408 | xlate_len = utf8 |
399 | ?utf8_wcstombs(bufname, unicode, sizeof(bufname)) | 409 | ?utf8_wcstombs(bufname, unicode, PAGE_SIZE) |
400 | :uni16_to_x8(bufname, unicode, uni_xlate, nls_io); | 410 | :uni16_to_x8(bufname, unicode, PAGE_SIZE, uni_xlate, nls_io); |
401 | if (xlate_len != name_len) | 411 | if (xlate_len != name_len) |
402 | continue; | 412 | continue; |
403 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | 413 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || |
@@ -416,6 +426,8 @@ Found: | |||
416 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); | 426 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); |
417 | err = 0; | 427 | err = 0; |
418 | EODir: | 428 | EODir: |
429 | if (bufname) | ||
430 | free_page((unsigned long)bufname); | ||
419 | if (unicode) | 431 | if (unicode) |
420 | free_page((unsigned long)unicode); | 432 | free_page((unsigned long)unicode); |
421 | 433 | ||
@@ -598,7 +610,7 @@ parse_record: | |||
598 | if (isvfat) { | 610 | if (isvfat) { |
599 | bufuname[j] = 0x0000; | 611 | bufuname[j] = 0x0000; |
600 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | 612 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) |
601 | : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); | 613 | : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io); |
602 | } | 614 | } |
603 | 615 | ||
604 | fill_name = bufname; | 616 | fill_name = bufname; |
@@ -610,7 +622,7 @@ parse_record: | |||
610 | int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0])); | 622 | int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0])); |
611 | int long_len = utf8 | 623 | int long_len = utf8 |
612 | ? utf8_wcstombs(longname, unicode, buf_size) | 624 | ? utf8_wcstombs(longname, unicode, buf_size) |
613 | : uni16_to_x8(longname, unicode, uni_xlate, nls_io); | 625 | : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io); |
614 | 626 | ||
615 | if (!both) { | 627 | if (!both) { |
616 | fill_name = longname; | 628 | fill_name = longname; |
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index efc70576e4b4..ab4f3da770f0 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c | |||
@@ -176,15 +176,10 @@ static inline int vfat_is_used_badchars(const wchar_t *s, int len) | |||
176 | for (i = 0; i < len; i++) | 176 | for (i = 0; i < len; i++) |
177 | if (vfat_bad_char(s[i])) | 177 | if (vfat_bad_char(s[i])) |
178 | return -EINVAL; | 178 | return -EINVAL; |
179 | return 0; | ||
180 | } | ||
181 | 179 | ||
182 | static int vfat_valid_longname(const unsigned char *name, unsigned int len) | 180 | if (s[i - 1] == ' ') /* last character cannot be space */ |
183 | { | ||
184 | if (name[len - 1] == ' ') | ||
185 | return -EINVAL; | 181 | return -EINVAL; |
186 | if (len >= 256) | 182 | |
187 | return -ENAMETOOLONG; | ||
188 | return 0; | 183 | return 0; |
189 | } | 184 | } |
190 | 185 | ||
@@ -485,11 +480,14 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, | |||
485 | */ | 480 | */ |
486 | *outlen -= (name_len - len); | 481 | *outlen -= (name_len - len); |
487 | 482 | ||
483 | if (*outlen > 255) | ||
484 | return -ENAMETOOLONG; | ||
485 | |||
488 | op = &outname[*outlen * sizeof(wchar_t)]; | 486 | op = &outname[*outlen * sizeof(wchar_t)]; |
489 | } else { | 487 | } else { |
490 | if (nls) { | 488 | if (nls) { |
491 | for (i = 0, ip = name, op = outname, *outlen = 0; | 489 | for (i = 0, ip = name, op = outname, *outlen = 0; |
492 | i < len && *outlen <= 260; | 490 | i < len && *outlen <= 255; |
493 | *outlen += 1) | 491 | *outlen += 1) |
494 | { | 492 | { |
495 | if (escape && (*ip == ':')) { | 493 | if (escape && (*ip == ':')) { |
@@ -525,18 +523,20 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, | |||
525 | op += 2; | 523 | op += 2; |
526 | } | 524 | } |
527 | } | 525 | } |
526 | if (i < len) | ||
527 | return -ENAMETOOLONG; | ||
528 | } else { | 528 | } else { |
529 | for (i = 0, ip = name, op = outname, *outlen = 0; | 529 | for (i = 0, ip = name, op = outname, *outlen = 0; |
530 | i < len && *outlen <= 260; | 530 | i < len && *outlen <= 255; |
531 | i++, *outlen += 1) | 531 | i++, *outlen += 1) |
532 | { | 532 | { |
533 | *op++ = *ip++; | 533 | *op++ = *ip++; |
534 | *op++ = 0; | 534 | *op++ = 0; |
535 | } | 535 | } |
536 | if (i < len) | ||
537 | return -ENAMETOOLONG; | ||
536 | } | 538 | } |
537 | } | 539 | } |
538 | if (*outlen > 260) | ||
539 | return -ENAMETOOLONG; | ||
540 | 540 | ||
541 | *longlen = *outlen; | 541 | *longlen = *outlen; |
542 | if (*outlen % 13) { | 542 | if (*outlen % 13) { |
@@ -574,9 +574,6 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name, | |||
574 | loff_t offset; | 574 | loff_t offset; |
575 | 575 | ||
576 | *nr_slots = 0; | 576 | *nr_slots = 0; |
577 | err = vfat_valid_longname(name, len); | ||
578 | if (err) | ||
579 | return err; | ||
580 | 577 | ||
581 | page = __get_free_page(GFP_KERNEL); | 578 | page = __get_free_page(GFP_KERNEL); |
582 | if (!page) | 579 | if (!page) |