diff mbox

Making shares unaccessible at root level mountable (aka solving bsc#8950 ...again)

Message ID 20160610171649.3e12b95c@aaptelpc (mailing list archive)
State New, archived
Headers show

Commit Message

Aurélien Aptel June 10, 2016, 3:16 p.m. UTC
On Thu, 9 Jun 2016 21:27:34 +0200 Marcus Hoffmann
<marcus.hoffmann@fu-berlin.de> wrote:
> Hey Aurélien,
> with your script I can reproduce the bug locally now.

Good.

> I can mount the share (which is on a Windows 8.1 vm) with a Windows 7
> PC with the restricted user account. (Even in hard mode.)
> I can mount the share from Linux-cifs using the admin user but not the
> restricted user.

I've moved some things around. All of the prefix path components are
now checked for accessibility in cifs_do_mount(). This is more
robust and it lets us set the CIFS_MOUNT_USE_PREFIX_PATH flag earlier.

I've updated the cifs_root_iget() to use the prefix path when necessary
which should take care of the last case (hard mode).

Please test my latest patch (attached).

> (I noticed though that no user has access to the file in the shared
> dir. But this doesn't really matter for the test.)

Indeed.

Comments

Marcus Hoffmann June 12, 2016, 6:01 p.m. UTC | #1
On 06/10/2016 05:16 PM, Aurélien Aptel wrote:
> On Thu, 9 Jun 2016 21:27:34 +0200 Marcus Hoffmann
> <marcus.hoffmann@fu-berlin.de> wrote:
>> Hey Aurélien,
>> with your script I can reproduce the bug locally now.
> 
> Good.
> 
>> I can mount the share (which is on a Windows 8.1 vm) with a Windows 7
>> PC with the restricted user account. (Even in hard mode.)
>> I can mount the share from Linux-cifs using the admin user but not the
>> restricted user.
> 
> I've moved some things around. All of the prefix path components are
> now checked for accessibility in cifs_do_mount(). This is more
> robust and it lets us set the CIFS_MOUNT_USE_PREFIX_PATH flag earlier.
> 
> I've updated the cifs_root_iget() to use the prefix path when necessary
> which should take care of the last case (hard mode).
> 
> Please test my latest patch (attached).

I can confirm it works with our setup now.
Any chance in getting this merged?

> 
>> (I noticed though that no user has access to the file in the shared
>> dir. But this doesn't really matter for the test.)
> 
> Indeed.
> 

Thanks for your work on this,
Marcus
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marcus Hoffmann July 1, 2016, 3:44 p.m. UTC | #2
On 06/10/2016 05:16 PM, Aurélien Aptel wrote:
> On Thu, 9 Jun 2016 21:27:34 +0200 Marcus Hoffmann
> <marcus.hoffmann@fu-berlin.de> wrote:
>> Hey Aurélien,
>> with your script I can reproduce the bug locally now.
> 
> Good.
> 
>> I can mount the share (which is on a Windows 8.1 vm) with a Windows 7
>> PC with the restricted user account. (Even in hard mode.)
>> I can mount the share from Linux-cifs using the admin user but not the
>> restricted user.
> 
> I've moved some things around. All of the prefix path components are
> now checked for accessibility in cifs_do_mount(). This is more
> robust and it lets us set the CIFS_MOUNT_USE_PREFIX_PATH flag earlier.
> 
> I've updated the cifs_root_iget() to use the prefix path when necessary
> which should take care of the last case (hard mode).
> 
> Please test my latest patch (attached).
> 
I just wanted to ask what can be done to get this merged.

>> (I noticed though that no user has access to the file in the shared
>> dir. But this doesn't really matter for the test.)
> 
> Indeed.
> 

Marcus
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve French July 1, 2016, 4:02 p.m. UTC | #3
I will take a look later today.

On Fri, Jul 1, 2016 at 10:44 AM, Marcus Hoffmann
<marcus.hoffmann@fu-berlin.de> wrote:
> On 06/10/2016 05:16 PM, Aurélien Aptel wrote:
>> On Thu, 9 Jun 2016 21:27:34 +0200 Marcus Hoffmann
>> <marcus.hoffmann@fu-berlin.de> wrote:
>>> Hey Aurélien,
>>> with your script I can reproduce the bug locally now.
>>
>> Good.
>>
>>> I can mount the share (which is on a Windows 8.1 vm) with a Windows 7
>>> PC with the restricted user account. (Even in hard mode.)
>>> I can mount the share from Linux-cifs using the admin user but not the
>>> restricted user.
>>
>> I've moved some things around. All of the prefix path components are
>> now checked for accessibility in cifs_do_mount(). This is more
>> robust and it lets us set the CIFS_MOUNT_USE_PREFIX_PATH flag earlier.
>>
>> I've updated the cifs_root_iget() to use the prefix path when necessary
>> which should take care of the last case (hard mode).
>>
>> Please test my latest patch (attached).
>>
> I just wanted to ask what can be done to get this merged.
>
>>> (I noticed though that no user has access to the file in the shared
>>> dir. But this doesn't really matter for the test.)
>>
>> Indeed.
>>
>
> Marcus
Pavel Shilovsky July 2, 2016, 7:02 a.m. UTC | #4
2016-06-10 18:16 GMT+03:00 Aurélien Aptel <aaptel@suse.com>:
...
> I've moved some things around. All of the prefix path components are
> now checked for accessibility in cifs_do_mount(). This is more
> robust and it lets us set the CIFS_MOUNT_USE_PREFIX_PATH flag earlier.
>
> I've updated the cifs_root_iget() to use the prefix path when necessary
> which should take care of the last case (hard mode).
>
> Please test my latest patch (attached).

Hi Aurélien,

Thank you for the patch, it looks good like a right thing to do.

I put my comments below:

@@ -649,6 +649,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
  dentry = child;
  } while (!IS_ERR(dentry));
  kfree(full_path);
+
  return dentry;
 }

Please remove this unnecessary change - probably it will go to stable
some day and may cause extra conflicts.


@@ -1002,10 +1002,21 @@ struct inode *cifs_root_iget(struct super_block *sb)
  struct inode *inode = NULL;
  long rc;
  struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ char *path = NULL;
+ int len;
+
+ if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
cifs_sb->prepath) {
+ len = strlen(cifs_sb->prepath);
+ path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
+ path[0] = '/';
+ memcpy(path+1, cifs_sb->prepath, len);
+ } else {
+ path = kstrdup("", GFP_KERNEL);
+ }

The above code should check for possible memory allocation failure.
Sachin Prabhu July 29, 2016, 1:11 p.m. UTC | #5
On Fri, 2016-06-10 at 17:16 +0200, Aurélien Aptel wrote:
> On Thu, 9 Jun 2016 21:27:34 +0200 Marcus Hoffmann
> <marcus.hoffmann@fu-berlin.de> wrote:
> > 
> > Hey Aurélien,
> > with your script I can reproduce the bug locally now.
> Good.
> 
> > 
> > I can mount the share (which is on a Windows 8.1 vm) with a Windows
> > 7
> > PC with the restricted user account. (Even in hard mode.)
> > I can mount the share from Linux-cifs using the admin user but not
> > the
> > restricted user.
> I've moved some things around. All of the prefix path components are
> now checked for accessibility in cifs_do_mount(). This is more
> robust and it lets us set the CIFS_MOUNT_USE_PREFIX_PATH flag
> earlier.
> 
> I've updated the cifs_root_iget() to use the prefix path when
> necessary
> which should take care of the last case (hard mode).
> 
> Please test my latest patch (attached).
> 
> > 
> > (I noticed though that no user has access to the file in the shared
> > dir. But this doesn't really matter for the test.)
> Indeed.
> 


Hello,

Sorry for the late reply but this has to be a NACK from me.

We need to check for CIFS_MOUNT_USE_PREFIX_PATH
and if set, check cifs_sb->prepath for both old and new
in cifs_match_super().

Else we have the following bug:

Consider 2 different mounts on a server where root access is limited. I
used the reproducer for this case but simply created a separate folder
in the root directory to which the user has access. I then attempt to
mount the 2 separate folders in 2 different locations.

# mount -t cifs -vvv -o username=wintest1,password=xxx //vm140-
52/test2/sub/dir /mnt
# mount -t cifs -vvv -o username=wintest1,password=xxx //vm140-
52/test2/sub2/ /mnt2

# grep mnt /proc/mounts
//vm140-52/test2/sub/dir /mnt cifs
rw,relatime,vers=1.0,cache=strict,username=wintest1,domain=ENG1,uid=0,n
oforceuid,gid=0,noforcegid,addr=192.168.140.52,file_mode=0755,dir_mode=
0755,nounix,serverino,mapposix,rsize=61440,wsize=16580,echo_interval=60
,actimeo=1 0 0
//vm140-52/test2/sub2/ /mnt2 cifs
rw,relatime,vers=1.0,cache=strict,username=wintest1,domain=ENG1,uid=0,n
oforceuid,gid=0,noforcegid,addr=192.168.140.52,file_mode=0755,dir_mode=
0755,nounix,serverino,mapposix,rsize=61440,wsize=16580,echo_interval=60
,actimeo=1 0 0

but since we do not compare the prepath, we end up with the same share
mounted at both mount points. This is the share mounted first.

To confirm.

# date >/mnt/test
# cat /mnt/test /mnt2/test
Fri 29 Jul 14:05:19 BST 2016
Fri 29 Jul 14:05:19 BST 2016

Steve, 

Can you recall the earlier patch or should I write a fix for this?

Sachin Prabhu
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sachin Prabhu July 29, 2016, 1:31 p.m. UTC | #6
On Fri, 2016-07-29 at 14:11 +0100, Sachin Prabhu wrote:
> On Fri, 2016-06-10 at 17:16 +0200, Aurélien Aptel wrote:
> > 
> > On Thu, 9 Jun 2016 21:27:34 +0200 Marcus Hoffmann
> > <marcus.hoffmann@fu-berlin.de> wrote:
> > > 
> > > 
> > > Hey Aurélien,
> > > with your script I can reproduce the bug locally now.
> > Good.
> > 
> > > 
> > > 
> > > I can mount the share (which is on a Windows 8.1 vm) with a
> > > Windows
> > > 7
> > > PC with the restricted user account. (Even in hard mode.)
> > > I can mount the share from Linux-cifs using the admin user but
> > > not
> > > the
> > > restricted user.
> > I've moved some things around. All of the prefix path components
> > are
> > now checked for accessibility in cifs_do_mount(). This is more
> > robust and it lets us set the CIFS_MOUNT_USE_PREFIX_PATH flag
> > earlier.
> > 
> > I've updated the cifs_root_iget() to use the prefix path when
> > necessary
> > which should take care of the last case (hard mode).
> > 
> > Please test my latest patch (attached).
> > 
> > > 
> > > 
> > > (I noticed though that no user has access to the file in the
> > > shared
> > > dir. But this doesn't really matter for the test.)
> > Indeed.
> > 
> 
> Hello,
> 
> Sorry for the late reply but this has to be a NACK from me.
> 
> We need to check for CIFS_MOUNT_USE_PREFIX_PATH
> and if set, check cifs_sb->prepath for both old and new
> in cifs_match_super().
> 
> Else we have the following bug:
> 
> Consider 2 different mounts on a server where root access is limited.
> I
> used the reproducer for this case but simply created a separate
> folder
> in the root directory to which the user has access. I then attempt to
> mount the 2 separate folders in 2 different locations.
> 
> # mount -t cifs -vvv -o username=wintest1,password=xxx //vm140-
> 52/test2/sub/dir /mnt
> # mount -t cifs -vvv -o username=wintest1,password=xxx //vm140-
> 52/test2/sub2/ /mnt2
> 
> # grep mnt /proc/mounts
> //vm140-52/test2/sub/dir /mnt cifs
> rw,relatime,vers=1.0,cache=strict,username=wintest1,domain=ENG1,uid=0
> ,n
> oforceuid,gid=0,noforcegid,addr=192.168.140.52,file_mode=0755,dir_mod
> e=
> 0755,nounix,serverino,mapposix,rsize=61440,wsize=16580,echo_interval=
> 60
> ,actimeo=1 0 0
> //vm140-52/test2/sub2/ /mnt2 cifs
> rw,relatime,vers=1.0,cache=strict,username=wintest1,domain=ENG1,uid=0
> ,n
> oforceuid,gid=0,noforcegid,addr=192.168.140.52,file_mode=0755,dir_mod
> e=
> 0755,nounix,serverino,mapposix,rsize=61440,wsize=16580,echo_interval=
> 60
> ,actimeo=1 0 0
> 
> but since we do not compare the prepath, we end up with the same
> share
> mounted at both mount points. This is the share mounted first.
> 
> To confirm.
> 
> # date >/mnt/test
> # cat /mnt/test /mnt2/test
> Fri 29 Jul 14:05:19 BST 2016
> Fri 29 Jul 14:05:19 BST 2016
> 
> Steve, 
> 
> Can you recall the earlier patch or should I write a fix for this?
> 
> Sachin Prabhu

This bug in the patch was masked by another issue which was fixed by
the patch

cifs: unbreak TCP session reuse
by Rabin Vincent which has been posted to go into upstream at the same
time as this patch.

Sachin Prabhu
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve French July 29, 2016, 8:20 p.m. UTC | #7
Let's add your fix as a followon patch

On Fri, Jul 29, 2016 at 8:31 AM, Sachin Prabhu <sprabhu@redhat.com> wrote:
> On Fri, 2016-07-29 at 14:11 +0100, Sachin Prabhu wrote:
>> On Fri, 2016-06-10 at 17:16 +0200, Aurélien Aptel wrote:
>> >
>> > On Thu, 9 Jun 2016 21:27:34 +0200 Marcus Hoffmann
>> > <marcus.hoffmann@fu-berlin.de> wrote:
>> > >
>> > >
>> > > Hey Aurélien,
>> > > with your script I can reproduce the bug locally now.
>> > Good.
>> >
>> > >
>> > >
>> > > I can mount the share (which is on a Windows 8.1 vm) with a
>> > > Windows
>> > > 7
>> > > PC with the restricted user account. (Even in hard mode.)
>> > > I can mount the share from Linux-cifs using the admin user but
>> > > not
>> > > the
>> > > restricted user.
>> > I've moved some things around. All of the prefix path components
>> > are
>> > now checked for accessibility in cifs_do_mount(). This is more
>> > robust and it lets us set the CIFS_MOUNT_USE_PREFIX_PATH flag
>> > earlier.
>> >
>> > I've updated the cifs_root_iget() to use the prefix path when
>> > necessary
>> > which should take care of the last case (hard mode).
>> >
>> > Please test my latest patch (attached).
>> >
>> > >
>> > >
>> > > (I noticed though that no user has access to the file in the
>> > > shared
>> > > dir. But this doesn't really matter for the test.)
>> > Indeed.
>> >
>>
>> Hello,
>>
>> Sorry for the late reply but this has to be a NACK from me.
>>
>> We need to check for CIFS_MOUNT_USE_PREFIX_PATH
>> and if set, check cifs_sb->prepath for both old and new
>> in cifs_match_super().
>>
>> Else we have the following bug:
>>
>> Consider 2 different mounts on a server where root access is limited.
>> I
>> used the reproducer for this case but simply created a separate
>> folder
>> in the root directory to which the user has access. I then attempt to
>> mount the 2 separate folders in 2 different locations.
>>
>> # mount -t cifs -vvv -o username=wintest1,password=xxx //vm140-
>> 52/test2/sub/dir /mnt
>> # mount -t cifs -vvv -o username=wintest1,password=xxx //vm140-
>> 52/test2/sub2/ /mnt2
>>
>> # grep mnt /proc/mounts
>> //vm140-52/test2/sub/dir /mnt cifs
>> rw,relatime,vers=1.0,cache=strict,username=wintest1,domain=ENG1,uid=0
>> ,n
>> oforceuid,gid=0,noforcegid,addr=192.168.140.52,file_mode=0755,dir_mod
>> e=
>> 0755,nounix,serverino,mapposix,rsize=61440,wsize=16580,echo_interval=
>> 60
>> ,actimeo=1 0 0
>> //vm140-52/test2/sub2/ /mnt2 cifs
>> rw,relatime,vers=1.0,cache=strict,username=wintest1,domain=ENG1,uid=0
>> ,n
>> oforceuid,gid=0,noforcegid,addr=192.168.140.52,file_mode=0755,dir_mod
>> e=
>> 0755,nounix,serverino,mapposix,rsize=61440,wsize=16580,echo_interval=
>> 60
>> ,actimeo=1 0 0
>>
>> but since we do not compare the prepath, we end up with the same
>> share
>> mounted at both mount points. This is the share mounted first.
>>
>> To confirm.
>>
>> # date >/mnt/test
>> # cat /mnt/test /mnt2/test
>> Fri 29 Jul 14:05:19 BST 2016
>> Fri 29 Jul 14:05:19 BST 2016
>>
>> Steve,
>>
>> Can you recall the earlier patch or should I write a fix for this?
>>
>> Sachin Prabhu
>
> This bug in the patch was masked by another issue which was fixed by
> the patch
>
> cifs: unbreak TCP session reuse
> by Rabin Vincent which has been posted to go into upstream at the same
> time as this patch.
>
> Sachin Prabhu
diff mbox

Patch

From e858c28b7bf9b1c76c0a9703727c7bd02bf4a434 Mon Sep 17 00:00:00 2001
From: Aurelien Aptel <aaptel@suse.com>
Date: Wed, 25 May 2016 19:59:09 +0200
Subject: [PATCH] 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>
---
 fs/cifs/cifs_fs_sb.h |  2 ++
 fs/cifs/cifsfs.c     | 15 ++++++++++++++-
 fs/cifs/connect.c    | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/dir.c        | 19 +++++++++++++++++--
 fs/cifs/inode.c      | 17 +++++++++++++++--
 5 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 3182273..02b9ac3 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -46,6 +46,7 @@ 
 #define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
 #define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
 #define CIFS_MOUNT_MAP_SFM_CHR	0x800000 /* SFM/MAC mapping for illegal chars */
+#define CIFS_MOUNT_USE_PREFIX_PATH 0x1000000 /* make subpath with unaccessible root mountable */
 
 struct cifs_sb_info {
 	struct rb_root tlink_tree;
@@ -67,5 +68,6 @@  struct cifs_sb_info {
 	struct backing_dev_info bdi;
 	struct delayed_work prune_tlinks;
 	struct rcu_head rcu;
+	char *prepath;
 };
 #endif				/* _CIFS_FS_SB_H */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 5d8b7ed..c75d80c 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -649,6 +649,7 @@  cifs_get_root(struct smb_vol *vol, struct super_block *sb)
 		dentry = child;
 	} while (!IS_ERR(dentry));
 	kfree(full_path);
+
 	return dentry;
 }
 
@@ -688,6 +689,14 @@  cifs_do_mount(struct file_system_type *fs_type,
 		goto out_cifs_sb;
 	}
 
+	if (volume_info->prepath) {
+		cifs_sb->prepath = kstrdup(volume_info->prepath, GFP_KERNEL);
+		if (cifs_sb->prepath == NULL) {
+			root = ERR_PTR(-ENOMEM);
+			goto out_cifs_sb;
+		}
+	}
+
 	cifs_setup_cifs_sb(volume_info, cifs_sb);
 
 	rc = cifs_mount(cifs_sb, volume_info);
@@ -726,7 +735,11 @@  cifs_do_mount(struct file_system_type *fs_type,
 		sb->s_flags |= MS_ACTIVE;
 	}
 
-	root = cifs_get_root(volume_info, sb);
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) {
+		root = dget(sb->s_root);
+	} else {
+		root = cifs_get_root(volume_info, sb);
+	}
 	if (IS_ERR(root))
 		goto out_super;
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 66736f5..b82d7b4 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3481,6 +3481,42 @@  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)
 {
@@ -3618,6 +3654,14 @@  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 directories 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);
 	}
 
@@ -3887,6 +3931,9 @@  cifs_umount(struct cifs_sb_info *cifs_sb)
 
 	bdi_destroy(&cifs_sb->bdi);
 	kfree(cifs_sb->mountdata);
+	if (cifs_sb->prepath) {
+		kfree(cifs_sb->prepath);
+	}
 	call_rcu(&cifs_sb->rcu, delayed_free);
 }
 
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index c3eb998..5374253 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -84,6 +84,7 @@  build_path_from_dentry(struct dentry *direntry)
 	struct dentry *temp;
 	int namelen;
 	int dfsplen;
