linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Brijesh Singh <brijesh.singh@amd.com>
To: Borislav Petkov <bp@alien8.de>
Cc: brijesh.singh@amd.com, linux-kernel@vger.kernel.org,
	x86@kernel.org, kvm@vger.kernel.org, ak@linux.intel.com,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, Joerg Roedel <jroedel@suse.de>,
	"H. Peter Anvin" <hpa@zytor.com>, Tony Luck <tony.luck@intel.com>,
	Dave Hansen <dave.hansen@intel.com>,
	"Peter Zijlstra (Intel)" <peterz@infradead.org>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	David Rientjes <rientjes@google.com>,
	Sean Christopherson <seanjc@google.com>
Subject: Re: [RFC Part1 PATCH 13/13] x86/kernel: add support to validate memory when changing C-bit
Date: Mon, 12 Apr 2021 07:55:01 -0500	[thread overview]
Message-ID: <f9a69ad8-54bb-70f1-d606-6497e5753bb0@amd.com> (raw)
In-Reply-To: <20210412114901.GB24283@zn.tnic>


On 4/12/21 6:49 AM, Borislav Petkov wrote:
> On Wed, Mar 24, 2021 at 11:44:24AM -0500, Brijesh Singh wrote:
>> @@ -161,3 +162,108 @@ void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr
>>  	 /* Ask hypervisor to make the memory shared in the RMP table. */
>>  	early_snp_set_page_state(paddr, npages, SNP_PAGE_STATE_SHARED);
>>  }
>> +
>> +static int snp_page_state_vmgexit(struct ghcb *ghcb, struct snp_page_state_change *data)
> That function name definitely needs changing. The
> vmgexit_page_state_change() one too. They're currenty confusing as hell
> and I can't know what each one does without looking at its function
> body.
>
>> +{
>> +	struct snp_page_state_header *hdr;
>> +	int ret = 0;
>> +
>> +	hdr = &data->header;
>> +
>> +	/*
>> +	 * The hypervisor can return before processing all the entries, the loop below retries
>> +	 * until all the entries are processed.
>> +	 */
>> +	while (hdr->cur_entry <= hdr->end_entry) {
> This doesn't make any sense: snp_set_page_state() builds a "set" of
> pages to change their state in a loop and this one iterates *again* over
> *something* which I'm not even clear on what.
>
> Is something setting cur_entry to end_entry eventually?
>
> In any case, why not issue those page state changes one-by-one in
> snp_set_page_state() or is it possible that HV can do a couple of
> them in one go so you have to poke it here until it sets cur_entry ==
> end_entry?


The cur_entry is updated by the hypervisor. While building the psc
buffer the guest sets the cur_entry=0 and the end_entry point to the
last valid entry. The cur_entry is incremented by the hypervisor after
it successfully processes one 4K page. As per the spec, the hypervisor
could get interrupted in middle of the page state change and cur_entry
allows the guest to resume the page state change from the point where it
was interrupted.

>
>> +		ghcb_set_sw_scratch(ghcb, (u64)__pa(data));


Since we can get interrupted while executing the PSC so just to be safe
I re-initialized the scratch scratch area with our buffer instead of
relying on old values.


> Why do you have to call that here for every loop iteration...
>
>> +		ret = vmgexit_page_state_change(ghcb, data);


As per the spec the caller must check that the cur_entry > end_entry to
determine whether all the entries are processed. If not then retry the
state change. The hypervisor will skip the previously processed entries.
The snp_page_state_vmgexit() is implemented to return only after all the
entries are changed.


> .... and in that function too?!
>
>> +		/* Page State Change VMGEXIT can pass error code through exit_info_2. */
>> +		if (ret || ghcb->save.sw_exit_info_2)
>> +			break;
>> +	}
>> +
>> +	return ret;
> You don't need that ret variable - just return value directly.


Noted.

>
>> +}
>> +
>> +static void snp_set_page_state(unsigned long paddr, unsigned int npages, int op)
>> +{
>> +	unsigned long paddr_end, paddr_next;
>> +	struct snp_page_state_change *data;
>> +	struct snp_page_state_header *hdr;
>> +	struct snp_page_state_entry *e;
>> +	struct ghcb_state state;
>> +	struct ghcb *ghcb;
>> +	int ret, idx;
>> +
>> +	paddr = paddr & PAGE_MASK;
>> +	paddr_end = paddr + (npages << PAGE_SHIFT);
>> +
>> +	ghcb = sev_es_get_ghcb(&state);
> That function can return NULL.


Ah good point. Will fix in next rev.

>
>> +	data = (struct snp_page_state_change *)ghcb->shared_buffer;
>> +	hdr = &data->header;
>> +	e = &(data->entry[0]);
> So
>
> 	e = data->entry;
>
> ?


Sure I can do that. It reads better that way.


>> +	memset(data, 0, sizeof (*data));
>> +
>> +	for (idx = 0; paddr < paddr_end; paddr = paddr_next) {
> As before, a while loop pls.


Noted.

>
>> +		int level = PG_LEVEL_4K;
> Why does this needs to happen on each loop iteration? It looks to me you
> wanna do below:
>
> 	e->pagesize = X86_RMP_PG_LEVEL(PG_LEVEL_4K);
>
> instead.


Noted. I will remove the local variable.


>> +
>> +		/* If we cannot fit more request then issue VMGEXIT before going further.  */
> 				   any more requests
>
> No "we" pls.


Noted.

>
>> +		if (hdr->end_entry == (SNP_PAGE_STATE_CHANGE_MAX_ENTRY - 1)) {
>> +			ret = snp_page_state_vmgexit(ghcb, data);
>> +			if (ret)
>> +				goto e_fail;
> WARN


Based on your feedback on previous patches I am going to replace it with
WARN() followed by special termination code to indicate that guest fail
to change the page state.


>
>> +
>> +			idx = 0;
>> +			memset(data, 0, sizeof (*data));
>> +			e = &(data->entry[0]);
>> +		}
> The order of the operations in this function looks weird: what you
> should do is:
>
> 	- clear stuff, memset etc.
> 	- build shared buffer
> 	- issue vmgexit
>
> so that you don't have the memset and e reinit twice and the flow can
> be more clear and you don't have two snp_page_state_vmgexit() function
> calls when there's a trailing set of entries which haven't reached
> SNP_PAGE_STATE_CHANGE_MAX_ENTRY.
>
> Maybe a double-loop or so.


Yes with a double loop I can rearrange it a bit better. I will look into
it for the v2. thanks


> ...
>
>> diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
>> index 16f878c26667..19ee18ddbc37 100644
>> --- a/arch/x86/mm/pat/set_memory.c
>> +++ b/arch/x86/mm/pat/set_memory.c
>> @@ -27,6 +27,8 @@
>>  #include <asm/proto.h>
>>  #include <asm/memtype.h>
>>  #include <asm/set_memory.h>
>> +#include <asm/mem_encrypt.h>
>> +#include <asm/sev-snp.h>
>>  
>>  #include "../mm_internal.h"
>>  
>> @@ -2001,8 +2003,25 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
>>  	 */
>>  	cpa_flush(&cpa, !this_cpu_has(X86_FEATURE_SME_COHERENT));
>>  
>> +	/*
>> +	 * To maintain the security gurantees of SEV-SNP guest invalidate the memory before
>> +	 * clearing the encryption attribute.
>> +	 */
> Align that comment on 80 cols, just like the rest of the comments do in
> this file. Below too.
>

Noted.

>> +	if (sev_snp_active() && !enc) {
> Push that sev_snp_active() inside the function. Below too.


Noted.

>
>> +		ret = snp_set_memory_shared(addr, numpages);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>>  	ret = __change_page_attr_set_clr(&cpa, 1);
>>  
>> +	/*
>> +	 * Now that memory is mapped encrypted in the page table, validate the memory range before
>> +	 * we return from here.
>> +	 */
>> +	if (!ret && sev_snp_active() && enc)
>> +		ret = snp_set_memory_private(addr, numpages);
>> +
>>  	/*
>>  	 * After changing the encryption attribute, we need to flush TLBs again
>>  	 * in case any speculative TLB caching occurred (but no need to flush

  reply	other threads:[~2021-04-12 12:55 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-24 16:44 [RFC Part1 PATCH 00/13] Add AMD Secure Nested Paging (SEV-SNP) Guest Support Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 01/13] x86/cpufeatures: Add SEV-SNP CPU feature Brijesh Singh
2021-03-25 10:54   ` Borislav Petkov
2021-03-25 14:50     ` Brijesh Singh
2021-03-25 16:29       ` Borislav Petkov
2021-03-24 16:44 ` [RFC Part1 PATCH 02/13] x86/mm: add sev_snp_active() helper Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 03/13] x86: add a helper routine for the PVALIDATE instruction Brijesh Singh
2021-03-26 14:30   ` Borislav Petkov
2021-03-26 15:42     ` Brijesh Singh
2021-03-26 18:22       ` Brijesh Singh
2021-03-26 19:12         ` Borislav Petkov
2021-03-26 20:04           ` Brijesh Singh
2021-03-26 19:22       ` Borislav Petkov
2021-03-26 20:01         ` Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 04/13] x86/sev-snp: define page state change VMGEXIT structure Brijesh Singh
2021-04-01 10:32   ` Borislav Petkov
2021-04-01 14:11     ` Brijesh Singh
2021-04-02 15:44       ` Borislav Petkov
2021-03-24 16:44 ` [RFC Part1 PATCH 05/13] X86/sev-es: move few helper functions in common file Brijesh Singh
2021-04-02 19:27   ` Borislav Petkov
2021-04-02 21:33     ` Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 06/13] x86/compressed: rescinds and validate the memory used for the GHCB Brijesh Singh
2021-04-06 10:33   ` Borislav Petkov
2021-04-06 15:47     ` Brijesh Singh
2021-04-06 19:42       ` Tom Lendacky
2021-04-07 11:25         ` Borislav Petkov
2021-04-07 19:45           ` Borislav Petkov
2021-04-08 13:57             ` Tom Lendacky
2021-04-07 11:16       ` Borislav Petkov
2021-04-07 13:35         ` Brijesh Singh
2021-04-07 14:21           ` Tom Lendacky
2021-04-07 17:15             ` Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 07/13] x86/compressed: register GHCB memory when SNP is active Brijesh Singh
2021-04-07 11:59   ` Borislav Petkov
2021-04-07 17:34     ` Brijesh Singh
2021-04-07 17:54       ` Tom Lendacky
2021-04-08  8:17       ` Borislav Petkov
2021-03-24 16:44 ` [RFC Part1 PATCH 08/13] x86/sev-es: register GHCB memory when SEV-SNP " Brijesh Singh
2021-04-08  8:38   ` Borislav Petkov
2021-03-24 16:44 ` [RFC Part1 PATCH 09/13] x86/kernel: add support to validate memory in early enc attribute change Brijesh Singh
2021-04-08 11:40   ` Borislav Petkov
2021-04-08 12:25     ` Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 10/13] X86: kernel: make the bss.decrypted section shared in RMP table Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 11/13] x86/kernel: validate rom memory before accessing when SEV-SNP is active Brijesh Singh
2021-04-09 16:53   ` Borislav Petkov
2021-04-09 17:40     ` Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 12/13] x86/sev-es: make GHCB get and put helper accessible outside Brijesh Singh
2021-03-24 16:44 ` [RFC Part1 PATCH 13/13] x86/kernel: add support to validate memory when changing C-bit Brijesh Singh
2021-04-12 11:49   ` Borislav Petkov
2021-04-12 12:55     ` Brijesh Singh [this message]
2021-04-12 13:05       ` Borislav Petkov
2021-04-12 14:31         ` Brijesh Singh

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f9a69ad8-54bb-70f1-d606-6497e5753bb0@amd.com \
    --to=brijesh.singh@amd.com \
    --cc=ak@linux.intel.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@intel.com \
    --cc=hpa@zytor.com \
    --cc=jroedel@suse.de \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rientjes@google.com \
    --cc=seanjc@google.com \
    --cc=tglx@linutronix.de \
    --cc=thomas.lendacky@amd.com \
    --cc=tony.luck@intel.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).