]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
bcachefs: Fix sb_field_downgrade validation
authorKent Overstreet <kent.overstreet@linux.dev>
Mon, 6 May 2024 13:16:33 +0000 (09:16 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Jul 2024 07:38:16 +0000 (09:38 +0200)
commit 692aa7a54b2b28d59f24b3bf8250837805484b99 upstream.

- bch2_sb_downgrade_validate() wasn't checking for a downgrade entry
  extending past the end of the superblock section

- for_each_downgrade_entry() is used in to_text() and needs to work on
  malformed input; it also was missing a check for a field extending
  past the end of the section

Reported-by: syzbot+e49ccab73449180bc9be@syzkaller.appspotmail.com
Fixes: 84f1638795da ("bcachefs: bch_sb_field_downgrade")
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/bcachefs/sb-downgrade.c

index a98ef940b7a3280bd0da0474ef4f387fdcd0cc18..13fb3292aba4068e851158b9567ecf041247bd56 100644 (file)
@@ -134,7 +134,8 @@ downgrade_entry_next_c(const struct bch_sb_field_downgrade_entry *e)
 #define for_each_downgrade_entry(_d, _i)                                               \
        for (const struct bch_sb_field_downgrade_entry *_i = (_d)->entries;             \
             (void *) _i        < vstruct_end(&(_d)->field) &&                          \
-            (void *) &_i->errors[0] < vstruct_end(&(_d)->field);                       \
+            (void *) &_i->errors[0] <= vstruct_end(&(_d)->field) &&                    \
+            (void *) downgrade_entry_next_c(_i) <= vstruct_end(&(_d)->field);          \
             _i = downgrade_entry_next_c(_i))
 
 static int bch2_sb_downgrade_validate(struct bch_sb *sb, struct bch_sb_field *f,
@@ -142,7 +143,9 @@ static int bch2_sb_downgrade_validate(struct bch_sb *sb, struct bch_sb_field *f,
 {
        struct bch_sb_field_downgrade *e = field_to_type(f, downgrade);
 
-       for_each_downgrade_entry(e, i) {
+       for (const struct bch_sb_field_downgrade_entry *i = e->entries;
+            (void *) i < vstruct_end(&e->field);
+            i = downgrade_entry_next_c(i)) {
                if (BCH_VERSION_MAJOR(le16_to_cpu(i->version)) !=
                    BCH_VERSION_MAJOR(le16_to_cpu(sb->version))) {
                        prt_printf(err, "downgrade entry with mismatched major version (%u != %u)",