Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4eccc579 authored by Lars Ellenberg's avatar Lars Ellenberg Committed by Philipp Reisner
Browse files

drbd: fix access of unallocated pages and kernel panic



BUG: unable to handle kernel NULL pointer dereference at (null)
...
 [<d1e17561>] ? _drbd_bm_set_bits+0x151/0x240 [drbd]
 [<d1e236f8>] ? receive_bitmap+0x4f8/0xbc0 [drbd]

This fixes an off-by-one error in the receive_bitmap() path,
if run-length encoded bitmap transfer is enabled.

If the bitmap is an exact multiple of PAGE_SIZE, which means the visible
capacity of the drbd device is an exact multiple of 128 MiB (for 4k page
size), and bitmap compression (use-rle) is enabled (which became default
with 8.4), and the very last bit is dirty and reported in an rle
comressed bitmap packet, we ended up trying to kmap_atomic a page pointer
that does not exist (bitmap->bm_pages[last index + 1]).

bug introduced by:
    Date:   Fri Jul 24 15:33:24 2009 +0200
    set bits: optimize for complete last word, fix off-by-one-word corner case

made effective by:
    Date:   Thu Dec 16 00:32:38 2010 +0100
    drbd: get rid of unused debug code

    Long time ago, we had paranoia code in the bitmap that allocated one
    extra word, assigned a magic value, and checked on every occasion that
    the magic value was still unchanged.

    That debug code is unused, the extra long word complicates code a bit.
    Get rid of it.

No-one triggered this bug in the last few years, because a large subset
of our userbase is unaffected:
 * typically the last few blocks of a device are not modified
   frequently, and remain unset
 * use-rle was disabled by default in drbd < 8.4
 * those with slightly "odd" device sizes, or
 * drbd internal meta data (which will skew the device size slightly,
   thus makes it harder to have a bug relevant device size)

Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent 4fd1ffaa
Loading
Loading
Loading
Loading
+9 −2
Original line number Original line Diff line number Diff line
@@ -1475,9 +1475,16 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
		first_word = 0;
		first_word = 0;
		spin_lock_irq(&b->bm_lock);
		spin_lock_irq(&b->bm_lock);
	}
	}

	/* last page (respectively only page, for first page == last page) */
	/* last page (respectively only page, for first page == last page) */
	last_word = MLPP(el >> LN2_BPL);
	last_word = MLPP(el >> LN2_BPL);

	/* consider bitmap->bm_bits = 32768, bitmap->bm_number_of_pages = 1. (or multiples).
	 * ==> e = 32767, el = 32768, last_page = 2,
	 * and now last_word = 0.
	 * We do not want to touch last_page in this case,
	 * as we did not allocate it, it is not present in bitmap->bm_pages.
	 */
	if (last_word)
		bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
		bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);


	/* possibly trailing bits.
	/* possibly trailing bits.