On Thu, 23 May 2013 14:47:44 -0400 Jeff Layton <jlayton@xxxxxxxxxx> wrote: > With the change to ignore the unc= and prefixpath= mount options, there > is no longer any need to add them to the options string when mounting. > By the same token, we now need to build a device name that includes the > prefixpath when mounting. > > To make things neater, the delimiters on the devicename are changed > to '/' since that's preferred when mounting anyway. > > While we're at it, fix a potential buffer overrun when building the > mount options string, if the new ip= option is much longer than the > original one. > > v2: fix some comments and don't bother looking at whether there is > a prepath in the ref->node_name when deciding whether to pass > a prepath to cifs_build_devname. > > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> > --- > fs/cifs/cifs_dfs_ref.c | 141 +++++++++++++++++++++++++------------------------ > fs/cifs/dns_resolve.c | 4 +- > 2 files changed, 74 insertions(+), 71 deletions(-) > > diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c > index 8e33ec6..43feb8d 100644 > --- a/fs/cifs/cifs_dfs_ref.c > +++ b/fs/cifs/cifs_dfs_ref.c > @@ -18,6 +18,7 @@ > #include <linux/slab.h> > #include <linux/vfs.h> > #include <linux/fs.h> > +#include <linux/inet.h> > #include "cifsglob.h" > #include "cifsproto.h" > #include "cifsfs.h" > @@ -48,58 +49,74 @@ void cifs_dfs_release_automount_timer(void) > } > > /** > - * cifs_get_share_name - extracts share name from UNC > - * @node_name: pointer to UNC string > + * cifs_build_devname - build a devicename from a UNC and optional prepath > + * @nodename: pointer to UNC string > + * @prepath: pointer to prefixpath (or NULL if there isn't one) > * > - * Extracts sharename form full UNC. > - * i.e. strips from UNC trailing path that is not part of share > - * name and fixup missing '\' in the beginning of DFS node refferal > - * if necessary. > - * Returns pointer to share name on success or ERR_PTR on error. > - * Caller is responsible for freeing returned string. > + * Build a new cifs devicename after chasing a DFS referral. Allocate a buffer > + * big enough to hold the final thing. Copy the UNC from the nodename, and > + * concatenate the prepath onto the end of it if there is one. > + * > + * Returns pointer to the built string, or a ERR_PTR. Caller is responsible > + * for freeing the returned string. > */ > -static char *cifs_get_share_name(const char *node_name) > +static char * > +cifs_build_devname(char *nodename, const char *prepath) > { > - int len; > - char *UNC; > - char *pSep; > - > - len = strlen(node_name); > - UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */, > - GFP_KERNEL); > - if (!UNC) > - return ERR_PTR(-ENOMEM); > + size_t pplen; > + size_t unclen; > + char *dev; > + char *pos; > + > + /* skip over any preceding delimiters */ > + nodename += strspn(nodename, "\\"); > + if (!*nodename) > + return ERR_PTR(-EINVAL); > > - /* get share name and server name */ > - if (node_name[1] != '\\') { > - UNC[0] = '\\'; > - strncpy(UNC+1, node_name, len); > - len++; > - UNC[len] = 0; > - } else { > - strncpy(UNC, node_name, len); > - UNC[len] = 0; > - } > + /* get length of UNC and set pos to last char */ > + unclen = strlen(nodename); > + pos = nodename + unclen - 1; > > - /* find server name end */ > - pSep = memchr(UNC+2, '\\', len-2); > - if (!pSep) { > - cifs_dbg(VFS, "%s: no server name end in node name: %s\n", > - __func__, node_name); > - kfree(UNC); > - return ERR_PTR(-EINVAL); > + /* trim off any trailing delimiters */ > + while(*pos == '\\') { > + --pos; > + --unclen; > } > > - /* find sharename end */ > - pSep++; > - pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC)); > - if (pSep) { > - /* trim path up to sharename end > - * now we have share name in UNC */ > - *pSep = 0; > + /* allocate a buffer: > + * +2 for preceding "//" > + * +1 for delimiter between UNC and prepath > + * +1 for trailing NULL > + */ > + pplen = prepath ? strlen(prepath) : 0; > + dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL); > + if (!dev) > + return ERR_PTR(-ENOMEM); > + > + pos = dev; > + /* add the initial "//" */ > + *pos = '/'; > + ++pos; > + *pos = '/'; > + ++pos; > + > + /* copy in the UNC portion from referral */ > + memcpy(pos, nodename, unclen); > + pos += unclen; > + > + /* copy the prefixpath remainder (if there is one) */ > + if (pplen) { > + *pos = '/'; > + ++pos; > + memcpy(pos, prepath, pplen); > + pos += pplen; > } > > - return UNC; > + /* NULL terminator */ > + *pos = '\0'; > + > + convert_delimiter(dev, '/'); > + return dev; > } > > > @@ -123,6 +140,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, > { > int rc; > char *mountdata = NULL; > + const char *prepath = NULL; > int md_len; > char *tkn_e; > char *srvIP = NULL; > @@ -132,7 +150,10 @@ char *cifs_compose_mount_options(const char *sb_mountdata, > if (sb_mountdata == NULL) > return ERR_PTR(-EINVAL); > > - *devname = cifs_get_share_name(ref->node_name); > + if (strlen(fullpath) - ref->path_consumed) > + prepath = fullpath + ref->path_consumed; > + > + *devname = cifs_build_devname(ref->node_name, prepath); > if (IS_ERR(*devname)) { > rc = PTR_ERR(*devname); > *devname = NULL; > @@ -146,12 +167,14 @@ char *cifs_compose_mount_options(const char *sb_mountdata, > goto compose_mount_options_err; > } > > - /* md_len = strlen(...) + 12 for 'sep+prefixpath=' > - * assuming that we have 'unc=' and 'ip=' in > - * the original sb_mountdata > + /* > + * In most cases, we'll be building a shorter string than the original, > + * but we do have to assume that the address in the ip= option may be > + * much longer than the original. Add the max length of an address > + * string to the length of the original string to allow for worst case. > */ > - md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12; > - mountdata = kzalloc(md_len+1, GFP_KERNEL); > + md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN; > + mountdata = kzalloc(md_len + 1, GFP_KERNEL); Hmm... on third thought, I'll go ahead and spin up a smaller patch that just fixes this potential buffer overrun so we can send it to stable, and re-base this patch on top of that. Sorry for the noise... -- Jeff Layton <jlayton@xxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html