Fix use-after-free in case of L2ARC prefetch failure
In case L2ARC read failed, l2arc_read_done() creates _different_ ZIO to read data from the original storage device. Unfortunately pointer to the failed ZIO remains in hdr->b_l1hdr.b_acb->acb_zio_head, and if some other read try to bump the ZIO priority, it will crash. The problem is reproducible by corrupting L2ARC content and reading some data with prefetch if l2arc_noprefetch tunable is changed to 0. With the default setting the issue is probably not reproducible now. Reviewed-by: Tom Caputi <tcaputi@datto.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Alexander Motin <mav@FreeBSD.org> Sponsored-By: iXsystems, Inc. Closes #9648
This commit is contained in:
parent
624222ae31
commit
5ff2249fa5
@ -7873,7 +7873,6 @@ l2arc_read_done(zio_t *zio)
|
||||
zio->io_private = hdr;
|
||||
arc_read_done(zio);
|
||||
} else {
|
||||
mutex_exit(hash_lock);
|
||||
/*
|
||||
* Buffer didn't survive caching. Increment stats and
|
||||
* reissue to the original storage device.
|
||||
@ -7898,10 +7897,24 @@ l2arc_read_done(zio_t *zio)
|
||||
|
||||
ASSERT(!pio || pio->io_child_type == ZIO_CHILD_LOGICAL);
|
||||
|
||||
zio_nowait(zio_read(pio, zio->io_spa, zio->io_bp,
|
||||
zio = zio_read(pio, zio->io_spa, zio->io_bp,
|
||||
abd, zio->io_size, arc_read_done,
|
||||
hdr, zio->io_priority, cb->l2rcb_flags,
|
||||
&cb->l2rcb_zb));
|
||||
&cb->l2rcb_zb);
|
||||
|
||||
/*
|
||||
* Original ZIO will be freed, so we need to update
|
||||
* ARC header with the new ZIO pointer to be used
|
||||
* by zio_change_priority() in arc_read().
|
||||
*/
|
||||
for (struct arc_callback *acb = hdr->b_l1hdr.b_acb;
|
||||
acb != NULL; acb = acb->acb_next)
|
||||
acb->acb_zio_head = zio;
|
||||
|
||||
mutex_exit(hash_lock);
|
||||
zio_nowait(zio);
|
||||
} else {
|
||||
mutex_exit(hash_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user