Patchwork [hardy,CVE,1/1] cifs: ensure we check both username and password when reusing a session

login
register
mail settings
Submitter Andy Whitcroft
Date Oct. 25, 2011, 4:12 p.m.
Message ID <1319559148-30401-2-git-send-email-apw@canonical.com>
Download mbox | patch
Permalink /patch/121733/
State New
Headers show

Comments

Andy Whitcroft - Oct. 25, 2011, 4:12 p.m.
In the case where we do match by username, we also need to match by
password.  That ensures that someone else doesn't "borrow" an existing
session without needing to know the password.

Also now that we may not reuse the connection ensure we do not force
disconnect any existing connection.

Equivalent to the CVE components of:
  commit 4ff67b720c02c36e54d55b88c2931879b7db1cd2
  commit fc87a40677bbe0937e2ff0642c7e83c9a4813f3d
  commit 24e6cf92fde1f140d8eb0bf7cd24c2c78149b6b2

CVE-2011-1585
BugLink: http://bugs.launchpad.net/bugs/869208
Signed-off-by: Andy Whitcroft <apw@canonical.com>
---
 fs/cifs/connect.c |   36 +++++++++++++++++++++++++++++-------
 1 files changed, 29 insertions(+), 7 deletions(-)

Patch

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 6eb27ff..f31f906 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1316,10 +1316,34 @@  cifs_parse_mount_options(char *options, const char *devname,
 	return 0;
 }
 
+int __username_password_chk(struct cifsSesInfo *ses, struct smb_vol *vol)
+{
+	struct TCP_Server_Info *server = ses->server;
+
+	switch (server->secType) {
+	case Kerberos:
+		if (vol->linux_uid != ses->linux_uid)
+			return 0;
+		break;
+	default:
+		/* anything else takes username/password */
+		if (strncmp(ses->userName, vol->username,
+			    MAX_USERNAME_SIZE))
+			return 0;
+		if (strlen(vol->username) != 0 &&
+		    ses->password != NULL &&
+		    strncmp(ses->password,
+			    vol->password ? vol->password : "",
+			    MAX_PASSWORD_SIZE))
+			return 0;
+	}
+	return 1;
+}
+
 static struct cifsSesInfo *
 cifs_find_tcp_session(struct in_addr *target_ip_addr,
 		struct in6_addr *target_ip6_addr,
-		 char *userName, struct TCP_Server_Info **psrvTcp)
+		struct smb_vol *vol, struct TCP_Server_Info **psrvTcp)
 {
 	struct list_head *tmp;
 	struct cifsSesInfo *ses;
@@ -1341,9 +1365,7 @@  cifs_find_tcp_session(struct in_addr *target_ip_addr,
 				*psrvTcp = ses->server;
 
 				/* BB check if reconnection needed */
-				if (strncmp
-				    (ses->userName, userName,
-				     MAX_USERNAME_SIZE) == 0){
+				if (__username_password_chk(ses, vol)) {
 					read_unlock(&GlobalSMBSeslock);
 					/* Found exact match on both TCP and
 					   SMB sessions */
@@ -1882,12 +1904,12 @@  cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 	if (address_type == AF_INET)
 		existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
 			NULL /* no ipv6 addr */,
-			volume_info.username, &srvTcp);
+			&volume_info, &srvTcp);
 	else if (address_type == AF_INET6) {
 		cFYI(1, ("looking for ipv6 address"));
 		existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
 			&sin_server6.sin6_addr,
-			volume_info.username, &srvTcp);
+			&volume_info, &srvTcp);
 	} else {
 		rc = -EINVAL;
 		goto out;
@@ -2178,7 +2200,7 @@  cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 						if (tsk)
 							kthread_stop(tsk);
 					}
-				} else {
+				} else if (atomic_read(&srvTcp->socketUseCount) == 0) {
 					cFYI(1, ("No session or bad tcon"));
 					if ((pSesInfo->server) &&
 					    (pSesInfo->server->tsk)) {