]> www.infradead.org Git - nvme.git/commitdiff
bcachefs: Inodes need extra padding for varint_decode_fast()
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 3 May 2024 15:31:22 +0000 (11:31 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 6 May 2024 14:58:17 +0000 (10:58 -0400)
Reported-by: syzbot+66b9b74f6520068596a9@syzkaller.appspotmail.com
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/io_write.c

index f137252bccc575b42a012a7876f8c81ddee28a21..b72cf31f72743c553c9f646f308986b93047ab64 100644 (file)
@@ -199,9 +199,6 @@ static inline int bch2_extent_update_i_size_sectors(struct btree_trans *trans,
                                                    u64 new_i_size,
                                                    s64 i_sectors_delta)
 {
-       struct btree_iter iter;
-       struct bkey_i *k;
-       struct bkey_i_inode_v3 *inode;
        /*
         * Crazy performance optimization:
         * Every extent update needs to also update the inode: the inode trigger
@@ -214,25 +211,36 @@ static inline int bch2_extent_update_i_size_sectors(struct btree_trans *trans,
         * lost, but that's fine.
         */
        unsigned inode_update_flags = BTREE_UPDATE_NOJOURNAL;
-       int ret;
 
-       k = bch2_bkey_get_mut_noupdate(trans, &iter, BTREE_ID_inodes,
+       struct btree_iter iter;
+       struct bkey_s_c k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_inodes,
                              SPOS(0,
                                   extent_iter->pos.inode,
                                   extent_iter->snapshot),
                              BTREE_ITER_CACHED);
-       ret = PTR_ERR_OR_ZERO(k);
+       int ret = bkey_err(k);
        if (unlikely(ret))
                return ret;
 
-       if (unlikely(k->k.type != KEY_TYPE_inode_v3)) {
-               k = bch2_inode_to_v3(trans, k);
-               ret = PTR_ERR_OR_ZERO(k);
+       /*
+        * varint_decode_fast(), in the inode .invalid method, reads up to 7
+        * bytes past the end of the buffer:
+        */
+       struct bkey_i *k_mut = bch2_trans_kmalloc_nomemzero(trans, bkey_bytes(k.k) + 8);
+       ret = PTR_ERR_OR_ZERO(k_mut);
+       if (unlikely(ret))
+               goto err;
+
+       bkey_reassemble(k_mut, k);
+
+       if (unlikely(k_mut->k.type != KEY_TYPE_inode_v3)) {
+               k_mut = bch2_inode_to_v3(trans, k_mut);
+               ret = PTR_ERR_OR_ZERO(k_mut);
                if (unlikely(ret))
                        goto err;
        }
 
-       inode = bkey_i_to_inode_v3(k);
+       struct bkey_i_inode_v3 *inode = bkey_i_to_inode_v3(k_mut);
 
        if (!(le64_to_cpu(inode->v.bi_flags) & BCH_INODE_i_size_dirty) &&
            new_i_size > le64_to_cpu(inode->v.bi_size)) {