Skip to content

Commit 47894e0

Browse files
pgondasuryasaimadhu
authored andcommitted
virt/sev-guest: Prevent IV reuse in the SNP guest driver
The AMD Secure Processor (ASP) and an SNP guest use a series of AES-GCM keys called VMPCKs to communicate securely with each other. The IV to this scheme is a sequence number that both the ASP and the guest track. Currently, this sequence number in a guest request must exactly match the sequence number tracked by the ASP. This means that if the guest sees an error from the host during a request it can only retry that exact request or disable the VMPCK to prevent an IV reuse. AES-GCM cannot tolerate IV reuse, see: "Authentication Failures in NIST version of GCM" - Antoine Joux et al. In order to address this, make handle_guest_request() delete the VMPCK on any non successful return. To allow userspace querying the cert_data length make handle_guest_request() save the number of pages required by the host, then have handle_guest_request() retry the request without requesting the extended data, then return the number of pages required back to userspace. [ bp: Massage, incorporate Tom's review comments. ] Fixes: fce96cf ("virt: Add SEV-SNP guest driver") Reported-by: Peter Gonda <[email protected]> Signed-off-by: Peter Gonda <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Reviewed-by: Tom Lendacky <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/r/[email protected]
1 parent eb70814 commit 47894e0

File tree

1 file changed

+70
-14
lines changed

1 file changed

+70
-14
lines changed

drivers/virt/coco/sev-guest/sev-guest.c

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,27 @@ static bool is_vmpck_empty(struct snp_guest_dev *snp_dev)
6767
return true;
6868
}
6969

70+
/*
71+
* If an error is received from the host or AMD Secure Processor (ASP) there
72+
* are two options. Either retry the exact same encrypted request or discontinue
73+
* using the VMPCK.
74+
*
75+
* This is because in the current encryption scheme GHCB v2 uses AES-GCM to
76+
* encrypt the requests. The IV for this scheme is the sequence number. GCM
77+
* cannot tolerate IV reuse.
78+
*
79+
* The ASP FW v1.51 only increments the sequence numbers on a successful
80+
* guest<->ASP back and forth and only accepts messages at its exact sequence
81+
* number.
82+
*
83+
* So if the sequence number were to be reused the encryption scheme is
84+
* vulnerable. If the sequence number were incremented for a fresh IV the ASP
85+
* will reject the request.
86+
*/
7087
static void snp_disable_vmpck(struct snp_guest_dev *snp_dev)
7188
{
89+
dev_alert(snp_dev->dev, "Disabling vmpck_id %d to prevent IV reuse.\n",
90+
vmpck_id);
7291
memzero_explicit(snp_dev->vmpck, VMPCK_KEY_LEN);
7392
snp_dev->vmpck = NULL;
7493
}
@@ -321,34 +340,71 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
321340
if (rc)
322341
return rc;
323342

324-
/* Call firmware to process the request */
343+
/*
344+
* Call firmware to process the request. In this function the encrypted
345+
* message enters shared memory with the host. So after this call the
346+
* sequence number must be incremented or the VMPCK must be deleted to
347+
* prevent reuse of the IV.
348+
*/
325349
rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err);
350+
351+
/*
352+
* If the extended guest request fails due to having too small of a
353+
* certificate data buffer, retry the same guest request without the
354+
* extended data request in order to increment the sequence number
355+
* and thus avoid IV reuse.
356+
*/
357+
if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST &&
358+
err == SNP_GUEST_REQ_INVALID_LEN) {
359+
const unsigned int certs_npages = snp_dev->input.data_npages;
360+
361+
exit_code = SVM_VMGEXIT_GUEST_REQUEST;
362+
363+
/*
364+
* If this call to the firmware succeeds, the sequence number can
365+
* be incremented allowing for continued use of the VMPCK. If
366+
* there is an error reflected in the return value, this value
367+
* is checked further down and the result will be the deletion
368+
* of the VMPCK and the error code being propagated back to the
369+
* user as an ioctl() return code.
370+
*/
371+
rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err);
372+
373+
/*
374+
* Override the error to inform callers the given extended
375+
* request buffer size was too small and give the caller the
376+
* required buffer size.
377+
*/
378+
err = SNP_GUEST_REQ_INVALID_LEN;
379+
snp_dev->input.data_npages = certs_npages;
380+
}
381+
326382
if (fw_err)
327383
*fw_err = err;
328384

329-
if (rc)
330-
return rc;
385+
if (rc) {
386+
dev_alert(snp_dev->dev,
387+
"Detected error from ASP request. rc: %d, fw_err: %llu\n",
388+
rc, *fw_err);
389+
goto disable_vmpck;
390+
}
331391

332-
/*
333-
* The verify_and_dec_payload() will fail only if the hypervisor is
334-
* actively modifying the message header or corrupting the encrypted payload.
335-
* This hints that hypervisor is acting in a bad faith. Disable the VMPCK so that
336-
* the key cannot be used for any communication. The key is disabled to ensure
337-
* that AES-GCM does not use the same IV while encrypting the request payload.
338-
*/
339392
rc = verify_and_dec_payload(snp_dev, resp_buf, resp_sz);
340393
if (rc) {
341394
dev_alert(snp_dev->dev,
342-
"Detected unexpected decode failure, disabling the vmpck_id %d\n",
343-
vmpck_id);
344-
snp_disable_vmpck(snp_dev);
345-
return rc;
395+
"Detected unexpected decode failure from ASP. rc: %d\n",
396+
rc);
397+
goto disable_vmpck;
346398
}
347399

348400
/* Increment to new message sequence after payload decryption was successful. */
349401
snp_inc_msg_seqno(snp_dev);
350402

351403
return 0;
404+
405+
disable_vmpck:
406+
snp_disable_vmpck(snp_dev);
407+
return rc;
352408
}
353409

354410
static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)

0 commit comments

Comments
 (0)