]> git.ipfire.org Git - thirdparty/kernel/linux.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)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 9 May 2024 20:23:36 +0000 (16:23 -0400)
- 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>
fs/bcachefs/sb-downgrade.c

index 7d2abadbd6e3972c29f7baaedc59028dc20b0c04..390a1bbd2567ac271f3c69b505753f969d0508eb 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,16 @@ 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 (flags & BCH_VALIDATE_write &&
+                   ((void *) &i->errors[0] > vstruct_end(&e->field) ||
+                    (void *) downgrade_entry_next_c(i) > vstruct_end(&e->field))) {
+                       prt_printf(err, "downgrade entry overruns end of superblock section)");
+                       return -BCH_ERR_invalid_sb_downgrade;
+               }
+
                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)",