Commit d9deef0a3f38bcc1c155e8d9a8b522404e5e648c

Authored by Jeff Layton
Committed by Steve French
1 parent 9c9c29e1af

cifs: fix composing of mount options for DFS referrals

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.

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.

v3: rebase on top of potential buffer overrun fix for stable

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

Showing 2 changed files with 73 additions and 72 deletions Side-by-side Diff

fs/cifs/cifs_dfs_ref.c
... ... @@ -49,58 +49,74 @@
49 49 }
50 50  
51 51 /**
52   - * cifs_get_share_name - extracts share name from UNC
53   - * @node_name: pointer to UNC string
  52 + * cifs_build_devname - build a devicename from a UNC and optional prepath
  53 + * @nodename: pointer to UNC string
  54 + * @prepath: pointer to prefixpath (or NULL if there isn't one)
54 55 *
55   - * Extracts sharename form full UNC.
56   - * i.e. strips from UNC trailing path that is not part of share
57   - * name and fixup missing '\' in the beginning of DFS node refferal
58   - * if necessary.
59   - * Returns pointer to share name on success or ERR_PTR on error.
60   - * Caller is responsible for freeing returned string.
  56 + * Build a new cifs devicename after chasing a DFS referral. Allocate a buffer
  57 + * big enough to hold the final thing. Copy the UNC from the nodename, and
  58 + * concatenate the prepath onto the end of it if there is one.
  59 + *
  60 + * Returns pointer to the built string, or a ERR_PTR. Caller is responsible
  61 + * for freeing the returned string.
61 62 */
62   -static char *cifs_get_share_name(const char *node_name)
  63 +static char *
  64 +cifs_build_devname(char *nodename, const char *prepath)
63 65 {
64   - int len;
65   - char *UNC;
66   - char *pSep;
  66 + size_t pplen;
  67 + size_t unclen;
  68 + char *dev;
  69 + char *pos;
67 70  
68   - len = strlen(node_name);
69   - UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
70   - GFP_KERNEL);
71   - if (!UNC)
72   - return ERR_PTR(-ENOMEM);
  71 + /* skip over any preceding delimiters */
  72 + nodename += strspn(nodename, "\\");
  73 + if (!*nodename)
  74 + return ERR_PTR(-EINVAL);
73 75  
74   - /* get share name and server name */
75   - if (node_name[1] != '\\') {
76   - UNC[0] = '\\';
77   - strncpy(UNC+1, node_name, len);
78   - len++;
79   - UNC[len] = 0;
80   - } else {
81   - strncpy(UNC, node_name, len);
82   - UNC[len] = 0;
83   - }
  76 + /* get length of UNC and set pos to last char */
  77 + unclen = strlen(nodename);
  78 + pos = nodename + unclen - 1;
84 79  
85   - /* find server name end */
86   - pSep = memchr(UNC+2, '\\', len-2);
87   - if (!pSep) {
88   - cifs_dbg(VFS, "%s: no server name end in node name: %s\n",
89   - __func__, node_name);
90   - kfree(UNC);
91   - return ERR_PTR(-EINVAL);
  80 + /* trim off any trailing delimiters */
  81 + while (*pos == '\\') {
  82 + --pos;
  83 + --unclen;
92 84 }
93 85  
94   - /* find sharename end */
95   - pSep++;
96   - pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
97   - if (pSep) {
98   - /* trim path up to sharename end
99   - * now we have share name in UNC */
100   - *pSep = 0;
  86 + /* allocate a buffer:
  87 + * +2 for preceding "//"
  88 + * +1 for delimiter between UNC and prepath
  89 + * +1 for trailing NULL
  90 + */
  91 + pplen = prepath ? strlen(prepath) : 0;
  92 + dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL);
  93 + if (!dev)
  94 + return ERR_PTR(-ENOMEM);
  95 +
  96 + pos = dev;
  97 + /* add the initial "//" */
  98 + *pos = '/';
  99 + ++pos;
  100 + *pos = '/';
  101 + ++pos;
  102 +
  103 + /* copy in the UNC portion from referral */
  104 + memcpy(pos, nodename, unclen);
  105 + pos += unclen;
  106 +
  107 + /* copy the prefixpath remainder (if there is one) */
  108 + if (pplen) {
  109 + *pos = '/';
  110 + ++pos;
  111 + memcpy(pos, prepath, pplen);
  112 + pos += pplen;
101 113 }
102 114  
103   - return UNC;
  115 + /* NULL terminator */
  116 + *pos = '\0';
  117 +
  118 + convert_delimiter(dev, '/');
  119 + return dev;
104 120 }
105 121  
106 122  
... ... @@ -124,6 +140,7 @@
124 140 {
125 141 int rc;
126 142 char *mountdata = NULL;
  143 + const char *prepath = NULL;
127 144 int md_len;
128 145 char *tkn_e;
129 146 char *srvIP = NULL;
... ... @@ -133,7 +150,10 @@
133 150 if (sb_mountdata == NULL)
134 151 return ERR_PTR(-EINVAL);
135 152  
136   - *devname = cifs_get_share_name(ref->node_name);
  153 + if (strlen(fullpath) - ref->path_consumed)
  154 + prepath = fullpath + ref->path_consumed;
  155 +
  156 + *devname = cifs_build_devname(ref->node_name, prepath);
137 157 if (IS_ERR(*devname)) {
138 158 rc = PTR_ERR(*devname);
139 159 *devname = NULL;
140 160  
... ... @@ -147,13 +167,14 @@
147 167 goto compose_mount_options_err;
148 168 }
149 169  
150   - /* md_len = strlen(...) + 12 for 'sep+prefixpath='
151   - * assuming that we have 'unc=' and 'ip=' in
152   - * the original sb_mountdata
  170 + /*
  171 + * In most cases, we'll be building a shorter string than the original,
  172 + * but we do have to assume that the address in the ip= option may be
  173 + * much longer than the original. Add the max length of an address
  174 + * string to the length of the original string to allow for worst case.
153 175 */
154   - md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12 +
155   - INET6_ADDRSTRLEN;
156   - mountdata = kzalloc(md_len+1, GFP_KERNEL);
  176 + md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN;
  177 + mountdata = kzalloc(md_len + 1, GFP_KERNEL);
157 178 if (mountdata == NULL) {
158 179 rc = -ENOMEM;
159 180 goto compose_mount_options_err;
... ... @@ -197,26 +218,6 @@
197 218 strncat(mountdata, &sep, 1);
198 219 strcat(mountdata, "ip=");
199 220 strcat(mountdata, srvIP);
200   - strncat(mountdata, &sep, 1);
201   - strcat(mountdata, "unc=");
202   - strcat(mountdata, *devname);
203   -
204   - /* find & copy prefixpath */
205   - tkn_e = strchr(ref->node_name + 2, '\\');
206   - if (tkn_e == NULL) {
207   - /* invalid unc, missing share name*/
208   - rc = -EINVAL;
209   - goto compose_mount_options_err;
210   - }
211   -
212   - tkn_e = strchr(tkn_e + 1, '\\');
213   - if (tkn_e || (strlen(fullpath) - ref->path_consumed)) {
214   - strncat(mountdata, &sep, 1);
215   - strcat(mountdata, "prefixpath=");
216   - if (tkn_e)
217   - strcat(mountdata, tkn_e + 1);
218   - strcat(mountdata, fullpath + ref->path_consumed);
219   - }
220 221  
221 222 /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
222 223 /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
fs/cifs/dns_resolve.c
... ... @@ -34,7 +34,7 @@
34 34  
35 35 /**
36 36 * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
37   - * @unc: UNC path specifying the server
  37 + * @unc: UNC path specifying the server (with '/' as delimiter)
38 38 * @ip_addr: Where to return the IP address.
39 39 *
40 40 * The IP address will be returned in string form, and the caller is
... ... @@ -64,7 +64,7 @@
64 64 hostname = unc + 2;
65 65  
66 66 /* Search for server name delimiter */
67   - sep = memchr(hostname, '\\', len);
  67 + sep = memchr(hostname, '/', len);
68 68 if (sep)
69 69 len = sep - hostname;
70 70 else