]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
nilfs2: fix failure to detect DAT corruption in btree and direct mappings
authorRyusuke Konishi <konishi.ryusuke@gmail.com>
Wed, 13 Mar 2024 10:58:26 +0000 (19:58 +0900)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 14 Mar 2024 16:17:29 +0000 (09:17 -0700)
Patch series "nilfs2: fix kernel bug at submit_bh_wbc()".

This resolves a kernel BUG reported by syzbot.  Since there are two
flaws involved, I've made each one a separate patch.

The first patch alone resolves the syzbot-reported bug, but I think
both fixes should be sent to stable, so I've tagged them as such.

This patch (of 2):

Syzbot has reported a kernel bug in submit_bh_wbc() when writing file data
to a nilfs2 file system whose metadata is corrupted.

There are two flaws involved in this issue.

The first flaw is that when nilfs_get_block() locates a data block using
btree or direct mapping, if the disk address translation routine
nilfs_dat_translate() fails with internal code -ENOENT due to DAT metadata
corruption, it can be passed back to nilfs_get_block().  This causes
nilfs_get_block() to misidentify an existing block as non-existent,
causing both data block lookup and insertion to fail inconsistently.

The second flaw is that nilfs_get_block() returns a successful status in
this inconsistent state.  This causes the caller __block_write_begin_int()
or others to request a read even though the buffer is not mapped,
resulting in a BUG_ON check for the BH_Mapped flag in submit_bh_wbc()
failing.

This fixes the first issue by changing the return value to code -EINVAL
when a conversion using DAT fails with code -ENOENT, avoiding the
conflicting condition that leads to the kernel bug described above.  Here,
code -EINVAL indicates that metadata corruption was detected during the
block lookup, which will be properly handled as a file system error and
converted to -EIO when passing through the nilfs2 bmap layer.

Link: https://lkml.kernel.org/r/20240313105827.5296-1-konishi.ryusuke@gmail.com
Link: https://lkml.kernel.org/r/20240313105827.5296-2-konishi.ryusuke@gmail.com
Fixes: c3a7abf06ce7 ("nilfs2: support contiguous lookup of blocks")
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Reported-by: syzbot+cfed5b56649bddf80d6e@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=cfed5b56649bddf80d6e
Tested-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/nilfs2/btree.c
fs/nilfs2/direct.c

index 13592e82eaf68b2d92851e0218a99bd7842af9c4..65659fa0372e6ca3ae53590b7dadd5e19cd2d728 100644 (file)
@@ -724,7 +724,7 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *btree,
                dat = nilfs_bmap_get_dat(btree);
                ret = nilfs_dat_translate(dat, ptr, &blocknr);
                if (ret < 0)
-                       goto out;
+                       goto dat_error;
                ptr = blocknr;
        }
        cnt = 1;
@@ -743,7 +743,7 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *btree,
                        if (dat) {
                                ret = nilfs_dat_translate(dat, ptr2, &blocknr);
                                if (ret < 0)
-                                       goto out;
+                                       goto dat_error;
                                ptr2 = blocknr;
                        }
                        if (ptr2 != ptr + cnt || ++cnt == maxblocks)
@@ -781,6 +781,11 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *btree,
  out:
        nilfs_btree_free_path(path);
        return ret;
+
+ dat_error:
+       if (ret == -ENOENT)
+               ret = -EINVAL;  /* Notify bmap layer of metadata corruption */
+       goto out;
 }
 
 static void nilfs_btree_promote_key(struct nilfs_bmap *btree,
index 4c85914f2abc37a7d2ccb66115072196d3f60427..893ab36824cc2b7f1fa323c1c365aa56cf981e71 100644 (file)
@@ -66,7 +66,7 @@ static int nilfs_direct_lookup_contig(const struct nilfs_bmap *direct,
                dat = nilfs_bmap_get_dat(direct);
                ret = nilfs_dat_translate(dat, ptr, &blocknr);
                if (ret < 0)
-                       return ret;
+                       goto dat_error;
                ptr = blocknr;
        }
 
@@ -79,7 +79,7 @@ static int nilfs_direct_lookup_contig(const struct nilfs_bmap *direct,
                if (dat) {
                        ret = nilfs_dat_translate(dat, ptr2, &blocknr);
                        if (ret < 0)
-                               return ret;
+                               goto dat_error;
                        ptr2 = blocknr;
                }
                if (ptr2 != ptr + cnt)
@@ -87,6 +87,11 @@ static int nilfs_direct_lookup_contig(const struct nilfs_bmap *direct,
        }
        *ptrp = ptr;
        return cnt;
+
+ dat_error:
+       if (ret == -ENOENT)
+               ret = -EINVAL;  /* Notify bmap layer of metadata corruption */
+       return ret;
 }
 
 static __u64