HomeFreeBSD

Fix DR_OVERRIDDEN use-after-free race in dbuf_sync_leaf

Description

Fix DR_OVERRIDDEN use-after-free race in dbuf_sync_leaf

In dbuf_sync_leaf, we clone the arc_buf in dr if we share it with db
except for overridden case. However, this exception causes a race where
dbuf_new_size could free the arc_buf after the last dereference of
*datap and causes use-after-free. We fix this by cloning the buf
regardless if it's overridden.

The race:

P0 P1

dbuf_hold_impl()
  // dbuf_hold_copy passed
  // because db_data_pending NULL

dbuf_sync_leaf()

// doesn't clone *datap
// *datap derefed to db_buf
dbuf_write(*datap)

                                     dbuf_new_size()
                                       dmu_buf_will_dirty()
                                         dbuf_fix_old_data()
                                           // alloc new buf for P0 dr
                                           // but can't change *datap

                                       arc_alloc_buf()
                                       arc_buf_destroy()
                                         // alloc new buf for db_buf
                                         // and destroy old buf

dbuf_write() // continue
  abd_get_from_buf(data->b_data,
  arc_buf_size(data))
    // use-after-free

Here's an example when it happens:

BUG: kernel NULL pointer dereference, address: 000000000000002e
RIP: 0010:arc_buf_size+0x1c/0x30 [zfs]
Call Trace:
dbuf_write+0x3ff/0x580 [zfs]
dbuf_sync_leaf+0x13c/0x530 [zfs]
dbuf_sync_list+0xbf/0x120 [zfs]
dnode_sync+0x3ea/0x7a0 [zfs]
sync_dnodes_task+0x71/0xa0 [zfs]
taskq_thread+0x2b8/0x4e0 [spl]
kthread+0x112/0x130
ret_from_fork+0x1f/0x30

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Signed-off-by: Chunwei Chen <david.chen@nutanix.com>
Co-authored-by: Chunwei Chen <david.chen@nutanix.com>
Closes #16854

Details

Provenance
Chunwei Chen <tuxoko@gmail.com>Authored on Dec 13 2024, 12:18 AM
GitHub <noreply@github.com>Committed on Dec 13 2024, 12:18 AM
Parents
rG19a04e5ad21e: BRT: Check bv_mos_entries in brt_entry_lookup()
Branches
Unknown
Tags
Unknown