Commit 970ab823 authored by Borislav Petkov (AMD)'s avatar Borislav Petkov (AMD)
Browse files

virt/coco/sev-guest: Simplify extended guest request handling



Return a specific error code - -ENOSPC - to signal the too small cert
data buffer instead of checking exit code and exitinfo2.

While at it, hoist the *fw_err assignment in snp_issue_guest_request()
so that a proper error value is returned to the callers.

  [ Tom: check override_err instead of err. ]

Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20230307192449.24732-4-bp@alien8.de
parent d6fd48ef
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -2209,16 +2209,17 @@ int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned
	if (ret)
		goto e_put;

	*fw_err = ghcb->save.sw_exit_info_2;
	if (ghcb->save.sw_exit_info_2) {
		/* Number of expected pages are returned in RBX */
		if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST &&
		    ghcb->save.sw_exit_info_2 == SNP_GUEST_REQ_INVALID_LEN)
		    ghcb->save.sw_exit_info_2 == SNP_GUEST_REQ_INVALID_LEN) {
			input->data_npages = ghcb_get_rbx(ghcb);

		*fw_err = ghcb->save.sw_exit_info_2;

			ret = -ENOSPC;
		} else {
			ret = -EIO;
		}
	}

e_put:
	__sev_put_ghcb(&state);
+26 −22
Original line number Diff line number Diff line
@@ -322,7 +322,8 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
				u8 type, void *req_buf, size_t req_sz, void *resp_buf,
				u32 resp_sz, __u64 *fw_err)
{
	unsigned long err;
	unsigned long err, override_err = 0;
	unsigned int override_npages = 0;
	u64 seqno;
	int rc;

@@ -338,6 +339,7 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
	if (rc)
		return rc;

retry_request:
	/*
	 * Call firmware to process the request. In this function the encrypted
	 * message enters shared memory with the host. So after this call the
@@ -346,18 +348,25 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
	 */
	rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err);

	switch (rc) {
	case -ENOSPC:
		/*
	 * If the extended guest request fails due to having too small of a
	 * certificate data buffer, retry the same guest request without the
	 * extended data request in order to increment the sequence number
	 * and thus avoid IV reuse.
		 * If the extended guest request fails due to having too
		 * small of a certificate data buffer, retry the same
		 * guest request without the extended data request in
		 * order to increment the sequence number and thus avoid
		 * IV reuse.
		 */
	if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST &&
	    err == SNP_GUEST_REQ_INVALID_LEN) {
		const unsigned int certs_npages = snp_dev->input.data_npages;

		override_npages = snp_dev->input.data_npages;
		exit_code	= SVM_VMGEXIT_GUEST_REQUEST;

		/*
		 * Override the error to inform callers the given extended
		 * request buffer size was too small and give the caller the
		 * required buffer size.
		 */
		override_err	= SNP_GUEST_REQ_INVALID_LEN;

		/*
		 * If this call to the firmware succeeds, the sequence number can
		 * be incremented allowing for continued use of the VMPCK. If
@@ -366,15 +375,7 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
		 * of the VMPCK and the error code being propagated back to the
		 * user as an ioctl() return code.
		 */
		rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err);

		/*
		 * Override the error to inform callers the given extended
		 * request buffer size was too small and give the caller the
		 * required buffer size.
		 */
		err = SNP_GUEST_REQ_INVALID_LEN;
		snp_dev->input.data_npages = certs_npages;
		goto retry_request;
	}

	/*
@@ -386,7 +387,10 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
	snp_inc_msg_seqno(snp_dev);

	if (fw_err)
		*fw_err = err;
		*fw_err = override_err ?: err;

	if (override_npages)
		snp_dev->input.data_npages = override_npages;

	/*
	 * If an extended guest request was issued and the supplied certificate
@@ -394,7 +398,7 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
	 * prevent IV reuse. If the standard request was successful, return -EIO
	 * back to the caller as would have originally been returned.
	 */
	if (!rc && err == SNP_GUEST_REQ_INVALID_LEN)
	if (!rc && override_err == SNP_GUEST_REQ_INVALID_LEN)
		return -EIO;

	if (rc) {