[PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support

Ashish Kalra posted 2 patches 1 month, 2 weeks ago
[PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support
Posted by Ashish Kalra 1 month, 2 weeks ago
From: Ashish Kalra <ashish.kalra@amd.com>

Ciphertext hiding prevents host accesses from reading the ciphertext of
SNP guest private memory. Instead of reading ciphertext, the host reads
will see constant default values (0xff).

The SEV ASID space is split into SEV and SEV-ES/SEV-SNP ASID ranges.
Enabling ciphertext hiding further splits the SEV-ES/SEV-SNP ASID space
into separate ASID ranges for SEV-ES and SEV-SNP guests.

Add a new off-by-default kvm-amd module parameter to enable ciphertext
hiding and allow the admin to configure the SEV-ES and SEV-SNP ASID
ranges. Simply cap the maximum SEV-SNP ASID as appropriate, i.e. don't
reject loading KVM or disable ciphertest hiding for a too-big value, as
KVM's general approach for module params is to sanitize inputs based on
hardware/kernel support, not burn the world down. This also allows the
admin to use -1u to assign all SEV-ES/SNP ASIDs to SNP without needing
dedicated handling in KVM.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 .../admin-guide/kernel-parameters.txt         | 19 +++++++++++
 arch/x86/kvm/svm/sev.c                        | 32 ++++++++++++++++++-
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 729728280438..fd59d129ad8a 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2957,6 +2957,25 @@
 			(enabled). Disable by KVM if hardware lacks support
 			for NPT.
 
+	kvm-amd.ciphertext_hiding_asids=
+			[KVM,AMD] Ciphertext hiding prevents disallowed accesses
+			to SNP private memory from reading ciphertext.  Instead,
+			reads will see constant default values (0xff).
+
+			If ciphertext hiding is enabled, the joint SEV-ES and SEV-SNP
+			ASID space is paritioned into separate SEV-ES and SEV-SNP
+			ASID ranges, with the SEV-SNP ASID range starting at 1.
+			For SEV-ES/SEV-SNP guests the maximum ASID is MIN_SEV_ASID-1,
+			where MIN_SEV_ASID value is discovered by CPUID
+			Fn8000_001F[EDX].
+
+			A non-zero value enables SEV-SNP ciphertext hiding and
+			adjusts the ASID ranges for SEV-ES and SEV-SNP guests.
+			KVM caps the number of SEV-SNP ASIDs at the maximum
+			possible value, e.g. specifying -1u will assign all
+			joint SEV-ES and SEV-SNP ASIDs to SEV-SNP and make
+			SEV-ES unusable.
+
 	kvm-arm.mode=
 			[KVM,ARM,EARLY] Select one of KVM/arm64's modes of
 			operation.
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index cd9ce100627e..5cad79ad1002 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -59,6 +59,9 @@ static bool sev_es_debug_swap_enabled = true;
 module_param_named(debug_swap, sev_es_debug_swap_enabled, bool, 0444);
 static u64 sev_supported_vmsa_features;
 
+static unsigned int nr_ciphertext_hiding_asids;
+module_param_named(ciphertext_hiding_asids, nr_ciphertext_hiding_asids, uint, 0444);
+
 #define AP_RESET_HOLD_NONE		0
 #define AP_RESET_HOLD_NAE_EVENT		1
 #define AP_RESET_HOLD_MSR_PROTO		2
@@ -201,6 +204,9 @@ static int sev_asid_new(struct kvm_sev_info *sev, unsigned long vm_type)
 	/*
 	 * The min ASID can end up larger than the max if basic SEV support is
 	 * effectively disabled by disallowing use of ASIDs for SEV guests.
+	 * Similarly for SEV-ES guests the min ASID can end up larger than the
+	 * max when ciphertext hiding is enabled, effectively disabling SEV-ES
+	 * support.
 	 */
 	if (min_asid > max_asid)
 		return -ENOTTY;
@@ -3064,10 +3070,32 @@ void __init sev_hardware_setup(void)
 out:
 	if (sev_enabled) {
 		init_args.probe = true;
+
+		if (sev_is_snp_ciphertext_hiding_supported())
+			init_args.max_snp_asid = min(nr_ciphertext_hiding_asids,
+						     min_sev_asid - 1);
+
 		if (sev_platform_init(&init_args))
 			sev_supported = sev_es_supported = sev_snp_supported = false;
 		else if (sev_snp_supported)
 			sev_snp_supported = is_sev_snp_initialized();
+
+		if (sev_snp_supported)
+			nr_ciphertext_hiding_asids = init_args.max_snp_asid;
+
+		/*
+		 * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP
+		 * ASID range is partitioned into separate SEV-ES and SEV-SNP
+		 * ASID ranges, with the SEV-SNP range being [1..max_snp_asid]
+		 * and the SEV-ES range being [max_snp_asid..max_sev_es_asid].
+		 * Note, SEV-ES may effectively be disabled if all ASIDs from
+		 * the joint range are assigned to SEV-SNP.
+		 */
+		if (nr_ciphertext_hiding_asids) {
+			max_snp_asid = nr_ciphertext_hiding_asids;
+			min_sev_es_asid = max_snp_asid + 1;
+			pr_info("SEV-SNP ciphertext hiding enabled\n");
+		}
 	}
 
 	if (boot_cpu_has(X86_FEATURE_SEV))
@@ -3078,7 +3106,9 @@ void __init sev_hardware_setup(void)
 			min_sev_asid, max_sev_asid);
 	if (boot_cpu_has(X86_FEATURE_SEV_ES))
 		pr_info("SEV-ES %s (ASIDs %u - %u)\n",
-			str_enabled_disabled(sev_es_supported),
+			sev_es_supported ? min_sev_es_asid <= max_sev_es_asid ? "enabled" :
+										"unusable" :
+										"disabled",
 			min_sev_es_asid, max_sev_es_asid);
 	if (boot_cpu_has(X86_FEATURE_SEV_SNP))
 		pr_info("SEV-SNP %s (ASIDs %u - %u)\n",
-- 
2.34.1
Re: [PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support
Posted by Randy Dunlap 1 month, 2 weeks ago

On 8/20/25 1:50 PM, Ashish Kalra wrote:
> @@ -3064,10 +3070,32 @@ void __init sev_hardware_setup(void)
>  out:
>  	if (sev_enabled) {
>  		init_args.probe = true;
> +
> +		if (sev_is_snp_ciphertext_hiding_supported())
> +			init_args.max_snp_asid = min(nr_ciphertext_hiding_asids,
> +						     min_sev_asid - 1);
> +
>  		if (sev_platform_init(&init_args))
>  			sev_supported = sev_es_supported = sev_snp_supported = false;
>  		else if (sev_snp_supported)
>  			sev_snp_supported = is_sev_snp_initialized();
> +
> +		if (sev_snp_supported)
> +			nr_ciphertext_hiding_asids = init_args.max_snp_asid;
> +
> +		/*
> +		 * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP
> +		 * ASID range is partitioned into separate SEV-ES and SEV-SNP
> +		 * ASID ranges, with the SEV-SNP range being [1..max_snp_asid]
> +		 * and the SEV-ES range being [max_snp_asid..max_sev_es_asid].

		                              [max_snp_asid + 1..max_sev_es_asid]
?

> +		 * Note, SEV-ES may effectively be disabled if all ASIDs from
> +		 * the joint range are assigned to SEV-SNP.
> +		 */
-- 
~Randy
Re: [PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support
Posted by Kalra, Ashish 1 month, 2 weeks ago

On 8/20/2025 5:45 PM, Randy Dunlap wrote:
> 
> 
> On 8/20/25 1:50 PM, Ashish Kalra wrote:
>> @@ -3064,10 +3070,32 @@ void __init sev_hardware_setup(void)
>>  out:
>>  	if (sev_enabled) {
>>  		init_args.probe = true;
>> +
>> +		if (sev_is_snp_ciphertext_hiding_supported())
>> +			init_args.max_snp_asid = min(nr_ciphertext_hiding_asids,
>> +						     min_sev_asid - 1);
>> +
>>  		if (sev_platform_init(&init_args))
>>  			sev_supported = sev_es_supported = sev_snp_supported = false;
>>  		else if (sev_snp_supported)
>>  			sev_snp_supported = is_sev_snp_initialized();
>> +
>> +		if (sev_snp_supported)
>> +			nr_ciphertext_hiding_asids = init_args.max_snp_asid;
>> +
>> +		/*
>> +		 * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP
>> +		 * ASID range is partitioned into separate SEV-ES and SEV-SNP
>> +		 * ASID ranges, with the SEV-SNP range being [1..max_snp_asid]
>> +		 * and the SEV-ES range being [max_snp_asid..max_sev_es_asid].
> 
> 		                              [max_snp_asid + 1..max_sev_es_asid]
> ?

Yes.

Thanks,
Ashish

> 
>> +		 * Note, SEV-ES may effectively be disabled if all ASIDs from
>> +		 * the joint range are assigned to SEV-SNP.
>> +		 */
Re: [PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support
Posted by Kim Phillips 1 month, 1 week ago
On 8/20/25 6:23 PM, Kalra, Ashish wrote:
> On 8/20/2025 5:45 PM, Randy Dunlap wrote:
>> On 8/20/25 1:50 PM, Ashish Kalra wrote:
>>> @@ -3064,10 +3070,32 @@ void __init sev_hardware_setup(void)
>>>   out:
>>>   	if (sev_enabled) {
>>>   		init_args.probe = true;
>>> +
>>> +		if (sev_is_snp_ciphertext_hiding_supported())
>>> +			init_args.max_snp_asid = min(nr_ciphertext_hiding_asids,
>>> +						     min_sev_asid - 1);
>>> +
>>>   		if (sev_platform_init(&init_args))
>>>   			sev_supported = sev_es_supported = sev_snp_supported = false;
>>>   		else if (sev_snp_supported)
>>>   			sev_snp_supported = is_sev_snp_initialized();
>>> +
>>> +		if (sev_snp_supported)
>>> +			nr_ciphertext_hiding_asids = init_args.max_snp_asid;
>>> +
>>> +		/*
>>> +		 * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP
>>> +		 * ASID range is partitioned into separate SEV-ES and SEV-SNP
>>> +		 * ASID ranges, with the SEV-SNP range being [1..max_snp_asid]
>>> +		 * and the SEV-ES range being [max_snp_asid..max_sev_es_asid].
>> 		                              [max_snp_asid + 1..max_sev_es_asid]
>> ?
> Yes.

So why wouldn't you have left Sean's original 
"(max_snp_asid..max_sev_es_asid]" as-is?

Kim
Re: [PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support
Posted by Kalra, Ashish 1 month, 1 week ago

On 8/21/2025 5:30 AM, Kim Phillips wrote:
> On 8/20/25 6:23 PM, Kalra, Ashish wrote:
>> On 8/20/2025 5:45 PM, Randy Dunlap wrote:
>>> On 8/20/25 1:50 PM, Ashish Kalra wrote:
>>>> @@ -3064,10 +3070,32 @@ void __init sev_hardware_setup(void)
>>>>   out:
>>>>       if (sev_enabled) {
>>>>           init_args.probe = true;
>>>> +
>>>> +        if (sev_is_snp_ciphertext_hiding_supported())
>>>> +            init_args.max_snp_asid = min(nr_ciphertext_hiding_asids,
>>>> +                             min_sev_asid - 1);
>>>> +
>>>>           if (sev_platform_init(&init_args))
>>>>               sev_supported = sev_es_supported = sev_snp_supported = false;
>>>>           else if (sev_snp_supported)
>>>>               sev_snp_supported = is_sev_snp_initialized();
>>>> +
>>>> +        if (sev_snp_supported)
>>>> +            nr_ciphertext_hiding_asids = init_args.max_snp_asid;
>>>> +
>>>> +        /*
>>>> +         * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP
>>>> +         * ASID range is partitioned into separate SEV-ES and SEV-SNP
>>>> +         * ASID ranges, with the SEV-SNP range being [1..max_snp_asid]
>>>> +         * and the SEV-ES range being [max_snp_asid..max_sev_es_asid].
>>>                                       [max_snp_asid + 1..max_sev_es_asid]
>>> ?
>> Yes.
> 
> So why wouldn't you have left Sean's original "(max_snp_asid..max_sev_es_asid]" as-is?
> 
> Kim
> 

Because that i believe is a typo and the correct SEV-ES range is [max_snp_asid + 1..max_sev_es_asid].

Ashish
Re: [PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support
Posted by Kim Phillips 1 month, 1 week ago
On 8/21/25 5:58 AM, Kalra, Ashish wrote:
> On 8/21/2025 5:30 AM, Kim Phillips wrote:
>> On 8/20/25 6:23 PM, Kalra, Ashish wrote:
>>> On 8/20/2025 5:45 PM, Randy Dunlap wrote:
>>>> On 8/20/25 1:50 PM, Ashish Kalra wrote:
>>>>> @@ -3064,10 +3070,32 @@ void __init sev_hardware_setup(void)
>>>>>    out:
>>>>>        if (sev_enabled) {
>>>>>            init_args.probe = true;
>>>>> +
>>>>> +        if (sev_is_snp_ciphertext_hiding_supported())
>>>>> +            init_args.max_snp_asid = min(nr_ciphertext_hiding_asids,
>>>>> +                             min_sev_asid - 1);
>>>>> +
>>>>>            if (sev_platform_init(&init_args))
>>>>>                sev_supported = sev_es_supported = sev_snp_supported = false;
>>>>>            else if (sev_snp_supported)
>>>>>                sev_snp_supported = is_sev_snp_initialized();
>>>>> +
>>>>> +        if (sev_snp_supported)
>>>>> +            nr_ciphertext_hiding_asids = init_args.max_snp_asid;
>>>>> +
>>>>> +        /*
>>>>> +         * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP
>>>>> +         * ASID range is partitioned into separate SEV-ES and SEV-SNP
>>>>> +         * ASID ranges, with the SEV-SNP range being [1..max_snp_asid]
>>>>> +         * and the SEV-ES range being [max_snp_asid..max_sev_es_asid].
>>>>                                        [max_snp_asid + 1..max_sev_es_asid]
>>>> ?
>>> Yes.
>> So why wouldn't you have left Sean's original "(max_snp_asid..max_sev_es_asid]" as-is?
>>
>> Kim
>>
> Because that i believe is a typo and the correct SEV-ES range is [max_snp_asid + 1..max_sev_es_asid].

It's not, though.

[max_snp_asid..max_sev_es_asid]

and

(max_snp_asid..max_sev_es_asid]

are two completely different things.


You also modified Sean's Documentation/ changes.  A consistent "joint 
SEV-ES+SEV-SNP" is preferred.

Thanks,

Kim
Re: [PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support
Posted by Sean Christopherson 1 month, 1 week ago
On Thu, Aug 21, 2025, Kim Phillips wrote:
> On 8/21/25 5:58 AM, Kalra, Ashish wrote:
> > On 8/21/2025 5:30 AM, Kim Phillips wrote:
> > > On 8/20/25 6:23 PM, Kalra, Ashish wrote:
> > > > On 8/20/2025 5:45 PM, Randy Dunlap wrote:
> > > > > On 8/20/25 1:50 PM, Ashish Kalra wrote:
> > > > > > +        /*
> > > > > > +         * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP
> > > > > > +         * ASID range is partitioned into separate SEV-ES and SEV-SNP
> > > > > > +         * ASID ranges, with the SEV-SNP range being [1..max_snp_asid]
> > > > > > +         * and the SEV-ES range being [max_snp_asid..max_sev_es_asid].
> > > > >                                        [max_snp_asid + 1..max_sev_es_asid]
> > > > > ?
> > > > Yes.
> > > So why wouldn't you have left Sean's original "(max_snp_asid..max_sev_es_asid]" as-is?
> > > 
> > > Kim
> > > 
> > Because that i believe is a typo and the correct SEV-ES range is
> > [max_snp_asid + 1..max_sev_es_asid].
> 
> It's not, though.
> 
> [max_snp_asid..max_sev_es_asid]
> 
> and
> 
> (max_snp_asid..max_sev_es_asid]
> 
> are two completely different things.

Yeah, inclusive versus exclusive (I'm quite proud that I remembered which was
which, _and_ that I got it right :-D).

> You also modified Sean's Documentation/ changes.  A consistent "joint
> SEV-ES+SEV-SNP" is preferred.

FWIW, I don't have a strong preference on the exact verbiage, so long as it's
consistent.
Re: [PATCH v9 2/2] KVM: SEV: Add SEV-SNP CipherTextHiding support
Posted by Kalra, Ashish 1 month, 1 week ago

On 8/21/2025 9:16 AM, Sean Christopherson wrote:
> On Thu, Aug 21, 2025, Kim Phillips wrote:
>> On 8/21/25 5:58 AM, Kalra, Ashish wrote:
>>> On 8/21/2025 5:30 AM, Kim Phillips wrote:
>>>> On 8/20/25 6:23 PM, Kalra, Ashish wrote:
>>>>> On 8/20/2025 5:45 PM, Randy Dunlap wrote:
>>>>>> On 8/20/25 1:50 PM, Ashish Kalra wrote:
>>>>>>> +        /*
>>>>>>> +         * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP
>>>>>>> +         * ASID range is partitioned into separate SEV-ES and SEV-SNP
>>>>>>> +         * ASID ranges, with the SEV-SNP range being [1..max_snp_asid]
>>>>>>> +         * and the SEV-ES range being [max_snp_asid..max_sev_es_asid].
>>>>>>                                        [max_snp_asid + 1..max_sev_es_asid]
>>>>>> ?
>>>>> Yes.
>>>> So why wouldn't you have left Sean's original "(max_snp_asid..max_sev_es_asid]" as-is?
>>>>
>>>> Kim
>>>>
>>> Because that i believe is a typo and the correct SEV-ES range is
>>> [max_snp_asid + 1..max_sev_es_asid].
>>
>> It's not, though.
>>
>> [max_snp_asid..max_sev_es_asid]
>>
>> and
>>
>> (max_snp_asid..max_sev_es_asid]
>>
>> are two completely different things.
> 
> Yeah, inclusive versus exclusive (I'm quite proud that I remembered which was
> which, _and_ that I got it right :-D).
>

Thanks for that explanation.
 
>> You also modified Sean's Documentation/ changes.  A consistent "joint
>> SEV-ES+SEV-SNP" is preferred.
> 
> FWIW, I don't have a strong preference on the exact verbiage, so long as it's
> consistent.

I have consistently modified all "SEV-ES+SEV-SNP" to "SEV-ES and SEV-SNP" inline/Documentation and commit logs.

I will post a revision fixing the comment above (if it is needed, unless this can be fixed during merge).

Thanks,
Ashish