diff options
| -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) |
