From: Keith Mok <ek9852@gmail.com>
To: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: linux-kernel@vger.kernel.org
Subject: Re: [PATCH] vfat: bug fix for vfat cannot handle filename with 255 asian characters when mounted with utf8
Date: Fri, 15 Feb 2008 18:40:32 +0800 [thread overview]
Message-ID: <47B56C20.3030200@gmail.com> (raw)
In-Reply-To: <87ejbea9xo.fsf@duaron.myhome.or.jp>
Patch modified according to coding style in Linux.
NLS and UTF8 filename length are checked and limited to 255 after convert to unicode in xlate_to_uni function.
Signed-off-by: Keith Mok <ek9852@gmail.com>
---
Keith Mok
--- linux-source-2.6.22/fs/fat/dir.c.orig 2007-07-09 07:32:17.000000000 +0800
+++ linux-source-2.6.22/fs/fat/dir.c 2008-02-15 17:24:18.000000000 +0800
@@ -124,7 +124,7 @@ static inline int fat_get_entry(struct i
* but ignore that right now.
* Ahem... Stack smashing in ring 0 isn't fun. Fixed.
*/
-static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
+static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, int uni_xlate,
struct nls_table *nls)
{
wchar_t *ip, ec;
@@ -135,10 +135,11 @@ static int uni16_to_x8(unsigned char *as
ip = uni;
op = ascii;
- while (*ip) {
+ while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) {
ec = *ip++;
if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
op += charlen;
+ len -= charlen;
} else {
if (uni_xlate == 1) {
*op = ':';
@@ -149,15 +150,18 @@ static int uni16_to_x8(unsigned char *as
ec >>= 4;
}
op += 5;
+ len -= 5;
} else {
*op++ = '?';
+ len--;
}
}
- /* We have some slack there, so it's OK */
- if (op>ascii+256) {
- op = ascii + 256;
- break;
- }
+ }
+
+ if(unlikely(*ip)) {
+ printk(KERN_WARNING
+ "FAT: truncated while convert unicode characters in %s\n",
+ __FUNCTION__);
}
*op = 0;
return (op - ascii);
@@ -311,9 +315,11 @@ int fat_search_long(struct inode *inode,
struct nls_table *nls_io = sbi->nls_io;
struct nls_table *nls_disk = sbi->nls_disk;
wchar_t bufuname[14];
- unsigned char xlate_len, nr_slots;
+ int xlate_len;
+ unsigned char nr_slots;
wchar_t *unicode = NULL;
- unsigned char work[8], bufname[260]; /* 256 + 4 */
+ unsigned char work[8];
+ unsigned char *bufname = NULL;
int uni_xlate = sbi->options.unicode_xlate;
int utf8 = sbi->options.utf8;
int anycase = (sbi->options.name_check != 's');
@@ -321,6 +327,10 @@ int fat_search_long(struct inode *inode,
loff_t cpos = 0;
int chl, i, j, last_u, err;
+ bufname = (unsigned char*)__get_free_page(GFP_KERNEL);
+ if (!bufname) {
+ return -ENOMEM;
+ }
err = -ENOENT;
while(1) {
if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
@@ -383,8 +393,8 @@ parse_record:
bufuname[last_u] = 0x0000;
xlate_len = utf8
- ?utf8_wcstombs(bufname, bufuname, sizeof(bufname))
- :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+ ?utf8_wcstombs(bufname, bufuname, PAGE_SIZE)
+ :uni16_to_x8(bufname, bufuname, PAGE_SIZE, uni_xlate, nls_io);
if (xlate_len == name_len)
if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
(anycase && !nls_strnicmp(nls_io, name, bufname,
@@ -393,8 +403,8 @@ parse_record:
if (nr_slots) {
xlate_len = utf8
- ?utf8_wcstombs(bufname, unicode, sizeof(bufname))
- :uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
+ ?utf8_wcstombs(bufname, unicode, PAGE_SIZE)
+ :uni16_to_x8(bufname, unicode, PAGE_SIZE, uni_xlate, nls_io);
if (xlate_len != name_len)
continue;
if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
@@ -413,6 +423,8 @@ Found:
sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
err = 0;
EODir:
+ if (bufname)
+ free_page((unsigned long)bufname);
if (unicode)
free_page((unsigned long)unicode);
@@ -593,7 +605,7 @@ parse_record:
if (isvfat) {
bufuname[j] = 0x0000;
i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname))
- : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+ : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io);
}
fill_name = bufname;
@@ -605,7 +617,7 @@ parse_record:
int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0]));
int long_len = utf8
? utf8_wcstombs(longname, unicode, buf_size)
- : uni16_to_x8(longname, unicode, uni_xlate, nls_io);
+ : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io);
if (!both) {
fill_name = longname;
--- linux-source-2.6.22/fs/vfat/namei.c.orig 2007-07-09 07:32:17.000000000 +0800
+++ linux-source-2.6.22/fs/vfat/namei.c 2008-02-15 18:33:15.000000000 +0800
@@ -176,15 +176,8 @@ static inline int vfat_is_used_badchars(
for (i = 0; i < len; i++)
if (vfat_bad_char(s[i]))
return -EINVAL;
- return 0;
-}
-
-static int vfat_valid_longname(const unsigned char *name, unsigned int len)
-{
- if (name[len - 1] == ' ')
+ if (s[i - 1] == 0x0020) /* last character cannot be space */
return -EINVAL;
- if (len >= 256)
- return -ENAMETOOLONG;
return 0;
}
@@ -485,11 +478,14 @@ xlate_to_uni(const unsigned char *name,
*/
*outlen -= (name_len - len);
+ if (*outlen > 255)
+ return -ENAMETOOLONG;
+
op = &outname[*outlen * sizeof(wchar_t)];
} else {
if (nls) {
for (i = 0, ip = name, op = outname, *outlen = 0;
- i < len && *outlen <= 260;
+ i < len && *outlen <= 255;
*outlen += 1)
{
if (escape && (*ip == ':')) {
@@ -525,18 +521,20 @@ xlate_to_uni(const unsigned char *name,
op += 2;
}
}
+ if (i < len)
+ return -ENAMETOOLONG;
} else {
for (i = 0, ip = name, op = outname, *outlen = 0;
- i < len && *outlen <= 260;
+ i < len && *outlen <= 255;
i++, *outlen += 1)
{
*op++ = *ip++;
*op++ = 0;
}
+ if (i < len)
+ return -ENAMETOOLONG;
}
}
- if (*outlen > 260)
- return -ENAMETOOLONG;
*longlen = *outlen;
if (*outlen % 13) {
@@ -574,9 +572,6 @@ static int vfat_build_slots(struct inode
loff_t offset;
*nr_slots = 0;
- err = vfat_valid_longname(name, len);
- if (err)
- return err;
page = __get_free_page(GFP_KERNEL);
if (!page)
next prev parent reply other threads:[~2008-02-15 10:39 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-13 16:56 [PATCH] vfat: bug fix for vfat cannot handle filename with 255 asian characters when mounted with utf8 Keith Mok
2008-02-15 8:41 ` OGAWA Hirofumi
2008-02-15 10:40 ` Keith Mok [this message]
2008-02-15 10:52 ` OGAWA Hirofumi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=47B56C20.3030200@gmail.com \
--to=ek9852@gmail.com \
--cc=hirofumi@mail.parknet.co.jp \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.