]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: possible race condition leads to use-after-free 9009/head
authorJason Dillaman <dillaman@redhat.com>
Tue, 3 May 2016 11:41:30 +0000 (07:41 -0400)
committerJason Dillaman <dillaman@redhat.com>
Tue, 10 May 2016 17:01:57 +0000 (13:01 -0400)
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 <dillaman@redhat.com>
(cherry picked from commit d9421a25b582e41550526714b71fb55f05abb1de)

src/librbd/Operations.cc

index 89eb63637e06fb2483a0f81b81d191fbb81d63a0..5c8b3d222ba4ec67112f11f1d66026f76a4ab5a2 100644 (file)
@@ -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<I>::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() {