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 */ |
