This adds a `struct vfsmount *mnt` parameters to
vfsub_lookup_one_len[_unlocked]() so that it can
pass a correct `struct path.mnt` value up to VFS
in vfsub_getattr().
Many other places in aufs do set/pass `mnt` right,
particularly seen w/ calls to vfsub_dentry_open(),
including another two callers of vfsub_get_attr().
Looking at fs/, other usage of `struct path.mnt`
never checks for NULL, so it's assumed to be set,
and thus should always be set by callers.
This fixes a potentially 10 year old bug that is
exposed by AppArmor when accessing the provided
`path.mnt.mnt_flags` since commit (torvalds.git):
(with a public report 4 years 10 months ago [1])
commit 02125a826459a6ad142f8d91c5b6357562f96615
Author: Al Viro <[email protected]>
Date: Mon Dec 5 08:43:34 2011 -0500
fix apparmor dereferencing potentially freed dentry,
sanitize__d_path() API
And `path.mnt` is NULL at least since early 2009,
maybe longer (aufs2-standalone.git, aufs2 branch):
commit d8a76a43eff98f77bf47650ff430e80952af5f82
Author: J. R. Okajima <[email protected]>
Date: Wed Mar 25 22:39:29 2009 +0900
aufs2 standalone version for linux-2.6.
Nowadays it can be hit without AppArmor in 5.15-rcN.
Traces:
---
AppArmor disabled:
[ 89.908402] BUG: kernel NULL pointer dereference, address:
0000000000000018
...
[ 89.918876] CPU: 0 PID: 669 Comm: openat Not tainted 5.15.0-rc2+ #4
[ 89.921600] Hardware name: QEMU Standard PC ...
[ 89.925159] RIP: 0010:vfs_getattr_nosec+0x81/0x140
...
[ 89.976333] Call Trace:
[ 89.977852] vfsub_update_h_iattr+0x92/0xa0
[ 89.980511] vfsub_lookup_one_len+0x5e/0x70
[ 89.984948] au_wh_test+0x1c/0x80
[ 89.986344] au_lkup_dentry+0x192/0x520
[ 89.988310] aufs_lookup.part.0+0x10e/0x200
[ 89.990470] aufs_atomic_open+0x198/0x400
[ 89.992114] ? may_create+0x133/0x140
[ 89.993037] path_openat+0x645/0x1070
[ 89.994588] do_filp_open+0xad/0x120
[ 89.995507] do_sys_openat2+0x241/0x320
[ 89.996685] do_sys_open+0x3f/0x80
[ 89.997795] do_syscall_64+0x3b/0x90
[ 89.998985] entry_SYSCALL_64_after_hwframe+0x44/0xae
AppArmor enabled:
[ 63.182645] BUG: kernel NULL pointer dereference, address:
0000000000000018
...
[ 63.203176] CPU: 0 PID: 799 Comm: openat Not tainted 5.15.0-rc2+ #4
[ 63.206765] Hardware name: QEMU Standard PC ...
[ 63.210428] RIP: 0010:common_perm_cond+0x17/0x70
...
[ 63.248667] Call Trace:
[ 63.249558] security_inode_getattr+0x2b/0x40
[ 63.251174] vfs_getattr+0x18/0x40
[ 63.252573] vfsub_update_h_iattr+0x92/0xa0
[ 63.253711] ? lookup_dcache+0x38/0x60
[ 63.254613] ? lookup_one_len+0x6b/0x90
[ 63.255545] vfsub_lookup_one_len+0x5e/0x70
[ 63.256631] au_wh_test+0x1c/0x80
[ 63.257459] au_lkup_dentry+0x192/0x520
[ 63.258431] aufs_lookup.part.0+0x10e/0x200
[ 63.259446] aufs_atomic_open+0x198/0x400
[ 63.260371] ? h_permission+0x5a/0xc0
[ 63.261074] path_openat+0x645/0x1070
[ 63.261769] do_filp_open+0xad/0x120
[ 63.262487] do_sys_openat2+0x241/0x320
[ 63.263229] do_sys_open+0x3f/0x80
[ 63.263835] do_syscall_64+0x3b/0x90
[ 63.264437] entry_SYSCALL_64_after_hwframe+0x44/0xae
Changes:
---
Unfortunately the changed functions (and callers)
are referenced in many locations in the aufs code,
so even though the core change is small, a lot of
resulting changes are required.
Thankfully it's a simple modification to provide
`struct vfsmount` in the function call and that's
usually already available (otherwise, get it with
`au_br_mnt(au_sbr(dentry->d_sb, bindex))` as done
in other functions in aufs.
vfsub_lookup_one_len
- au_drinfo_do_store
- au_drinfo_do_load
- vfsub_lkup_one
- - au_do_ren_after_cpup
- - au_do_lookup
- - au_sio_lkup_one
- - - au_do_lookup
- - - au_lkup_neg
- - - au_may_del
- - - au_wh_test
- - - au_whtmp_lkup
- - au_h_verify_dentry
- - au_dr_hino
- - au_ren_rev_rename
- - au_ren_rev_whtmp
- - au_do_plink_lkup
- - do_whplink
- - vfsub_call_lkup_one
- - - au_sio_lkup_one
- - au_wh_test
- - - au_do_lookup
- - - au_diropq_test
- - - - au_do_lookup
- - unlink_wh_name
- - do_diropq
- - au_wh_lkup
- au_xino_create2
vfsub_lookup_one_len_unlocked
- au_lkup_by_ino
Reproducer:
---
- openat("test", O_CREAT)
- read-only branch with "test" file
(apparently for vfsub_lookup_one_len() -> vfsub_update_h_iattr())
- read-write branch on fuseblk
(for vfsub_update_h_iattr() -> vfsub_getattr())
without the "test" file
- [optional: apparmor-enabled application]
1) test app
# cat openat.c
#include <stdio.h>
#include <fcntl.h>
int main() {
int rc;
rc = openat(AT_FDCWD, "test", O_RDWR | O_CREAT | S_IRWXU);
if (rc < 0) {
perror("openat");
return 1;
}
return 0;
}
# gcc -o openat openat.c
2) ntfs-3g mount (fuseblk)
# truncate -s 1g ntfs.img
# DEV=$(losetup -f --show ntfs.img)
# mkfs.ntfs --fast $DEV
# mkdir ntfs
# mount -t ntfs-3g $DEV ntfs
# mount | grep ntfs
/dev/loop6 on /home/ubuntu/ntfs type fuseblk
(rw,relatime,user_id=0,group_id=0,allow_other,blksize=4096)
3) aufs mount (with 'test' file in the read-only branch)
# mkdir ro aufs
# touch ro/test
# mount -t aufs -o br=ntfs:ro none aufs
4) [optional] enable apparmor for the test app (even in complain mode for
aa-genprof)
# aa-genprof ./openat &
...
Please start the application to be profiled in
another window and exercise its functionality now.
...
<press enter>
[1]+ Stopped aa-genprof ./openat
5) remove 'test' file from read-write branch (still exists in read-only branch)
# cd aufs
# rm test
6) run the test app
# ../openat
Killed
(See kernel error above.)
[1]
https://unix.stackexchange.com/questions/324571/docker-run-causing-kernel-panic
Signed-off-by: Mauricio Faria de Oliveira <[email protected]>
---
fs/aufs/cpup.c | 4 +++-
fs/aufs/dentry.c | 24 +++++++++++++++---------
fs/aufs/dentry.h | 2 +-
fs/aufs/dirren.c | 15 +++++++--------
fs/aufs/export.c | 2 +-
fs/aufs/i_op_del.c | 6 +++++-
fs/aufs/i_op_ren.c | 10 ++++++++--
fs/aufs/plink.c | 5 +++--
fs/aufs/vfsub.c | 15 ++++++++-------
fs/aufs/vfsub.h | 11 +++++++----
fs/aufs/whout.c | 23 ++++++++++++++---------
fs/aufs/whout.h | 5 +++--
fs/aufs/xino.c | 4 ++--
13 files changed, 77 insertions(+), 49 deletions(-)
diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c
index dbaa01a55904..b50c705595b4 100644
--- a/fs/aufs/cpup.c
+++ b/fs/aufs/cpup.c
@@ -763,7 +763,9 @@ static int au_do_ren_after_cpup(struct au_cp_generic *cpg,
struct path *h_path)
parent = dget_parent(dentry);
h_parent = au_h_dptr(parent, bdst);
dput(parent);
- h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent);
+ /* h_path->mnt was set by single caller au_cpup_single() */
+ h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent,
+ h_path->mnt);
if (IS_ERR(h_path->dentry))
err = PTR_ERR(h_path->dentry);
}
diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c
index 4b63daab7220..69ee48fae27c 100644
--- a/fs/aufs/dentry.c
+++ b/fs/aufs/dentry.c
@@ -35,6 +35,7 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
struct dentry *h_dentry;
struct inode *h_inode;
struct au_branch *br;
+ struct vfsmount *mnt;
struct user_namespace *h_userns;
int wh_found, opq;
unsigned char wh_able;
@@ -44,11 +45,12 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
wh_found = 0;
br = au_sbr(dentry->d_sb, bindex);
+ mnt = au_br_mnt(br);
h_userns = au_br_userns(br);
wh_able = !!au_br_whable(br->br_perm);
if (wh_able)
wh_found = au_wh_test(h_userns, h_parent, &args->whname,
- ignore_perm);
+ ignore_perm, mnt);
h_dentry = ERR_PTR(wh_found);
if (!wh_found)
goto real_lookup;
@@ -63,9 +65,9 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
real_lookup:
if (!ignore_perm)
- h_dentry = vfsub_lkup_one(args->name, h_parent);
+ h_dentry = vfsub_lkup_one(args->name, h_parent, mnt);
else
- h_dentry = au_sio_lkup_one(h_userns, args->name, h_parent);
+ h_dentry = au_sio_lkup_one(h_userns, args->name, h_parent, mnt);
if (IS_ERR(h_dentry)) {
if (PTR_ERR(h_dentry) == -ENAMETOOLONG
&& !allow_neg)
@@ -100,7 +102,7 @@ real_lookup:
goto out; /* success */
inode_lock_shared_nested(h_inode, AuLsc_I_CHILD);
- opq = au_diropq_test(h_userns, h_dentry);
+ opq = au_diropq_test(h_userns, h_dentry, mnt);
inode_unlock_shared(h_inode);
if (opq > 0)
au_set_dbdiropq(dentry, bindex);
@@ -246,18 +248,19 @@ out:
}
struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr
*name,
- struct dentry *parent)
+ struct dentry *parent, struct vfsmount *mnt)
{
struct dentry *dentry;
int wkq_err;
if (!au_test_h_perm_sio(userns, d_inode(parent), MAY_EXEC))
- dentry = vfsub_lkup_one(name, parent);
+ dentry = vfsub_lkup_one(name, parent, mnt);
else {
struct vfsub_lkup_one_args args = {
.errp = &dentry,
.name = name,
- .parent = parent
+ .parent = parent,
+ .mnt = mnt
};
wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args);
@@ -277,15 +280,17 @@ int au_lkup_neg(struct dentry *dentry, aufs_bindex_t
bindex, int wh)
struct dentry *parent, *h_parent, *h_dentry;
struct au_branch *br;
struct user_namespace *h_userns;
+ struct vfsmount *mnt;
parent = dget_parent(dentry);
h_parent = au_h_dptr(parent, bindex);
br = au_sbr(dentry->d_sb, bindex);
h_userns = au_br_userns(br);
+ mnt = au_br_mnt(br);
if (wh)
h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
else
- h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent);
+ h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent,
mnt);
err = PTR_ERR(h_dentry);
if (IS_ERR(h_dentry))
goto out;
@@ -360,6 +365,7 @@ static int au_h_verify_dentry(struct dentry *h_dentry,
struct dentry *h_parent,
struct inode *h_inode;
struct dentry *h_d;
struct super_block *h_sb;
+ struct vfsmount *mnt = au_br_mnt(br);
err = 0;
memset(&ia, -1, sizeof(ia));
@@ -374,7 +380,7 @@ static int au_h_verify_dentry(struct dentry *h_dentry,
struct dentry *h_parent,
goto out;
/* main purpose is namei.c:cached_lookup() and d_revalidate */
- h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent);
+ h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent, mnt);
err = PTR_ERR(h_d);
if (IS_ERR(h_d))
goto out;
diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h
index a1df828fd132..6658d3ceaed0 100644
--- a/fs/aufs/dentry.h
+++ b/fs/aufs/dentry.h
@@ -74,7 +74,7 @@ struct au_do_lookup_args {
extern const struct dentry_operations aufs_dop, aufs_dop_noreval;
struct au_branch;
struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr
*name,
- struct dentry *parent);
+ struct dentry *parent, struct vfsmount *mnt);
int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode
*h_dir,
struct dentry *h_parent, struct au_branch *br);
diff --git a/fs/aufs/dirren.c b/fs/aufs/dirren.c
index 42f590603c91..fd7fdf4ee8fe 100644
--- a/fs/aufs/dirren.c
+++ b/fs/aufs/dirren.c
@@ -263,11 +263,11 @@ static int au_dr_hino(struct super_block *sb,
aufs_bindex_t bindex,
dir = d_inode(path->dentry);
inode_lock_nested(dir, AuLsc_I_CHILD);
}
- hinopath.dentry = vfsub_lkup_one(&hinoname, path->dentry);
+ hinopath.mnt = path->mnt;
+ hinopath.dentry = vfsub_lkup_one(&hinoname, path->dentry, hinopath.mnt);
err = PTR_ERR(hinopath.dentry);
if (IS_ERR(hinopath.dentry))
goto out_unlock;
- hinopath.mnt = path->mnt;
err = 0;
flags = O_RDONLY;
@@ -609,9 +609,7 @@ static int au_drinfo_do_store(struct au_drinfo_store *w,
int err, len;
ssize_t ssz;
loff_t pos;
- struct path infopath = {
- .mnt = w->h_ppath.mnt
- };
+ struct path infopath;
struct inode *h_dir, *h_inode, *delegated;
struct file *infofile;
struct qstr *qname;
@@ -619,8 +617,9 @@ static int au_drinfo_do_store(struct au_drinfo_store *w,
AuDebugOn(elm
&& memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm)));
+ infopath.mnt = w->h_ppath.mnt;
infopath.dentry = vfsub_lookup_one_len(w->whname, w->h_ppath.dentry,
- w->whnamelen);
+ w->whnamelen, infopath.mnt);
AuTraceErrPtr(infopath.dentry);
if (IS_ERR(infopath.dentry)) {
err = PTR_ERR(infopath.dentry);
@@ -1003,8 +1002,9 @@ static struct au_drinfo *au_drinfo_do_load(struct path
*h_ppath,
unlocked = 0;
h_dir = d_inode(h_ppath->dentry);
inode_lock_shared_nested(h_dir, AuLsc_I_PARENT);
+ infopath.mnt = h_ppath->mnt;
infopath.dentry = vfsub_lookup_one_len(whname, h_ppath->dentry,
- whnamelen);
+ whnamelen, infopath.mnt);
if (IS_ERR(infopath.dentry)) {
drinfo = (void *)infopath.dentry;
goto out;
@@ -1013,7 +1013,6 @@ static struct au_drinfo *au_drinfo_do_load(struct path
*h_ppath,
if (d_is_negative(infopath.dentry))
goto out_dput; /* success */
- infopath.mnt = h_ppath->mnt;
f = vfsub_dentry_open(&infopath, O_RDONLY);
inode_unlock_shared(h_dir);
unlocked = 1;
diff --git a/fs/aufs/export.c b/fs/aufs/export.c
index cb4bcfc8af40..6419c06c6cd4 100644
--- a/fs/aufs/export.c
+++ b/fs/aufs/export.c
@@ -406,7 +406,7 @@ static struct dentry *au_lkup_by_ino(struct path *path,
ino_t ino,
/* do not call vfsub_lkup_one() */
dir = d_inode(parent);
- dentry = vfsub_lookup_one_len_unlocked(arg.name, parent, arg.namelen);
+ dentry = vfsub_lookup_one_len_unlocked(arg.name, parent, arg.namelen,
path->mnt);
AuTraceErrPtr(dentry);
if (IS_ERR(dentry))
goto out_name;
diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c
index a11987581548..e6b3cd59f0ae 100644
--- a/fs/aufs/i_op_del.c
+++ b/fs/aufs/i_op_del.c
@@ -95,6 +95,8 @@ int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
struct dentry *h_dentry, *h_latest;
struct inode *h_inode;
struct user_namespace *h_userns;
+ struct au_branch *br;
+ struct vfsmount *mnt;
h_dentry = au_h_dptr(dentry, bindex);
if (d_really_is_positive(dentry)) {
@@ -138,7 +140,9 @@ int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
MAY_EXEC | MAY_WRITE)))
goto out;
- h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent);
+ br = au_sbr(dentry->d_sb, bindex);
+ mnt = au_br_mnt(br);
+ h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent, mnt);
err = -EIO;
if (IS_ERR(h_latest))
goto out;
diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c
index 022b6e8cef11..d72f52f9d3d0 100644
--- a/fs/aufs/i_op_ren.c
+++ b/fs/aufs/i_op_ren.c
@@ -151,8 +151,11 @@ static void au_ren_rev_rename(int err, struct au_ren_args
*a)
int rerr;
struct inode *delegated;
+ /* a->h_path->mnt was set by single caller chain
+ * aufs_rename() -> do_rename() -> au_ren_rev_rename() */
a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name,
- a->src_h_parent);
+ a->src_h_parent,
+ a->h_path.mnt);
rerr = PTR_ERR(a->h_path.dentry);
if (IS_ERR(a->h_path.dentry)) {
RevertFailure("lkup one %pd", a->src_dentry);
@@ -180,8 +183,11 @@ static void au_ren_rev_whtmp(int err, struct au_ren_args
*a)
int rerr;
struct inode *delegated;
+ /* a->h_path->mnt was set by single caller chain
+ * aufs_rename() -> do_rename() -> au_ren_rev_whtmp */
a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name,
- a->dst_h_parent);
+ a->dst_h_parent,
+ a->h_path.mnt);
rerr = PTR_ERR(a->h_path.dentry);
if (IS_ERR(a->h_path.dentry)) {
RevertFailure("lkup one %pd", a->dst_dentry);
diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c
index 518350041aa2..64c1d10931ae 100644
--- a/fs/aufs/plink.c
+++ b/fs/aufs/plink.c
@@ -216,10 +216,11 @@ static struct dentry *au_do_plink_lkup(struct qstr
*tgtname,
{
struct dentry *h_dentry;
struct inode *h_inode;
+ struct vfsmount *mnt = au_br_mnt(br);
h_inode = d_inode(h_parent);
inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2);
- h_dentry = vfsub_lkup_one(tgtname, h_parent);
+ h_dentry = vfsub_lkup_one(tgtname, h_parent, mnt);
inode_unlock_shared(h_inode);
return h_dentry;
}
@@ -275,7 +276,7 @@ static int do_whplink(struct qstr *tgt, struct dentry
*h_parent,
h_dir = d_inode(h_parent);
inode_lock_nested(h_dir, AuLsc_I_CHILD2);
again:
- h_path.dentry = vfsub_lkup_one(tgt, h_parent);
+ h_path.dentry = vfsub_lkup_one(tgt, h_parent, h_path.mnt);
err = PTR_ERR(h_path.dentry);
if (IS_ERR(h_path.dentry))
goto out;
diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c
index 77682fba944f..63a15e973c94 100644
--- a/fs/aufs/vfsub.c
+++ b/fs/aufs/vfsub.c
@@ -166,10 +166,10 @@ int vfsub_kern_path(const char *name, unsigned int flags,
struct path *path)
}
struct dentry *__vfsub_lookup_one_len(const char *name, struct dentry *parent,
- int len, bool locked)
+ int len, struct vfsmount *mnt, bool
locked)
{
struct path path = {
- .mnt = NULL
+ .mnt = mnt
};
if (locked) {
@@ -191,21 +191,22 @@ out:
}
struct dentry *vfsub_lookup_one_len_unlocked(const char *name,
- struct dentry *parent, int len)
+ struct dentry *parent, int len,
+ struct vfsmount *mnt)
{
- return __vfsub_lookup_one_len(name, parent, len, false);
+ return __vfsub_lookup_one_len(name, parent, len, mnt, false);
}
struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
- int len)
+ int len, struct vfsmount *mnt)
{
- return __vfsub_lookup_one_len(name, parent, len, true);
+ return __vfsub_lookup_one_len(name, parent, len, mnt, true);
}
void vfsub_call_lkup_one(void *args)
{
struct vfsub_lkup_one_args *a = args;
- *a->errp = vfsub_lkup_one(a->name, a->parent);
+ *a->errp = vfsub_lkup_one(a->name, a->parent, a->mnt);
}
/* ---------------------------------------------------------------------- */
diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h
index 8e1fca0406e4..0b0263d5febf 100644
--- a/fs/aufs/vfsub.h
+++ b/fs/aufs/vfsub.h
@@ -103,20 +103,23 @@ int vfsub_atomic_open(struct inode *dir, struct dentry
*dentry,
int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
struct dentry *vfsub_lookup_one_len_unlocked(const char *name,
- struct dentry *parent, int len);
+ struct dentry *parent, int len,
+ struct vfsmount *mnt);
struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
- int len);
+ int len, struct vfsmount *mnt);
struct vfsub_lkup_one_args {
struct dentry **errp;
struct qstr *name;
struct dentry *parent;
+ struct vfsmount *mnt;
};
static inline struct dentry *vfsub_lkup_one(struct qstr *name,
- struct dentry *parent)
+ struct dentry *parent,
+ struct vfsmount *mnt)
{
- return vfsub_lookup_one_len(name->name, parent, name->len);
+ return vfsub_lookup_one_len(name->name, parent, name->len, mnt);
}
void vfsub_call_lkup_one(void *args);
diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c
index 8849e6239dd1..61b3ba05139c 100644
--- a/fs/aufs/whout.c
+++ b/fs/aufs/whout.c
@@ -65,15 +65,15 @@ int au_wh_name_alloc(struct qstr *wh, const struct qstr
*name)
* @try_sio specifies the necessary of super-io.
*/
int au_wh_test(struct user_namespace *h_userns, struct dentry *h_parent,
- struct qstr *wh_name, int try_sio)
+ struct qstr *wh_name, int try_sio, struct vfsmount *mnt)
{
int err;
struct dentry *wh_dentry;
if (!try_sio)
- wh_dentry = vfsub_lkup_one(wh_name, h_parent);
+ wh_dentry = vfsub_lkup_one(wh_name, h_parent, mnt);
else
- wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_parent);
+ wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_parent, mnt);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry)) {
if (err == -ENAMETOOLONG)
@@ -102,14 +102,15 @@ out:
/*
* test if the @h_dentry sets opaque or not.
*/
-int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry)
+int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry,
+ struct vfsmount *mnt)
{
int err;
struct inode *h_dir;
h_dir = d_inode(h_dentry);
err = au_wh_test(h_userns, h_dentry, &diropq_name,
- au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC));
+ au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC), mnt);
return err;
}
@@ -127,6 +128,7 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent,
struct au_branch *br,
static unsigned short cnt;
struct qstr qs;
struct user_namespace *h_userns;
+ struct vfsmount *mnt = au_br_mnt(br);
BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN);
@@ -154,7 +156,7 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent,
struct au_branch *br,
qs.name = name;
for (i = 0; i < 3; i++) {
sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++);
- dentry = au_sio_lkup_one(h_userns, &qs, h_parent);
+ dentry = au_sio_lkup_one(h_userns, &qs, h_parent, mnt);
if (IS_ERR(dentry) || d_is_negative(dentry))
goto out_name;
dput(dentry);
@@ -257,7 +259,7 @@ static int unlink_wh_name(struct dentry *h_parent, struct
qstr *wh,
};
err = 0;
- h_path.dentry = vfsub_lkup_one(wh, h_parent);
+ h_path.dentry = vfsub_lkup_one(wh, h_parent, h_path.mnt);
if (IS_ERR(h_path.dentry))
err = PTR_ERR(h_path.dentry);
else {
@@ -705,12 +707,14 @@ static struct dentry *do_diropq(struct dentry *dentry,
aufs_bindex_t bindex,
struct dentry *opq_dentry, *h_dentry;
struct super_block *sb;
struct au_branch *br;
+ struct vfsmount *mnt;
int err;
sb = dentry->d_sb;
br = au_sbr(sb, bindex);
+ mnt = au_br_mnt(br);
h_dentry = au_h_dptr(dentry, bindex);
- opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry);
+ opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry, mnt);
if (IS_ERR(opq_dentry))
goto out;
@@ -791,11 +795,12 @@ struct dentry *au_wh_lkup(struct dentry *h_parent, struct
qstr *base_name,
int err;
struct qstr wh_name;
struct dentry *wh_dentry;
+ struct vfsmount *mnt = au_br_mnt(br);
err = au_wh_name_alloc(&wh_name, base_name);
wh_dentry = ERR_PTR(err);
if (!err) {
- wh_dentry = vfsub_lkup_one(&wh_name, h_parent);
+ wh_dentry = vfsub_lkup_one(&wh_name, h_parent, mnt);
au_kfree_try_rcu(wh_name.name);
}
return wh_dentry;
diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h
index 08bce298f8a3..5d4571f7d2c9 100644
--- a/fs/aufs/whout.h
+++ b/fs/aufs/whout.h
@@ -30,8 +30,9 @@
/* whout.c */
int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
int au_wh_test(struct user_namespace *h_userns, struct dentry *h_parent,
- struct qstr *wh_name, int try_sio);
-int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry);
+ struct qstr *wh_name, int try_sio, struct vfsmount *mnt);
+int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry,
+ struct vfsmount *mnt);
struct au_branch;
struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
struct qstr *prefix);
diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c
index b126b34206f3..cc097e736e11 100644
--- a/fs/aufs/xino.c
+++ b/fs/aufs/xino.c
@@ -250,7 +250,8 @@ struct file *au_xino_create2(struct super_block *sb, struct
path *base,
IMustLock(dir);
name = &dentry->d_name;
- path.dentry = vfsub_lookup_one_len(name->name, parent, name->len);
+ path.mnt = base->mnt;
+ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len,
path.mnt);
if (IS_ERR(path.dentry)) {
file = (void *)path.dentry;
pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry));
@@ -265,7 +266,6 @@ struct file *au_xino_create2(struct super_block *sb, struct
path *base,
goto out_dput;
}
- path.mnt = base->mnt;
file = vfsub_dentry_open(&path,
O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
/* | __FMODE_NONOTIFY */);
--
2.30.2