Author: mav
Date: Thu Nov 28 18:28:35 2019
New Revision: 355182
URL: https://svnweb.freebsd.org/changeset/base/355182

Log:
  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.
  
  MFC after:    2 weeks
  Sponsored by: iXsystems, Inc.

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c   Thu Nov 28 
18:18:10 2019        (r355181)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c   Thu Nov 28 
18:28:35 2019        (r355182)
@@ -7886,7 +7886,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.
@@ -7909,11 +7908,17 @@ 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,
                            hdr->b_l1hdr.b_pabd, zio->io_size, arc_read_done,
                            hdr, zio->io_priority, cb->l2rcb_flags,
-                           &cb->l2rcb_zb));
-               }
+                           &cb->l2rcb_zb);
+                       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);
        }
 
        kmem_free(cb, sizeof (l2arc_read_callback_t));
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to