summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/CHANGES6
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifssmb.c20
-rw-r--r--fs/cifs/inode.c21
-rw-r--r--fs/cifs/readdir.c2
5 files changed, 33 insertions, 18 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 9d1fb6ec8a5..1bf81813627 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,9 @@
+Version 1.58
+------------
+Guard against buffer overruns in various UCS-2 to UTF-8 string conversions
+when the UTF-8 string is composed of unusually long (more than 4 byte) converted
+characters.
+
Version 1.57
------------
Improve support for multiple security contexts to the same server. We
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 77e190dc288..051b71cfdea 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */
-#define CIFS_VERSION "1.57"
+#define CIFS_VERSION "1.58"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index a0845dc7b8a..a02c43b3faf 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -88,29 +88,29 @@ static struct {
* on failure - errno
*/
static int
-cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
+cifs_strlcpy_to_host(char **dst, const char *src, const int maxlen,
const bool is_unicode, const struct nls_table *nls_codepage)
{
int plen;
if (is_unicode) {
plen = UniStrnlen((wchar_t *)src, maxlen);
- *dst = kmalloc(plen + 2, GFP_KERNEL);
+ *dst = kmalloc((4 * plen) + 2, GFP_KERNEL);
if (!*dst)
- goto cifs_strncpy_to_host_ErrExit;
+ goto cifs_strlcpy_to_host_ErrExit;
cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
+ (*dst)[plen] = 0;
+ (*dst)[plen+1] = 0; /* needed for Unicode */
} else {
plen = strnlen(src, maxlen);
*dst = kmalloc(plen + 2, GFP_KERNEL);
if (!*dst)
- goto cifs_strncpy_to_host_ErrExit;
- strncpy(*dst, src, plen);
+ goto cifs_strlcpy_to_host_ErrExit;
+ strlcpy(*dst, src, plen);
}
- (*dst)[plen] = 0;
- (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
return 0;
-cifs_strncpy_to_host_ErrExit:
+cifs_strlcpy_to_host_ErrExit:
cERROR(1, ("Failed to allocate buffer for string\n"));
return -ENOMEM;
}
@@ -4029,7 +4029,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
/* copy DfsPath */
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
max_len = data_end - temp;
- rc = cifs_strncpy_to_host(&(node->path_name), temp,
+ rc = cifs_strlcpy_to_host(&(node->path_name), temp,
max_len, is_unicode, nls_codepage);
if (rc)
goto parse_DFS_referrals_exit;
@@ -4037,7 +4037,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
/* copy link target UNC */
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
max_len = data_end - temp;
- rc = cifs_strncpy_to_host(&(node->node_name), temp,
+ rc = cifs_strlcpy_to_host(&(node->node_name), temp,
max_len, is_unicode, nls_codepage);
if (rc)
goto parse_DFS_referrals_exit;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f36b4e40e44..9c869a6dcba 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -962,13 +962,21 @@ undo_setattr:
goto out_close;
}
+
+/*
+ * If dentry->d_inode is null (usually meaning the cached dentry
+ * is a negative dentry) then we would attempt a standard SMB delete, but
+ * if that fails we can not attempt the fall back mechanisms on EACESS
+ * but will return the EACESS to the caller. Note that the VFS does not call
+ * unlink on negative dentries currently.
+ */
int cifs_unlink(struct inode *dir, struct dentry *dentry)
{
int rc = 0;
int xid;
char *full_path = NULL;
struct inode *inode = dentry->d_inode;
- struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+ struct cifsInodeInfo *cifs_inode;
struct super_block *sb = dir->i_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *tcon = cifs_sb->tcon;
@@ -1012,7 +1020,7 @@ psx_del_no_retry:
rc = cifs_rename_pending_delete(full_path, dentry, xid);
if (rc == 0)
drop_nlink(inode);
- } else if (rc == -EACCES && dosattr == 0) {
+ } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
if (attrs == NULL) {
rc = -ENOMEM;
@@ -1020,7 +1028,8 @@ psx_del_no_retry:
}
/* try to reset dos attributes */
- origattr = cifsInode->cifsAttrs;
+ cifs_inode = CIFS_I(inode);
+ origattr = cifs_inode->cifsAttrs;
if (origattr == 0)
origattr |= ATTR_NORMAL;
dosattr = origattr & ~ATTR_READONLY;
@@ -1041,13 +1050,13 @@ psx_del_no_retry:
out_reval:
if (inode) {
- cifsInode = CIFS_I(inode);
- cifsInode->time = 0; /* will force revalidate to get info
+ cifs_inode = CIFS_I(inode);
+ cifs_inode->time = 0; /* will force revalidate to get info
when needed */
inode->i_ctime = current_fs_time(sb);
}
dir->i_ctime = dir->i_mtime = current_fs_time(sb);
- cifsInode = CIFS_I(dir);
+ cifs_inode = CIFS_I(dir);
CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
kfree(full_path);
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 1a8be622833..ebd0da7ecb3 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -1074,7 +1074,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
with the rare long characters alloc more to account for
such multibyte target UTF-8 characters. cifs_unicode.c,
which actually does the conversion, has the same limit */
- tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
+ tmp_buf = kmalloc((4 * NAME_MAX) + 2, GFP_KERNEL);
for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
if (current_entry == NULL) {
/* evaluate whether this case is an error */