gfs2: fix use-after-free in trans_drain
authorBob Peterson <rpeterso@redhat.com>
Thu, 25 Feb 2021 16:11:09 +0000 (11:11 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 30 Mar 2021 12:31:49 +0000 (14:31 +0200)
[ Upstream commit 1a5a2cfd34c17db73c53ef127272c8c1ae220485 ]

This patch adds code to function trans_drain to remove drained
bd elements from the ail lists, if queued, before freeing the bd.
If we don't remove the bd from the ail, function ail_drain will
try to reference the bd after it has been freed by trans_drain.

Thanks to Andy Price for his analysis of the problem.

Reported-by: Andy Price <anprice@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/gfs2/log.c
fs/gfs2/trans.c

index 2e93140..1955dea 100644 (file)
@@ -935,12 +935,16 @@ static void trans_drain(struct gfs2_trans *tr)
        while (!list_empty(head)) {
                bd = list_first_entry(head, struct gfs2_bufdata, bd_list);
                list_del_init(&bd->bd_list);
+               if (!list_empty(&bd->bd_ail_st_list))
+                       gfs2_remove_from_ail(bd);
                kmem_cache_free(gfs2_bufdata_cachep, bd);
        }
        head = &tr->tr_databuf;
        while (!list_empty(head)) {
                bd = list_first_entry(head, struct gfs2_bufdata, bd_list);
                list_del_init(&bd->bd_list);
+               if (!list_empty(&bd->bd_ail_st_list))
+                       gfs2_remove_from_ail(bd);
                kmem_cache_free(gfs2_bufdata_cachep, bd);
        }
 }
index 6d4bf7e..7f850ff 100644 (file)
@@ -134,6 +134,8 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
        bd->bd_bh = bh;
        bd->bd_gl = gl;
        INIT_LIST_HEAD(&bd->bd_list);
+       INIT_LIST_HEAD(&bd->bd_ail_st_list);
+       INIT_LIST_HEAD(&bd->bd_ail_gl_list);
        bh->b_private = bd;
        return bd;
 }