diff options
Diffstat (limited to 'security/apparmor/path.c')
-rw-r--r-- | security/apparmor/path.c | 47 |
1 files changed, 13 insertions, 34 deletions
diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 96bab9469d48..82396050f186 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c | |||
@@ -59,39 +59,22 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, | |||
59 | { | 59 | { |
60 | struct path root, tmp; | 60 | struct path root, tmp; |
61 | char *res; | 61 | char *res; |
62 | int deleted, connected; | 62 | int connected, error = 0; |
63 | int error = 0; | ||
64 | 63 | ||
65 | /* Get the root we want to resolve too */ | 64 | /* Get the root we want to resolve too, released below */ |
66 | if (flags & PATH_CHROOT_REL) { | 65 | if (flags & PATH_CHROOT_REL) { |
67 | /* resolve paths relative to chroot */ | 66 | /* resolve paths relative to chroot */ |
68 | read_lock(¤t->fs->lock); | 67 | get_fs_root(current->fs, &root); |
69 | root = current->fs->root; | ||
70 | /* released below */ | ||
71 | path_get(&root); | ||
72 | read_unlock(¤t->fs->lock); | ||
73 | } else { | 68 | } else { |
74 | /* resolve paths relative to namespace */ | 69 | /* resolve paths relative to namespace */ |
75 | root.mnt = current->nsproxy->mnt_ns->root; | 70 | root.mnt = current->nsproxy->mnt_ns->root; |
76 | root.dentry = root.mnt->mnt_root; | 71 | root.dentry = root.mnt->mnt_root; |
77 | /* released below */ | ||
78 | path_get(&root); | 72 | path_get(&root); |
79 | } | 73 | } |
80 | 74 | ||
81 | spin_lock(&dcache_lock); | 75 | spin_lock(&dcache_lock); |
82 | /* There is a race window between path lookup here and the | 76 | tmp = root; |
83 | * need to strip the " (deleted) string that __d_path applies | 77 | res = __d_path(path, &tmp, buf, buflen); |
84 | * Detect the race and relookup the path | ||
85 | * | ||
86 | * The stripping of (deleted) is a hack that could be removed | ||
87 | * with an updated __d_path | ||
88 | */ | ||
89 | do { | ||
90 | tmp = root; | ||
91 | deleted = d_unlinked(path->dentry); | ||
92 | res = __d_path(path, &tmp, buf, buflen); | ||
93 | |||
94 | } while (deleted != d_unlinked(path->dentry)); | ||
95 | spin_unlock(&dcache_lock); | 78 | spin_unlock(&dcache_lock); |
96 | 79 | ||
97 | *name = res; | 80 | *name = res; |
@@ -103,21 +86,17 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, | |||
103 | *name = buf; | 86 | *name = buf; |
104 | goto out; | 87 | goto out; |
105 | } | 88 | } |
106 | if (deleted) { | ||
107 | /* On some filesystems, newly allocated dentries appear to the | ||
108 | * security_path hooks as a deleted dentry except without an | ||
109 | * inode allocated. | ||
110 | * | ||
111 | * Remove the appended deleted text and return as string for | ||
112 | * normal mediation, or auditing. The (deleted) string is | ||
113 | * guaranteed to be added in this case, so just strip it. | ||
114 | */ | ||
115 | buf[buflen - 11] = 0; /* - (len(" (deleted)") +\0) */ | ||
116 | 89 | ||
117 | if (path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) { | 90 | /* Handle two cases: |
91 | * 1. A deleted dentry && profile is not allowing mediation of deleted | ||
92 | * 2. On some filesystems, newly allocated dentries appear to the | ||
93 | * security_path hooks as a deleted dentry except without an inode | ||
94 | * allocated. | ||
95 | */ | ||
96 | if (d_unlinked(path->dentry) && path->dentry->d_inode && | ||
97 | !(flags & PATH_MEDIATE_DELETED)) { | ||
118 | error = -ENOENT; | 98 | error = -ENOENT; |
119 | goto out; | 99 | goto out; |
120 | } | ||
121 | } | 100 | } |
122 | 101 | ||
123 | /* Determine if the path is connected to the expected root */ | 102 | /* Determine if the path is connected to the expected root */ |