The Samba-Bugzilla – Attachment 850 Details for
Bug 2176
[kernel oops] browsing a directory
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
this patch prevents kernel oops with unicode directory entry
linux-2.6.9_cifs_unicode_dir_entry_problem_fixes (text/plain), 17.79 KB, created by
Han, Donghoon
on 2004-12-21 00:26:07 UTC
(
hide
)
Description:
this patch prevents kernel oops with unicode directory entry
Filename:
MIME Type:
Creator:
Han, Donghoon
Created:
2004-12-21 00:26:07 UTC
Size:
17.79 KB
patch
obsolete
>--- linux-2.6.9/fs/cifs/cifs_unicode.h 2004-10-19 06:55:28.000000000 +0900 >+++ linux-2.6.9-1.681_FC3/fs/cifs/cifs_unicode.h 2004-12-21 15:36:24.034446688 +0900 >@@ -29,6 +29,8 @@ > * The upper/lower functions are based on a table created by mkupr. > * This is a compressed table of upper and lower case conversion. > * >+ * Modified By: Han, Donghoon (nazgul33 at nazgul33 dot com) 2004/12/21 >+ * > */ > > #include <asm/byteorder.h> >@@ -61,6 +63,7 @@ extern struct UniCaseRange UniLowerRange > #ifdef __KERNEL__ > int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); > int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); >+int cifs_strfromUCS_le_fitBufLen(char *, int, const wchar_t *, int, const struct nls_table *); > #endif > > /* >--- linux-2.6.9/fs/cifs/cifs_unicode.c 2004-12-19 02:55:01.000000000 +0900 >+++ linux-2.6.9-1.681_FC3/fs/cifs/cifs_unicode.c 2004-12-21 15:36:05.561255040 +0900 >@@ -17,6 +17,8 @@ > * You should have received a copy of the GNU General Public License > * along with this program; if not, write to the Free Software > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >+ * >+ * Modified By: Han, Donghoon (nazgul33 at nazgul33 dot com) 2004/12/21 > */ > #include <linux/fs.h> > #include "cifs_unicode.h" >@@ -37,25 +39,24 @@ cifs_strfromUCS_le(char *to, const wchar > int i; > int outlen = 0; > >-printk( KERN_ERR "cifs_strfromUCS_le : ." ); >+ printk(KERN_ERR "cifs_strfromUCS_le() : begins : to 0x%08x, from 0x%08x, len %d\n", to, from, len); >+ > for (i = 0; (i < len) && from[i]; i++) { > int charlen; > /* 2.4.0 kernel or greater */ >-printk( KERN_ERR "1" ); > charlen = > codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], > NLS_MAX_CHARSET_SIZE); >-printk( KERN_ERR "2" ); > if (charlen > 0) { > outlen += charlen; >-printk( KERN_ERR "3" ); > } else { > to[outlen++] = '?'; >-printk( KERN_ERR "4" ); > } > } > to[outlen] = 0; >-printk( KERN_ERR "..%d chars converted\n", outlen ); >+ >+ printk(KERN_ERR "cifs_strfromUCS_le() : ends : outlen %d\n", outlen); >+ > return outlen; > } > >@@ -91,3 +92,53 @@ cifs_strtoUCS(wchar_t * to, const char * > return i; > } > >+/* >+ * NAME: cifs_strfromUCS() >+ * >+ * FUNCTION: Convert little-endian unicode string to character string >+ * Converted multibyte string never exceeds to buffer length >+ * if exceeds, remainder will be represented as '~' >+ */ >+int cifs_strfromUCS_le_fitBufLen( char * to, int to_len, const wchar_t * from, int from_len, const struct nls_table *codepage ) >+{ >+ int i,j; >+ int outlen = 0; >+ >+ to_len--; // reserved for null termination >+ >+ for ( i=0; (i<from_len) && from[i]; i++ ) { >+ int charlen; >+ char conv_buffer[NLS_MAX_CHARSET_SIZE]; >+ >+ charlen = >+ codepage->uni2char(le16_to_cpu(from[i]), conv_buffer, >+ NLS_MAX_CHARSET_SIZE); >+ if ( charlen > 0 ) { >+ /* test if converted mbChar fits in to buffer */ >+ if ( ( charlen < to_len - outlen ) || >+ ((charlen == to_len - outlen) >+ && ((i+1>=from_len) || from[i+1]==0)) ) { >+ for(j=0; j<charlen; j++) to[outlen+j]=conv_buffer[j]; >+ outlen += charlen; >+ } else { >+ to[outlen++]='~'; >+ break; // no more room to convert >+ } >+ } else { >+ /* test if we ran out of buffer */ >+ if ( (outlen+1<to_len) || >+ ((outlen+1==to_len) && >+ ((i+1>=from_len) || from[i+1]==0)) ) { >+ to[outlen++]='?'; >+ } else { >+ to[outlen++]='~'; >+ break; >+ } >+ } >+ } >+ to[outlen] = 0; >+ >+ return outlen; >+} >+ >+ >--- linux-2.6.9/fs/cifs/file.c 2004-12-19 03:51:56.000000000 +0900 >+++ linux-2.6.9-1.681_FC3/fs/cifs/file.c 2004-12-21 15:36:28.574756456 +0900 >@@ -19,6 +19,9 @@ > * You should have received a copy of the GNU Lesser General Public License > * along with this library; if not, write to the Free Software > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >+ * >+ * >+ * Modified By: Han, Donghoon (nazgul33 at nazgul33 dot com) 2004/12/21 > */ > #include <linux/fs.h> > #include <linux/stat.h> >@@ -35,8 +38,7 @@ > #include "cifs_debug.h" > #include "cifs_fs_sb.h" > >-int >-cifs_open(struct inode *inode, struct file *file) >+int cifs_open(struct inode *inode, struct file *file) > { > int rc = -EACCES; > int xid, oplock; >@@ -1564,7 +1566,8 @@ construct_dentry(struct qstr *qstring, s > > static void reset_resume_key(struct file * dir_file, > unsigned char * filename, >- unsigned int len,int Unicode,struct nls_table * nls_tab) { >+ unsigned int len) >+{ > struct cifsFileInfo *cifsFile; > > cifsFile = (struct cifsFileInfo *)dir_file->private_data; >@@ -1574,24 +1577,24 @@ static void reset_resume_key(struct file > kfree(cifsFile->search_resume_name); > } > >- if(Unicode) >- len *= 2; >+ /* for safe null termination */ > cifsFile->resume_name_length = len; > > cifsFile->search_resume_name = >- kmalloc(cifsFile->resume_name_length, GFP_KERNEL); >+ kmalloc(cifsFile->resume_name_length + 2, GFP_KERNEL); > > if(cifsFile->search_resume_name == NULL) { > cERROR(1,("failed new resume key allocate, length %d", > cifsFile->resume_name_length)); > return; > } >- if(Unicode) >- cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, >- filename, len, nls_tab); >- else >- memcpy(cifsFile->search_resume_name, filename, >- cifsFile->resume_name_length); >+ >+ memcpy(cifsFile->search_resume_name, filename, >+ cifsFile->resume_name_length); >+ >+ /* for safe null termination */ >+ cifsFile->search_resume_name[len] = 0; >+ cifsFile->search_resume_name[len+1] = 0; > cFYI(1,("Reset resume key to: %s with len %d",filename,len)); > return; > } >@@ -1600,13 +1603,16 @@ static void reset_resume_key(struct file > > static int > cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, >- struct file *file, filldir_t filldir, void *direntry) >+ struct file *file, filldir_t filldir, void *direntry, char * mbFileName ) > { > struct inode *tmp_inode; > struct dentry *tmp_dentry; > int object_type,rc; > >- pqstring->name = pfindData->FileName; >+ if ( mbFileName == NULL ) >+ mbFileName = pfindData->FileName; >+ >+ pqstring->name = mbFileName; > /* pqstring->len is already set by caller */ > > construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); >@@ -1614,12 +1620,12 @@ cifs_filldir(struct qstr *pqstring, FILE > return -ENOMEM; > } > fill_in_inode(tmp_inode, pfindData, &object_type); >- rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, >+ rc = filldir(direntry, mbFileName, pqstring->len, file->f_pos, > tmp_inode->i_ino, object_type); > if(rc) { > /* due to readdir error we need to recalculate resume > key so next readdir will restart on right entry */ >- cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); >+ cFYI(1,("Error %d on filldir of %s",rc , mbFileName)); > } > dput(tmp_dentry); > return rc; >@@ -1628,14 +1634,17 @@ cifs_filldir(struct qstr *pqstring, FILE > static int > cifs_filldir_unix(struct qstr *pqstring, > FILE_UNIX_INFO * pUnixFindData, struct file *file, >- filldir_t filldir, void *direntry) >+ filldir_t filldir, void *direntry, char * mbFileName ) > { > struct inode *tmp_inode; > struct dentry *tmp_dentry; > int object_type, rc; > >- pqstring->name = pUnixFindData->FileName; >- pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); >+ if ( mbFileName == NULL ) >+ mbFileName = pUnixFindData->FileName; >+ >+ pqstring->name = mbFileName; >+ pqstring->len = strnlen(mbFileName, MAX_PATHCONF); > > construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); > if((tmp_inode == NULL) || (tmp_dentry == NULL)) { >@@ -1643,12 +1652,12 @@ cifs_filldir_unix(struct qstr *pqstring, > } > > unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); >- rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, >+ rc = filldir(direntry, mbFileName, pqstring->len, > file->f_pos, tmp_inode->i_ino, object_type); > if(rc) { > /* due to readdir error we need to recalculate resume > key so next readdir will restart on right entry */ >- cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); >+ cFYI(1,("Error %d on filldir of %s",rc , mbFileName)); > } > dput(tmp_dentry); > return rc; >@@ -1661,8 +1670,6 @@ cifs_readdir(struct file *file, void *di > int xid; > int Unicode = FALSE; > int UnixSearch = FALSE; >- int FindDataLength = 0; >- > unsigned int bufsize, i; > __u16 searchHandle; > struct cifs_sb_info *cifs_sb; >@@ -1680,9 +1687,6 @@ cifs_readdir(struct file *file, void *di > xid = GetXid(); > > cifs_sb = CIFS_SB(file->f_dentry->d_sb); >-/* */ >- printk( KERN_ERR "cifs_readdir : local nls -> %s\n", cifs_sb->local_nls->charset ); >-/* */ > pTcon = cifs_sb->tcon; > bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; > if(bufsize > CIFS_MAX_MSGSIZE) { >@@ -1749,7 +1753,7 @@ cifs_readdir(struct file *file, void *di > } > rc = CIFSFindFirst(xid, pTcon, full_path, pfindData, > &findParms, cifs_sb->local_nls, >- &Unicode, &UnixSearch, &FindDataLength ); >+ &Unicode, &UnixSearch); > cFYI(1, ("Count: %d End: %d ", > le16_to_cpu(findParms.SearchCount), > le16_to_cpu(findParms.EndofSearch))); >@@ -1840,83 +1844,89 @@ cifs_readdir(struct file *file, void *di > cifsFile->resume_name_length); > } > for (i = 2; i < count + 2; i++) { >+ /* unicode conversion buffer */ >+ char convBuf[MAX_PATHCONF]; >+ char *pmbFileName = NULL; >+ > if (UnixSearch == FALSE) { > __u32 len = le32_to_cpu(pfindData->FileNameLength); >- if (Unicode == TRUE) { >+ pmbFileName = pfindData->FileName; >+ if (Unicode == TRUE) >+ { >+ pmbFileName = convBuf; > len = >- cifs_strfromUCS_le >- (pfindData->FileName, >- (wchar_t *) >- pfindData->FileName, >- len / 2, >- cifs_sb->local_nls); >-/* */ >- printk( KERN_ERR "cifs_readdir : 1.filename -> %s\n", pfindData->FileName ); >-/* */ >+ cifs_strfromUCS_le_fitBufLen( >+ pmbFileName, MAX_PATHCONF, >+ (wchar_t *) pfindData->FileName, len / 2, >+ cifs_sb->local_nls); > } > qstring.len = len; > if (((len != 1) >- || (pfindData->FileName[0] != '.')) >+ || (pmbFileName[0] != '.')) > && ((len != 2) >- || (pfindData-> >- FileName[0] != '.') >- || (pfindData-> >- FileName[1] != '.'))) { >+ || (pmbFileName[0] != '.') >+ || (pmbFileName[1] != '.'))) { > if(cifs_filldir(&qstring, > pfindData, > file, filldir, >- direntry)) { >+ direntry, pmbFileName)) { > /* do not end search if > kernel not ready to take > remaining entries yet */ >- reset_resume_key(file, pfindData->FileName,qstring.len, >- Unicode, cifs_sb->local_nls); >+ reset_resume_key(file, pfindData->FileName, >+ le32_to_cpu(pfindData->FileNameLength)); > findParms.EndofSearch = 0; > break; > } > file->f_pos++; > } > } else { /* UnixSearch */ >- pfindDataUnix = >- (FILE_UNIX_INFO *) pfindData; >+ __u32 len = 0; >+ pfindDataUnix = (FILE_UNIX_INFO *) pfindData; >+ pmbFileName = pfindDataUnix->FileName; >+ /* calculate safe length */ >+ len = le32_to_cpu(pfindDataUnix->NextEntryOffset) >+ - (__u32)(sizeof(FILE_UNIX_INFO)-1); >+ /* trim extra null chars */ >+ if (Unicode == TRUE) { >+ __u32 lenTmp = len/2-1; >+ wchar_t * pwc = (wchar_t*)pfindDataUnix->FileName; >+ while ( lenTmp>1 && pwc[lenTmp-1] == 0 && pwc[lenTmp] == 0 ) >+ lenTmp--; >+ len=lenTmp*2; >+ } else { >+ __u32 lenTmp = len-1; >+ char * pmb = pfindDataUnix->FileName; >+ while ( lenTmp>1 && pmb[lenTmp-1] == 0 && pmb[lenTmp] == 0 ) >+ lenTmp--; >+ len = lenTmp; >+ } > > if (Unicode == TRUE) { >- __u32 len = FindDataLength + 1 - sizeof(FILE_UNIX_INFO); >+ pmbFileName = convBuf; > qstring.len = >- cifs_strfromUCS_le >- (pfindDataUnix->FileName, >- (wchar_t *) >- pfindDataUnix->FileName, >- /* MAX_PATHCONF, */ len, >- cifs_sb->local_nls); >-/* */ >- printk( KERN_ERR "cifs_readdir : 2.filename -> %s\n", pfindDataUnix->FileName ); >-/* */ >- } >- else >+ cifs_strfromUCS_le_fitBufLen( >+ pmbFileName, MAX_PATHCONF, >+ (wchar_t *) pfindDataUnix->FileName, len / 2, >+ cifs_sb->local_nls); >+ } else > qstring.len = >- strnlen(pfindDataUnix-> >- FileName, >- MAX_PATHCONF); >- if (((qstring.len != 1) >- || (pfindDataUnix-> >- FileName[0] != '.')) >- && ((qstring.len != 2) >- || (pfindDataUnix-> >- FileName[0] != '.') >- || (pfindDataUnix-> >- FileName[1] != '.'))) { >+ strnlen(pmbFileName, len); >+ >+ if (((qstring.len != 1) || (pmbFileName[0] != '.')) >+ && ((qstring.len != 2) || (pmbFileName[0] != '.') >+ || (pmbFileName[1] != '.'))) { > if(cifs_filldir_unix(&qstring, > pfindDataUnix, > file, > filldir, >- direntry)) { >+ direntry, >+ pmbFileName)) { > /* do not end search if > kernel not ready to take > remaining entries yet */ > findParms.EndofSearch = 0; >- reset_resume_key(file, pfindDataUnix->FileName, >- qstring.len,Unicode,cifs_sb->local_nls); >+ reset_resume_key(file, pfindDataUnix->FileName, len ); > break; > } > file->f_pos++; >@@ -1960,7 +1970,7 @@ cifs_readdir(struct file *file, void *di > cifsFile->search_resume_name, > cifsFile->resume_name_length, > cifsFile->resume_key, >- &Unicode, &UnixSearch, &FindDataLength); >+ &Unicode, &UnixSearch); > cFYI(1,("Count: %d End: %d ", > le16_to_cpu(findNextParms.SearchCount), > le16_to_cpu(findNextParms.EndofSearch))); >@@ -2047,86 +2057,88 @@ cifs_readdir(struct file *file, void *di > } > > for (i = 0; i < count; i++) { >- __u32 len = le32_to_cpu(pfindData-> >- FileNameLength); >+ /* unicode conversion buffer */ >+ char convBuf[MAX_PATHCONF]; >+ char *pmbFileName = NULL; >+ > if (UnixSearch == FALSE) { >- if (Unicode == TRUE) { >+ __u32 len = le32_to_cpu(pfindData->FileNameLength); >+ pmbFileName = pfindData->FileName; >+ if (Unicode == TRUE) >+ { >+ pmbFileName = convBuf; > len = >- cifs_strfromUCS_le >- (pfindData->FileName, >- (wchar_t *) >- pfindData->FileName, >- len / 2, >- cifs_sb->local_nls); >-/* */ >- printk( KERN_ERR "cifs_readdir : 3.filename -> %s\n", pfindData->FileName ); >-/* */ >+ cifs_strfromUCS_le_fitBufLen( >+ pmbFileName, MAX_PATHCONF, >+ (wchar_t *)pfindData->FileName, len / 2, >+ cifs_sb->local_nls); > } > qstring.len = len; >- if (((len != 1) >- || (pfindData->FileName[0] != '.')) >+ if (((len != 1) || (pmbFileName[0] != '.')) > && ((len != 2) >- || (pfindData->FileName[0] != '.') >- || (pfindData->FileName[1] != >- '.'))) { >+ || (pmbFileName[0] != '.') >+ || (pmbFileName[1] != '.'))) { > if(cifs_filldir > (&qstring, > pfindData, > file, filldir, >- direntry)) { >+ direntry, pmbFileName)) { > /* do not end search if > kernel not ready to take > remaining entries yet */ > findNextParms.EndofSearch = 0; >- reset_resume_key(file, pfindData->FileName,qstring.len, >- Unicode,cifs_sb->local_nls); >+ reset_resume_key(file, pfindData->FileName, >+ le32_to_cpu(pfindData->FileNameLength)); > break; > } > file->f_pos++; > } > } else { /* UnixSearch */ >- pfindDataUnix = >- (FILE_UNIX_INFO *) >- pfindData; >+ __u32 len = 0; >+ pfindDataUnix = (FILE_UNIX_INFO *) pfindData; >+ pmbFileName = pfindDataUnix->FileName; >+ /* calculate safe length */ >+ len = le32_to_cpu(pfindDataUnix->NextEntryOffset) >+ - (__u32)(sizeof(FILE_UNIX_INFO)-1); >+ /* trim extra null chars */ > if (Unicode == TRUE) { >- __u32 len = FindDataLength + 1 - sizeof(FILE_UNIX_INFO); >- qstring.len = >- cifs_strfromUCS_le >- (pfindDataUnix->FileName, >- (wchar_t *) >- pfindDataUnix->FileName, >- /*MAX_PATHCONF,*/ len, >- cifs_sb->local_nls); >-/* */ >- printk( KERN_ERR "cifs_readdir : 4.filename -> %s\n", pfindData->FileName ); >-/* */ >+ __u32 lenTmp = len/2-1; >+ wchar_t * pwc = (wchar_t*)pfindDataUnix->FileName; >+ while ( lenTmp>1 && pwc[lenTmp-1] == 0 && pwc[lenTmp] == 0 ) >+ lenTmp--; >+ len=lenTmp*2; >+ } else { >+ __u32 lenTmp = len-1; >+ char * pmb = pfindDataUnix->FileName; >+ while ( lenTmp>1 && pmb[lenTmp-1] == 0 && pmb[lenTmp] == 0 ) >+ lenTmp--; >+ len = lenTmp; > } >- else >+ >+ if (Unicode == TRUE) { >+ pmbFileName = convBuf; >+ qstring.len = >+ cifs_strfromUCS_le_fitBufLen( >+ pmbFileName, MAX_PATHCONF, >+ (wchar_t *)pfindDataUnix->FileName, len / 2, >+ cifs_sb->local_nls); >+ } else > qstring.len = >- strnlen >- (pfindDataUnix-> >- FileName, >- MAX_PATHCONF); >- if (((qstring.len != 1) >- || (pfindDataUnix-> >- FileName[0] != '.')) >- && ((qstring.len != 2) >- || (pfindDataUnix-> >- FileName[0] != '.') >- || (pfindDataUnix-> >- FileName[1] != >- '.'))) { >+ strnlen(pmbFileName, len); >+ >+ if (((qstring.len != 1) || (pmbFileName[0] != '.')) >+ && ((qstring.len != 2) || (pmbFileName[0] != '.') >+ || (pmbFileName[1] != '.'))) { > if(cifs_filldir_unix > (&qstring, > pfindDataUnix, > file, filldir, >- direntry)) { >+ direntry, pmbFileName)) { > /* do not end search if > kernel not ready to take > remaining entries yet */ > findNextParms.EndofSearch = 0; >- reset_resume_key(file, pfindDataUnix->FileName,qstring.len, >- Unicode,cifs_sb->local_nls); >+ reset_resume_key(file, pfindDataUnix->FileName, len ); > break; > } > file->f_pos++;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 2176
:
850
|
851
|
852
|
860