md: check that internal bitmap does not overlap other data
[cascardo/linux.git] / drivers / md / bitmap.c
index 9620d45..ae94f3b 100644 (file)
@@ -268,6 +268,31 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
                        if (page->index == bitmap->file_pages-1)
                                size = roundup(bitmap->last_page_size,
                                               bdev_hardsect_size(rdev->bdev));
+                       /* Just make sure we aren't corrupting data or
+                        * metadata
+                        */
+                       if (bitmap->offset < 0) {
+                               /* DATA  BITMAP METADATA  */
+                               if (bitmap->offset
+                                   + page->index * (PAGE_SIZE/512)
+                                   + size/512 > 0)
+                                       /* bitmap runs in to metadata */
+                                       return -EINVAL;
+                               if (rdev->data_offset + mddev->size*2
+                                   > rdev->sb_offset*2 + bitmap->offset)
+                                       /* data runs in to bitmap */
+                                       return -EINVAL;
+                       } else if (rdev->sb_offset*2 < rdev->data_offset) {
+                               /* METADATA BITMAP DATA */
+                               if (rdev->sb_offset*2
+                                   + bitmap->offset
+                                   + page->index*(PAGE_SIZE/512) + size/512
+                                   > rdev->data_offset)
+                                       /* bitmap runs in to data */
+                                       return -EINVAL;
+                       } else {
+                               /* DATA METADATA BITMAP - no problems */
+                       }
                        md_super_write(mddev, rdev,
                                       (rdev->sb_offset<<1) + bitmap->offset
                                       + page->index * (PAGE_SIZE/512),
@@ -287,8 +312,14 @@ static int write_page(struct bitmap *bitmap, struct page *page, int wait)
 {
        struct buffer_head *bh;
 
-       if (bitmap->file == NULL)
-               return write_sb_page(bitmap, page, wait);
+       if (bitmap->file == NULL) {
+               switch (write_sb_page(bitmap, page, wait)) {
+               case -EINVAL:
+                       bitmap->flags |= BITMAP_WRITE_ERROR;
+                       return -EIO;
+               }
+               return 0;
+       }
 
        bh = page_buffers(page);