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

md: check that internal bitmap does not overlap other data

We current completely trust user-space to set up metadata describing an
consistant array. In particlar, that the metadata, data, and bitmap do not
overlap.

But userspace can be buggy, and it is better to report an error than corrupt
data. So put in some appropriate checks.

Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

NeilBrown and committed by
Linus Torvalds
f0d76d70 713f6ab1

+54 -3
+33 -2
drivers/md/bitmap.c
··· 268 268 if (page->index == bitmap->file_pages-1) 269 269 size = roundup(bitmap->last_page_size, 270 270 bdev_hardsect_size(rdev->bdev)); 271 + /* Just make sure we aren't corrupting data or 272 + * metadata 273 + */ 274 + if (bitmap->offset < 0) { 275 + /* DATA BITMAP METADATA */ 276 + if (bitmap->offset 277 + + page->index * (PAGE_SIZE/512) 278 + + size/512 > 0) 279 + /* bitmap runs in to metadata */ 280 + return -EINVAL; 281 + if (rdev->data_offset + mddev->size*2 282 + > rdev->sb_offset*2 + bitmap->offset) 283 + /* data runs in to bitmap */ 284 + return -EINVAL; 285 + } else if (rdev->sb_offset*2 < rdev->data_offset) { 286 + /* METADATA BITMAP DATA */ 287 + if (rdev->sb_offset*2 288 + + bitmap->offset 289 + + page->index*(PAGE_SIZE/512) + size/512 290 + > rdev->data_offset) 291 + /* bitmap runs in to data */ 292 + return -EINVAL; 293 + } else { 294 + /* DATA METADATA BITMAP - no problems */ 295 + } 271 296 md_super_write(mddev, rdev, 272 297 (rdev->sb_offset<<1) + bitmap->offset 273 298 + page->index * (PAGE_SIZE/512), ··· 312 287 { 313 288 struct buffer_head *bh; 314 289 315 - if (bitmap->file == NULL) 316 - return write_sb_page(bitmap, page, wait); 290 + if (bitmap->file == NULL) { 291 + switch (write_sb_page(bitmap, page, wait)) { 292 + case -EINVAL: 293 + bitmap->flags |= BITMAP_WRITE_ERROR; 294 + return -EIO; 295 + } 296 + return 0; 297 + } 317 298 318 299 bh = page_buffers(page); 319 300
+21 -1
drivers/md/md.c
··· 3176 3176 * Drop all container device buffers, from now on 3177 3177 * the only valid external interface is through the md 3178 3178 * device. 3179 - * Also find largest hardsector size 3180 3179 */ 3181 3180 ITERATE_RDEV(mddev,rdev,tmp) { 3182 3181 if (test_bit(Faulty, &rdev->flags)) 3183 3182 continue; 3184 3183 sync_blockdev(rdev->bdev); 3185 3184 invalidate_bdev(rdev->bdev); 3185 + 3186 + /* perform some consistency tests on the device. 3187 + * We don't want the data to overlap the metadata, 3188 + * Internal Bitmap issues has handled elsewhere. 3189 + */ 3190 + if (rdev->data_offset < rdev->sb_offset) { 3191 + if (mddev->size && 3192 + rdev->data_offset + mddev->size*2 3193 + > rdev->sb_offset*2) { 3194 + printk("md: %s: data overlaps metadata\n", 3195 + mdname(mddev)); 3196 + return -EINVAL; 3197 + } 3198 + } else { 3199 + if (rdev->sb_offset*2 + rdev->sb_size/512 3200 + > rdev->data_offset) { 3201 + printk("md: %s: metadata overlaps data\n", 3202 + mdname(mddev)); 3203 + return -EINVAL; 3204 + } 3205 + } 3186 3206 } 3187 3207 3188 3208 md_probe(mddev->unit, NULL, NULL);