--- /dev/null
+From 6df90c02bae468a3a6110bafbc659884d0c4966c Mon Sep 17 00:00:00 2001
+From: Milan Broz <gmazyland@gmail.com>
+Date: Wed, 18 Dec 2024 13:56:58 +0100
+Subject: dm-verity FEC: Fix RS FEC repair for roots unaligned to block size (take 2)
+
+From: Milan Broz <gmazyland@gmail.com>
+
+commit 6df90c02bae468a3a6110bafbc659884d0c4966c upstream.
+
+This patch fixes an issue that was fixed in the commit
+ df7b59ba9245 ("dm verity: fix FEC for RS roots unaligned to block size")
+but later broken again in the commit
+ 8ca7cab82bda ("dm verity fec: fix misaligned RS roots IO")
+
+If the Reed-Solomon roots setting spans multiple blocks, the code does not
+use proper parity bytes and randomly fails to repair even trivial errors.
+
+This bug cannot happen if the sector size is multiple of RS roots
+setting (Android case with roots 2).
+
+The previous solution was to find a dm-bufio block size that is multiple
+of the device sector size and roots size. Unfortunately, the optimization
+in commit 8ca7cab82bda ("dm verity fec: fix misaligned RS roots IO")
+is incorrect and uses data block size for some roots (for example, it uses
+4096 block size for roots = 20).
+
+This patch uses a different approach:
+
+ - It always uses a configured data block size for dm-bufio to avoid
+ possible misaligned IOs.
+
+ - and it caches the processed parity bytes, so it can join it
+ if it spans two blocks.
+
+As the RS calculation is called only if an error is detected and
+the process is computationally intensive, copying a few more bytes
+should not introduce performance issues.
+
+The issue was reported to cryptsetup with trivial reproducer
+ https://gitlab.com/cryptsetup/cryptsetup/-/issues/923
+
+Reproducer (with roots=20):
+
+ # create verity device with RS FEC
+ dd if=/dev/urandom of=data.img bs=4096 count=8 status=none
+ veritysetup format data.img hash.img --fec-device=fec.img --fec-roots=20 | \
+ awk '/^Root hash/{ print $3 }' >roothash
+
+ # create an erasure that should always be repairable with this roots setting
+ dd if=/dev/zero of=data.img conv=notrunc bs=1 count=4 seek=4 status=none
+
+ # try to read it through dm-verity
+ veritysetup open data.img test hash.img --fec-device=fec.img --fec-roots=20 $(cat roothash)
+ dd if=/dev/mapper/test of=/dev/null bs=4096 status=noxfer
+
+ Even now the log says it cannot repair it:
+ : verity-fec: 7:1: FEC 0: failed to correct: -74
+ : device-mapper: verity: 7:1: data block 0 is corrupted
+ ...
+
+With this fix, errors are properly repaired.
+ : verity-fec: 7:1: FEC 0: corrected 4 errors
+
+Signed-off-by: Milan Broz <gmazyland@gmail.com>
+Fixes: 8ca7cab82bda ("dm verity fec: fix misaligned RS roots IO")
+Cc: stable@vger.kernel.org
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Milan Broz <gmazyland@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-verity-fec.c | 39 ++++++++++++++++++++++++++-------------
+ 1 file changed, 26 insertions(+), 13 deletions(-)
+
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -60,14 +60,19 @@ static int fec_decode_rs8(struct dm_veri
+ * to the data block. Caller is responsible for releasing buf.
+ */
+ static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
+- unsigned int *offset, struct dm_buffer **buf)
++ unsigned int *offset, unsigned int par_buf_offset,
++ struct dm_buffer **buf)
+ {
+ u64 position, block, rem;
+ u8 *res;
+
++ /* We have already part of parity bytes read, skip to the next block */
++ if (par_buf_offset)
++ index++;
++
+ position = (index + rsb) * v->fec->roots;
+ block = div64_u64_rem(position, v->fec->io_size, &rem);
+- *offset = (unsigned int)rem;
++ *offset = par_buf_offset ? 0 : (unsigned int)rem;
+
+ res = dm_bufio_read(v->fec->bufio, block, buf);
+ if (IS_ERR(res)) {
+@@ -127,10 +132,11 @@ static int fec_decode_bufs(struct dm_ver
+ {
+ int r, corrected = 0, res;
+ struct dm_buffer *buf;
+- unsigned int n, i, offset;
+- u8 *par, *block;
++ unsigned int n, i, offset, par_buf_offset = 0;
++ u8 *par, *block, par_buf[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN];
+
+- par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
++ par = fec_read_parity(v, rsb, block_offset, &offset,
++ par_buf_offset, &buf);
+ if (IS_ERR(par))
+ return PTR_ERR(par);
+
+@@ -140,7 +146,8 @@ static int fec_decode_bufs(struct dm_ver
+ */
+ fec_for_each_buffer_rs_block(fio, n, i) {
+ block = fec_buffer_rs_block(v, fio, n, i);
+- res = fec_decode_rs8(v, fio, block, &par[offset], neras);
++ memcpy(&par_buf[par_buf_offset], &par[offset], v->fec->roots - par_buf_offset);
++ res = fec_decode_rs8(v, fio, block, par_buf, neras);
+ if (res < 0) {
+ r = res;
+ goto error;
+@@ -153,12 +160,21 @@ static int fec_decode_bufs(struct dm_ver
+ if (block_offset >= 1 << v->data_dev_block_bits)
+ goto done;
+
+- /* read the next block when we run out of parity bytes */
+- offset += v->fec->roots;
++ /* Read the next block when we run out of parity bytes */
++ offset += (v->fec->roots - par_buf_offset);
++ /* Check if parity bytes are split between blocks */
++ if (offset < v->fec->io_size && (offset + v->fec->roots) > v->fec->io_size) {
++ par_buf_offset = v->fec->io_size - offset;
++ memcpy(par_buf, &par[offset], par_buf_offset);
++ offset += par_buf_offset;
++ } else
++ par_buf_offset = 0;
++
+ if (offset >= v->fec->io_size) {
+ dm_bufio_release(buf);
+
+- par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
++ par = fec_read_parity(v, rsb, block_offset, &offset,
++ par_buf_offset, &buf);
+ if (IS_ERR(par))
+ return PTR_ERR(par);
+ }
+@@ -743,10 +759,7 @@ int verity_fec_ctr(struct dm_verity *v)
+ return -E2BIG;
+ }
+
+- if ((f->roots << SECTOR_SHIFT) & ((1 << v->data_dev_block_bits) - 1))
+- f->io_size = 1 << v->data_dev_block_bits;
+- else
+- f->io_size = v->fec->roots << SECTOR_SHIFT;
++ f->io_size = 1 << v->data_dev_block_bits;
+
+ f->bufio = dm_bufio_client_create(f->dev->bdev,
+ f->io_size,
--- /dev/null
+From b7d0a97b28083084ebdd8e5c6bccd12e6ec18faa Mon Sep 17 00:00:00 2001
+From: Ye Bin <yebin10@huawei.com>
+Date: Sat, 12 Oct 2024 00:44:50 +0800
+Subject: f2fs: fix null-ptr-deref in f2fs_submit_page_bio()
+
+From: Ye Bin <yebin10@huawei.com>
+
+commit b7d0a97b28083084ebdd8e5c6bccd12e6ec18faa upstream.
+
+There's issue as follows when concurrently installing the f2fs.ko
+module and mounting the f2fs file system:
+KASAN: null-ptr-deref in range [0x0000000000000020-0x0000000000000027]
+RIP: 0010:__bio_alloc+0x2fb/0x6c0 [f2fs]
+Call Trace:
+ <TASK>
+ f2fs_submit_page_bio+0x126/0x8b0 [f2fs]
+ __get_meta_page+0x1d4/0x920 [f2fs]
+ get_checkpoint_version.constprop.0+0x2b/0x3c0 [f2fs]
+ validate_checkpoint+0xac/0x290 [f2fs]
+ f2fs_get_valid_checkpoint+0x207/0x950 [f2fs]
+ f2fs_fill_super+0x1007/0x39b0 [f2fs]
+ mount_bdev+0x183/0x250
+ legacy_get_tree+0xf4/0x1e0
+ vfs_get_tree+0x88/0x340
+ do_new_mount+0x283/0x5e0
+ path_mount+0x2b2/0x15b0
+ __x64_sys_mount+0x1fe/0x270
+ do_syscall_64+0x5f/0x170
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+Above issue happens as the biset of the f2fs file system is not
+initialized before register "f2fs_fs_type".
+To address above issue just register "f2fs_fs_type" at the last in
+init_f2fs_fs(). Ensure that all f2fs file system resources are
+initialized.
+
+Fixes: f543805fcd60 ("f2fs: introduce private bioset")
+Signed-off-by: Ye Bin <yebin10@huawei.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Bin Lan <lanbincn@qq.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/super.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -4931,9 +4931,6 @@ static int __init init_f2fs_fs(void)
+ err = register_shrinker(&f2fs_shrinker_info, "f2fs-shrinker");
+ if (err)
+ goto free_sysfs;
+- err = register_filesystem(&f2fs_fs_type);
+- if (err)
+- goto free_shrinker;
+ f2fs_create_root_stats();
+ err = f2fs_init_post_read_processing();
+ if (err)
+@@ -4956,7 +4953,12 @@ static int __init init_f2fs_fs(void)
+ err = f2fs_create_casefold_cache();
+ if (err)
+ goto free_compress_cache;
++ err = register_filesystem(&f2fs_fs_type);
++ if (err)
++ goto free_casefold_cache;
+ return 0;
++free_casefold_cache:
++ f2fs_destroy_casefold_cache();
+ free_compress_cache:
+ f2fs_destroy_compress_cache();
+ free_compress_mempool:
+@@ -4971,8 +4973,6 @@ free_post_read:
+ f2fs_destroy_post_read_processing();
+ free_root_stats:
+ f2fs_destroy_root_stats();
+- unregister_filesystem(&f2fs_fs_type);
+-free_shrinker:
+ unregister_shrinker(&f2fs_shrinker_info);
+ free_sysfs:
+ f2fs_exit_sysfs();
+@@ -4996,6 +4996,7 @@ fail:
+
+ static void __exit exit_f2fs_fs(void)
+ {
++ unregister_filesystem(&f2fs_fs_type);
+ f2fs_destroy_casefold_cache();
+ f2fs_destroy_compress_cache();
+ f2fs_destroy_compress_mempool();
+@@ -5004,7 +5005,6 @@ static void __exit exit_f2fs_fs(void)
+ f2fs_destroy_iostat_processing();
+ f2fs_destroy_post_read_processing();
+ f2fs_destroy_root_stats();
+- unregister_filesystem(&f2fs_fs_type);
+ unregister_shrinker(&f2fs_shrinker_info);
+ f2fs_exit_sysfs();
+ f2fs_destroy_garbage_collection_cache();