[PATCH OLK-6.6] md: fix out-of-bound by adding checks at store
hulk inclusion category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/10161 Reference: https://lore.kernel.org/all/e743762c-2ed0-465b-bfa1-57e75aabf034@fygo.io/ -------------------------------- syzbot reported array-index-out-of-bounds in super_90_sync() UBSAN: array-index-out-of-bounds in drivers/md/md.c:1697:17 index 124 is out of range for type 'mdp_disk_t [27]' CPU: 1 UID: 0 PID: 10197 Comm: syz.3.1362 Tainted: G L syzkaller #0 PREEMPT(full) Tainted: [L]=SOFTLOCKUP Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/05/2026 Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120 ubsan_epilogue+0xa/0x30 lib/ubsan.c:233 __ubsan_handle_out_of_bounds+0xcc/0xf0 lib/ubsan.c:455 super_90_sync+0x1eed/0x1ff0 drivers/md/md.c:1697 ... super_90_sync() exists for older version 0.90, which supports up to 27 maximum disks (MD_SB_DISKS). This function doesn't contain any bound checks for raid disks. The repro wrote higher value (124) in raid_disks sysfs attribute to trigger this bug. Add bound checks in three entry points that can set raid_disks or major_version without validating against the v0.90 superblock limit: - raid_disks_store(): add max_disks check in the reshape branch and the else branch, mirroring the existing check in update_raid_disks(). - metadata_store(): reject major_version=0 when the existing raid_disks already exceeds MD_SB_DISKS. - md_set_array_info(): reject the creation path when persistent and raid_disks >= MD_SB_DISKS. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Zhou Minqiang <zhouminqiang2@huawei.com> --- drivers/md/md.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 80d2bddb9e46..b8ddc1959871 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4357,11 +4357,20 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len) goto out_unlock; } err = 0; + if (mddev->max_disks && n >= mddev->max_disks) { + err = -EINVAL; + goto out_unlock; + } mddev->delta_disks = n - olddisks; mddev->raid_disks = n; mddev->reshape_backwards = (mddev->delta_disks < 0); - } else + } else { + if (mddev->max_disks && n >= mddev->max_disks) { + err = -EINVAL; + goto out_unlock; + } mddev->raid_disks = n; + } out_unlock: mddev_unlock_and_resume(mddev); return err ? err : len; @@ -4912,6 +4921,7 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len) mddev->external = 0; mddev->major_version = 0; mddev->minor_version = 90; + mddev->max_disks = 0; goto out_unlock; } if (strncmp(buf, "external:", 9) == 0) { @@ -4926,6 +4936,7 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len) mddev->external = 1; mddev->major_version = 0; mddev->minor_version = 90; + mddev->max_disks = 0; goto out_unlock; } major = simple_strtoul(buf, &e, 10); @@ -4936,12 +4947,18 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len) minor = simple_strtoul(buf, &e, 10); if (e==buf || (*e && *e != '\n') ) goto out_unlock; + if (major == 0 && mddev->raid_disks >= MD_SB_DISKS) + goto out_unlock; err = -ENOENT; if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL) goto out_unlock; mddev->major_version = major; mddev->minor_version = minor; mddev->persistent = 1; + if (major == 0) + mddev->max_disks = MD_SB_DISKS; + else if (major == 1) + mddev->max_disks = (4096 - 256) / 2; mddev->external = 0; err = 0; out_unlock: @@ -7421,12 +7438,23 @@ int md_set_array_info(struct mddev *mddev, struct mdu_array_info_s *info) mddev->minor_version = info->minor_version; mddev->patch_version = info->patch_version; mddev->persistent = !info->not_persistent; + if (mddev->persistent == 1) { + if (mddev->major_version == 0) + mddev->max_disks = MD_SB_DISKS; + else if (mddev->major_version == 1) + mddev->max_disks = (4096 - 256) / 2; + } /* ensure mddev_put doesn't delete this now that there * is some minimal configuration. */ mddev->ctime = ktime_get_real_seconds(); return 0; } + if (!info->not_persistent && info->raid_disks >= MD_SB_DISKS) { + pr_warn("md: raid disks (%d) exceeds max disks (%d) for metadata version 0.90\n", + info->raid_disks, MD_SB_DISKS); + return -EINVAL; + } mddev->major_version = MD_MAJOR_VERSION; mddev->minor_version = MD_MINOR_VERSION; mddev->patch_version = MD_PATCHLEVEL_VERSION; -- 2.52.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/30449 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/6MG... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/30449 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/6MG...
participants (2)
-
patchwork bot -
Zhou Minqiang