Skip to content

Commit

Permalink
Fix use-after-free in case of L2ARC prefetch failure.
Browse files Browse the repository at this point in the history
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.

Sponsored-By: iXsystems, Inc.
Signed-off-by: Alexander Motin <[email protected]>
  • Loading branch information
amotin committed Dec 2, 2019
1 parent a7c3588 commit 164b2c0
Showing 1 changed file with 16 additions and 3 deletions.
19 changes: 16 additions & 3 deletions module/zfs/arc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
}
}

Expand Down

0 comments on commit 164b2c0

Please sign in to comment.