]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: SEV: Drop WARN on large size for KVM_MEMORY_ENCRYPT_REG_REGION
authorSean Christopherson <seanjc@google.com>
Fri, 13 Mar 2026 00:32:58 +0000 (17:32 -0700)
committerSean Christopherson <seanjc@google.com>
Fri, 3 Apr 2026 16:37:25 +0000 (09:37 -0700)
Drop the WARN in sev_pin_memory() on npages overflowing an int, as the
WARN is comically trivially to trigger from userspace, e.g. by doing:

  struct kvm_enc_region range = {
          .addr = 0,
          .size = -1ul,
  };

  __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_REG_REGION, &range);

Note, the checks in sev_mem_enc_register_region() that presumably exist to
verify the incoming address+size are completely worthless, as both "addr"
and "size" are u64s and SEV is 64-bit only, i.e. they _can't_ be greater
than ULONG_MAX.  That wart will be cleaned up in the near future.

if (range->addr > ULONG_MAX || range->size > ULONG_MAX)
return -EINVAL;

Opportunistically add a comment to explain why the code calculates the
number of pages the "hard" way, e.g. instead of just shifting @ulen.

Fixes: 78824fabc72e ("KVM: SVM: fix svn_pin_memory()'s use of get_user_pages_fast()")
Cc: stable@vger.kernel.org
Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
Tested-by: Liam Merwick <liam.merwick@oracle.com>
Link: https://patch.msgid.link/20260313003302.3136111-2-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/svm/sev.c

index 77ebc166abfd138adb6e34d39e6c882752a691c1..2c216726718d9a8a17d1085f3766919ea191a597 100644 (file)
@@ -690,10 +690,16 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
        if (ulen == 0 || uaddr + ulen < uaddr)
                return ERR_PTR(-EINVAL);
 
-       /* Calculate number of pages. */
+       /*
+        * Calculate the number of pages that need to be pinned to cover the
+        * entire range.  Note!  This isn't simply ulen >> PAGE_SHIFT, as KVM
+        * doesn't require the incoming address+size to be page aligned!
+        */
        first = (uaddr & PAGE_MASK) >> PAGE_SHIFT;
        last = ((uaddr + ulen - 1) & PAGE_MASK) >> PAGE_SHIFT;
        npages = (last - first + 1);
+       if (npages > INT_MAX)
+               return ERR_PTR(-EINVAL);
 
        locked = sev->pages_locked + npages;
        lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
@@ -702,9 +708,6 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
                return ERR_PTR(-ENOMEM);
        }
 
-       if (WARN_ON_ONCE(npages > INT_MAX))
-               return ERR_PTR(-EINVAL);
-
        /* Avoid using vmalloc for smaller buffers. */
        size = npages * sizeof(struct page *);
        if (size > PAGE_SIZE)