fs/cifs: make share unaccessible at root level mountable

if, when mounting //HOST/share/sub/dir/foo we can query /sub/dir/foo but
not any of the path components above:

- store the /sub/dir/foo prefix in the cifs super_block info
- in the superblock, set root dentry to the subpath dentry (instead of
  the share root)
- set a flag in the superblock to remember it
- use prefixpath when building path from a dentry

fixes bso#8950

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
CC: Stable <stable@vger.kernel.org>
Reviewed-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
Aurelien Aptel
2016-05-25 19:59:09 +02:00
committed by Steve French
parent bd975d1eea
commit a6b5058faf
5 changed files with 104 additions and 5 deletions

View File

@@ -3485,6 +3485,44 @@ cifs_get_volume_info(char *mount_data, const char *devname)
return volume_info;
}
static int
cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
char *full_path)
{
int rc;
char *s;
char sep, tmp;
sep = CIFS_DIR_SEP(cifs_sb);
s = full_path;
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
while (rc == 0) {
/* skip separators */
while (*s == sep)
s++;
if (!*s)
break;
/* next separator */
while (*s && *s != sep)
s++;
/*
* temporarily null-terminate the path at the end of
* the current component
*/
tmp = *s;
*s = 0;
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
full_path);
*s = tmp;
}
return rc;
}
int
cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
{
@@ -3622,6 +3660,16 @@ remote_path_check:
kfree(full_path);
goto mount_fail_check;
}
rc = cifs_are_all_path_components_accessible(server,
xid, tcon, cifs_sb,
full_path);
if (rc != 0) {
cifs_dbg(VFS, "cannot query dirs between root and final path, "
"enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
rc = 0;
}
kfree(full_path);
}
@@ -3891,6 +3939,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
bdi_destroy(&cifs_sb->bdi);
kfree(cifs_sb->mountdata);
kfree(cifs_sb->prepath);
call_rcu(&cifs_sb->rcu, delayed_free);
}