mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
dmu_direct: avoid UAF in dmu_write_direct_done()
dmu_write_direct_done() passes dmu_sync_arg_t to dmu_sync_done(), which updates the override state and frees the completion context. The Direct I/O error path then still dereferences dsa->dsa_tx while rolling the dirty record back with dbuf_undirty(), resulting in a use-after-free. Save dsa->dsa_tx in a local variable before calling dmu_sync_done() and use that saved tx for the error rollback. This preserves the existing ownership model for dsa and does not change the Direct I/O write semantics. Reviewed-by: Brian Atkinson <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Co-authored-by: gality369 <[email protected]> Signed-off-by: ZhengYuan Huang <[email protected]> Closes #18440
This commit is contained in:
1 parent
ddf19dcbe1
commit
37e3a260fd
1 file changed
+7
-1
@@ -91,6 +91,7 @@ dmu_write_direct_done(zio_t *zio)
|
||||
dmu_sync_arg_t *dsa = zio->io_private;
|
||||
dbuf_dirty_record_t *dr = dsa->dsa_dr;
|
||||
dmu_buf_impl_t *db = dr->dr_dbuf;
|
||||
dmu_tx_t *tx = dsa->dsa_tx;
|
||||
|
||||
abd_free(zio->io_abd);
|
||||
|
||||
@@ -101,6 +102,11 @@ dmu_write_direct_done(zio_t *zio)
|
||||
db->db_state = DB_UNCACHED;
|
||||
mutex_exit(&db->db_mtx);
|
||||
|
||||
/*
|
||||
* dmu_sync_done() owns dsa and frees it after publishing the final
|
||||
* override state. The direct-I/O error path still needs the original
|
||||
* open-context tx to roll the dirty record back with dbuf_undirty().
|
||||
*/
|
||||
dmu_sync_done(zio, NULL, zio->io_private);
|
||||
|
||||
if (zio->io_error != 0) {
|
||||
@@ -120,7 +126,7 @@ dmu_write_direct_done(zio_t *zio)
|
||||
* calling dbuf_undirty().
|
||||
*/
|
||||
mutex_enter(&db->db_mtx);
|
||||
VERIFY3B(dbuf_undirty(db, dsa->dsa_tx), ==, B_FALSE);
|
||||
VERIFY3B(dbuf_undirty(db, tx), ==, B_FALSE);
|
||||
mutex_exit(&db->db_mtx);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user