cifs: fix parsing of password mount option
Subsystems (2)
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
@@ -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]
Sachin Prabhu
NAKQuoted 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 settingtmp_endto 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()fromcifs_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_lenabove so that we need not call strlen(value) twice.Signed-off-by Suresh Jayaraman <sjayaraman-IBi9RG/[email protected]>--- fs/cifs/connect.c | 37 ++++++++++++++++++++----------------- 1 files changed, 20 insertions(+), 17 deletions(-)fs/cifs/connect.c +13
-16@@ -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
-0vol->password =kzalloc (temp_len+1 ,GFP_KERNEL );if (vol->password ==NULL ) { printk(KERN_WARNING "CIFS: no memory "
Nack.
Sachin Prabhu
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 settingtmp_endto 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()fromcifs_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_lenabove so that we need not call strlen(value) twice.Signed-off-by Suresh Jayaraman <sjayaraman-IBi9RG/[email protected]>--- fs/cifs/connect.c | 37 ++++++++++++++++++++----------------- 1 files changed, 20 insertions(+), 17 deletions(-)fs/cifs/connect.c +20
-16@@ -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
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