summaryrefslogtreecommitdiff
path: root/fs/ceph
diff options
context:
space:
mode:
authorXiubo Li <xiubo.li@clyso.com>2026-07-14 14:20:37 +0800
committerIlya Dryomov <idryomov@gmail.com>2026-08-26 19:57:27 +0200
commita354d7eaa1a57f1532c8072a424cc2d339a73cc0 (patch)
tree87c0cbca244bc5b466357aa7ce3d1ac861979bcb /fs/ceph
parentaf59562a5b3d34fb3aa7753f2543393578d06dbf (diff)
ceph: fix use-after-dereference of NULL ci in __ceph_remove_cap()
The NULL check for "ci" in __ceph_remove_cap() was dead code because ci was dereferenced via &ci->netfs.inode before the check, and cap->session was dereferenced via session->s_mdsc->fsc->client even earlier. On a double-remove, both cap->ci and cap->session are set to NULL by the first call, so the second call would crash before ever reaching the guard. Move ci, session, cl, and inode initializations after the NULL check so that the early-return actually works. Signed-off-by: Xiubo Li <xiubo.li@clyso.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r--fs/ceph/caps.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 1e6ffe23fd08..f3110e8d19a8 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -1129,18 +1129,21 @@ int ceph_is_any_caps(struct inode *inode)
*/
void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release)
{
- struct ceph_mds_session *session = cap->session;
- struct ceph_client *cl = session->s_mdsc->fsc->client;
- struct ceph_inode_info *ci = cap->ci;
- struct inode *inode = &ci->netfs.inode;
+ struct ceph_mds_session *session;
+ struct ceph_client *cl;
+ struct ceph_inode_info *ci;
+ struct inode *inode;
struct ceph_mds_client *mdsc;
int removed = 0;
/* 'ci' being NULL means the remove have already occurred */
- if (!ci) {
- doutc(cl, "inode is NULL\n");
+ ci = cap->ci;
+ if (!ci)
return;
- }
+
+ session = cap->session;
+ cl = session->s_mdsc->fsc->client;
+ inode = &ci->netfs.inode;
lockdep_assert_held(&ci->i_ceph_lock);