Skip to contentSkip to conversation

cifs: fix parsing of password mount option

PATCH Superseded Suresh Jayaraman 2 participants 4 messages Jun 11, 2012 – Jun 12, 2012 3 messages not in the archive

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 cifs: fix parsing of password mount option

The double delimiter check that allows a comma in the password parsing code is unconditional. We set "tmp_end" to the end of the string and we continue to check for double delimiter. In the case where the password doesn't contain a comma we end up setting tmp_end to NULL and eventually setting "options" to "end". This results in the premature termination of the options string and hence the values of UNCip and UNC are being set to NULL. This results in mount failure with "Connecting to DFS root not implemented yet" error.

This error is usually not noticable as we have password as the last option in the superblock mountdata. But when we call expand_dfs_referral() from cifs_mount() and try to compose mount options for the submount, the resulting mountdata will be of the form

",ver=1,user=foo,pass=bar,ip=x.x.x.x,unc=\\server\share"

and hence results in the above error. This bug has been seen with older NAS servers running Samba 3.0.24.

Fix this by moving the double delimiter check inside the conditional loop. Also move the assignment of temp_len above so that we need not call strlen(value) twice.

---
 fs/cifs/connect.c |   37 ++++++++++++++++++++-----------------
 1 files changed, 20 insertions(+), 17 deletions(-)
fs/cifs/connect.c +20 -17
index 78db68a..fdbbb56 100644
@@ -1646,34 +1646,37 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 			value = strchr(data, '=');
 			value++;
 
+			temp_len = strlen(value);
+
 			/* Set tmp_end to end of the string */
-			tmp_end = (char *) value + strlen(value);
+			tmp_end = (char *) value + temp_len;
 
 			/* Check if following character is the deliminator
 			 * If yes, we have encountered a double deliminator
 			 * reset the NULL character to the deliminator
 			 */
-			if (tmp_end < end && tmp_end[1] == delim)
+			if (tmp_end < end && tmp_end[1] == delim) {
 				tmp_end[0] = delim;
 
-			/* Keep iterating until we get to a single deliminator
-			 * OR the end
-			 */
-			while ((tmp_end = strchr(tmp_end, delim)) != NULL &&
-			       (tmp_end[1] == delim)) {
-				tmp_end = (char *) &tmp_end[2];
-			}
+				/* Keep iterating until we get to a single
+				 * deliminator OR the end
+				 */
+				while ((tmp_end = strchr(tmp_end, delim))
+					!= NULL && (tmp_end[1] == delim)) {
+						tmp_end = (char *) &tmp_end[2];
+				}
 
-			/* Reset var options to point to next element */
-			if (tmp_end) {
-				tmp_end[0] = '\0';
-				options = (char *) &tmp_end[1];
-			} else
-				/* Reached the end of the mount option string */
-				options = end;
+				/* Reset var options to point to next element */
+				if (tmp_end) {
+					tmp_end[0] = '\0';
+					options = (char *) &tmp_end[1];
+				} else
+					/* Reached the end of the mount option
+					 * string */
+					options = end;
+			}
 
 			/* Now build new password string */
