Skip to contentSkip to conversation

FAILED: patch "[PATCH] vfio/type1: Unpin zero pages" failed to apply to 5.10-stable tree

PATCH [email protected] 1 participant 1 message Sep 9, 2022

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

Possible dependencies:

873aefb376bb ("vfio/type1: Unpin zero pages")
4b6c33b32296 ("vfio/type1: Prepare for batched pinning with struct vfio_batch") be16c1fd99f4 ("vfio/type1: Change success value of vaddr_get_pfn()")

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 873aefb376bbc0ed1dd2381ea1d6ec88106fdbd4 Mon Sep 17 00:00:00 2001
From: Alex Williamson <[email protected]>
Date: Mon, 29 Aug 2022 21:05:40 -0600
Subject: [PATCH] vfio/type1: Unpin zero pages

There's currently a reference count leak on the zero page. We increment the reference via pin_user_pages_remote(), but the page is later handled as an invalid/reserved page, therefore it's not accounted against the user and not unpinned by our put_pfn().

Introducing special zero page handling in put_pfn() would resolve the leak, but without accounting of the zero page, a single user could still create enough mappings to generate a reference count overflow.

The zero page is always resident, so for our purposes there's no reason to keep it pinned. Therefore, add a loop to walk pages returned from pin_user_pages_remote() and unpin any zero pages.

drivers/vfio/vfio_iommu_type1.c +12 -0
index db516c90a977..8706482665d1 100644
@@ -558,6 +558,18 @@ static int vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
 	ret = pin_user_pages_remote(mm, vaddr, npages, flags | FOLL_LONGTERM,
 				    pages, NULL, NULL);
 	if (ret > 0) {
+		int i;
+
+		/*
+		 * The zero page is always resident, we don't need to pin it
+		 * and it falls into our invalid/reserved test so we don't
+		 * unpin in put_pfn().  Unpin all zero pages in the batch here.
+		 */
+		for (i = 0 ; i < ret; i++) {
+			if (unlikely(is_zero_pfn(page_to_pfn(pages[i]))))
+				unpin_user_page(pages[i]);
+		}
+
 		*pfn = page_to_pfn(pages[0]);
 		goto done;
 	}