| From stable-bounces@linux.kernel.org Sat Aug 5 12:15:54 2006 |
| Message-Id: <200608051914.k75JEthD011006@shell0.pdx.osdl.net> |
| To: torvalds@osdl.org |
| From: akpm@osdl.org |
| Date: Sat, 05 Aug 2006 12:14:55 -0700 |
| Cc: akpm@osdl.org, greg@kroah.com, jjk@acm.org, diegocg@gmail.com, stable@kernel.org |
| Subject: Fix BeFS slab corruption |
| |
| From: Diego Calleja <diegocg@gmail.com> |
| |
| In bugzilla #6941, Jens Kilian reported: |
| |
| "The function befs_utf2nls (in fs/befs/linuxvfs.c) writes a 0 byte past the |
| end of a block of memory allocated via kmalloc(), leading to memory |
| corruption. This happens only for filenames which are pure ASCII and a |
| multiple of 4 bytes in length. [...] |
| |
| Without DEBUG_SLAB, this leads to further corruption and hard lockups; I |
| believe this is the bug which has made kernels later than 2.6.8 unusable |
| for me. (This must be due to changes in memory management, the bug has |
| been in the BeFS driver since the time it was introduced (AFAICT).) |
| |
| Steps to reproduce: |
| Create a directory (in BeOS, naturally :-) with files named, e.g., |
| "1", "22", "333", "4444", ... Mount it in Linux and do an "ls" or "find"" |
| |
| This patch implements the suggested fix. Credits to Jens Kilian for |
| debugging the problem and finding the right fix. |
| |
| Signed-off-by: Diego Calleja <diegocg@gmail.com> |
| Cc: Jens Kilian <jjk@acm.org> |
| Signed-off-by: Andrew Morton <akpm@osdl.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/befs/linuxvfs.c | 11 +++++++++-- |
| 1 file changed, 9 insertions(+), 2 deletions(-) |
| |
| --- linux-2.6.17.8.orig/fs/befs/linuxvfs.c |
| +++ linux-2.6.17.8/fs/befs/linuxvfs.c |
| @@ -512,7 +512,11 @@ befs_utf2nls(struct super_block *sb, con |
| wchar_t uni; |
| int unilen, utflen; |
| char *result; |
| - int maxlen = in_len; /* The utf8->nls conversion can't make more chars */ |
| + /* The utf8->nls conversion won't make the final nls string bigger |
| + * than the utf one, but if the string is pure ascii they'll have the |
| + * same width and an extra char is needed to save the additional \0 |
| + */ |
| + int maxlen = in_len + 1; |
| |
| befs_debug(sb, "---> utf2nls()"); |
| |
| @@ -588,7 +592,10 @@ befs_nls2utf(struct super_block *sb, con |
| wchar_t uni; |
| int unilen, utflen; |
| char *result; |
| - int maxlen = 3 * in_len; |
| + /* There're nls characters that will translate to 3-chars-wide UTF-8 |
| + * characters, a additional byte is needed to save the final \0 |
| + * in special cases */ |
| + int maxlen = (3 * in_len) + 1; |
| |
| befs_debug(sb, "---> nls2utf()\n"); |
| |