virt/coco/sev-guest: Simplify extended guest request handling
authorBorislav Petkov (AMD) <bp@alien8.de>
Wed, 15 Feb 2023 10:39:41 +0000 (11:39 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Mar 2023 12:34:05 +0000 (13:34 +0100)
commit 970ab823743fb54b42002ec76c51481f67436444 upstream.

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: Borislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20230307192449.24732-4-bp@alien8.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kernel/sev.c
drivers/virt/coco/sev-guest/sev-guest.c

index 2e739b0..5dc9c53 100644 (file)
@@ -2209,15 +2209,16 @@ 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 = -EIO;
+                       ret = -ENOSPC;
+               } else {
+                       ret = -EIO;
+               }
        }
 
 e_put:
index 57089c0..2fac7f7 100644 (file)
@@ -324,7 +324,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;
 
@@ -340,6 +341,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
@@ -348,17 +350,24 @@ 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);
 
-       /*
-        * 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;
+       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.
+                */
+               override_npages = snp_dev->input.data_npages;
+               exit_code       = SVM_VMGEXIT_GUEST_REQUEST;
 
-               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
@@ -368,15 +377,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;
        }
 
        /*
@@ -388,7 +389,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
@@ -396,7 +400,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) {