diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/CHANGES | 6 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 20 | ||||
-rw-r--r-- | fs/cifs/inode.c | 21 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 2 |
5 files changed, 33 insertions, 18 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 9d1fb6ec8a5a..1bf818136276 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,9 @@ | |||
1 | Version 1.58 | ||
2 | ------------ | ||
3 | Guard against buffer overruns in various UCS-2 to UTF-8 string conversions | ||
4 | when the UTF-8 string is composed of unusually long (more than 4 byte) converted | ||
5 | characters. | ||
6 | |||
1 | Version 1.57 | 7 | Version 1.57 |
2 | ------------ | 8 | ------------ |
3 | Improve support for multiple security contexts to the same server. We | 9 | Improve support for multiple security contexts to the same server. We |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 77e190dc2883..051b71cfdea9 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); | |||
100 | extern const struct export_operations cifs_export_ops; | 100 | extern const struct export_operations cifs_export_ops; |
101 | #endif /* EXPERIMENTAL */ | 101 | #endif /* EXPERIMENTAL */ |
102 | 102 | ||
103 | #define CIFS_VERSION "1.57" | 103 | #define CIFS_VERSION "1.58" |
104 | #endif /* _CIFSFS_H */ | 104 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a0845dc7b8a9..a02c43b3faf5 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -88,29 +88,29 @@ static struct { | |||
88 | * on failure - errno | 88 | * on failure - errno |
89 | */ | 89 | */ |
90 | static int | 90 | static int |
91 | cifs_strncpy_to_host(char **dst, const char *src, const int maxlen, | 91 | cifs_strlcpy_to_host(char **dst, const char *src, const int maxlen, |
92 | const bool is_unicode, const struct nls_table *nls_codepage) | 92 | const bool is_unicode, const struct nls_table *nls_codepage) |
93 | { | 93 | { |
94 | int plen; | 94 | int plen; |
95 | 95 | ||
96 | if (is_unicode) { | 96 | if (is_unicode) { |
97 | plen = UniStrnlen((wchar_t *)src, maxlen); | 97 | plen = UniStrnlen((wchar_t *)src, maxlen); |
98 | *dst = kmalloc(plen + 2, GFP_KERNEL); | 98 | *dst = kmalloc((4 * plen) + 2, GFP_KERNEL); |
99 | if (!*dst) | 99 | if (!*dst) |
100 | goto cifs_strncpy_to_host_ErrExit; | 100 | goto cifs_strlcpy_to_host_ErrExit; |
101 | cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage); | 101 | cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage); |
102 | (*dst)[plen] = 0; | ||
103 | (*dst)[plen+1] = 0; /* needed for Unicode */ | ||
102 | } else { | 104 | } else { |
103 | plen = strnlen(src, maxlen); | 105 | plen = strnlen(src, maxlen); |
104 | *dst = kmalloc(plen + 2, GFP_KERNEL); | 106 | *dst = kmalloc(plen + 2, GFP_KERNEL); |
105 | if (!*dst) | 107 | if (!*dst) |
106 | goto cifs_strncpy_to_host_ErrExit; | 108 | goto cifs_strlcpy_to_host_ErrExit; |
107 | strncpy(*dst, src, plen); | 109 | strlcpy(*dst, src, plen); |
108 | } | 110 | } |
109 | (*dst)[plen] = 0; | ||
110 | (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */ | ||
111 | return 0; | 111 | return 0; |
112 | 112 | ||
113 | cifs_strncpy_to_host_ErrExit: | 113 | cifs_strlcpy_to_host_ErrExit: |
114 | cERROR(1, ("Failed to allocate buffer for string\n")); | 114 | cERROR(1, ("Failed to allocate buffer for string\n")); |
115 | return -ENOMEM; | 115 | return -ENOMEM; |
116 | } | 116 | } |
@@ -4029,7 +4029,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
4029 | /* copy DfsPath */ | 4029 | /* copy DfsPath */ |
4030 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); | 4030 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); |
4031 | max_len = data_end - temp; | 4031 | max_len = data_end - temp; |
4032 | rc = cifs_strncpy_to_host(&(node->path_name), temp, | 4032 | rc = cifs_strlcpy_to_host(&(node->path_name), temp, |
4033 | max_len, is_unicode, nls_codepage); | 4033 | max_len, is_unicode, nls_codepage); |
4034 | if (rc) | 4034 | if (rc) |
4035 | goto parse_DFS_referrals_exit; | 4035 | goto parse_DFS_referrals_exit; |
@@ -4037,7 +4037,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
4037 | /* copy link target UNC */ | 4037 | /* copy link target UNC */ |
4038 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); | 4038 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); |
4039 | max_len = data_end - temp; | 4039 | max_len = data_end - temp; |
4040 | rc = cifs_strncpy_to_host(&(node->node_name), temp, | 4040 | rc = cifs_strlcpy_to_host(&(node->node_name), temp, |
4041 | max_len, is_unicode, nls_codepage); | 4041 | max_len, is_unicode, nls_codepage); |
4042 | if (rc) | 4042 | if (rc) |
4043 | goto parse_DFS_referrals_exit; | 4043 | goto parse_DFS_referrals_exit; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f36b4e40e443..9c869a6dcba1 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -962,13 +962,21 @@ undo_setattr: | |||
962 | goto out_close; | 962 | goto out_close; |
963 | } | 963 | } |
964 | 964 | ||
965 | |||
966 | /* | ||
967 | * If dentry->d_inode is null (usually meaning the cached dentry | ||
968 | * is a negative dentry) then we would attempt a standard SMB delete, but | ||
969 | * if that fails we can not attempt the fall back mechanisms on EACESS | ||
970 | * but will return the EACESS to the caller. Note that the VFS does not call | ||
971 | * unlink on negative dentries currently. | ||
972 | */ | ||
965 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 973 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
966 | { | 974 | { |
967 | int rc = 0; | 975 | int rc = 0; |
968 | int xid; | 976 | int xid; |
969 | char *full_path = NULL; | 977 | char *full_path = NULL; |
970 | struct inode *inode = dentry->d_inode; | 978 | struct inode *inode = dentry->d_inode; |
971 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 979 | struct cifsInodeInfo *cifs_inode; |
972 | struct super_block *sb = dir->i_sb; | 980 | struct super_block *sb = dir->i_sb; |
973 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 981 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
974 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 982 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
@@ -1012,7 +1020,7 @@ psx_del_no_retry: | |||
1012 | rc = cifs_rename_pending_delete(full_path, dentry, xid); | 1020 | rc = cifs_rename_pending_delete(full_path, dentry, xid); |
1013 | if (rc == 0) | 1021 | if (rc == 0) |
1014 | drop_nlink(inode); | 1022 | drop_nlink(inode); |
1015 | } else if (rc == -EACCES && dosattr == 0) { | 1023 | } else if ((rc == -EACCES) && (dosattr == 0) && inode) { |
1016 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); | 1024 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); |
1017 | if (attrs == NULL) { | 1025 | if (attrs == NULL) { |
1018 | rc = -ENOMEM; | 1026 | rc = -ENOMEM; |
@@ -1020,7 +1028,8 @@ psx_del_no_retry: | |||
1020 | } | 1028 | } |
1021 | 1029 | ||
1022 | /* try to reset dos attributes */ | 1030 | /* try to reset dos attributes */ |
1023 | origattr = cifsInode->cifsAttrs; | 1031 | cifs_inode = CIFS_I(inode); |
1032 | origattr = cifs_inode->cifsAttrs; | ||
1024 | if (origattr == 0) | 1033 | if (origattr == 0) |
1025 | origattr |= ATTR_NORMAL; | 1034 | origattr |= ATTR_NORMAL; |
1026 | dosattr = origattr & ~ATTR_READONLY; | 1035 | dosattr = origattr & ~ATTR_READONLY; |
@@ -1041,13 +1050,13 @@ psx_del_no_retry: | |||
1041 | 1050 | ||
1042 | out_reval: | 1051 | out_reval: |
1043 | if (inode) { | 1052 | if (inode) { |
1044 | cifsInode = CIFS_I(inode); | 1053 | cifs_inode = CIFS_I(inode); |
1045 | cifsInode->time = 0; /* will force revalidate to get info | 1054 | cifs_inode->time = 0; /* will force revalidate to get info |
1046 | when needed */ | 1055 | when needed */ |
1047 | inode->i_ctime = current_fs_time(sb); | 1056 | inode->i_ctime = current_fs_time(sb); |
1048 | } | 1057 | } |
1049 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); | 1058 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); |
1050 | cifsInode = CIFS_I(dir); | 1059 | cifs_inode = CIFS_I(dir); |
1051 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ | 1060 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ |
1052 | 1061 | ||
1053 | kfree(full_path); | 1062 | kfree(full_path); |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 1a8be6228333..ebd0da7ecb3d 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) | |||
1074 | with the rare long characters alloc more to account for | 1074 | with the rare long characters alloc more to account for |
1075 | such multibyte target UTF-8 characters. cifs_unicode.c, | 1075 | such multibyte target UTF-8 characters. cifs_unicode.c, |
1076 | which actually does the conversion, has the same limit */ | 1076 | which actually does the conversion, has the same limit */ |
1077 | tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); | 1077 | tmp_buf = kmalloc((4 * NAME_MAX) + 2, GFP_KERNEL); |
1078 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { | 1078 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { |
1079 | if (current_entry == NULL) { | 1079 | if (current_entry == NULL) { |
1080 | /* evaluate whether this case is an error */ | 1080 | /* evaluate whether this case is an error */ |