-			temp_len = strlen(value);
 			vol->password = kzalloc(temp_len+1, GFP_KERNEL);
 			if (vol->password == NULL) {
 				printk(KERN_WARNING "CIFS: no memory "

A message that is not in the archive (sent off-list or not yet received): 4FD60F7E.2060608-IBi9RG/[email protected]

#2 lore raw
Quoted 73 lines · Suresh Jayaraman

The double delimiter check that allows a comma in the password parsing code is unconditional. We set "tmp_end" to the end of the string and we continue to check for double delimiter. In the case where the password doesn't contain a comma we end up setting tmp_end to NULL and eventually setting "options" to "end". This results in the premature termination of the options string and hence the values of UNCip and UNC are being set to NULL. This results in mount failure with "Connecting to DFS root not implemented yet" error.

This error is usually not noticable as we have password as the last option in the superblock mountdata. But when we call expand_dfs_referral() from cifs_mount() and try to compose mount options for the submount, the resulting mountdata will be of the form

   ",ver=1,user=foo,pass=bar,ip=x.x.x.x,unc=\\server\share"

and hence results in the above error. This bug has been seen with older NAS servers running Samba 3.0.24.

Fix this by moving the double delimiter check inside the conditional loop. Also move the assignment of temp_len above so that we need not call strlen(value) twice.

---
 fs/cifs/connect.c |   37 ++++++++++++++++++++-----------------
 1 files changed, 20 insertions(+), 17 deletions(-)
fs/cifs/connect.c +13 -16
index 78db68a..fdbbb56 100644
@@ -1646,34 +1646,37 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 			value = strchr(data, '=');
 			value++;
 
+			temp_len = strlen(value);
+
 			/* Set tmp_end to end of the string */
-			tmp_end = (char *) value + strlen(value);
+			tmp_end = (char *) value + temp_len;
 
 			/* Check if following character is the deliminator
 			 * If yes, we have encountered a double deliminator
 			 * reset the NULL character to the deliminator
 			 */
-			if (tmp_end < end && tmp_end[1] == delim)
+			if (tmp_end < end && tmp_end[1] == delim) {
 				tmp_end[0] = delim;
 
-			/* Keep iterating until we get to a single deliminator
-			 * OR the end
-			 */
-			while ((tmp_end = strchr(tmp_end, delim)) != NULL &&
-			       (tmp_end[1] == delim)) {
-				tmp_end = (char *) &tmp_end[2];
-			}
+				/* Keep iterating until we get to a single
+				 * deliminator OR the end
+				 */
+				while ((tmp_end = strchr(tmp_end, delim))
+					!= NULL && (tmp_end[1] == delim)) {
+						tmp_end = (char *) &tmp_end[2];
+				}
 
-			/* Reset var options to point to next element */
-			if (tmp_end) {
-				tmp_end[0] = '\0';
-				options = (char *) &tmp_end[1];
-			} else
-				/* Reached the end of the mount option string */
-				options = end;
+				/* Reset var options to point to next element */
+				if (tmp_end) {

fs/cifs/connect.c cifs_parse_mount_options(const char *mountdata, const char *devname, · line 1676

Quoted 10 lines
fs/cifs/connect.c +7 -1
+					tmp_end[0] = '\0';
+					options = (char *) &tmp_end[1];
+				} else
+					/* Reached the end of the mount option
+					 * string */
+					options = end;
+			}
 
 			/* Now build new password string */
-			temp_len = strlen(value);

The bug fix is correct but you cannot optimise the second strlen() call in this manner since at this point if we had encountered a double delimiter the end of the value string is shifted down further until we hit a single instance of the delimiter. The length of the password at this stage in this case is different to the one calculated above.

fs/cifs/connect.c cifs_parse_mount_options(const char *mountdata, const char *devname, · line 1682

Quoted 3 lines
fs/cifs/connect.c +0 -0
 			vol->password = kzalloc(temp_len+1, GFP_KERNEL);
 			if (vol->password == NULL) {
 				printk(KERN_WARNING "CIFS: no memory "

Nack.

Sachin Prabhu

#3 lore raw
Quoted 82 lines · Sachin Prabhu
Quoted 81 lines · Suresh Jayaraman

The double delimiter check that allows a comma in the password parsing code is unconditional. We set "tmp_end" to the end of the string and we continue to check for double delimiter. In the case where the password doesn't contain a comma we end up setting tmp_end to NULL and eventually setting "options" to "end". This results in the premature termination of the options string and hence the values of UNCip and UNC are being set to NULL. This results in mount failure with "Connecting to DFS root not implemented yet" error.

This error is usually not noticable as we have password as the last option in the superblock mountdata. But when we call expand_dfs_referral() from cifs_mount() and try to compose mount options for the submount, the resulting mountdata will be of the form

   ",ver=1,user=foo,pass=bar,ip=x.x.x.x,unc=\\server\share"

and hence results in the above error. This bug has been seen with older NAS servers running Samba 3.0.24.

Fix this by moving the double delimiter check inside the conditional loop. Also move the assignment of temp_len above so that we need not call strlen(value) twice.

---
 fs/cifs/connect.c |   37 ++++++++++++++++++++-----------------
 1 files changed, 20 insertions(+), 17 deletions(-)
fs/cifs/connect.c +20 -16
index 78db68a..fdbbb56 100644
@@ -1646,34 +1646,37 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 			value = strchr(data, '=');
 			value++;
 
+			temp_len = strlen(value);
+
 			/* Set tmp_end to end of the string */
-			tmp_end = (char *) value + strlen(value);
+			tmp_end = (char *) value + temp_len;
 
 			/* Check if following character is the deliminator
 			 * If yes, we have encountered a double deliminator
 			 * reset the NULL character to the deliminator
 			 */
-			if (tmp_end < end && tmp_end[1] == delim)
+			if (tmp_end < end && tmp_end[1] == delim) {
 				tmp_end[0] = delim;
 
-			/* Keep iterating until we get to a single deliminator
-			 * OR the end
-			 */
-			while ((tmp_end = strchr(tmp_end, delim)) != NULL &&
-			       (tmp_end[1] == delim)) {
-				tmp_end = (char *) &tmp_end[2];
-			}
+				/* Keep iterating until we get to a single
+				 * deliminator OR the end
+				 */
+				while ((tmp_end = strchr(tmp_end, delim))
+					!= NULL && (tmp_end[1] == delim)) {
+						tmp_end = (char *) &tmp_end[2];
+				}
 
-			/* Reset var options to point to next element */
-			if (tmp_end) {
-				tmp_end[0] = '\0';
-				options = (char *) &tmp_end[1];
-			} else
-				/* Reached the end of the mount option string */
-				options = end;
+				/* Reset var options to point to next element */
+				if (tmp_end) {
+					tmp_end[0] = '\0';
+					options = (char *) &tmp_end[1];
+				} else
+					/* Reached the end of the mount option
+					 * string */
+					options = end;
+			}
 
Quoted 6 lines

fs/cifs/connect.c cifs_parse_mount_options(const char *mountdata, const char *devname, · line 1676

Quoted 2 lines
fs/cifs/connect.c +0 -1
 			/* Now build new password string */
-			temp_len = strlen(value);

The bug fix is correct but you cannot optimise the second strlen() call in this manner since at this point if we had encountered a double delimiter the end of the value string is shifted down further until we

Doh, you're right. I'll respin the fixed one.

A message that is not in the archive (sent off-list or not yet received): CAH2r5mukodjGqKNvbo6HB_PhUBzauckeSKCqCEYzpQGxbUtAMw@mail.gmail.com

A message that is not in the archive (sent off-list or not yet received): CAH2r5mukodjGqKNvbo6HB_PhUBzauckeSKCqCEYzpQGxbUtAMw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#6 lore raw
Quoted 2 lines · Steve French

Wouldn't this also have to go cc: stable since it involves password check logic in last release too?

yes, this has to go to stable, specifically for 3.1 and above. Once reviewed and accepted, please add

Thanks
Suresh