]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd/migration/QCOWFormat: avoid use-after-free in execute_request() 67919/head
authorIlya Dryomov <idryomov@gmail.com>
Wed, 11 Mar 2026 11:04:24 +0000 (12:04 +0100)
committerIlya Dryomov <idryomov@gmail.com>
Fri, 20 Mar 2026 15:28:05 +0000 (16:28 +0100)
Both L2TableCache and QCOWFormat can be destroyed after the completion
for the last L2 cache request is posted, particularly so in unit tests.
The strand destructor doesn't drain the handler queue in any way but
merely ensures that previously posted handlers would get dispatched in
a non-concurrent fashion.  As a result, use-after-free can ensue when
execute_request() unnecessarily dispatches itself for the last time.

Fixes: https://tracker.ceph.com/issues/75378
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
src/librbd/migration/QCOWFormat.cc

index b011d33a03e63955195102799da5f8a81db55d0c..fc13beed0242ff748dad640778ad335339918853 100644 (file)
@@ -411,13 +411,19 @@ private:
       ceph_assert(false);
     }
 
+    requests.pop_front();
+    bool more = !requests.empty();
+
     // complete the L2 cache request
+    // expect to be destroyed after posting completion if there are no
+    // more requests
     boost::asio::post(*qcow_format->m_image_ctx->asio_engine,
                       [r, ctx=request.on_finish]() { ctx->complete(r); });
-    requests.pop_front();
 
     // process next request (if any)
-    dispatch_request();
+    if (more) {
+      dispatch_request();
+    }
   }
 
   int l2_table_lookup(uint64_t l2_offset,