mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
60 lines
1.9 KiB
Diff
60 lines
1.9 KiB
Diff
From: Andreas Gruenbacher <agruen@suse.de>
|
|
Subject: Make d_path() consistent across mount operations
|
|
|
|
The path that __d_path() computes can become slightly inconsistent when it
|
|
races with mount operations: it grabs the vfsmount_lock when traversing mount
|
|
points but immediately drops it again, only to re-grab it when it reaches the
|
|
next mount point. The result is that the filename computed is not always
|
|
consisent, and the file may never have had that name. (This is unlikely, but
|
|
still possible.)
|
|
|
|
Fix this by grabbing the vfsmount_lock when the first mount point is reached,
|
|
and holding onto it until the d_cache lookup is completed.
|
|
|
|
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|
Signed-off-by: John Johansen <jjohansen@suse.de>
|
|
|
|
---
|
|
fs/dcache.c | 14 ++++++++------
|
|
1 file changed, 8 insertions(+), 6 deletions(-)
|
|
|
|
--- a/fs/dcache.c
|
|
+++ b/fs/dcache.c
|
|
@@ -1786,7 +1786,7 @@ static char *__d_path(struct dentry *den
|
|
struct dentry *root, struct vfsmount *rootmnt,
|
|
char *buffer, int buflen, int fail_deleted)
|
|
{
|
|
- int namelen, is_slash;
|
|
+ int namelen, is_slash, vfsmount_locked = 0;
|
|
|
|
if (buflen < 2)
|
|
return ERR_PTR(-ENAMETOOLONG);
|
|
@@ -1809,14 +1809,14 @@ static char *__d_path(struct dentry *den
|
|
struct dentry * parent;
|
|
|
|
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
|
- spin_lock(&vfsmount_lock);
|
|
- if (vfsmnt->mnt_parent == vfsmnt) {
|
|
- spin_unlock(&vfsmount_lock);
|
|
- goto global_root;
|
|
+ if (!vfsmount_locked) {
|
|
+ spin_lock(&vfsmount_lock);
|
|
+ vfsmount_locked = 1;
|
|
}
|
|
+ if (vfsmnt->mnt_parent == vfsmnt)
|
|
+ goto global_root;
|
|
dentry = vfsmnt->mnt_mountpoint;
|
|
vfsmnt = vfsmnt->mnt_parent;
|
|
- spin_unlock(&vfsmount_lock);
|
|
continue;
|
|
}
|
|
parent = dentry->d_parent;
|
|
@@ -1835,6 +1835,8 @@ static char *__d_path(struct dentry *den
|
|
*--buffer = '/';
|
|
|
|
out:
|
|
+ if (vfsmount_locked)
|
|
+ spin_unlock(&vfsmount_lock);
|
|
spin_unlock(&dcache_lock);
|
|
return buffer;
|
|
|