lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241220141321.GA26794@willie-the-truck>
Date: Fri, 20 Dec 2024 14:13:22 +0000
From: Will Deacon <will@...nel.org>
To: Quentin Perret <qperret@...gle.com>
Cc: Marc Zyngier <maz@...nel.org>, Oliver Upton <oliver.upton@...ux.dev>,
	Joey Gouly <joey.gouly@....com>,
	Suzuki K Poulose <suzuki.poulose@....com>,
	Zenghui Yu <yuzenghui@...wei.com>,
	Catalin Marinas <catalin.marinas@....com>,
	linux-arm-kernel@...ts.infradead.org, kvmarm@...ts.linux.dev,
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH] KVM: arm64: Selftest for pKVM transitions

On Fri, Nov 29, 2024 at 12:58:00PM +0000, Quentin Perret wrote:
> We have recently found a bug [1] in the pKVM memory ownership
> transitions by code inspection, but it could have been caught with a
> test.
> 
> Introduce a boot-time selftest exercising all the known pKVM memory
> transitions and importantly checks the rejection of illegal transitions.

Thanks for doing this!

> 
> The new test is hidden behind a new Kconfig option separate from
> CONFIG_EL2_NVHE_DEBUG on purpose as that has side effects on the
> transition checks ([1] doesn't reproduce with EL2 debug enabled).

Hmm. What does a test failure look like without CONFIG_EL2_NVHE_DEBUG
enabled? Do we still get file:line information?

[...]

> +void pkvm_ownership_selftest(void)
> +{
> +	void *virt = hyp_alloc_pages(&host_s2_pool, 0);
> +	u64 phys, size, pfn;
> +
> +	WARN_ON(!virt);
> +	selftest_page = hyp_virt_to_page(virt);
> +	selftest_page->refcount = 0;
> +
> +	size = PAGE_SIZE << selftest_page->order;
> +	phys = hyp_virt_to_phys(virt);
> +	pfn = hyp_phys_to_pfn(phys);
> +
> +	selftest_state.host = PKVM_NOPAGE;
> +	selftest_state.hyp = PKVM_PAGE_OWNED;
> +	assert_page_state();
> +	assert_transition_res(-EPERM,	__pkvm_host_donate_hyp, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_host_unshare_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_ffa, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_host_unshare_ffa, pfn, 1);
> +	assert_transition_res(-EPERM,	hyp_pin_shared_mem, virt, virt + size);
> +
> +	selftest_state.host = PKVM_PAGE_OWNED;
> +	selftest_state.hyp = PKVM_NOPAGE;
> +	assert_transition_res(0,	__pkvm_hyp_donate_host, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_hyp_donate_host, pfn, 1);
> +	assert_transition_res(-EPERM,	hyp_pin_shared_mem, virt, virt + size);

Should we recheck the unshare transitions here?

> +	selftest_state.host = PKVM_PAGE_SHARED_OWNED;
> +	selftest_state.hyp = PKVM_PAGE_SHARED_BORROWED;
> +	assert_transition_res(0,	__pkvm_host_share_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_host_donate_hyp, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_ffa, pfn, 1);

We could check unshare_ffa here.

> +	assert_transition_res(-EPERM,	__pkvm_hyp_donate_host, pfn, 1);
> +
> +	assert_transition_res(0,	hyp_pin_shared_mem, virt, virt + size);

Is it worth trying an extra pin + unpin?

> +	WARN_ON(!hyp_page_count(virt));

Can we assert an exact value (e.g. count == 1)?

> +	assert_transition_res(-EBUSY,	__pkvm_host_unshare_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_host_donate_hyp, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_ffa, pfn, 1);

unshare_ffa again here.

> +	assert_transition_res(-EPERM,	__pkvm_hyp_donate_host, pfn, 1);
> +
> +	hyp_unpin_shared_mem(virt, virt + size);
> +	assert_page_state();
> +	WARN_ON(hyp_page_count(virt));
> +	assert_transition_res(-EPERM,	__pkvm_host_share_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_host_donate_hyp, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_ffa, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_hyp_donate_host, pfn, 1);

Is this block actually testing anything new? Once we've asserted the page
state and checked the refcount, the transitions seem redundant to me.

> +	selftest_state.host = PKVM_PAGE_OWNED;
> +	selftest_state.hyp = PKVM_NOPAGE;
> +	assert_transition_res(0,	__pkvm_host_unshare_hyp, pfn);
> +
> +	selftest_state.host = PKVM_PAGE_SHARED_OWNED;
> +	selftest_state.hyp = PKVM_NOPAGE;
> +	assert_transition_res(0,	__pkvm_host_share_ffa, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_ffa, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_host_donate_hyp, pfn, 1);
> +	assert_transition_res(-EPERM,	__pkvm_host_share_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_host_unshare_hyp, pfn);
> +	assert_transition_res(-EPERM,	__pkvm_hyp_donate_host, pfn, 1);
> +	assert_transition_res(-EPERM,	hyp_pin_shared_mem, virt, virt + size);
> +
> +	selftest_state.host = PKVM_PAGE_OWNED;
> +	selftest_state.hyp = PKVM_NOPAGE;
> +	assert_transition_res(0,	__pkvm_host_unshare_ffa, pfn, 1);

Try it twice?

Will

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