mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-25 02:49:32 +03:00
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
9cf46ddedc
commit
388ef045b2
@ -8561,7 +8561,6 @@ l2arc_read_done(zio_t *zio)
|
|||||||
zio->io_private = hdr;
|
zio->io_private = hdr;
|
||||||
arc_read_done(zio);
|
arc_read_done(zio);
|
||||||
} else {
|
} else {
|
||||||
mutex_exit(hash_lock);
|
|
||||||
/*
|
/*
|
||||||
* Buffer didn't survive caching. Increment stats and
|
* Buffer didn't survive caching. Increment stats and
|
||||||
* reissue to the original storage device.
|
* reissue to the original storage device.
|
||||||
@ -8586,10 +8585,24 @@ l2arc_read_done(zio_t *zio)
|
|||||||
|
|
||||||
ASSERT(!pio || pio->io_child_type == ZIO_CHILD_LOGICAL);
|
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,
|
abd, zio->io_size, arc_read_done,
|
||||||
hdr, zio->io_priority, cb->l2rcb_flags,
|
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