]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: SEV: Disallow pinning more pages than exist in the system
authorSean Christopherson <seanjc@google.com>
Fri, 13 Mar 2026 00:33:00 +0000 (17:33 -0700)
committerSean Christopherson <seanjc@google.com>
Fri, 3 Apr 2026 16:37:25 +0000 (09:37 -0700)
Explicitly disallow pinning more pages for an SEV VM than exist in the
system to defend against absurd userspace requests without relying on
somewhat arbitrary kernel functionality to prevent truly stupid KVM
behavior.  E.g. even with the INT_MAX check, userspace can request that
KVM pin nearly 8TiB of memory, regardless of how much RAM exists in the
system.

Opportunistically rename "locked" to a more descriptive "total_npages".

Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
Tested-by: Liam Merwick <liam.merwick@oracle.com>
Link: https://patch.msgid.link/20260313003302.3136111-4-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/svm/sev.c

index aa4499a235f2e13ef8c4561d9021f30b0ea9a5a4..f37e23496b64d64ab11d18eefb14a701b54c06f6 100644 (file)
@@ -680,7 +680,7 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
        struct kvm_sev_info *sev = to_kvm_sev_info(kvm);
        unsigned long npages, size;
        int npinned;
-       unsigned long locked, lock_limit;
+       unsigned long total_npages, lock_limit;
        struct page **pages;
        unsigned long first, last;
        int ret;
@@ -701,10 +701,14 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
        if (npages > INT_MAX)
                return ERR_PTR(-EINVAL);
 
-       locked = sev->pages_locked + npages;
+       total_npages = sev->pages_locked + npages;
+       if (total_npages > totalram_pages())
+               return ERR_PTR(-EINVAL);
+
        lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-       if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
-               pr_err("SEV: %lu locked pages exceed the lock limit of %lu.\n", locked, lock_limit);
+       if (total_npages > lock_limit && !capable(CAP_IPC_LOCK)) {
+               pr_err("SEV: %lu total pages would exceed the lock limit of %lu.\n",
+                      total_npages, lock_limit);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -727,7 +731,7 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
        }
 
        *n = npages;
-       sev->pages_locked = locked;
+       sev->pages_locked = total_npages;
 
        return pages;