Skip to content

Commit 8e18587

Browse files
lxbszidryomov
authored andcommitted
ceph: avoid use-after-free in ceph_fl_release_lock()
When ceph releasing the file_lock it will try to get the inode pointer from the fl->fl_file, which the memory could already be released by another thread in filp_close(). Because in VFS layer the fl->fl_file doesn't increase the file's reference counter. Will switch to use ceph dedicate lock info to track the inode. And in ceph_fl_release_lock() we should skip all the operations if the fl->fl_u.ceph.inode is not set, which should come from the request file_lock. And we will set fl->fl_u.ceph.inode when inserting it to the inode lock list, which is when copying the lock. Link: https://tracker.ceph.com/issues/57986 Signed-off-by: Xiubo Li <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Reviewed-by: Ilya Dryomov <[email protected]> Signed-off-by: Ilya Dryomov <[email protected]>
1 parent 461ab10 commit 8e18587

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

fs/ceph/locks.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,34 @@ static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
3434
{
3535
struct inode *inode = file_inode(dst->fl_file);
3636
atomic_inc(&ceph_inode(inode)->i_filelock_ref);
37+
dst->fl_u.ceph.inode = igrab(inode);
3738
}
3839

40+
/*
41+
* Do not use the 'fl->fl_file' in release function, which
42+
* is possibly already released by another thread.
43+
*/
3944
static void ceph_fl_release_lock(struct file_lock *fl)
4045
{
41-
struct inode *inode = file_inode(fl->fl_file);
42-
struct ceph_inode_info *ci = ceph_inode(inode);
46+
struct inode *inode = fl->fl_u.ceph.inode;
47+
struct ceph_inode_info *ci;
48+
49+
/*
50+
* If inode is NULL it should be a request file_lock,
51+
* nothing we can do.
52+
*/
53+
if (!inode)
54+
return;
55+
56+
ci = ceph_inode(inode);
4357
if (atomic_dec_and_test(&ci->i_filelock_ref)) {
4458
/* clear error when all locks are released */
4559
spin_lock(&ci->i_ceph_lock);
4660
ci->i_ceph_flags &= ~CEPH_I_ERROR_FILELOCK;
4761
spin_unlock(&ci->i_ceph_lock);
4862
}
63+
fl->fl_u.ceph.inode = NULL;
64+
iput(inode);
4965
}
5066

5167
static const struct file_lock_operations ceph_fl_lock_ops = {

include/linux/fs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,9 @@ struct file_lock {
11191119
int state; /* state of grant or error if -ve */
11201120
unsigned int debug_id;
11211121
} afs;
1122+
struct {
1123+
struct inode *inode;
1124+
} ceph;
11221125
} fl_u;
11231126
} __randomize_layout;
11241127

0 commit comments

Comments
 (0)