Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 9d1fb6e..1bf8181 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 77e190d..051b71c 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -100,5 +100,5 @@
 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 a0845dc..a02c43b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -88,29 +88,29 @@
  *	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 @@
 		/* 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 @@
 		/* 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 f36b4e4..9c869a6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -962,13 +962,21 @@
 	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 @@
 		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 @@
 		}
 
 		/* 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 @@
 
 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 1a8be62..ebd0da7 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -1074,7 +1074,7 @@
 		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 */
diff --git a/include/linux/nls.h b/include/linux/nls.h
index 6a88220..52b1a76 100644
--- a/include/linux/nls.h
+++ b/include/linux/nls.h
@@ -58,6 +58,25 @@
 	return 0;
 }
 
+/*
+ * nls_nullsize - return length of null character for codepage
+ * @codepage - codepage for which to return length of NULL terminator
+ *
+ * Since we can't guarantee that the null terminator will be a particular
+ * length, we have to check against the codepage. If there's a problem
+ * determining it, assume a single-byte NULL terminator.
+ */
+static inline int
+nls_nullsize(const struct nls_table *codepage)
+{
+	int charlen;
+	char tmp[NLS_MAX_CHARSET_SIZE];
+
+	charlen = codepage->uni2char(0, tmp, NLS_MAX_CHARSET_SIZE);
+
+	return charlen > 0 ? charlen : 1;
+}
+
 #define MODULE_ALIAS_NLS(name)	MODULE_ALIAS("nls_" __stringify(name))
 
 #endif /* _LINUX_NLS_H */