linux/drivers/mtd
Guo Xuenan fbed4baed0 ubi: fix slab-out-of-bounds in ubi_eba_get_ldesc+0xfb/0x130
When using the ioctl interface to resize a UBI volume, `ubi_resize_volume`
resizes the EBA table first but does not change `vol->reserved_pebs` in
the same atomic context, which may cause concurrent access to the EBA table.

For example, when a user shrinks UBI volume A by calling `ubi_resize_volume`,
while another thread is writing to volume B and triggering wear-leveling,
which may call `ubi_write_fastmap`, under these circumstances, KASAN may
report a slab-out-of-bounds error in `ubi_eba_get_ldesc+0xfb/0x130`.

This patch fixes race conditions in `ubi_resize_volume` and
`ubi_update_fastmap` to avoid out-of-bounds reads of `eba_tbl`. First,
it ensures that updates to `eba_tbl` and `reserved_pebs` are protected
by `vol->volumes_lock`. Second, it implements a rollback mechanism in case
of resize failure. It is also worth mentioning that for volume shrinkage
failures, since part of the volume has already been shrunk and unmapped,
there is no need to recover `{rsvd/avail}_pebs`.

==================================================================
BUG: KASAN: slab-out-of-bounds in ubi_eba_get_ldesc+0xfb/0x130 [ubi]
Read of size 4 at addr ffff88800f43f570 by task kworker/u16:0/7
CPU: 0 PID: 7 Comm: kworker/u16:0 Not tainted 5.16.0-rc7 #3
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Workqueue: writeback wb_workfn (flush-ubifs_0_0)
Call Trace:
 <TASK>
 dump_stack_lvl+0x4d/0x66
 print_address_description.constprop.0+0x41/0x60
 kasan_report.cold+0x83/0xdf
 ubi_eba_get_ldesc+0xfb/0x130 [ubi]
 ubi_update_fastmap.cold+0x60f/0xc7d [ubi]
 ubi_wl_get_peb+0x25b/0x4f0 [ubi]
 try_write_vid_and_data+0x9a/0x4d0 [ubi]
 ubi_eba_write_leb+0x7e4/0x17d0 [ubi]
 ubi_leb_map+0x1a0/0x2c0 [ubi]
 ubifs_leb_map+0x139/0x270 [ubifs]
 ubifs_add_bud_to_log+0xb40/0xf30 [ubifs]
 make_reservation+0x86e/0xb00 [ubifs]
 ubifs_jnl_write_data+0x430/0x9d0 [ubifs]
 do_writepage+0x1d1/0x550 [ubifs]
 ubifs_writepage+0x37c/0x670 [ubifs]
 __writepage+0x67/0x170
 write_cache_pages+0x259/0xa90
 do_writepages+0x277/0x5d0
 __writeback_single_inode+0xb8/0x850
 writeback_sb_inodes+0x4b3/0xb20
 __writeback_inodes_wb+0xc1/0x220
 wb_writeback+0x59f/0x740
 wb_workfn+0x6d0/0xca0
 process_one_work+0x711/0xfc0
 worker_thread+0x95/0xd00
 kthread+0x3a6/0x490
 ret_from_fork+0x1f/0x30
 </TASK>

Allocated by task 711:
 kasan_save_stack+0x1e/0x50
 __kasan_kmalloc+0x81/0xa0
 ubi_eba_create_table+0x88/0x1a0 [ubi]
 ubi_resize_volume.cold+0x175/0xae7 [ubi]
 ubi_cdev_ioctl+0x57f/0x1a60 [ubi]
 __x64_sys_ioctl+0x13a/0x1c0
 do_syscall_64+0x35/0x80
 entry_SYSCALL_64_after_hwframe+0x44/0xae

Last potentially related work creation:
 kasan_save_stack+0x1e/0x50
 __kasan_record_aux_stack+0xb7/0xc0
 call_rcu+0xd6/0x1000
 blk_stat_free_callback+0x28/0x30
 blk_release_queue+0x8a/0x2e0
 kobject_put+0x186/0x4c0
 scsi_device_dev_release_usercontext+0x620/0xbd0
 execute_in_process_context+0x2f/0x120
 device_release+0xa4/0x240
 kobject_put+0x186/0x4c0
 put_device+0x20/0x30
 __scsi_remove_device+0x1c3/0x300
 scsi_probe_and_add_lun+0x2140/0x2eb0
 __scsi_scan_target+0x1f2/0xbb0
 scsi_scan_channel+0x11b/0x1a0
 scsi_scan_host_selected+0x24c/0x310
 do_scsi_scan_host+0x1e0/0x250
 do_scan_async+0x45/0x490
 async_run_entry_fn+0xa2/0x530
 process_one_work+0x711/0xfc0
 worker_thread+0x95/0xd00
 kthread+0x3a6/0x490
 ret_from_fork+0x1f/0x30
The buggy address belongs to the object at ffff88800f43f500
 which belongs to the cache kmalloc-128 of size 128
The buggy address is located 112 bytes inside of
 128-byte region [ffff88800f43f500, ffff88800f43f580)
