diff options
author | Jeff Layton <jlayton@kernel.org> | 2019-04-26 13:33:39 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2019-05-07 13:22:37 -0400 |
commit | 69a10fb3f4b8769ffd44e4eaa662ab691fa61f4c (patch) | |
tree | 5a3503f0c6662a5767fecb4da4a41c45301493b8 /fs/ceph | |
parent | ff4a80bf2d3f8005dc5890381bc8ca48e259c60d (diff) |
ceph: fix potential use-after-free in ceph_mdsc_build_path
temp is not defined outside of the RCU critical section here. Ensure
we grab that value before we drop the rcu_read_lock.
Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/mds_client.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 761cb669aa13..b01e2043b1b2 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -2089,13 +2089,14 @@ static inline u64 __get_oldest_tid(struct ceph_mds_client *mdsc) | |||
2089 | * Encode hidden .snap dirs as a double /, i.e. | 2089 | * Encode hidden .snap dirs as a double /, i.e. |
2090 | * foo/.snap/bar -> foo//bar | 2090 | * foo/.snap/bar -> foo//bar |
2091 | */ | 2091 | */ |
2092 | char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, | 2092 | char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase, |
2093 | int stop_on_nosnap) | 2093 | int stop_on_nosnap) |
2094 | { | 2094 | { |
2095 | struct dentry *temp; | 2095 | struct dentry *temp; |
2096 | char *path; | 2096 | char *path; |
2097 | int len, pos; | 2097 | int len, pos; |
2098 | unsigned seq; | 2098 | unsigned seq; |
2099 | u64 base; | ||
2099 | 2100 | ||
2100 | if (!dentry) | 2101 | if (!dentry) |
2101 | return ERR_PTR(-EINVAL); | 2102 | return ERR_PTR(-EINVAL); |
@@ -2151,6 +2152,7 @@ retry: | |||
2151 | path[--pos] = '/'; | 2152 | path[--pos] = '/'; |
2152 | temp = temp->d_parent; | 2153 | temp = temp->d_parent; |
2153 | } | 2154 | } |
2155 | base = ceph_ino(d_inode(temp)); | ||
2154 | rcu_read_unlock(); | 2156 | rcu_read_unlock(); |
2155 | if (pos != 0 || read_seqretry(&rename_lock, seq)) { | 2157 | if (pos != 0 || read_seqretry(&rename_lock, seq)) { |
2156 | pr_err("build_path did not end path lookup where " | 2158 | pr_err("build_path did not end path lookup where " |
@@ -2163,10 +2165,10 @@ retry: | |||
2163 | goto retry; | 2165 | goto retry; |
2164 | } | 2166 | } |
2165 | 2167 | ||
2166 | *base = ceph_ino(d_inode(temp)); | 2168 | *pbase = base; |
2167 | *plen = len; | 2169 | *plen = len; |
2168 | dout("build_path on %p %d built %llx '%.*s'\n", | 2170 | dout("build_path on %p %d built %llx '%.*s'\n", |
2169 | dentry, d_count(dentry), *base, len, path); | 2171 | dentry, d_count(dentry), base, len, path); |
2170 | return path; | 2172 | return path; |
2171 | } | 2173 | } |
2172 | 2174 | ||