All of lore.kernel.org
 help / color / mirror / Atom feed
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)




  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.