The buggy address belongs to the page:
page:ffffea00003d0f00 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xf43c
head:ffffea00003d0f00 order:2 compound_mapcount:0 compound_pincount:0
flags: 0x1fffff80010200(slab|head|node=0|zone=1|lastcpupid=0x1fffff)
raw: 001fffff80010200 ffffea000046ba08 ffffea0000457208 ffff88810004d1c0
raw: 0000000000000000 0000000000190019 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
 ffff88800f43f400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff88800f43f480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> ffff88800f43f500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fc fc
                                                             ^
 ffff88800f43f580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff88800f43f600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc

The following steps can used to reproduce:
Process 1: write and trigger ubi wear-leveling
    ubimkvol /dev/ubi0 -s 5000MiB -N v1
    ubimkvol /dev/ubi0 -s 2000MiB -N v2
    ubimkvol /dev/ubi0 -s 10MiB -N v3
    mount -t ubifs /dev/ubi0_0 /mnt/ubifs
    while true;
    do
        filename=/mnt/ubifs/$((RANDOM))
        dd if=/dev/random of=${filename} bs=1M count=$((RANDOM % 1000))
        rm -rf ${filename}
        sync /mnt/ubifs/
    done

Process 2: do random resize
    struct ubi_rsvol_req req;
    req.vol_id = 1;
    req.bytes = (rand() % 50) * 512KB;
    ioctl(fd, UBI_IOCRSVOL, &req);

V3:
 - Fix the commit message error.

V2:
 - Add volumes_lock in ubi_eba_copy_leb() to avoid race caused by
   updating eba_tbl.

V1:
 - Rebase the patch on the latest mainline.

Signed-off-by: Guo Xuenan <guoxuenan@huawei.com>
Signed-off-by: ZhaoLong Wang <wangzhaolong1@huawei.com>
Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
2024-02-25 21:38:41 +01:00
..
chips mtd: cfi_cmdset_0001: Byte swap OTP info 2023-10-27 19:45:11 +02:00
devices The main load of changes is related to Uwe's work converting platform 2023-11-04 11:04:30 -10:00
hyperbus mtd: hyperbus: rpc-if: Convert to platform remove callback returning void 2023-10-16 10:56:48 +02:00
lpddr mtd: lpddr2_nvm: Convert to platform remove callback returning void 2023-10-16 10:56:48 +02:00
maps mtd: maps: vmu-flash: Fix the (mtd core) switch to ref counters 2023-12-14 16:43:17 +01:00
nand * MTD 2024-01-09 15:40:59 -08:00
parsers mtd: parsers: ar7: remove support 2023-10-19 10:31:44 +02:00
spi-nor * MTD 2024-01-09 15:40:59 -08:00
tests treewide: use get_random_u32_below() instead of deprecated function 2022-11-18 02:15:15 +01:00
ubi ubi: fix slab-out-of-bounds in ubi_eba_get_ldesc+0xfb/0x130 2024-02-25 21:38:41 +01:00
ftl.c mtd: ftl: use container_of() rather than cast 2022-09-19 18:14:53 +02:00
inftlcore.c mtd: inftlcore: fix repeated words in comments 2022-11-07 17:14:21 +01:00
inftlmount.c
Kconfig
Makefile
mtd_blkdevs.c for-6.8/block-2024-01-08 2024-01-11 13:58:04 -08:00
mtdblock_ro.c mtdblock: make warning messages ratelimited 2023-07-27 17:16:14 +02:00
mtdblock.c mtdblock: make warning messages ratelimited 2023-07-27 17:16:14 +02:00
mtdchar.c mtdchar: mark bits of ioctl handler noinline 2023-06-01 18:12:31 +02:00
mtdconcat.c mtd: fix repeated word in comment 2022-09-20 10:40:30 +02:00
mtdcore.c mtd: Add several functions to the fail_function list 2024-01-06 23:47:07 +01:00
mtdcore.h mtd: use refcount to prevent corruption 2023-07-12 13:30:08 +02:00
mtdoops.c mtd: mtdoops: panic caused mtdoops to call mtdoops_erase function immediately 2022-11-07 17:08:00 +01:00
mtdpart.c mtd: mtdpart: check for subpartitions parsing result 2023-10-16 10:50:32 +02:00
mtdpstore.c mtd: Fix a typo in a comment 2022-09-19 18:14:53 +02:00
mtdsuper.c mtd: key superblock by device number 2023-08-31 12:47:15 +02:00
mtdswap.c mtd: always initialize 'stats' in struct mtd_oob_ops 2022-09-21 10:38:07 +02:00
nftlcore.c mtd: always initialize 'stats' in struct mtd_oob_ops 2022-09-21 10:38:07 +02:00
nftlmount.c
rfd_ftl.c
sm_ftl.c mtd: sm_ftl: Fix typos in comments 2023-06-22 23:00:43 +02:00
sm_ftl.h
ssfdc.c mtd: ssfdc: Remove an unused variable 2023-12-14 16:43:15 +01:00