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

Commit 644bd2f0 authored by Neil Brown's avatar Neil Brown Committed by Jens Axboe
Browse files

Fix memory leak in dm-crypt



dm-crypt used the ->bi_size member in the bio endio handling to
free the appropriate pages, but it frees all of it from both call
paths. With the ->bi_end_io() changes, ->bi_size was always 0 since
we don't do partial completes. This caused dm-crypt to leak memory.

Fix this by removing the size argument from crypt_free_buffer_pages().

Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 3eed13fd
Loading
Loading
Loading
Loading
+5 −26
Original line number Diff line number Diff line
@@ -441,33 +441,12 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
	return clone;
}

static void crypt_free_buffer_pages(struct crypt_config *cc,
                                    struct bio *clone, unsigned int bytes)
static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone)
{
	unsigned int i, start, end;
	unsigned int i;
	struct bio_vec *bv;

	/*
	 * This is ugly, but Jens Axboe thinks that using bi_idx in the
	 * endio function is too dangerous at the moment, so I calculate the
	 * correct position using bi_vcnt and bi_size.
	 * The bv_offset and bv_len fields might already be modified but we
	 * know that we always allocated whole pages.
	 * A fix to the bi_idx issue in the kernel is in the works, so
	 * we will hopefully be able to revert to the cleaner solution soon.
	 */
	i = clone->bi_vcnt - 1;
	bv = bio_iovec_idx(clone, i);
	end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - clone->bi_size;
	start = end - bytes;

	start >>= PAGE_SHIFT;
	if (!clone->bi_size)
		end = clone->bi_vcnt;
	else
		end >>= PAGE_SHIFT;

	for (i = start; i < end; i++) {
	for (i = 0; i < clone->bi_vcnt; i++) {
		bv = bio_iovec_idx(clone, i);
		BUG_ON(!bv->bv_page);
		mempool_free(bv->bv_page, cc->page_pool);
@@ -519,7 +498,7 @@ static void crypt_endio(struct bio *clone, int error)
	 * free the processed pages
	 */
	if (!read_io) {
		crypt_free_buffer_pages(cc, clone, clone->bi_size);
		crypt_free_buffer_pages(cc, clone);
		goto out;
	}

@@ -608,7 +587,7 @@ static void process_write(struct dm_crypt_io *io)
		ctx.idx_out = 0;

		if (unlikely(crypt_convert(cc, &ctx) < 0)) {
			crypt_free_buffer_pages(cc, clone, clone->bi_size);
			crypt_free_buffer_pages(cc, clone);
			bio_put(clone);
			dec_pending(io, -EIO);
			return;