mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 13:44:15 +08:00
ceph: fix potential mdsc use-after-free crash
Make sure the delayed work stopped before releasing the resources. cancel_delayed_work_sync() will only guarantee that the work finishes executing if the work is already in the ->worklist. That means after the cancel_delayed_work_sync() returns, it will leave the work requeued if it was rearmed at the end. That can lead to a use after free once the work struct is freed. Fix it by flushing the delayed work instead of trying to cancel it, and ensure that the work doesn't rearm if the mdsc is stopping. URL: https://tracker.ceph.com/issues/46293 Signed-off-by: Xiubo Li <xiubli@redhat.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
parent
b682c6d41b
commit
fa99677342
@ -4330,6 +4330,9 @@ static void delayed_work(struct work_struct *work)
|
||||
|
||||
dout("mdsc delayed_work\n");
|
||||
|
||||
if (mdsc->stopping)
|
||||
return;
|
||||
|
||||
mutex_lock(&mdsc->mutex);
|
||||
renew_interval = mdsc->mdsmap->m_session_timeout >> 2;
|
||||
renew_caps = time_after_eq(jiffies, HZ*renew_interval +
|
||||
@ -4689,7 +4692,16 @@ void ceph_mdsc_force_umount(struct ceph_mds_client *mdsc)
|
||||
static void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
|
||||
{
|
||||
dout("stop\n");
|
||||
cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
|
||||
/*
|
||||
* Make sure the delayed work stopped before releasing
|
||||
* the resources.
|
||||
*
|
||||
* Because the cancel_delayed_work_sync() will only
|
||||
* guarantee that the work finishes executing. But the
|
||||
* delayed work will re-arm itself again after that.
|
||||
*/
|
||||
flush_delayed_work(&mdsc->delayed_work);
|
||||
|
||||
if (mdsc->mdsmap)
|
||||
ceph_mdsmap_destroy(mdsc->mdsmap);
|
||||
kfree(mdsc->sessions);
|
||||
|
Loading…
Reference in New Issue
Block a user