md_set_array_info() accepts raid_disks from user space without any
range check. The value is stored directly into mddev->raid_disks and
flows unchecked into md_run(), which only tests for zero. A negative
or excessively large raid_disks then reaches the personality ->run()
callback, where it scales several allocations:

  raid0:  kvzalloc(array3_size(..., raid_disks)) in create_strip_zones
  raid1:  kzalloc(array3_size(..., raid_disks, 2)) for mirrors and
          mempool_create_kmalloc_pool(offsetof(r1bio, bios[raid_disks*2]))
  raid5:  kzalloc_objs(disk_info, max_disks) and alloc_page() loop
  raid10: kzalloc_objs(raid10_info, raid_disks + ...) for mirrors

cf5963d6781dd ("md/raid0: validate device count before allocating
devlist") already fixes the raid0 warning. However raid1/5/10 still
hit the MAX_PAGE_ORDER WARN, and simply switching their kzalloc_objs
calls to kvzalloc_objs does not help because kvmalloc_node rejects
sizes above INT_MAX. The proper fix is to validate raid_disks before
any allocation takes place.

Add a MAX_RAID_DEVICES (253) bounds check in md_run() before
pers->run. This is the single choke point covering ioctl RUN_ARRAY,
dm-raid ctr, and reshape paths. Move the existing dm-raid private
definition to md.h so both subsystems share the same limit.

Signed-off-by: Ran Hongyun <[email protected]>
---
 drivers/md/dm-raid.c | 1 -
 drivers/md/md.c      | 7 +++++++
 drivers/md/md.h      | 3 +++
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index ac019a0f5a92..29c41a04773e 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -18,7 +18,6 @@
 #include <linux/device-mapper.h>
 
 #define DM_MSG_PREFIX "raid"
-#define        MAX_RAID_DEVICES        253 /* md-raid kernel limit */
 
 /*
  * Minimum sectors of free reshape space per raid device
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 03e35386a802..7b202b483e98 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6703,6 +6703,13 @@ int md_run(struct mddev *mddev)
                        return -EINVAL;
        }
 
+       if (mddev->raid_disks <= 0 ||
+           mddev->raid_disks > MAX_RAID_DEVICES) {
+               pr_warn("md: %s: raid_disks %d out of range [1, %d]\n",
+                       mdname(mddev), mddev->raid_disks, MAX_RAID_DEVICES);
+               return -EINVAL;
+       }
+
        if (mddev->level != LEVEL_NONE)
                request_module("md-level-%d", mddev->level);
        else if (mddev->clevel[0])
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 6440da292105..75d7f4b14d39 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -22,6 +22,9 @@
 #include <trace/events/block.h>
 
 #define MaxSector (~(sector_t)0)
+
+#define MAX_RAID_DEVICES       253 /* md-raid kernel limit */
+
 /*
  * Number of guaranteed raid bios in case of extreme VM load:
  */
-- 
2.52.0


Reply via email to