Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm table: remove unused buggy code that extends the targets array

A device mapper table is allocated in the following way:
* The function dm_table_create is called, it gets the number of targets
as an argument -- it allocates a targets array accordingly.
* For each target, we call dm_table_add_target.

If we add more targets than were specified in dm_table_create, the
function dm_table_add_target reallocates the targets array. However,
this reallocation code is wrong - it moves the targets array to a new
location, while some target constructors hold pointers to the array in
the old location.

The following DM target drivers save the pointer to the target
structure, so they corrupt memory if the target array is moved:
multipath, raid, mirror, snapshot, stripe, switch, thin, verity.

Under normal circumstances, the reallocation function is not called
(because dm_table_create is called with the correct number of targets),
so the buggy reallocation code is not used.

Prior to the fix "dm table: fail dm_table_create on dm_round_up
overflow", the reallocation code could only be used in case the user
specifies too large a value in param->target_count, such as 0xffffffff.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>

authored by

Mikulas Patocka and committed by
Mike Snitzer
57a2f238 19fa1a67

+2 -20
+2 -20
drivers/md/dm-table.c
··· 155 155 { 156 156 sector_t *n_highs; 157 157 struct dm_target *n_targets; 158 - int n = t->num_targets; 159 158 160 159 /* 161 160 * Allocate both the target array and offset array at once. ··· 168 169 169 170 n_targets = (struct dm_target *) (n_highs + num); 170 171 171 - if (n) { 172 - memcpy(n_highs, t->highs, sizeof(*n_highs) * n); 173 - memcpy(n_targets, t->targets, sizeof(*n_targets) * n); 174 - } 175 - 176 - memset(n_highs + n, -1, sizeof(*n_highs) * (num - n)); 172 + memset(n_highs, -1, sizeof(*n_highs) * num); 177 173 vfree(t->highs); 178 174 179 175 t->num_allocated = num; ··· 252 258 dm_free_md_mempools(t->mempools); 253 259 254 260 kfree(t); 255 - } 256 - 257 - /* 258 - * Checks to see if we need to extend highs or targets. 259 - */ 260 - static inline int check_space(struct dm_table *t) 261 - { 262 - if (t->num_targets >= t->num_allocated) 263 - return alloc_targets(t, t->num_allocated * 2); 264 - 265 - return 0; 266 261 } 267 262 268 263 /* ··· 714 731 return -EINVAL; 715 732 } 716 733 717 - if ((r = check_space(t))) 718 - return r; 734 + BUG_ON(t->num_targets >= t->num_allocated); 719 735 720 736 tgt = t->targets + t->num_targets; 721 737 memset(tgt, 0, sizeof(*tgt));