+	int pplen = 0;
 	char *full_path;
 	char dirsep;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
@@ -95,8 +96,12 @@  build_path_from_dentry(struct dentry *direntry)
 		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
 	else
 		dfsplen = 0;
+
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+		pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
+
 cifs_bp_rename_retry:
-	namelen = dfsplen;
+	namelen = dfsplen + pplen;
 	seq = read_seqbegin(&rename_lock);
 	rcu_read_lock();
 	for (temp = direntry; !IS_ROOT(temp);) {
@@ -137,7 +142,7 @@  cifs_bp_rename_retry:
 		}
 	}
 	rcu_read_unlock();
-	if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
+	if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) {
 		cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n",
 			 namelen, dfsplen);
 		/* presumably this is only possible if racing with a rename
@@ -153,6 +158,16 @@  cifs_bp_rename_retry:
 	   those safely to '/' if any are found in the middle of the prepath */
 	/* BB test paths to Windows with '/' in the midst of prepath */
 
+	if (pplen) {
+		int i;
+		cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath);
+		memcpy(full_path+dfsplen+1, cifs_sb->prepath, pplen-1);
+		full_path[dfsplen] = '\\';
+		for (i = 0; i < pplen-1; i++)
+			if (full_path[dfsplen+1+i] == '/')
+				full_path[dfsplen+1+i] = CIFS_DIR_SEP(cifs_sb);
+	}
+
 	if (dfsplen) {
 		strncpy(full_path, tcon->treeName, dfsplen);
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 514dadb..7c6edd7 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1002,10 +1002,21 @@  struct inode *cifs_root_iget(struct super_block *sb)
 	struct inode *inode = NULL;
 	long rc;
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+	char *path = NULL;
+	int len;
+
+	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && cifs_sb->prepath) {
+		len = strlen(cifs_sb->prepath);
+		path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
+		path[0] = '/';
+		memcpy(path+1, cifs_sb->prepath, len);
+	} else {
+		path = kstrdup("", GFP_KERNEL);
+	}
 
 	xid = get_xid();
 	if (tcon->unix_ext) {
-		rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
+		rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
 		/* some servers mistakenly claim POSIX support */
 		if (rc != -EOPNOTSUPP)
 			goto iget_no_retry;
@@ -1013,7 +1024,8 @@  struct inode *cifs_root_iget(struct super_block *sb)
 		tcon->unix_ext = false;
 	}
 
-	rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
+	convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
+	rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
 
 iget_no_retry:
 	if (!inode) {
@@ -1042,6 +1054,7 @@  iget_no_retry:
 	}
 
 out:
+	kfree(path);
 	/* can not call macro free_xid here since in a void func
 	 * TODO: This is no longer true
 	 */
-- 
2.1.4