From a73b9dd670bcd3a77611c7240d86963b29527983 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Tue, 3 May 2016 07:41:30 -0400 Subject: [PATCH] librbd: possible race condition leads to use-after-free The invoke async operation state machine can complete before the owner lock is released. Use a stack reference to prevent use-after-free. Fixes: http://tracker.ceph.com/issues/15690 Signed-off-by: Jason Dillaman (cherry picked from commit d9421a25b582e41550526714b71fb55f05abb1de) --- src/librbd/Operations.cc | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/librbd/Operations.cc b/src/librbd/Operations.cc index 89eb63637e0..5c8b3d222ba 100644 --- a/src/librbd/Operations.cc +++ b/src/librbd/Operations.cc @@ -152,12 +152,14 @@ struct C_InvokeAsyncRequest : public Context { } void send_acquire_exclusive_lock() { - image_ctx.owner_lock.get_read(); + // context can complete before owner_lock is unlocked + RWLock &owner_lock(image_ctx.owner_lock); + owner_lock.get_read(); image_ctx.snap_lock.get_read(); if (image_ctx.read_only || (!permit_snapshot && image_ctx.snap_id != CEPH_NOSNAP)) { image_ctx.snap_lock.put_read(); - image_ctx.owner_lock.put_read(); + owner_lock.put_read(); complete(-EROFS); return; } @@ -165,10 +167,10 @@ struct C_InvokeAsyncRequest : public Context { if (image_ctx.exclusive_lock == nullptr) { send_local_request(); - image_ctx.owner_lock.put_read(); + owner_lock.put_read(); return; } else if (image_ctx.image_watcher == nullptr) { - image_ctx.owner_lock.put_read(); + owner_lock.put_read(); complete(-EROFS); return; } @@ -176,7 +178,7 @@ struct C_InvokeAsyncRequest : public Context { if (image_ctx.exclusive_lock->is_lock_owner() && image_ctx.exclusive_lock->accept_requests()) { send_local_request(); - image_ctx.owner_lock.put_read(); + owner_lock.put_read(); return; } @@ -188,7 +190,7 @@ struct C_InvokeAsyncRequest : public Context { &C_InvokeAsyncRequest::handle_acquire_exclusive_lock>( this); image_ctx.exclusive_lock->try_lock(ctx); - image_ctx.owner_lock.put_read(); + owner_lock.put_read(); } void handle_acquire_exclusive_lock(int r) { @@ -200,15 +202,17 @@ struct C_InvokeAsyncRequest : public Context { return; } - image_ctx.owner_lock.get_read(); + // context can complete before owner_lock is unlocked + RWLock &owner_lock(image_ctx.owner_lock); + owner_lock.get_read(); if (image_ctx.exclusive_lock->is_lock_owner()) { send_local_request(); - image_ctx.owner_lock.put_read(); + owner_lock.put_read(); return; } send_remote_request(); - image_ctx.owner_lock.put_read(); + owner_lock.put_read(); } void send_remote_request() { -- 2.47.3