]> git.baikalelectronics.ru Git - kernel.git/commitdiff
dm clone: Add overflow check for number of regions
authorNikos Tsironis <ntsironis@arrikto.com>
Fri, 27 Mar 2020 14:01:09 +0000 (16:01 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 17 Apr 2020 08:50:17 +0000 (10:50 +0200)
commit ba39a7ceb8579e898d6ea6d84bdedc881ce0031d upstream.

Add overflow check for clone->nr_regions variable, which holds the
number of regions of the target.

The overflow can occur with sufficiently large devices, if BITS_PER_LONG
== 32. E.g., if the region size is 8 sectors (4K), the overflow would
occur for device sizes > 34359738360 sectors (~16TB).

This could result in multiple device sectors wrongly mapping to the same
region number, due to the truncation from 64 bits to 32 bits, which
would lead to data corruption.

Fixes: 926c5639707c ("dm: add clone target")
Cc: stable@vger.kernel.org # v5.4+
Signed-off-by: Nikos Tsironis <ntsironis@arrikto.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/md/dm-clone-target.c

index e6e5d24a79f5672c4808de197102fc9671b8422f..e9d405e9a5bd24a20759a4fb8a0d89f2d7de9f94 100644 (file)
@@ -1775,6 +1775,7 @@ error:
 static int clone_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
        int r;
+       sector_t nr_regions;
        struct clone *clone;
        struct dm_arg_set as;
 
@@ -1816,7 +1817,16 @@ static int clone_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto out_with_source_dev;
 
        clone->region_shift = __ffs(clone->region_size);
-       clone->nr_regions = dm_sector_div_up(ti->len, clone->region_size);
+       nr_regions = dm_sector_div_up(ti->len, clone->region_size);
+
+       /* Check for overflow */
+       if (nr_regions != (unsigned long)nr_regions) {
+               ti->error = "Too many regions. Consider increasing the region size";
+               r = -EOVERFLOW;
+               goto out_with_source_dev;
+       }
+
+       clone->nr_regions = nr_regions;
 
        r = validate_nr_regions(clone->nr_regions, &ti->error);
        if (r)