Commit fd948c3f authored by Carlos López's avatar Carlos López Committed by Borislav Petkov (AMD)
Browse files

virt: sev-guest: Explicitly leak pages in unknown state



When set_memory_{encrypted,decrypted}() fail, the user cannot know at which
point the function failed, meaning that the pages are left in an unknown state
from the point of view of the caller.

Since the pages may be left in an unencrypted state, they are not suitable for
general use, and cannot be returned safely to the buddy allocator. Avoid the
issue by never freeing the pages, and then do the proper accounting by calling
snp_leak_pages().

Fixes: 3e385c0d ("virt: sev-guest: Move SNP Guest Request data pages handling under snp_cmd_mutex")
Signed-off-by: default avatarCarlos López <clopez@suse.de>
Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Cc: stable@kernel.org
parent 44126343
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
	struct snp_guest_req req = {};
	int ret, npages = 0, resp_len;
	sockptr_t certs_address;
	u64 pfn;

	if (sockptr_is_null(io->req_data) || sockptr_is_null(io->resp_data))
		return -EINVAL;
@@ -215,10 +216,11 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
	if (!req.certs_data)
		return -ENOMEM;

	pfn = PHYS_PFN(virt_to_phys(req.certs_data));
	ret = set_memory_decrypted((unsigned long)req.certs_data, npages);
	if (ret) {
		pr_err("failed to mark page shared, ret=%d\n", ret);
		free_pages_exact(req.certs_data, npages << PAGE_SHIFT);
		snp_leak_pages(pfn, npages);
		return -EFAULT;
	}

@@ -272,11 +274,13 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
	kfree(report_resp);
e_free_data:
	if (npages) {
		if (set_memory_encrypted((unsigned long)req.certs_data, npages))
		if (set_memory_encrypted((unsigned long)req.certs_data, npages)) {
			WARN_ONCE(ret, "failed to restore encryption mask (leak it)\n");
		else
			snp_leak_pages(pfn, npages);
		} else {
			free_pages_exact(req.certs_data, npages << PAGE_SHIFT);
		}
	}
	return ret;
}