KVM: PPC: Book3S PR: Check copy_to/from_user return values
authorPaul Mackerras <paulus@ozlabs.org>
Thu, 11 May 2017 01:33:30 +0000 (11:33 +1000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Apr 2018 17:47:55 +0000 (19:47 +0200)
[ Upstream commit 67325e988faea735d663799b6d152b5f4254093c ]

The PR KVM implementation of the PAPR HPT hypercalls (H_ENTER etc.)
access an image of the HPT in userspace memory using copy_from_user
and copy_to_user.  Recently, the declarations of those functions were
annotated to indicate that the return value must be checked.  Since
this code doesn't currently check the return value, this causes
compile warnings like the ones shown below, and since on PPC the
default is to compile arch/powerpc with -Werror, this causes the
build to fail.

To fix this, we check the return values, and if non-zero, fail the
hypercall being processed with a H_FUNCTION error return value.
There is really no good error return value to use since PAPR didn't
envisage the possibility that the hypervisor may not be able to access
the guest's HPT, and H_FUNCTION (function not supported) seems as
good as any.

The typical compile warnings look like this:

  CC      arch/powerpc/kvm/book3s_pr_papr.o
/home/paulus/kernel/kvm/arch/powerpc/kvm/book3s_pr_papr.c: In function ‘kvmppc_h_pr_enter’:
/home/paulus/kernel/kvm/arch/powerpc/kvm/book3s_pr_papr.c:53:2: error: ignoring return value of ‘copy_from_user’, declared with attribute warn_unused_result [-Werror=unused-result]
  copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
  ^
/home/paulus/kernel/kvm/arch/powerpc/kvm/book3s_pr_papr.c:74:2: error: ignoring return value of ‘copy_to_user’, declared with attribute warn_unused_result [-Werror=unused-result]
  copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE);
  ^

... etc.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/powerpc/kvm/book3s_pr_papr.c

index 02176fd52f84b85187f8a57a5e434bd56299a151..286a3b051ff6e261c2e40b3cea196724cdc959ed 100644 (file)
@@ -50,7 +50,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
        pteg_addr = get_pteg_addr(vcpu, pte_index);
 
        mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-       copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
+       ret = H_FUNCTION;
+       if (copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)))
+               goto done;
        hpte = pteg;
 
        ret = H_PTEG_FULL;
@@ -71,7 +73,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
        hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6));
        hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7));
        pteg_addr += i * HPTE_SIZE;
-       copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE);
+       ret = H_FUNCTION;
+       if (copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE))
+               goto done;
        kvmppc_set_gpr(vcpu, 4, pte_index | i);
        ret = H_SUCCESS;
 
@@ -93,7 +97,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu)
 
        pteg = get_pteg_addr(vcpu, pte_index);
        mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-       copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+       ret = H_FUNCTION;
+       if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
+               goto done;
        pte[0] = be64_to_cpu((__force __be64)pte[0]);
        pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -103,7 +109,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu)
            ((flags & H_ANDCOND) && (pte[0] & avpn) != 0))
                goto done;
 
-       copy_to_user((void __user *)pteg, &v, sizeof(v));
+       ret = H_FUNCTION;
+       if (copy_to_user((void __user *)pteg, &v, sizeof(v)))
+               goto done;
 
        rb = compute_tlbie_rb(pte[0], pte[1], pte_index);
        vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
@@ -171,7 +179,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu)
                }
 
                pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
-               copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+               if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) {
+                       ret = H_FUNCTION;
+                       break;
+               }
                pte[0] = be64_to_cpu((__force __be64)pte[0]);
                pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -184,7 +195,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu)
                        tsh |= H_BULK_REMOVE_NOT_FOUND;
                } else {
                        /* Splat the pteg in (userland) hpt */
-                       copy_to_user((void __user *)pteg, &v, sizeof(v));
+                       if (copy_to_user((void __user *)pteg, &v, sizeof(v))) {
+                               ret = H_FUNCTION;
+                               break;
+                       }
 
                        rb = compute_tlbie_rb(pte[0], pte[1],
                                              tsh & H_BULK_REMOVE_PTEX);
@@ -211,7 +225,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
 
        pteg = get_pteg_addr(vcpu, pte_index);
        mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-       copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+       ret = H_FUNCTION;
+       if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
+               goto done;
        pte[0] = be64_to_cpu((__force __be64)pte[0]);
        pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -234,7 +250,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
        vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
        pte[0] = (__force u64)cpu_to_be64(pte[0]);
        pte[1] = (__force u64)cpu_to_be64(pte[1]);
-       copy_to_user((void __user *)pteg, pte, sizeof(pte));
+       ret = H_FUNCTION;
+       if (copy_to_user((void __user *)pteg, pte, sizeof(pte)))
+               goto done;
        ret = H_SUCCESS;
 
  done: