From nobody Sun Jun 14 07:35:51 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 77FE5421F17 for ; Fri, 1 May 2026 20:35:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667744; cv=none; b=UQjRVLVX4ifYx6I8g+0NvYA+tNyMbIBpJn3d78p9yk7ZxtpL6FpFJNRrU/vvox/h9TsbsiFQt01XXc6AcnVkft9a3DJRenUJrabvdgOBsdhUmLA1ttGERcG7KxywASgosUbCtAPk/wI1m9b9gewdUTbaFo3orUgPZFtSpvjpxhs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667744; c=relaxed/simple; bh=SAroxcNKrFSAqe7ITVNTDHFdcLEWgqlAkm56XUN81KE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=bOSmFqHYGvQhfQrUYPTwrQaaLk32DHDOIdHsh9AyGwHnpyUFkjLXNWe+fP/XJ8FNJ0C6pdJ7xhm5sExkxvKNz5V/eamDUSpx1fHURB5xzPLJkpd1IMjqgqLnQPyQqbO9PSo7CvNbOpxztEmNgTef872HARLFq2ni2JZpP+kEINQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=onpZAtcL; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="onpZAtcL" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-35da97f6a6dso2877498a91.0 for ; Fri, 01 May 2026 13:35:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1777667743; x=1778272543; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=pYJswTuz+l+2YoiILOIj0xmNxa9rLIxr+BM7pEgolkw=; b=onpZAtcL8IHQbFnSemTLo3ZcEe84BtOrqVKt8V9WYoBDcZ2ixuYdsh4b4iuaog0MdA wazu4OEAQ63iLa1fOVi4ol3jFufnigWPcSGgOmeVW2/VO6NZ8+BIZNA0cvyktv/jVDf3 TFtrvEn7I5L5KYWIN/Y8hqWlU2KFELJy7CqDb/eWVh5Pz64cMHe1+oRKZ+7doylAbTiA 5i6K7RXFKm7iB2BoQtftiSuBRvJPeZ08p+Hw5bCVCp+esXafhZDZ2UgpRv7fid1QT9yK wRyzf/MsYQdDF+P6zcWhQooeO2yUD74u1VzlLw6r4D5HVBgVa/evfMguaYyaC4+c/EVL /AEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777667743; x=1778272543; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=pYJswTuz+l+2YoiILOIj0xmNxa9rLIxr+BM7pEgolkw=; b=p7dv3A5sIN6OoRemo/2aFg5gMQCu3kqtjVA462GsdAw2bOOeNq3ROYRx00Ad/3SFTz 9j5/UZAFD4xNk/boTW6/fqMmIEbAxnNgTq7HFEA6anDqLkJF4mCJKx8ZSsrTQsx+rRuT CHIBpm1jUKeJcb+SI7qg1LMQIiIpXr/YaATa9w5j/Wp4+FtF1DUQLStag0KC9sq+5+NJ +gt6/YzltjxrfladvHeT1XcmFXLEAzbVyIgBNxAt6TJbD/a8IglheugJbjlOAPC+kE1p 6buC8TtOM6UXkL2Byp8mBy1EqYtQgvPv/I2apI6uB9MiE5+dXlFq9N6sOfaMASu9fuVY cN4w== X-Forwarded-Encrypted: i=1; AFNElJ/yOAVgOugB8CPmL20o7js5ZVhGjPHUbZiZBAJkJsAeDqx0HK/1k7njDp4sxXDrPYPx4DXUoos41rSuIqM=@vger.kernel.org X-Gm-Message-State: AOJu0YyppEpdP73nnu6Hywtz3WeTUX/eyl1hdrbq/wux7PiswHjvLckt BI7z50byMtPjQOm/y3H/0Fs20oCVbob+5d2cErx9yZrff+zFWbBvVuCqYAOjDMlPzS9iYym1dsa l1mVTrA== X-Received: from pjbdw12.prod.google.com ([2002:a17:90b:94c:b0:35f:b193:747d]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90a:e18c:b0:35d:a4c0:a0ac with SMTP id 98e67ed59e1d1-3650ccefc6cmr735595a91.3.1777667742797; Fri, 01 May 2026 13:35:42 -0700 (PDT) Reply-To: Sean Christopherson Date: Fri, 1 May 2026 13:35:32 -0700 In-Reply-To: <20260501203537.2120074-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260501203537.2120074-1-seanjc@google.com> X-Mailer: git-send-email 2.54.0.545.g6539524ca2-goog Message-ID: <20260501203537.2120074-2-seanjc@google.com> Subject: [PATCH v2 1/6] KVM: SVM: Fix page overflow in sev_dbg_crypt() for ENCRYPT path From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Ashutosh Desai Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ashutosh Desai In sev_dbg_crypt(), the per-iteration transfer length is bounded by the source page offset (PAGE_SIZE - s_off) but not by the destination page offset (PAGE_SIZE - d_off). When d_off > s_off, the encrypt path (__sev_dbg_encrypt_user) performs a read-modify-write using a single-page intermediate buffer (dst_tpage): 1. __sev_dbg_decrypt() expands the size to round_up(len + (d_off & 15), 1= 6) before issuing the PSP command. If len + (d_off & 15) > PAGE_SIZE, the PSP writes beyond the end of the 4096-byte dst_tpage allocation. 2. The subsequent memcpy()/copy_from_user() into page_address(dst_tpage) + (d_off & 15) of 'len' bytes overflows by up to 15 bytes under the same condition. Trigger example: s_off =3D 0, d_off =3D 1, debug.len =3D PAGE_SIZE - the PSP is instructed to write round_up(4097, 16) =3D 4112 bytes to a 4096-byte buffer. Fix by also bounding len by (PAGE_SIZE - d_off), the same check that sev_send_update_data() already performs for its single-page guest region. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D BUG: KASAN: slab-use-after-free in sev_dbg_crypt+0x993/0xd10 [kvm_amd] Write of size 4095 at addr ff110062293bb009 by task sev_dbg_test/228214 CPU: 96 UID: 0 PID: 228214 Comm: sev_dbg_test Tainted: G U W = 7.0.0-smp--5ce9b0c48211-dbg #156 PREEMPTLAZY Tainted: [U]=3DUSER, [W]=3DWARN Hardware name: Google Astoria/astoria, BIOS 0.20250817.1-0 08/25/2025 Call Trace: dump_stack_lvl+0x54/0x70 print_report+0xbc/0x260 kasan_report+0xa2/0xd0 kasan_check_range+0x25f/0x2c0 __asan_memcpy+0x40/0x70 sev_dbg_crypt+0x993/0xd10 [kvm_amd] sev_mem_enc_ioctl+0x33c/0x450 [kvm_amd] kvm_vm_ioctl+0x65d/0x6d0 [kvm] __se_sys_ioctl+0xb2/0x100 do_syscall_64+0xe8/0x870 entry_SYSCALL_64_after_hwframe+0x4b/0x53 The buggy address belongs to the physical page: page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x7fe72b6a0 pfn= :0x62293bb memcg:ff11000112827d82 flags: 0x1400000000000000(node=3D1|zone=3D1) raw: 1400000000000000 0000000000000000 dead000000000122 0000000000000000 raw: 00000007fe72b6a0 0000000000000000 00000001ffffffff ff11000112827d82 page dumped because: kasan: bad access detected Memory state around the buggy address: ff110062293bbf00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff110062293bbf80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ff110062293bc000: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ ff110062293bc080: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ff110062293bc100: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Disabling lock debugging due to kernel taint Fixes: 24f41fb23a39 ("KVM: SVM: Add support for SEV DEBUG_DECRYPT command") Fixes: 7d1594f5d94b ("KVM: SVM: Add support for SEV DEBUG_ENCRYPT command") Cc: stable@vger.kernel.org Signed-off-by: Ashutosh Desai [sean: add sample KASAN splat, Fixes, and stable@] Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index c2126b3c3072..b9d7bd868e0b 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1396,6 +1396,7 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm_= sev_cmd *argp, bool dec) s_off =3D vaddr & ~PAGE_MASK; d_off =3D dst_vaddr & ~PAGE_MASK; len =3D min_t(size_t, (PAGE_SIZE - s_off), size); + len =3D min_t(size_t, len, PAGE_SIZE - d_off); =20 if (dec) ret =3D __sev_dbg_decrypt_user(kvm, --=20 2.54.0.545.g6539524ca2-goog From nobody Sun Jun 14 07:35:51 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B1A4242314E for ; Fri, 1 May 2026 20:35:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667747; cv=none; b=U9zubmuuvXd+HzhHIKo/Z1eJpplGgTePSMgOSLm+pmndT0/Nwd2MVGMYr3VF7SJXkCxNvjHw/6vAbJxm6zQLdqNsWJTt5hCbZ5h9TbodfH6MhOyvXjtFIeMAhoxtt02JoEMNUOtY//CSKncLk8sW6Q/Y1gLLgXj6p2iBc8j8H5o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667747; c=relaxed/simple; bh=T8keK2iQ6iTkPs8KyUsMfRfqAPB/cM9X954693/oHy8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=bNN0WHpQS19A08vjQK1FmWACHmppTwiEgMZC9dt1lmzzeaRCoAkGjg+IGpxmjbED5hqXyvDv+Vx8hMJSqruJ+RWUWLU5yY3bsdCQleLE1Of64DCQMAbjnIeg08ew6E1dnxXyZEkqYFqaPnzUB937q45bmVAklIzpI6yfzWHXeXI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=tuRSEtTW; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="tuRSEtTW" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-35fbb5779e8so2615089a91.3 for ; Fri, 01 May 2026 13:35:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1777667745; x=1778272545; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=Fixb+34puzyJhKjzcaNI0NuMW7dHJYkjk7ReqMjzN1Y=; b=tuRSEtTWeqaYMl3t498MMCdf4CJNiHtYWm8E1Rbco20T98FcRPal46mC6mpr6DXztJ hPpWWBE6EEeoKWRqOhPHXiSktcUiJV1ldn3zf0ZrelvNVSYvfHqBAoohi88W7n/okGZ6 SbCFlE5vnJx9bKsYq89cXRRVjSeDJJPD/+mD9MHgRNsn9yxB1ku3NC/4KgWGXs2ypCzr TH/RDrX0aS1svGwbYqn+K+TqR4ce+duXGv632PkF8pLzkxAVBb+1dxagcIXez9cGX3Vx GAofFqWngeUGZnbc8v4j+dQY7fUe9WwnQWgE7uoa7zl/7uRUep1yZQ1HL7Th6mpfeTDv //mA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777667745; x=1778272545; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=Fixb+34puzyJhKjzcaNI0NuMW7dHJYkjk7ReqMjzN1Y=; b=V/hf4DaKKsiqllpE/YCpz3N0ByV/fydQVShCEXmOCFqWQJTP1QsA9I1XUWMwWXs0L2 EseoEpB2QfOdrvm9P0D0JldeuvMfZknC1eHYU6RVb+L56y8D79OgDtPR46KQsCHSMlle /55CbfYVwewllm0r75gOOvg41Au2fe1JNBjF8Yg8v4hRi30O3OvTIhnF9FeoyES5EA65 NuksRDeXg1k/dcQq6nb5+aRw+TZNwLhTBzZTxfQD5n3Iw7yghRO+4xy7kKYyH+6/Gvvx 1v2gfAGgZ+USUA70oNrRSunmvJtcSC/Wld74dIujC398DYolreHaxevfTHs/WAAoc2su z16w== X-Forwarded-Encrypted: i=1; AFNElJ/LT50eiWj/XtP0dXX63bJ709YXeoV3R/6/bqB+qkCDDCxy0FvJ7BbIAhKPjdZxh2S5OBw+eJqnjV9klNA=@vger.kernel.org X-Gm-Message-State: AOJu0Yyo8mbuovYsJTF3adc8El4UT4wCOjSv7KWRAato4cLqWy5dfX7C rZcd4/U3lISzSPlExe8YbvUSa3RD5rdv2rTfTysnOlzQx+OY1T2/2Dal4vkfDa3I/MEUii4aNJz rNzLifA== X-Received: from pjbbt14.prod.google.com ([2002:a17:90a:f00e:b0:35c:20f3:4ec]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:510b:b0:35f:b46e:e329 with SMTP id 98e67ed59e1d1-3650cd08149mr770187a91.6.1777667744898; Fri, 01 May 2026 13:35:44 -0700 (PDT) Reply-To: Sean Christopherson Date: Fri, 1 May 2026 13:35:33 -0700 In-Reply-To: <20260501203537.2120074-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260501203537.2120074-1-seanjc@google.com> X-Mailer: git-send-email 2.54.0.545.g6539524ca2-goog Message-ID: <20260501203537.2120074-3-seanjc@google.com> Subject: [PATCH v2 2/6] KVM: selftests: Add a test to verify SEV {en,de}crypt debug ioctls From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Ashutosh Desai Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a selftest to verify KVM's handling of {de,en}crypt debug ioctls, specifically focusing on edge cases around the chunk (16 bytes) and page (4096) sizes, where KVM had multiple bugs. E.g. KVM would fail to handle small sizes that aren't naturally aligned and sized, would buffer overflow if the destination was unaligned but the source was not, etc. Attempt to strike a balance between an exhaustive test and a reasonable runtime. On a system with both SEV and SEV-ES support, the current runtime is under 45 seconds. Which isn't great, but it's tolerable, and it's not obvious which of the combinations are "better" than the others. Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile.kvm | 1 + tools/testing/selftests/kvm/include/x86/sev.h | 24 ++++ .../testing/selftests/kvm/x86/sev_dbg_test.c | 118 ++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/sev_dbg_test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 9118a5a51b89..82fa943b9503 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -140,6 +140,7 @@ TEST_GEN_PROGS_x86 +=3D x86/tsc_msrs_test TEST_GEN_PROGS_x86 +=3D x86/vmx_pmu_caps_test TEST_GEN_PROGS_x86 +=3D x86/xen_shinfo_test TEST_GEN_PROGS_x86 +=3D x86/xen_vmcall_test +TEST_GEN_PROGS_x86 +=3D x86/sev_dbg_test TEST_GEN_PROGS_x86 +=3D x86/sev_init2_tests TEST_GEN_PROGS_x86 +=3D x86/sev_migrate_tests TEST_GEN_PROGS_x86 +=3D x86/sev_smoke_test diff --git a/tools/testing/selftests/kvm/include/x86/sev.h b/tools/testing/= selftests/kvm/include/x86/sev.h index 1af44c151d60..dec383e59a47 100644 --- a/tools/testing/selftests/kvm/include/x86/sev.h +++ b/tools/testing/selftests/kvm/include/x86/sev.h @@ -144,4 +144,28 @@ static inline void snp_launch_update_data(struct kvm_v= m *vm, gpa_t gpa, vm_sev_ioctl(vm, KVM_SEV_SNP_LAUNCH_UPDATE, &update_data); } =20 +static inline void sev_dbg_crypt_memory(struct kvm_vm *vm, unsigned int cm= d, + void *dst, void *src, unsigned int len) +{ + struct kvm_sev_dbg dbg =3D { + .src_uaddr =3D (unsigned long)src, + .dst_uaddr =3D (unsigned long)dst, + .len =3D len, + }; + + vm_sev_ioctl(vm, cmd, &dbg); +} + +static inline void sev_decrypt_memory(struct kvm_vm *vm, void *dst, void *= src, + unsigned int len) +{ + sev_dbg_crypt_memory(vm, KVM_SEV_DBG_DECRYPT, dst, src, len); +} + +static inline void sev_encrypt_memory(struct kvm_vm *vm, void *dst, void *= src, + unsigned int len) +{ + sev_dbg_crypt_memory(vm, KVM_SEV_DBG_ENCRYPT, dst, src, len); +} + #endif /* SELFTEST_KVM_SEV_H */ diff --git a/tools/testing/selftests/kvm/x86/sev_dbg_test.c b/tools/testing= /selftests/kvm/x86/sev_dbg_test.c new file mode 100644 index 000000000000..55530cc2be05 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/sev_dbg_test.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "sev.h" + +#define BUFFER_SIZE (PAGE_SIZE * 2) + +static u8 *data; +static u8 src[BUFFER_SIZE] __aligned(PAGE_SIZE); +static u8 dst[BUFFER_SIZE] __aligned(PAGE_SIZE); + +static void validate_dst(int i, int nr_bytes, u8 pattern) +{ + for ( ; i < nr_bytes; i++) + TEST_ASSERT(dst[i] =3D=3D pattern, + "Expected 0x%x at byte %u, got 0x%x", + pattern, i, dst[i]); +} + +static void validate_buffers(void) +{ + int i; + + for (i =3D 0; i < BUFFER_SIZE; i++) + TEST_ASSERT(src[i] =3D=3D dst[i], + "Expected src[%u] (0x%x) =3D=3D dst[%u] (0x%x)", + i, src[i], i, dst[i]); +} + +static void ____test_sev_dbg(struct kvm_vm *vm, int i, int j, int nr_bytes) +{ + u8 pattern =3D guest_random_u32(&guest_rng); + + if (i + nr_bytes > BUFFER_SIZE || j + nr_bytes > BUFFER_SIZE) + return; + + memset(&src[i], pattern, nr_bytes); + sev_encrypt_memory(vm, &data[j], &src[i], nr_bytes); + sev_decrypt_memory(vm, &dst[i], &data[j], nr_bytes); + validate_buffers(); + validate_dst(i, nr_bytes, pattern); +} + +static void __test_sev_dbg(struct kvm_vm *vm, int nr_bytes) +{ + /* + * In a perfect world, all sizes at all combinations within the buffers + * would be tested. In reality, even this much testing is quite slow. + * Target sizes and offsets around the chunk (16 bytes) and page (4096 + * bytes) sizes. + */ + int x[] =3D { 1, 8, 15, 16, 23 }; + int p =3D PAGE_SIZE - 24; + int i, j; + + ____test_sev_dbg(vm, 0, 0, nr_bytes); + + for (i =3D 0; i < ARRAY_SIZE(x); i++) { + for (j =3D 0; j < ARRAY_SIZE(x); j++) { + ____test_sev_dbg(vm, x[i], x[j], nr_bytes); + ____test_sev_dbg(vm, x[i], p + x[j], nr_bytes); + ____test_sev_dbg(vm, p + x[i], x[j], nr_bytes); + ____test_sev_dbg(vm, p + x[i], p + x[j], nr_bytes); + } + } +} + +static void test_sev_dbg(uint32_t type, uint64_t policy) +{ + int sizes[] =3D { 1, 8, 15, 16, 17, 32, 33 }; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int i; + + if (!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(type))) + return; + + vm =3D vm_sev_create_with_one_vcpu(type, NULL, &vcpu); + + data =3D addr_gva2hva(vm, vm_vaddr_alloc(vm, BUFFER_SIZE, KVM_UTIL_MIN_VA= DDR)); + memset(data, 0xaa, BUFFER_SIZE); + + vm_sev_launch(vm, policy, NULL); + + sev_decrypt_memory(vm, dst, data, BUFFER_SIZE); + validate_dst(0, BUFFER_SIZE, 0xaa); + + memset(src, 0x55, BUFFER_SIZE); + sev_encrypt_memory(vm, data, src, BUFFER_SIZE); + sev_decrypt_memory(vm, dst, data, BUFFER_SIZE); + validate_dst(0, BUFFER_SIZE, 0x55); + + __test_sev_dbg(vm, PAGE_SIZE); + + for (i =3D 0; i < ARRAY_SIZE(sizes); i++) { + __test_sev_dbg(vm, sizes[i]); + __test_sev_dbg(vm, PAGE_SIZE - sizes[i]); + __test_sev_dbg(vm, PAGE_SIZE + sizes[i]); + __test_sev_dbg(vm, BUFFER_SIZE - sizes[i]); + } + + kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV)); + + /* Note, KVM doesn't support {de,en}crypt commands for SNP. */ + test_sev_dbg(KVM_X86_SEV_VM, 0); + test_sev_dbg(KVM_X86_SEV_ES_VM, SEV_POLICY_ES); + return 0; +} --=20 2.54.0.545.g6539524ca2-goog From nobody Sun Jun 14 07:35:51 2026 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A18C7421F01 for ; Fri, 1 May 2026 20:35:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667750; cv=none; b=Tf1Cm8lYMaNxSUz96AHYpEbe2qnm17iIv07RKnsaRBQe+bFbDeIoQvLv2fCRwK4YYFjC2pu/TtUEIOvufhnNogykIFRiJWkk2kZXSMvykijlGVz45xw2sIh0T7uasJd0qJ/TkYRQO8xtrhkJe2k+E+eFeqSzVdvZG3unVcY+5Sc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667750; c=relaxed/simple; bh=02VpepIxKDwd6JSFwiFOibCa1QXJfBVYk/8UJWozIXo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=f2fbzW8pkEwd4X9bN6X68x/GvHhcUW1dpMnfL9UY0UUSnWrrMKeL+tCGXB9EP1o6XeFqRu5vJ6tOb1LvbWXy2C0PieTalZr8AvyPqbqmbNc5UCv51p64tX0Olf+YRdJIW4wmFslsmCQVa1k/Kb844YWhNuCpq+4CSdIhB5PzOAU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=aFifwHHm; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="aFifwHHm" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-8230d6d54a5so2188380b3a.1 for ; Fri, 01 May 2026 13:35:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1777667747; x=1778272547; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=BinFFV1dkoZUzfCSB4lA7tacHEnMisx6I/yLVxf53IU=; b=aFifwHHm3sJPJjoX5loWOyYF9BK6WBbfvEmQQJI5uSQLLGi/vn+YCXbtZml4z6VRDA w6Vqm7CZU4OKmt0t7JFpAIz3yllVFizpDvuh+yOqIiWKsazYzWuzOU3aScux6eb+/7id nxU6g7Odgi48IKhCZKuiq7519hsWSend8Q6PONbtSxI1kxiupCfy1s/EYbPOW4LhjA7X 27JOFrzOEEj4cyFLucNTxQydr98e5St1RvQMG0heCC1HG4YaLuQDghhUErrvFZ2oS+B3 10LqhCdUck/Xnx2j2hLDeg+N0f6yCF3bBUkh74oRN0XSrKd9eZg9QJY1dqk4kp5zQlXh W5rA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777667747; x=1778272547; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=BinFFV1dkoZUzfCSB4lA7tacHEnMisx6I/yLVxf53IU=; b=YZp07ke1BzDZVVtCghvuogAjjrGAydlcmtm1BJOu9xrF0JS6z+Qx6Ma/APvcxqeavE 5hRrqHR9DWJA38ZJah4M4b8TyOpTuW3AThJ6SQ7Ij7FDJCfWCeWwd/AiqQ6mVsEPyFkW +NT4p8a59woIV7154lvsJmiIBnILjMvz21tpCWBgV+NrbxCAsK6XaXzBw5J2bpEtrQDQ icvI5FunPue+BEktiSAYQZlzISK0chrzB1ug1en9elvSy/lzyINsgOoigcO0sb5SgYXh /w+CAa0WvkFFJdkzCtGsdVn8RDHX1Dju5UL+Ht0L90SLsS6Q0idanpgcAAxoq9Wuq3ID 3VCA== X-Forwarded-Encrypted: i=1; AFNElJ9aEvl1RxVB55rTKvfpof0moy7XTLlCqjYFfE7OxPVP1fdPe62PqANOrjukKzVT/a/UThfol9DYojCoaT8=@vger.kernel.org X-Gm-Message-State: AOJu0YwY25HCvROmHkaWkta1nevqA7Dx/et4pHxXYID/DspvSi0OC7jg g7mzUmQdMdiSwOTtY1wyRN7wUhmrWDKEEZMSaz3wgJfHctsLXWY1fbfnfxfDnl2wOhcxLguoyI8 ypl6CjA== X-Received: from pfdd11.prod.google.com ([2002:a05:6a00:bc0b:b0:82f:61ed:8b2]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:4292:b0:82a:76ab:3279 with SMTP id d2e1a72fcca58-834ffed2e45mr7068807b3a.4.1777667746892; Fri, 01 May 2026 13:35:46 -0700 (PDT) Reply-To: Sean Christopherson Date: Fri, 1 May 2026 13:35:34 -0700 In-Reply-To: <20260501203537.2120074-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260501203537.2120074-1-seanjc@google.com> X-Mailer: git-send-email 2.54.0.545.g6539524ca2-goog Message-ID: <20260501203537.2120074-4-seanjc@google.com> Subject: [PATCH v2 3/6] KVM: SEV: Explicitly validate the dst buffer for debug operations From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Ashutosh Desai Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When encrypting/decrypting guest memory, explicitly check that the destination is non-NULL and doesn't wrap instead of subtly relying on sev_pin_memory() to perform the check. This will allow adding and using a more focused single-page pinning helper. Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index b9d7bd868e0b..9d2044fd910d 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1357,9 +1357,11 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm= _sev_cmd *argp, bool dec) if (copy_from_user(&debug, u64_to_user_ptr(argp->data), sizeof(debug))) return -EFAULT; =20 - if (!debug.len || debug.src_uaddr + debug.len < debug.src_uaddr) + if (!debug.len || !debug.src_uaddr || !debug.dst_uaddr) return -EINVAL; - if (!debug.dst_uaddr) + + if (debug.src_uaddr + debug.len < debug.src_uaddr || + debug.dst_uaddr + debug.len < debug.dst_uaddr) return -EINVAL; =20 vaddr =3D debug.src_uaddr; --=20 2.54.0.545.g6539524ca2-goog From nobody Sun Jun 14 07:35:51 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B133F3D16EC for ; Fri, 1 May 2026 20:35:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667753; cv=none; b=t18IC5be0rqz78OXOFq6OzxFnHUjLU0MyqLAuABRodJ49/Fam60mThP/841suXCLrJfh9fkSRAYYCt9vjJaAnrXP9Hsy9oD2SKHvatgs6PrBmHMV9HhO8iD3K96edwOrdgwKEOL2//84WY5Kr356zbyqM2PU4nB5OqsGCvK8SnY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667753; c=relaxed/simple; bh=Rlg4Fh/OJMOGGM68mvWjoZtGIv4+CjGrzl5e3f/h7OQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=DMLExrzu1GWivdsjr32JfYfsdkjH7xujaFEkM9G4pSDqW3RlglDlm/yUnjG3oMLMsNmBWJb3oFIJdHuQaaIwhUeKJ95UZd9l8AbJwB3QPbkbvsFWZIm32P3diQczwGaacXx9GPmlNMEXeb1DLP9RvuyOl3nCEw0ldxxwfTDnecM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=aGTgjfCX; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="aGTgjfCX" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-82fd55bf6cdso1744395b3a.3 for ; Fri, 01 May 2026 13:35:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1777667749; x=1778272549; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=K56fVDi5EkAo7p4gllqrxnHbaoeRU2pIE/SomnN3Fyk=; b=aGTgjfCXJ7phaQ0DopTy2LAUNmGddZ9gmgA/7mzUbQPF15nNJG274/nVDE87VLcRTv BwA94zYh5eetUvmIlWNhDsorfBnb+9kSMubOFtXVd6Rj7Vwk7phAGDW4kniMBu6Wy2EG pow7m/taPj1kmmN3XBPh/sRVbQE5soyKNQ3GBMTsEyij5aq14IcsDS0AOQJxrJGwJTSZ p/K/HEU8RJBezNh3icZrLoG4XjAERGsL3Q8jntm+e0tYGMa1ONSavUFNjBzDB6v5PHdK 8immsamlrkc9CrFZYTkkCjUoP8vueQJ1map+6wPwHYfI9aVHjPCfmw9ShkWOdy7IyU2t Qz2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777667749; x=1778272549; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=K56fVDi5EkAo7p4gllqrxnHbaoeRU2pIE/SomnN3Fyk=; b=GoXIvtN4z8zz8k6yw+bJ85gVFxWlQ0BW0/458TKgS+EJ2fr450/LGgjxkJH0EWrhQP zENk1tbdVwN8iUgn54aZvrqdoouk7xIyqIlLGQuX2LL57v30JrVgxHcCOPpg21QrvkyK J0GXxe3fB8zc/qFzavDCQabn2MgPVbUAvTqh+HKC8bc2hzuMWle63f/XGYS8rxprIZAX OMIFwet8fJiBoMRLc3g1U/XNGjH4AZ5AUJYkJaqBhB89EiPi5WNaN+INYqU+Ne5exTBP xn5Nm4Yp2XhCfBqYIDPb807om53YTCZzynY+Xv/jt6Yk2hE2MFjkvwjolTpcOKSfN7Oa Up/w== X-Forwarded-Encrypted: i=1; AFNElJ9yZriIoDeriO16zFQEz8AJ9U9zV6gnmpEKydykau5Bi9a91xZa4aWbnOJIHuZmuyRj7tAOMq6riUgzPf8=@vger.kernel.org X-Gm-Message-State: AOJu0YzBkByXF0tFEtCbtODjCavntIOcEeilAc9HQlBYTR/reJXD3Tw7 xMNxm6IYZNAcs51BFwXi+CgxvcCEHEBab00e9xm8b4cq0xlMygBRB1HUo+uRP4nKZlPoGYzuMnE RmpR9aQ== X-Received: from pfbbn21.prod.google.com ([2002:a05:6a00:3255:b0:82f:8cba:4285]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:430a:b0:82c:6b23:6d10 with SMTP id d2e1a72fcca58-8352d03a355mr645681b3a.3.1777667748889; Fri, 01 May 2026 13:35:48 -0700 (PDT) Reply-To: Sean Christopherson Date: Fri, 1 May 2026 13:35:35 -0700 In-Reply-To: <20260501203537.2120074-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260501203537.2120074-1-seanjc@google.com> X-Mailer: git-send-email 2.54.0.545.g6539524ca2-goog Message-ID: <20260501203537.2120074-5-seanjc@google.com> Subject: [PATCH v2 4/6] KVM: SEV: Add helper function to pin/unpin a single page From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Ashutosh Desai Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add helpers to pin/unpin a single page, and use it in all flows that pin exactly one page. None of the single-page users actually check that the correct number of pages was pinned, which is functionally ok, but visually jarring, especially in the decrypt/encrypt flow, which separately pins two pages, but uses a single variable to track how pages were pinned each time. Again, it's functionally ok since core mm guarantees exactly one page will be pinned on success, but it's ugly. Opportunistically use page_to_phys() instead of open coding an equivalent via page_to_pfn(). Note, all users of the single-page helper pre-validate the address and length, i.e. don't rely on the sanity check in sev_pin_memory(). No functional change intended. Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 145 +++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 55 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 9d2044fd910d..4146c91788fb 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -720,14 +720,50 @@ static int sev_launch_start(struct kvm *kvm, struct k= vm_sev_cmd *argp) return ret; } =20 +static int sev_check_pin_count(struct kvm *kvm, unsigned long npages) +{ + unsigned long total_npages, lock_limit; + + total_npages =3D to_kvm_sev_info(kvm)->pages_locked + npages; + if (total_npages > totalram_pages()) + return -EINVAL; + + lock_limit =3D rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; + if (total_npages > lock_limit && !capable(CAP_IPC_LOCK)) { + pr_err_ratelimited("SEV: %lu total pages would exceed the lock limit of = %lu.\n", + total_npages, lock_limit); + return -ENOMEM; + } + + return 0; +} + +static int sev_pin_user_pages(struct kvm *kvm, unsigned long addr, int npa= ges, + unsigned int gup_flags, struct page **pages) +{ + int npinned; + + lockdep_assert_held(&kvm->lock); + + npinned =3D pin_user_pages_fast(addr, npages, gup_flags, pages); + if (npinned !=3D npages) { + if (npinned > 0) + unpin_user_pages(pages, npinned); + pr_err_ratelimited("SEV: Failure locking %u pages.\n", npages); + return -ENOMEM; + } + + to_kvm_sev_info(kvm)->pages_locked +=3D npages; + return 0; +} + static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr, unsigned long ulen, unsigned long *n, unsigned int flags) { - struct kvm_sev_info *sev =3D to_kvm_sev_info(kvm); - unsigned long npages, total_npages, lock_limit; + unsigned long npages; struct page **pages; - int npinned, ret; + int ret; =20 lockdep_assert_held(&kvm->lock); =20 @@ -743,16 +779,9 @@ static struct page **sev_pin_memory(struct kvm *kvm, u= nsigned long uaddr, if (npages > INT_MAX) return ERR_PTR(-EINVAL); =20 - total_npages =3D sev->pages_locked + npages; - if (total_npages > totalram_pages()) - return ERR_PTR(-EINVAL); - - lock_limit =3D rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - 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); - } + ret =3D sev_check_pin_count(kvm, npages); + if (ret) + return ERR_PTR(ret); =20 /* * Don't WARN if the kernel (rightly) thinks the total size is absurd, @@ -764,25 +793,14 @@ static struct page **sev_pin_memory(struct kvm *kvm, = unsigned long uaddr, if (!pages) return ERR_PTR(-ENOMEM); =20 - /* Pin the user virtual address. */ - npinned =3D pin_user_pages_fast(uaddr, npages, flags, pages); - if (npinned !=3D npages) { - pr_err("SEV: Failure locking %lu pages.\n", npages); - ret =3D -ENOMEM; - goto err; + ret =3D sev_pin_user_pages(kvm, uaddr, npages, flags, pages); + if (ret) { + kvfree(pages); + return ERR_PTR(ret); } =20 *n =3D npages; - sev->pages_locked =3D total_npages; - return pages; - -err: - if (npinned > 0) - unpin_user_pages(pages, npinned); - - kvfree(pages); - return ERR_PTR(ret); } =20 static void sev_unpin_memory(struct kvm *kvm, struct page **pages, @@ -793,6 +811,29 @@ static void sev_unpin_memory(struct kvm *kvm, struct p= age **pages, to_kvm_sev_info(kvm)->pages_locked -=3D npages; } =20 +static struct page *sev_pin_page(struct kvm *kvm, unsigned long addr, + unsigned int flags) +{ + struct page *page; + int r; + + r =3D sev_check_pin_count(kvm, 1); + if (r) + return ERR_PTR(r); + + r =3D sev_pin_user_pages(kvm, addr, 1, flags, &page); + if (r) + return ERR_PTR(r); + + return page; +} + +static void sev_unpin_page(struct kvm *kvm, struct page *page) +{ + unpin_user_pages(&page, 1); + to_kvm_sev_info(kvm)->pages_locked -=3D 1; +} + static void sev_clflush_pages(struct page *pages[], unsigned long npages) { uint8_t *page_virtual; @@ -1345,9 +1386,8 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm_= sev_cmd *argp, bool dec) { unsigned long vaddr, vaddr_end, next_vaddr; unsigned long dst_vaddr; - struct page **src_p, **dst_p; + struct page *src_p, *dst_p; struct kvm_sev_dbg debug; - unsigned long n; unsigned int size; int ret; =20 @@ -1373,13 +1413,13 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kv= m_sev_cmd *argp, bool dec) int len, s_off, d_off; =20 /* lock userspace source and destination page */ - src_p =3D sev_pin_memory(kvm, vaddr & PAGE_MASK, PAGE_SIZE, &n, 0); + src_p =3D sev_pin_page(kvm, vaddr & PAGE_MASK, 0); if (IS_ERR(src_p)) return PTR_ERR(src_p); =20 - dst_p =3D sev_pin_memory(kvm, dst_vaddr & PAGE_MASK, PAGE_SIZE, &n, FOLL= _WRITE); + dst_p =3D sev_pin_page(kvm, dst_vaddr & PAGE_MASK, FOLL_WRITE); if (IS_ERR(dst_p)) { - sev_unpin_memory(kvm, src_p, n); + sev_unpin_page(kvm, src_p); return PTR_ERR(dst_p); } =20 @@ -1388,8 +1428,8 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm_= sev_cmd *argp, bool dec) * the pages; flush the destination too so that future accesses do not * see stale data. */ - sev_clflush_pages(src_p, 1); - sev_clflush_pages(dst_p, 1); + sev_clflush_pages(&src_p, 1); + sev_clflush_pages(&dst_p, 1); =20 /* * Since user buffer may not be page aligned, calculate the @@ -1402,20 +1442,20 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kv= m_sev_cmd *argp, bool dec) =20 if (dec) ret =3D __sev_dbg_decrypt_user(kvm, - __sme_page_pa(src_p[0]) + s_off, + __sme_page_pa(src_p) + s_off, (void __user *)dst_vaddr, - __sme_page_pa(dst_p[0]) + d_off, + __sme_page_pa(dst_p) + d_off, len, &argp->error); else ret =3D __sev_dbg_encrypt_user(kvm, - __sme_page_pa(src_p[0]) + s_off, + __sme_page_pa(src_p) + s_off, (void __user *)vaddr, - __sme_page_pa(dst_p[0]) + d_off, + __sme_page_pa(dst_p) + d_off, (void __user *)dst_vaddr, len, &argp->error); =20 - sev_unpin_memory(kvm, src_p, n); - sev_unpin_memory(kvm, dst_p, n); + sev_unpin_page(kvm, src_p); + sev_unpin_page(kvm, dst_p); =20 if (ret) goto err; @@ -1698,8 +1738,7 @@ static int sev_send_update_data(struct kvm *kvm, stru= ct kvm_sev_cmd *argp) struct sev_data_send_update_data data; struct kvm_sev_send_update_data params; void *hdr, *trans_data; - struct page **guest_page; - unsigned long n; + struct page *guest_page; int ret, offset; =20 if (!sev_guest(kvm)) @@ -1723,8 +1762,7 @@ static int sev_send_update_data(struct kvm *kvm, stru= ct kvm_sev_cmd *argp) return -EINVAL; =20 /* Pin guest memory */ - guest_page =3D sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK, - PAGE_SIZE, &n, 0); + guest_page =3D sev_pin_page(kvm, params.guest_uaddr & PAGE_MASK, 0); if (IS_ERR(guest_page)) return PTR_ERR(guest_page); =20 @@ -1745,7 +1783,7 @@ static int sev_send_update_data(struct kvm *kvm, stru= ct kvm_sev_cmd *argp) data.trans_len =3D params.trans_len; =20 /* The SEND_UPDATE_DATA command requires C-bit to be always set. */ - data.guest_address =3D (page_to_pfn(guest_page[0]) << PAGE_SHIFT) + offse= t; + data.guest_address =3D page_to_phys(guest_page) + offset; data.guest_address |=3D sev_me_mask; data.guest_len =3D params.guest_len; data.handle =3D to_kvm_sev_info(kvm)->handle; @@ -1772,8 +1810,7 @@ static int sev_send_update_data(struct kvm *kvm, stru= ct kvm_sev_cmd *argp) e_free_hdr: kfree(hdr); e_unpin: - sev_unpin_memory(kvm, guest_page, n); - + sev_unpin_page(kvm, guest_page); return ret; } =20 @@ -1878,8 +1915,7 @@ static int sev_receive_update_data(struct kvm *kvm, s= truct kvm_sev_cmd *argp) struct kvm_sev_receive_update_data params; struct sev_data_receive_update_data data; void *hdr =3D NULL, *trans =3D NULL; - struct page **guest_page; - unsigned long n; + struct page *guest_page; int ret, offset; =20 if (!sev_guest(kvm)) @@ -1916,8 +1952,7 @@ static int sev_receive_update_data(struct kvm *kvm, s= truct kvm_sev_cmd *argp) data.trans_len =3D params.trans_len; =20 /* Pin guest memory */ - guest_page =3D sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK, - PAGE_SIZE, &n, FOLL_WRITE); + guest_page =3D sev_pin_page(kvm, params.guest_uaddr & PAGE_MASK, FOLL_WRI= TE); if (IS_ERR(guest_page)) { ret =3D PTR_ERR(guest_page); goto e_free_trans; @@ -1928,10 +1963,10 @@ static int sev_receive_update_data(struct kvm *kvm,= struct kvm_sev_cmd *argp) * encrypts the written data with the guest's key, and the cache may * contain dirty, unencrypted data. */ - sev_clflush_pages(guest_page, n); + sev_clflush_pages(&guest_page, 1); =20 /* The RECEIVE_UPDATE_DATA command requires C-bit to be always set. */ - data.guest_address =3D (page_to_pfn(guest_page[0]) << PAGE_SHIFT) + offse= t; + data.guest_address =3D page_to_phys(guest_page) + offset; data.guest_address |=3D sev_me_mask; data.guest_len =3D params.guest_len; data.handle =3D to_kvm_sev_info(kvm)->handle; @@ -1939,7 +1974,7 @@ static int sev_receive_update_data(struct kvm *kvm, s= truct kvm_sev_cmd *argp) ret =3D sev_issue_cmd(kvm, SEV_CMD_RECEIVE_UPDATE_DATA, &data, &argp->error); =20 - sev_unpin_memory(kvm, guest_page, n); + sev_unpin_page(kvm, guest_page); =20 e_free_trans: kfree(trans); --=20 2.54.0.545.g6539524ca2-goog From nobody Sun Jun 14 07:35:51 2026 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C83804219E7 for ; Fri, 1 May 2026 20:35:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667754; cv=none; b=OfBvFYj10l/3m/hgO8vUCrzYE67YT2/oEiIzM5psYp4Xd/y5HoOmiDrxLhQ0piDMWaRYyEwQ1MySXd3ahlr2rAjwGxiX/BpRKzwahQrpTONIXpUu37tzrH4PP+9JHuQVIBkbB1vjEphi7IEvXzua7Hh2lerV/xJXaxzAoS5ivLY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667754; c=relaxed/simple; bh=owBtY1ELTAvA1+3avvZSr0u1v4pPHYD2JReBYyVBKOs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=DNXkUVuBJkT5wK7KFp0kgeIftI0ivff69U/d0nB7SXnbfFA+yBpqsnoRpXKqI7uM0DwS17PO8+MI1lCTPThUdUppXVOMa0nzlJK2uw9qbl9PShan1TNkdkGKAzXUrwxj8FoELkIDsXQC1GNbnb7f9M0P8fdSkAftQL9VGS2ufPE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=TmT3E4L9; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="TmT3E4L9" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-35e56ed5d5bso3691237a91.0 for ; Fri, 01 May 2026 13:35:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1777667752; x=1778272552; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=f7ChgRzJoZv20LTTFq5AT076grxjadNMggjOvVlT0J0=; b=TmT3E4L98GsK7p04jHp0WklS51KJM4oaxuO5Q+ybbxmcmPLssaN5SxwSChQUDwVezo +cE7705YaapoNaYHbviieal6VYtNCKyEPZ7Dmvm1v8Lb4RwtPhR2rF+G98h4XVV8vTDy JUVKrsxFMFLx7EoE+xnRV3mswAOcQ8jSKCO/5YtWHr55a0ZM0xttD30Roif6FmlGufiH sjv7OsJlyIjhs1zB4+qP0QHMP3GvYd6IxoB1ZtDzNFi0adQ2b2c1XVY95e6pjRl4cAsp UF43LUfNS0gj5vVbZiUU4O6qAcv9PHiPy7oefhtYxAkY7QyO8TiVUM7LxYCY0i3T6nDi pLcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777667752; x=1778272552; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=f7ChgRzJoZv20LTTFq5AT076grxjadNMggjOvVlT0J0=; b=AWjNNqhi8isT6ta9wmygxGPdDUANvDouIAmRIPgO4+YHwiLqlp0Pt1iFin+DZbfRXS YzibYvoWHkGWHlF5kVQAvKEOZfsoKEjZzb4MXAXNQEBhXWYMi4aERoFc0padxDYNKMtJ Hc8KA4tAoaKG9gEN+jxuHcE+ifRrXP+kt1Xqcm9sAdvKp4ps5a94BjVA21l2OIJqcjel ebBIkpqeHB+aZi7FM9C3pex95hSCatQCNvB5aYWvhbgED23ZD9jQMjy6iZOJepe2yBuH K/02jt8yjjnJs+UitZ8x8IkGv22FjIW+JdmIxeqLjMqMIOyL3wsag89hsLxbOw+Cl6Ya L93A== X-Forwarded-Encrypted: i=1; AFNElJ8X46DnQB0Jz45drcsKAxJUqtVcqSDu1TLsVb2xDWh6EMVRYEUp3XH0PHdXx/9YBcR8PZ1IKld5WUXZMok=@vger.kernel.org X-Gm-Message-State: AOJu0YzyN8K6pClw1GRT8ZlwJxWsagGrISLP5TVXmlAOfi3RW+VncJBs bYBw/WjmB5Y9kSF5ghJW9clGdR8U5J1ktwxUceZ63jbeuU165DR4Z3+I48MxwKFDJuwpYvIfvrM oxn2CxQ== X-Received: from pglq9.prod.google.com ([2002:a63:5049:0:b0:c79:81bb:79dd]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:3d26:b0:3a0:71f:ea41 with SMTP id adf61e73a8af0-3a3d21b2f69mr7795242637.33.1777667751923; Fri, 01 May 2026 13:35:51 -0700 (PDT) Reply-To: Sean Christopherson Date: Fri, 1 May 2026 13:35:36 -0700 In-Reply-To: <20260501203537.2120074-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260501203537.2120074-1-seanjc@google.com> X-Mailer: git-send-email 2.54.0.545.g6539524ca2-goog Message-ID: <20260501203537.2120074-6-seanjc@google.com> Subject: [PATCH v2 5/6] KVM: SEV: Rewrite logic to {de,en}crypt memory for debug From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Ashutosh Desai Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Wholesale rewrite the guts of the debug {de,en}crypt flows, as the existing code is broken, e.g. doesn't handle cases where the access isn't naturally sized and aligned, and is so wildly flawed that attempting to salvage the current code in an iterative fashion would be more risky than a rewrite. E.g. when encrypting 9 bytes at offset 8, KVM needs to _decrypt_ destination[31:0] into a temporary buffer, buffer[31:0], then copy 9 bytes from source[8:0] to buffer[16:8], then encrypt buffer[31:0] back into destination[31:0]. The current code only ever copies 16 bytes, and bizarrely uses a temporary buffer for the source as well. To keep the code easier to read and maintain, send the unaligned cases down dedicated "slow" paths instead of trying to mix and match the possible combinations in one helper. For now, preserve the basic approach of the current code, e.g. allocate an entire page for the temporary buffer, to minimize unwanted changes in functionality. Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 306 +++++++++++++++++++---------------------- 1 file changed, 139 insertions(+), 167 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 4146c91788fb..89586f821c9c 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1237,159 +1237,140 @@ static int sev_guest_status(struct kvm *kvm, stru= ct kvm_sev_cmd *argp) return ret; } =20 -static int __sev_issue_dbg_cmd(struct kvm *kvm, unsigned long src, - unsigned long dst, int size, - int *error, bool enc) +static int sev_issue_dbg_cmd(struct kvm *kvm, unsigned long src_pa, + unsigned long dst_pa, unsigned int size, + unsigned int ioctl, int *error) { - struct sev_data_dbg data; + int cmd =3D ioctl =3D=3D KVM_SEV_DBG_DECRYPT ? SEV_CMD_DBG_DECRYPT : + SEV_CMD_DBG_ENCRYPT; + struct sev_data_dbg data =3D { + .handle =3D to_kvm_sev_info(kvm)->handle, + .dst_addr =3D dst_pa, + .src_addr =3D src_pa, + .len =3D size, + }; + + return sev_issue_cmd(kvm, cmd, &data, error); +} + +static struct page *sev_alloc_dbg_buffer(void **buf) +{ + struct page *buf_p; =20 - data.reserved =3D 0; - data.handle =3D to_kvm_sev_info(kvm)->handle; - data.dst_addr =3D dst; - data.src_addr =3D src; - data.len =3D size; + buf_p =3D alloc_page(GFP_KERNEL); + if (!buf_p) + return NULL; + + *buf =3D kmap_local_page(buf_p); + return buf_p; +} =20 - return sev_issue_cmd(kvm, - enc ? SEV_CMD_DBG_ENCRYPT : SEV_CMD_DBG_DECRYPT, - &data, error); +static void sev_free_dbg_buffer(struct page *buf_p, void *buf) +{ + kunmap_local(buf); + __free_page(buf_p); } =20 -static int __sev_dbg_decrypt(struct kvm *kvm, unsigned long src_paddr, - unsigned long dst_paddr, int sz, int *err) +static unsigned int sev_dbg_crypt_slow_addr_and_size(struct page *page, + unsigned long __va, + unsigned int len, + unsigned long *pa) { - int offset; + /* The number of bytes to {de,en}crypt must be 16-byte aligned. */ + unsigned int nr_bytes =3D round_up(len, 16); + unsigned long va =3D ALIGN_DOWN(__va, 16); + + /* + * Increase the number of bytes to {de,en}crypt by one chunk (16 bytes) + * if the aligned address and length doesn't cover the unaligned range, + * e.g. if the address is unaligned _and_ the access will split a chunk + * at the tail. + */ + if (va + nr_bytes < __va + len) + nr_bytes +=3D 16; + + *pa =3D __sme_page_pa(page) + (va & ~PAGE_MASK); =20 /* - * Its safe to read more than we are asked, caller should ensure that - * destination has enough space. + * Sanity check that the new access won't split a page. This should + * never happen; just squash the access and let the firmware command + * fail. */ - offset =3D src_paddr & 15; - src_paddr =3D round_down(src_paddr, 16); - sz =3D round_up(sz + offset, 16); + if (WARN_ON_ONCE((*pa & PAGE_MASK) !=3D ((*pa + nr_bytes - 1) & PAGE_MASK= ))) + return 0; =20 - return __sev_issue_dbg_cmd(kvm, src_paddr, dst_paddr, sz, err, false); + return nr_bytes; } =20 -static int __sev_dbg_decrypt_user(struct kvm *kvm, unsigned long paddr, - void __user *dst_uaddr, - unsigned long dst_paddr, - int size, int *err) +static int sev_dbg_decrypt_slow(struct kvm *kvm, unsigned long src, + struct page *src_p, unsigned long dst, + unsigned int len, int *err) { - struct page *tpage =3D NULL; - int ret, offset; - - /* if inputs are not 16-byte then use intermediate buffer */ - if (!IS_ALIGNED(dst_paddr, 16) || - !IS_ALIGNED(paddr, 16) || - !IS_ALIGNED(size, 16)) { - tpage =3D (void *)alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); - if (!tpage) - return -ENOMEM; - - dst_paddr =3D __sme_page_pa(tpage); - } - - ret =3D __sev_dbg_decrypt(kvm, paddr, dst_paddr, size, err); - if (ret) - goto e_free; - - if (tpage) { - offset =3D paddr & 15; - if (copy_to_user(dst_uaddr, page_address(tpage) + offset, size)) - ret =3D -EFAULT; - } - -e_free: - if (tpage) - __free_page(tpage); - - return ret; + unsigned int nr_bytes; + unsigned long src_pa; + struct page *buf_p; + void *buf; + int r; + + buf_p =3D sev_alloc_dbg_buffer(&buf); + if (!buf_p) + return -ENOMEM; + + nr_bytes =3D sev_dbg_crypt_slow_addr_and_size(src_p, src, len, &src_pa); + + r =3D sev_issue_dbg_cmd(kvm, src_pa, __sme_page_pa(buf_p), + nr_bytes, KVM_SEV_DBG_DECRYPT, err); + if (r) + goto out; + + if (copy_to_user((void __user *)dst, buf + (src & 15), len)) + r =3D -EFAULT; +out: + sev_free_dbg_buffer(buf_p, buf); + return r; } =20 -static int __sev_dbg_encrypt_user(struct kvm *kvm, unsigned long paddr, - void __user *vaddr, - unsigned long dst_paddr, - void __user *dst_vaddr, - int size, int *error) +static int sev_dbg_encrypt_slow(struct kvm *kvm, unsigned long src, + unsigned long dst, struct page *dst_p, + unsigned int len, int *err) { - struct page *src_tpage =3D NULL; - struct page *dst_tpage =3D NULL; - int ret, len =3D size; + unsigned int nr_bytes; + unsigned long dst_pa; + struct page *buf_p; + void *buf; + int r; =20 - /* If source buffer is not aligned then use an intermediate buffer */ - if (!IS_ALIGNED((unsigned long)vaddr, 16)) { - src_tpage =3D alloc_page(GFP_KERNEL_ACCOUNT); - if (!src_tpage) - return -ENOMEM; + buf_p =3D sev_alloc_dbg_buffer(&buf); + if (!buf_p) + return -ENOMEM; =20 - if (copy_from_user(page_address(src_tpage), vaddr, size)) { - __free_page(src_tpage); - return -EFAULT; - } + /* Decrypt the _destination_ to do a RMW on plaintext. */ + nr_bytes =3D sev_dbg_crypt_slow_addr_and_size(dst_p, dst, len, &dst_pa); =20 - paddr =3D __sme_page_pa(src_tpage); - } + r =3D sev_issue_dbg_cmd(kvm, dst_pa, __sme_page_pa(buf_p), + nr_bytes, KVM_SEV_DBG_DECRYPT, err); + if (r) + goto out; =20 /* - * If destination buffer or length is not aligned then do read-modify-wr= ite: - * - decrypt destination in an intermediate buffer - * - copy the source buffer in an intermediate buffer - * - use the intermediate buffer as source buffer + * Copy from the source into the intermediate buffer, and then + * re-encrypt the buffer into the destination. */ - if (!IS_ALIGNED((unsigned long)dst_vaddr, 16) || !IS_ALIGNED(size, 16)) { - int dst_offset; - - dst_tpage =3D alloc_page(GFP_KERNEL_ACCOUNT); - if (!dst_tpage) { - ret =3D -ENOMEM; - goto e_free; - } - - ret =3D __sev_dbg_decrypt(kvm, dst_paddr, - __sme_page_pa(dst_tpage), size, error); - if (ret) - goto e_free; - - /* - * If source is kernel buffer then use memcpy() otherwise - * copy_from_user(). - */ - dst_offset =3D dst_paddr & 15; - - if (src_tpage) - memcpy(page_address(dst_tpage) + dst_offset, - page_address(src_tpage), size); - else { - if (copy_from_user(page_address(dst_tpage) + dst_offset, - vaddr, size)) { - ret =3D -EFAULT; - goto e_free; - } - } - - paddr =3D __sme_page_pa(dst_tpage); - dst_paddr =3D round_down(dst_paddr, 16); - len =3D round_up(size, 16); - } - - ret =3D __sev_issue_dbg_cmd(kvm, paddr, dst_paddr, len, error, true); - -e_free: - if (src_tpage) - __free_page(src_tpage); - if (dst_tpage) - __free_page(dst_tpage); - return ret; + if (copy_from_user(buf + (dst & 15), (void __user *)src, len)) + r =3D -EFAULT; + else + r =3D sev_issue_dbg_cmd(kvm, __sme_page_pa(buf_p), dst_pa, + nr_bytes, KVM_SEV_DBG_ENCRYPT, err); +out: + sev_free_dbg_buffer(buf_p, buf); + return r; } =20 -static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool d= ec) +static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, + unsigned int cmd) { - unsigned long vaddr, vaddr_end, next_vaddr; - unsigned long dst_vaddr; - struct page *src_p, *dst_p; struct kvm_sev_dbg debug; - unsigned int size; - int ret; + unsigned int i, len; =20 if (!sev_guest(kvm)) return -ENOTTY; @@ -1404,20 +1385,29 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kv= m_sev_cmd *argp, bool dec) debug.dst_uaddr + debug.len < debug.dst_uaddr) return -EINVAL; =20 - vaddr =3D debug.src_uaddr; - size =3D debug.len; - vaddr_end =3D vaddr + size; - dst_vaddr =3D debug.dst_uaddr; + for (i =3D 0; i < debug.len; i +=3D len) { + unsigned long src =3D debug.src_uaddr + i; + unsigned long dst =3D debug.dst_uaddr + i; + unsigned long s_off =3D src & ~PAGE_MASK; + unsigned long d_off =3D dst & ~PAGE_MASK; + struct page *src_p, *dst_p; + int ret; =20 - for (; vaddr < vaddr_end; vaddr =3D next_vaddr) { - int len, s_off, d_off; + /* + * Copy as many remaining bytes as possible while staying in a + * single page for both the source and destination. + */ + len =3D min3(debug.len - i, PAGE_SIZE - s_off, PAGE_SIZE - d_off); =20 - /* lock userspace source and destination page */ - src_p =3D sev_pin_page(kvm, vaddr & PAGE_MASK, 0); + /* + * Pin the source and destination pages; firmware operates on + * physical addresses. + */ + src_p =3D sev_pin_page(kvm, src & PAGE_MASK, 0); if (IS_ERR(src_p)) return PTR_ERR(src_p); =20 - dst_p =3D sev_pin_page(kvm, dst_vaddr & PAGE_MASK, FOLL_WRITE); + dst_p =3D sev_pin_page(kvm, dst & PAGE_MASK, FOLL_WRITE); if (IS_ERR(dst_p)) { sev_unpin_page(kvm, src_p); return PTR_ERR(dst_p); @@ -1431,41 +1421,25 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kv= m_sev_cmd *argp, bool dec) sev_clflush_pages(&src_p, 1); sev_clflush_pages(&dst_p, 1); =20 - /* - * Since user buffer may not be page aligned, calculate the - * offset within the page. - */ - s_off =3D vaddr & ~PAGE_MASK; - d_off =3D dst_vaddr & ~PAGE_MASK; - len =3D min_t(size_t, (PAGE_SIZE - s_off), size); - len =3D min_t(size_t, len, PAGE_SIZE - d_off); - - if (dec) - ret =3D __sev_dbg_decrypt_user(kvm, - __sme_page_pa(src_p) + s_off, - (void __user *)dst_vaddr, - __sme_page_pa(dst_p) + d_off, - len, &argp->error); + if (IS_ALIGNED(src, 16) && IS_ALIGNED(dst, 16) && IS_ALIGNED(len, 16)) + ret =3D sev_issue_dbg_cmd(kvm, + __sme_page_pa(src_p) + s_off, + __sme_page_pa(dst_p) + d_off, + len, cmd, &argp->error); + else if (cmd =3D=3D KVM_SEV_DBG_DECRYPT) + ret =3D sev_dbg_decrypt_slow(kvm, src, src_p, dst, + len, &argp->error); else - ret =3D __sev_dbg_encrypt_user(kvm, - __sme_page_pa(src_p) + s_off, - (void __user *)vaddr, - __sme_page_pa(dst_p) + d_off, - (void __user *)dst_vaddr, - len, &argp->error); + ret =3D sev_dbg_encrypt_slow(kvm, src, dst, dst_p, + len, &argp->error); =20 sev_unpin_page(kvm, src_p); sev_unpin_page(kvm, dst_p); =20 if (ret) - goto err; - - next_vaddr =3D vaddr + len; - dst_vaddr =3D dst_vaddr + len; - size -=3D len; + return ret; } -err: - return ret; + return 0; } =20 static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp) @@ -2727,10 +2701,8 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *= argp) r =3D sev_guest_status(kvm, &sev_cmd); break; case KVM_SEV_DBG_DECRYPT: - r =3D sev_dbg_crypt(kvm, &sev_cmd, true); - break; case KVM_SEV_DBG_ENCRYPT: - r =3D sev_dbg_crypt(kvm, &sev_cmd, false); + r =3D sev_dbg_crypt(kvm, &sev_cmd, sev_cmd.id); break; case KVM_SEV_LAUNCH_SECRET: r =3D sev_launch_secret(kvm, &sev_cmd); --=20 2.54.0.545.g6539524ca2-goog From nobody Sun Jun 14 07:35:51 2026 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7C49842316F for ; Fri, 1 May 2026 20:35:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667758; cv=none; b=PNaFkuFug8C2nfE7fLJyL2z4HPwGWLiJHilHqzNQTtWLQWBKvYHOB0XjAtTSk/tTFf8u8i5Dbb0DecViA8k/xi4KECUG33eP8Syw9ht++L3mMXxff9pKYNjHlYzb3RvkGtmbfgWZ0SP7xJ9KbH/ZMdpQ7vigHYih5YK7up4rpGk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777667758; c=relaxed/simple; bh=zbH2ZSJhkTnv7M6GW+1yYa9nXucIRak6aeyoMh/dwdw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=jTsptaRHWAYaE0C9GPtMB8GH0PUMbt+sx56hU5Y+nvGtHqEMiFSYuRxLX1RlO/4T2h5/SfeNguX43u/JjTvvlWiRO3dV/LzfG3M+tIcf5TmoZshX99oGJe9ECgL+p3lR2yStIFc0tl/gON/npovgijuxW883nKp6pIIIwssC6Ow= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=fdMSkQRa; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="fdMSkQRa" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-2b4654f9bb6so26509775ad.2 for ; Fri, 01 May 2026 13:35:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1777667754; x=1778272554; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=2rmwcvThwjw92x9D0plyk0s/qULXiJrO5D2DLQI9XGw=; b=fdMSkQRaoWtBC+/v2fM75t1VOpgap1y/zAaWot+MGt/URr9Gt0WVnK11O8ttgk9vaX BCrX2MCeBFEWkrtrMvIjwaZ/2YzPNVXMg3hT32CEzbybwky45YeTFrX1a/CYIEEpzrFL B7FjCuC/d7ZeHt3uB6UfcXhxXXiMRPxrHctV3DDSHYlbfKkYEdlHsFGuP5S+52oinJsZ u29UQfzViy8PwnfmZg2MsYddXMwej4hnUNwe5VUxLYOrX+ixCvA2idAAIGbzcQ+zIFDM +u/M87qaY3lb16HbEPgwCEPzlWtjfe3LMxo4yfGXScLMuMqoMneIqVyxAcpme9fwJDs2 DdWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777667754; x=1778272554; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=2rmwcvThwjw92x9D0plyk0s/qULXiJrO5D2DLQI9XGw=; b=YS1DbqaU9228ZupJX9aNjNz1ysMp4ZxowstF0H+BA/rHD8/QgcH1tDwlsGNl1zq8dr zb7LuSlGB/H05Pzcha4MnizHzid8xY2lIT2WHtOdrqVWn9ONBA7Bpxn9cdQCa3oGT+QU 0Mk/CWhTVLhoJ9u/Zve24laCX3UbC7pYtEJtyEhR3GjRsGfb0Ijwy7jhRAVrGssOYU13 /AUe8DdcmdgHmjhTKXUXAPeqbAz5JpLcopVEo1e7Oh37+oWVa67stb10+upvlCmCkOcu J1Nq4wikfEisj5ClDCRnKspFSWDVafX8fOH0dyAkK6yMtKJWCOaQZsRsV+c46c60rVQC AZmw== X-Forwarded-Encrypted: i=1; AFNElJ+iniZsU0S968T5jSwll9adBasBZPZHfrd+2djI8bYTmcLUOT2G5k77Cjs1whq0JTTHArkbzKM+i4xL4s0=@vger.kernel.org X-Gm-Message-State: AOJu0Yw4JbfNU0LNHvQgJUOzct8/1Ya+DKew+z7U3KWgEebSvwg5TI3w UGW45+N9zo7e806YNPOe0Q7RGr25rK86ioez50q6NJCYfpCNmG7oiE7wtroetIgIu5enGZUdF78 dX/pnwQ== X-Received: from plmt18.prod.google.com ([2002:a17:903:3d52:b0:2b2:cc58:2a31]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:3e0d:b0:2ae:6092:8d93 with SMTP id d9443c01a7336-2b9f2825508mr4439065ad.28.1777667753622; Fri, 01 May 2026 13:35:53 -0700 (PDT) Reply-To: Sean Christopherson Date: Fri, 1 May 2026 13:35:37 -0700 In-Reply-To: <20260501203537.2120074-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260501203537.2120074-1-seanjc@google.com> X-Mailer: git-send-email 2.54.0.545.g6539524ca2-goog Message-ID: <20260501203537.2120074-7-seanjc@google.com> Subject: [PATCH v2 6/6] KVM: SEV: Allocate only as many bytes as needed for temp crypt buffers From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Ashutosh Desai Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When using a temporary buffer to {de,en}crypt unaligned memory for debug, allocate only the number of bytes that are needed instead of allocating an entire page. The most common case for unaligned accesses will be reading or writing less than 16 bytes. Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 69 ++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 47 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 89586f821c9c..0865ce4bcecb 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1253,53 +1253,34 @@ static int sev_issue_dbg_cmd(struct kvm *kvm, unsig= ned long src_pa, return sev_issue_cmd(kvm, cmd, &data, error); } =20 -static struct page *sev_alloc_dbg_buffer(void **buf) +static void *sev_dbg_crypt_slow_alloc(struct page *page, unsigned long __v= a, + unsigned int len, unsigned long *pa, + unsigned int *nr_bytes) { - struct page *buf_p; - - buf_p =3D alloc_page(GFP_KERNEL); - if (!buf_p) - return NULL; - - *buf =3D kmap_local_page(buf_p); - return buf_p; -} - -static void sev_free_dbg_buffer(struct page *buf_p, void *buf) -{ - kunmap_local(buf); - __free_page(buf_p); -} - -static unsigned int sev_dbg_crypt_slow_addr_and_size(struct page *page, - unsigned long __va, - unsigned int len, - unsigned long *pa) -{ - /* The number of bytes to {de,en}crypt must be 16-byte aligned. */ - unsigned int nr_bytes =3D round_up(len, 16); unsigned long va =3D ALIGN_DOWN(__va, 16); =20 + /* The number of bytes to {de,en}crypt must be 16-byte aligned. */ + *nr_bytes =3D round_up(len, 16); + /* * Increase the number of bytes to {de,en}crypt by one chunk (16 bytes) * if the aligned address and length doesn't cover the unaligned range, * e.g. if the address is unaligned _and_ the access will split a chunk * at the tail. */ - if (va + nr_bytes < __va + len) - nr_bytes +=3D 16; + if (va + *nr_bytes < __va + len) + *nr_bytes +=3D 16; =20 *pa =3D __sme_page_pa(page) + (va & ~PAGE_MASK); =20 /* * Sanity check that the new access won't split a page. This should - * never happen; just squash the access and let the firmware command - * fail. + * never happen; just pretend the allocation failed. */ - if (WARN_ON_ONCE((*pa & PAGE_MASK) !=3D ((*pa + nr_bytes - 1) & PAGE_MASK= ))) - return 0; + if (WARN_ON_ONCE((*pa & PAGE_MASK) !=3D ((*pa + *nr_bytes - 1) & PAGE_MAS= K))) + return NULL; =20 - return nr_bytes; + return kmalloc(*nr_bytes, GFP_KERNEL); } =20 static int sev_dbg_decrypt_slow(struct kvm *kvm, unsigned long src, @@ -1308,17 +1289,14 @@ static int sev_dbg_decrypt_slow(struct kvm *kvm, un= signed long src, { unsigned int nr_bytes; unsigned long src_pa; - struct page *buf_p; void *buf; int r; =20 - buf_p =3D sev_alloc_dbg_buffer(&buf); - if (!buf_p) + buf =3D sev_dbg_crypt_slow_alloc(src_p, src, len, &src_pa, &nr_bytes); + if (!buf) return -ENOMEM; =20 - nr_bytes =3D sev_dbg_crypt_slow_addr_and_size(src_p, src, len, &src_pa); - - r =3D sev_issue_dbg_cmd(kvm, src_pa, __sme_page_pa(buf_p), + r =3D sev_issue_dbg_cmd(kvm, src_pa, __sme_set(__pa(buf)), nr_bytes, KVM_SEV_DBG_DECRYPT, err); if (r) goto out; @@ -1326,7 +1304,7 @@ static int sev_dbg_decrypt_slow(struct kvm *kvm, unsi= gned long src, if (copy_to_user((void __user *)dst, buf + (src & 15), len)) r =3D -EFAULT; out: - sev_free_dbg_buffer(buf_p, buf); + kfree(buf); return r; } =20 @@ -1336,18 +1314,15 @@ static int sev_dbg_encrypt_slow(struct kvm *kvm, un= signed long src, { unsigned int nr_bytes; unsigned long dst_pa; - struct page *buf_p; void *buf; int r; =20 - buf_p =3D sev_alloc_dbg_buffer(&buf); - if (!buf_p) - return -ENOMEM; - /* Decrypt the _destination_ to do a RMW on plaintext. */ - nr_bytes =3D sev_dbg_crypt_slow_addr_and_size(dst_p, dst, len, &dst_pa); + buf =3D sev_dbg_crypt_slow_alloc(dst_p, dst, len, &dst_pa, &nr_bytes); + if (!buf) + return -ENOMEM; =20 - r =3D sev_issue_dbg_cmd(kvm, dst_pa, __sme_page_pa(buf_p), + r =3D sev_issue_dbg_cmd(kvm, dst_pa, __sme_set(__pa(buf)), nr_bytes, KVM_SEV_DBG_DECRYPT, err); if (r) goto out; @@ -1359,10 +1334,10 @@ static int sev_dbg_encrypt_slow(struct kvm *kvm, un= signed long src, if (copy_from_user(buf + (dst & 15), (void __user *)src, len)) r =3D -EFAULT; else - r =3D sev_issue_dbg_cmd(kvm, __sme_page_pa(buf_p), dst_pa, + r =3D sev_issue_dbg_cmd(kvm, __sme_set(__pa(buf)), dst_pa, nr_bytes, KVM_SEV_DBG_ENCRYPT, err); out: - sev_free_dbg_buffer(buf_p, buf); + kfree(buf); return r; } =20 --=20 2.54.0.545.g6539524ca2-goog