From nobody Mon Nov 25 05:01:01 2024 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.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 6A065201033 for ; Tue, 29 Oct 2024 18:39:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730227167; cv=none; b=qZ7pmewodO/3D7IDxN3a11m5F1LkjpNr+Krkzjd5UneNXUbnYjJbHJeEwJMVjBMCNt5lY5pcTctpnYJ5dieBI7N24OaCUz8DFq0zsKOvMjiqfQFgjPXvuJ8t5pFGU1Hf+xl76iMMs7eT97sCnT30Avsc1HPo0lhXOtkHhpkmvAo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730227167; c=relaxed/simple; bh=QIBlHzKCzpo0A0kJ+Ne7rtACUMRu45enr6WWGFjIwAk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=YyzH+XPSSFn2YIx+UtaS4QhPLcC17Y40i6CbS5zsYjAsRp9hffSvIxEa3TAezpoBtLd1/ZRngZ8XAivBY/KOL4Zb2Is9Xr4FiDMgzMHsd8trYfx25AGBPnHp5LfBrfEBiExcFizue8BrDigvCRy5+pxar8KLesoIXPiXsXm//vc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dionnaglaze.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=gHlYeR4W; arc=none smtp.client-ip=209.85.215.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--dionnaglaze.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="gHlYeR4W" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-7eb0a32fc5aso4821698a12.2 for ; Tue, 29 Oct 2024 11:39:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1730227165; x=1730831965; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=VFCC0Ppe61h9DsEPIrRB8kBdqdokYkAqWCjQxVIFEok=; b=gHlYeR4WzPapIGrZKM3D1c9UwgcCv1ioFJsqzkm2x6I5Ncq7smnFwsaflMv8fiU5vs uL7As5pHRRnjfP5Gngl0HBoRslj2VFbT/DAoJ7zEAPo5uw+Z42aGUntyUpnswochB8tP qMmi0juYamDZm7ZOQ0fx4LvMuN04H6/ghCAD5P9Vea0G1K97IVAvY28iwufSo4+hNvLm sYH2kwiTwGl1iS9MUNKzm1POJf3du5biBIC70BCaNb4bZncfhJbh82ETSmWfr+St578s 4O+CH8brHt4s56ACzrbPVSfqNebhz48Xq0c29h045xJFA2BIb0OkFi4TR5lQ9nD8ER2b po6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730227165; x=1730831965; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=VFCC0Ppe61h9DsEPIrRB8kBdqdokYkAqWCjQxVIFEok=; b=rOdWaEU2qmYUkYE+1c0e7d7+Tytoq0rXHN9vWRvWpdRjkUo06Gcuj5xzyhrh3BTtyi TW+PW/u2npimU+vQ30WS2Sh93GOQj7AJL0pmvyRbLfMJIZEfTT9iOrSh2glo4HTkMcV6 1BheoySzjRTqS3gdKPte9QsDDk6YTEJ18Bt/N0KwChWaIMZo+ffQLh8DsJA1bWw4zkFY LUxiPCaPNSKAh2+Cd5e1rxrcC8gsVK1xIE+6erCKqgJ4Qpk/cq94C5JZoabxdlojTBdQ 1iWh3nJLobhtMz02BDRXekfX5ZtDI13YlAYov9CLn+dl6QplKEWvruukwPWI5Qh0m4mA TVJw== X-Gm-Message-State: AOJu0YyhwxajaLDwOSnvZxbBROXR4iuUhsiokE10zjzonkRsOrxexdBP IuyvDFyTdRJwZJaue4FqW/R5wPDPGpW+WIc0jD59dneoaVTN+B+WLnZiCBSaTb7RgBlDkWCSs3Q xP1BfkFfUTVy+ApHkIlFNVnCI26lXhAZQJJSK/UCtGBIu99dOQXiz3/B/6vlSXsL+MC5wAhvjGA 9nHUq7vlj/V3mpVV9aFm55NndtLVwtIbhl/TH11hDWY/Wpi/gWwHE2aDvl1W8RGkdokpU= X-Google-Smtp-Source: AGHT+IHX5lwAS9LIgoFFUtnChrdz7z7B7bwmI4NPfhehjIuR/74lymdkTB0KkRffRLZp83XLD8FH6uu+JFCbE/BFSA== X-Received: from dionnaglaze.c.googlers.com ([fda3:e722:ac3:cc00:36:e7b8:ac13:c9e8]) (user=dionnaglaze job=sendgmr) by 2002:a63:4f62:0:b0:6d4:4eea:bd22 with SMTP id 41be03b00d2f7-7edd7b857bfmr21710a12.4.1730227163130; Tue, 29 Oct 2024 11:39:23 -0700 (PDT) Date: Tue, 29 Oct 2024 18:39:01 +0000 In-Reply-To: <20241029183907.3536683-1-dionnaglaze@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241029183907.3536683-1-dionnaglaze@google.com> X-Mailer: git-send-email 2.47.0.163.g1226f6d8fa-goog Message-ID: <20241029183907.3536683-2-dionnaglaze@google.com> Subject: [PATCH 1/4] kvm: svm: Fix gctx page leak on invalid inputs From: Dionna Glaze To: linux-kernel@vger.kernel.org, x86@kernel.org, Sean Christopherson , Paolo Bonzini , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , Brijesh Singh , Michael Roth , Ashish Kalra Cc: Dionna Glaze , kvm@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Ensure that snp gctx page allocation is adequately deallocated on failure during snp_launch_start. Fixes: 136d8bc931c84f ("KVM: SEV: Add KVM_SEV_SNP_LAUNCH_START command") CC: Sean Christopherson CC: Paolo Bonzini CC: Thomas Gleixner CC: Ingo Molnar CC: Borislav Petkov CC: Dave Hansen Change-Id: Ief6e728d0c859c24a286d8a7e49f9ad2eb47b889 Signed-off-by: Dionna Glaze --- arch/x86/kvm/svm/sev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 714c517dd4b72..f6e96ec0a5caa 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2212,10 +2212,6 @@ static int snp_launch_start(struct kvm *kvm, struct = kvm_sev_cmd *argp) if (sev->snp_context) return -EINVAL; =20 - sev->snp_context =3D snp_context_create(kvm, argp); - if (!sev->snp_context) - return -ENOTTY; - if (params.flags) return -EINVAL; =20 @@ -2230,6 +2226,10 @@ static int snp_launch_start(struct kvm *kvm, struct = kvm_sev_cmd *argp) if (params.policy & SNP_POLICY_MASK_SINGLE_SOCKET) return -EINVAL; =20 + sev->snp_context =3D snp_context_create(kvm, argp); + if (!sev->snp_context) + return -ENOTTY; + start.gctx_paddr =3D __psp_pa(sev->snp_context); start.policy =3D params.policy; memcpy(start.gosvw, params.gosvw, sizeof(params.gosvw)); --=20 2.47.0.163.g1226f6d8fa-goog From nobody Mon Nov 25 05:01:01 2024 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 AAB9F205E2D for ; Tue, 29 Oct 2024 18:39:27 +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=1730227169; cv=none; b=dygGogVtUeX0BlsR63WLlGk6TeyfmXseHhBW9XEtNnIs5b/Uwjt2ItNlAsEqsNE3RQIkH2t1Zgt7nzHHCXfQA18FXYNtx1WbUQ0bhAWoVbRap8p0h/c8V2sUXvUE6qEpK5UjjAV878e/ZoNiPi73N/sOsraWcxDwLQNIrFda6DY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730227169; c=relaxed/simple; bh=94yI4N5JGZdOOiutAa3nIsdWx3G03s90rBf2KdVvRMI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=XzmGf3dJsJwdnOanK3lekaUxPvCIo4cpbek4m281InIZXs3Qbc7pClcUaRgMuy5V1gokKh3RgyzizYvqFQ3DvUKH4zXE0HAZQCZcSkB7F9PEC9w+hdZH1E2h5BIztlPsT8JX/lD554FiC0W/6b8g/UKX9xjynspNAIWoNTwW2Yc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dionnaglaze.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=XfLt64U8; 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--dionnaglaze.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="XfLt64U8" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-20c3d9a0eb2so74209945ad.0 for ; Tue, 29 Oct 2024 11:39:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1730227167; x=1730831967; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=q+sirgv64HIH9D2cMsnXNX5bNxSs6bhRNy8+QTukeFg=; b=XfLt64U8iaOCSwaZe/HrDVckBD2EjR/YdNM+ZtYwxLVH4CxQj4xKhnnOGlQvF3+7PH etqD1wBZBw3lmQBz0/o6GORUNWjCSJ6r9vobL1zkCxEsWhSG7KaECpryjExIdme22H04 kiccs9KilPVBaAW4OUtKIMGCnT4jui/Y/Vob2EPISDpyMtxw/9gklowJvvSmQBYTXlsq HxJ3sfsN2RGgnnTk5+e8fZJATXTFi5+Azx2+QMV8GsRdlbeydqhGvOROjAnFA/I1UbgR xNiJEUbGUfPpAoz9131dD1Cn9yi91YNRNSnt+SA2/EVYptkMUvAe5u+C4KmCTKvMW84n t5jA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730227167; x=1730831967; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=q+sirgv64HIH9D2cMsnXNX5bNxSs6bhRNy8+QTukeFg=; b=wdF9t61doqX1FfNqPNfyGwwHqQb1P8KOXr5WJgqjtCyZmJy6W6ZdypLqdUdPRq9hNg zl6u2dWrPF+PBwhlZBlVyfgw21PC8X85x7KGg7OByvNMkcgof/6giAvSch1+fIQg35xU /8Yfi9HESyHj5iioZplKNEyBpFFYeEP4HnirxuoeTskOU5JHh4k6wf3NXsFauShxWP74 tTQYpZvrHgPmV39tlKbMArt/neQlGyAe47pPuxuzhPHMVEVu9CarJKg2RGv9wwNBQW7y iJ3JOI5gW2V1Rs9OUBixJAk0Yu+7owPS8CST+syQ2tPkJ9nsFILaJYu4S7N201QGmIaM JUDQ== X-Gm-Message-State: AOJu0YwPmqX61Qe0bd334p252xuAC0v1Zb8ezryjD3i51Rk65VbJxtv6 psarzWVSAQLhwZV6xpJkIVNysx4v1rPj6X2Mw7jKcm2jPE0+tw6qK7I45FQV63qxY6kTSj1q96S 59hDrB+iUsJySa8gWkEbVyLNYeZge2GE/kI99HogbWUTksKOgU8+hEBsEKa6oaAXHfuZo1vWnNP AKx1Cr5U7iJ6GF1ziMWbtEEQdK7LPj5KqqHZOAeaHmvyv+MnVNz/4DAgax63IGaMKN3ec= X-Google-Smtp-Source: AGHT+IFs2W/MyS9XsGU5bPCMvLUacuJRkIgwcuKhWpCA0n9zD1Gt02pWARRJIj0P7Rm9hsEly5oft1ma7Sq2HT4aWQ== X-Received: from dionnaglaze.c.googlers.com ([fda3:e722:ac3:cc00:36:e7b8:ac13:c9e8]) (user=dionnaglaze job=sendgmr) by 2002:a17:903:1c3:b0:20c:716c:5af with SMTP id d9443c01a7336-210c68d81b2mr502565ad.3.1730227166315; Tue, 29 Oct 2024 11:39:26 -0700 (PDT) Date: Tue, 29 Oct 2024 18:39:02 +0000 In-Reply-To: <20241029183907.3536683-1-dionnaglaze@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241029183907.3536683-1-dionnaglaze@google.com> X-Mailer: git-send-email 2.47.0.163.g1226f6d8fa-goog Message-ID: <20241029183907.3536683-3-dionnaglaze@google.com> Subject: [PATCH 2/4] firmware_loader: Move module refcounts to allow unloading From: Dionna Glaze To: linux-kernel@vger.kernel.org, x86@kernel.org, Luis Chamberlain , Russ Weight , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tianfei zhang Cc: Dionna Glaze , Russ Weight Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If a kernel module registers a firmware upload API ops set, then it's unable to be moved due to effectively a cyclic reference that the module depends on the upload which depends on the module. Instead, only require the try_module_get when an upload is requested to disallow unloading a module only while the upload is in progress. Fixes: 97730bbb242cd ("firmware_loader: Add firmware-upload support") CC: Luis Chamberlain CC: Russ Weight CC: Danilo Krummrich CC: Greg Kroah-Hartman CC: "Rafael J. Wysocki" CC: Tianfei zhang Signed-off-by: Dionna Glaze Change-Id: Ifac9513de2f58a5120d4c0a681e969cd71cd3c68 --- drivers/base/firmware_loader/sysfs_upload.c | 28 ++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/fir= mware_loader/sysfs_upload.c index 829270067d163..97b0ae855b5f0 100644 --- a/drivers/base/firmware_loader/sysfs_upload.c +++ b/drivers/base/firmware_loader/sysfs_upload.c @@ -103,6 +103,10 @@ static ssize_t cancel_store(struct device *dev, struct= device_attribute *attr, if (fwlp->progress =3D=3D FW_UPLOAD_PROG_IDLE) ret =3D -ENODEV; =20 + /* + * Not idle, so fw_upload_start already called try_module_get. + * No need to get/put around cancel. + */ fwlp->ops->cancel(fwlp->fw_upload); mutex_unlock(&fwlp->lock); =20 @@ -164,11 +168,13 @@ static void fw_upload_main(struct work_struct *work) enum fw_upload_err ret; struct device *fw_dev; struct fw_upload *fwl; + struct module *module; =20 fwlp =3D container_of(work, struct fw_upload_priv, work); fwl =3D fwlp->fw_upload; fw_sysfs =3D (struct fw_sysfs *)fwl->priv; fw_dev =3D &fw_sysfs->dev; + module =3D fwlp->module; =20 fw_upload_update_progress(fwlp, FW_UPLOAD_PROG_PREPARING); ret =3D fwlp->ops->prepare(fwl, fwlp->data, fwlp->remaining_size); @@ -204,6 +210,7 @@ static void fw_upload_main(struct work_struct *work) fwlp->ops->cleanup(fwl); =20 putdev_exit: + module_put(module); put_device(fw_dev->parent); =20 /* @@ -238,7 +245,11 @@ int fw_upload_start(struct fw_sysfs *fw_sysfs) return 0; } =20 + fwlp =3D fw_sysfs->fw_upload_priv; + if (!try_module_get(fwlp->module)) /* released in fw_upload_main */ + return -EFAULT; + mutex_lock(&fwlp->lock); =20 /* Do not interfere with an on-going fw_upload */ @@ -310,13 +321,10 @@ firmware_upload_register(struct module *module, struc= t device *parent, return ERR_PTR(-EINVAL); } =20 - if (!try_module_get(module)) - return ERR_PTR(-EFAULT); - fw_upload =3D kzalloc(sizeof(*fw_upload), GFP_KERNEL); if (!fw_upload) { ret =3D -ENOMEM; - goto exit_module_put; + goto exit_err; } =20 fw_upload_priv =3D kzalloc(sizeof(*fw_upload_priv), GFP_KERNEL); @@ -358,7 +366,7 @@ firmware_upload_register(struct module *module, struct = device *parent, if (ret) { dev_err(fw_dev, "%s: device_register failed\n", __func__); put_device(fw_dev); - goto exit_module_put; + goto exit_err; } =20 return fw_upload; @@ -372,8 +380,7 @@ firmware_upload_register(struct module *module, struct = device *parent, free_fw_upload: kfree(fw_upload); =20 -exit_module_put: - module_put(module); +exit_err: =20 return ERR_PTR(ret); } @@ -387,7 +394,6 @@ void firmware_upload_unregister(struct fw_upload *fw_up= load) { struct fw_sysfs *fw_sysfs =3D fw_upload->priv; struct fw_upload_priv *fw_upload_priv =3D fw_sysfs->fw_upload_priv; - struct module *module =3D fw_upload_priv->module; =20 mutex_lock(&fw_upload_priv->lock); if (fw_upload_priv->progress =3D=3D FW_UPLOAD_PROG_IDLE) { @@ -395,6 +401,11 @@ void firmware_upload_unregister(struct fw_upload *fw_u= pload) goto unregister; } =20 + /* + * No need to try_module_get/module_put around the op since only the + * module itself will call unregister, usually when the refcount has + * dropped to zero and it's cleaning up dependencies to destroy itself. + */ fw_upload_priv->ops->cancel(fw_upload); mutex_unlock(&fw_upload_priv->lock); =20 @@ -403,6 +414,5 @@ void firmware_upload_unregister(struct fw_upload *fw_up= load) =20 unregister: device_unregister(&fw_sysfs->dev); - module_put(module); } EXPORT_SYMBOL_GPL(firmware_upload_unregister); --=20 2.47.0.163.g1226f6d8fa-goog From nobody Mon Nov 25 05:01:01 2024 Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.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 F1A6B1DA305 for ; Tue, 29 Oct 2024 18:39:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730227175; cv=none; b=rGrRCY0cs893EDos70sZ+xH+cEIvWXW7CTERI2JbQ9kuwM1OaVt99uDuXjiuIz1u3F8sJf2TbNOBPsOfmxajADS+rbFDBgNmka+aH9jHGzN2f98oIw6Q4+y0Sqve3IopRZRKAQayaRJ7csLxvZauZApm79jG7HiAtsvo4WUJTi8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730227175; c=relaxed/simple; bh=T2rivRAiC8Z4Tr1Eyh4GGjjedPa64v/mc1wiqkY92ww=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=eOPg7jMPD2qJL/RDWFg0769JAV4f2y2U5AwwqSbvBbiBbet4sgKq9y3CWdpifhKsWT41x7ogj1rey5Ai6G/ZhVGhExYSqGkR6Vse28nTeZ2+J9/mOKIc9IlZWBh87Ojomd30ZaLYrW/TF7H1Ls0IVb0eM/HRDscWI1QMx5fFx9g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dionnaglaze.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ootvFGzr; arc=none smtp.client-ip=209.85.128.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--dionnaglaze.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ootvFGzr" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-6e9d6636498so79637467b3.2 for ; Tue, 29 Oct 2024 11:39:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1730227171; x=1730831971; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=TTk3x5CChIeotgkpQE6tX++ixV+XP+5/E4fu5Geofmc=; b=ootvFGzr9I1Lnrgxq9Ftp8oCBLYlVy0IBaseNsHq4zpjTNoPiDeKOhJ7bm0Te0RLL/ foPXdYsnSwVI+qT4eRru2eMRlBIhxjdct4oqEDi+TIt1wKu7HNqUuZ3Dg20UGBDVQ+29 hGkmsfRuE6/IsbXndXtPPVNoIAU5kkh9V8hx5AkWUYppY8A9o3Nfxdftuk7lnhY8Q894 Zp5U+b/gVjOGN7P/w3Co+IhcV8yBBbYshgci1N/pEw/mPg40HdRkmh+s1M9r5GoxdJyO jJXwB0SOTkw1sGD4mMohpUsCL8GgXc6UI7p5/QqjK/GyeeKTbouV4md0CZLe3JT4ASoa r1dQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730227171; x=1730831971; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=TTk3x5CChIeotgkpQE6tX++ixV+XP+5/E4fu5Geofmc=; b=E8GQ5U5MiVPvnZ5WbsUKZf9naAiNoIcRwX6GhWUA/U8N99buGPEvJU7iiIM+AlElN2 Tz+XSSD2wC91ln3DJN9XZgRjYZo5Q8t3pEitts1RTZ6kLSUHNd/1UrwauF7zHZmTlTeq 4etBA7zLdxRIUN4WYdAxJkhh5QWsq3hSpA+nmJ8n835wadimJ+pvhaLULkSU2noEePkA zZZ5hIqjdNrguceSGUiqpFqzNW2fU2kaEgGwK1jbnpUr9BHrgO3ntuZGnrWyoD64/ZmK BL4Fwz8ivMVCmg5XEeK09OrU/VGKZGb657p9Di3y2qOU6m3yA4kh9gaShWk4ZRTCL5D8 SemA== X-Gm-Message-State: AOJu0YxgK8Ks96v4sUE5ol+1/N3Kkscw5uG8l7s/Irt3d+9hEcAH1CsU wnQgtF6Po0Mqys8VOOo+6gDJJxYpIEYKR7Fc2arJ5BLVF87Jvprv6P4zkifY2BIa98ZcFDzK6Cb c9fV6yS1ZjgRZ+dgthMDo3jc1rW7RMMHJpvLfKuUIvrGEQIstVx3pWE7+sF9A8DUlbPCmVwPK92 vBHxy9pGVfLJ481EkQbJgVlxtEpiRpudIYSQOWLNygM3kqX2WKM1TxUs1N4ozqjeMhonM= X-Google-Smtp-Source: AGHT+IFxFGu+8uvfJ6rFJY7cYkDeTmqIadIoyjO5UEJvePR4uc7OnxNkpGvTkaB9Ktu20kjz+v/AU1Q2xT8xxpDKWw== X-Received: from dionnaglaze.c.googlers.com ([fda3:e722:ac3:cc00:36:e7b8:ac13:c9e8]) (user=dionnaglaze job=sendgmr) by 2002:a25:9c82:0:b0:e30:d445:a7c with SMTP id 3f1490d57ef6-e30d4450d48mr9276.1.1730227170103; Tue, 29 Oct 2024 11:39:30 -0700 (PDT) Date: Tue, 29 Oct 2024 18:39:03 +0000 In-Reply-To: <20241029183907.3536683-1-dionnaglaze@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241029183907.3536683-1-dionnaglaze@google.com> X-Mailer: git-send-email 2.47.0.163.g1226f6d8fa-goog Message-ID: <20241029183907.3536683-4-dionnaglaze@google.com> Subject: [PATCH 3/4] crypto: ccp: Add SNP firmware hotload support From: Dionna Glaze To: linux-kernel@vger.kernel.org, x86@kernel.org, Tom Lendacky , John Allen , Herbert Xu , "David S. Miller" , Ashish Kalra Cc: Dionna Glaze , Michael Roth , "Borislav Petkov (AMD)" , linux-crypto@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" uapi changes: The status values added are defined in AMD's SEV-SNP API documentation as new error modes for the DOWNLOAD_FIRMWARE_EX command. On init, the ccp device will make /sys/class/firmware/amd/loading etc firmware upload API attributes available to late-load a SEV-SNP firmware binary. The firmware upload api errors reported are actionable in the following ways: * FW_UPLOAD_ERR_HW_ERROR: the machine is in an unstable state and must be reset. * FW_UPLOAD_ERR_RW_ERROR: the firmware update went bad but can be recovered by hotloading the previous firmware version. Also used in the case that the kernel used the API wrong (bug). * FW_UPLOAD_ERR_FW_INVALID: user error with the data provided, but no instability is expected and no recovery actions are needed. * FW_UPLOAD_ERR_BUSY: upload attempted at a bad time either due to overload or the machine is in the wrong platform state. snp_asid_to_gctx_page_map: The SEV-SNP API documents that before a firmware is committed, all active GCTX pages should be updated with SNP_GUEST_STATUS to ensure their data structure remaiins consistent for the new firmware version. There can only be cpuid_edx(0x8000001f)-1 many SEV-SNP asids in use at one time, so this map associates asid to gctx in order to track which addresses are active gctx pages that need updating. When an asid and gctx page are decommissioned, the page is removed from tracking for update-purposes. Given that GCTX page creation and binding through the SNP_ACTIVATE command are separate, the creation operation also tracks pages that are yet to be bound to an asid. synthetic_restore_required: Instead of tracking the status of whether an individual GCTX is safe for use in a firmware command, force all following commands to fail with an error that is indicative of needing a firmware rollback. A sev_platform_init call when only SEV-SNP VMs are expected should set supports_download_firmware_ex to delay legacy initialization actions. The firmware can only be hotloaded when legacy initialization has not happened. To test: 1. Build the kernel enabling SEV-SNP as normal and add CONFIG_FW_UPLOAD=3Dy. 2. Add the following to your kernel_cmdline: ccp.psp_init_on_probe=3D0. 3.Get an AMD SEV-SNP firmware sbin appropriate to your Epyc chip model at https://www.amd.com/en/developer/sev.html and extract to get a .sbin file. 4. Run the following with your sbinfile in FW: echo 1 > /sys/class/firmware/snp_dlfw_ex/loading cat "${FW?}" > /sys/class/firmware/snp_dlfw_ex/data echo 0 > /sys/class/firmware/snp_dlfw_ex/loading 5. Verify changes. There is no easy sysfs interface to SNP_PLATFORM_STATUS, you'll need an application to run the ioctl and interpret the results. A before and after should show different CURRENT_TCB, build, minor, major values if you were running an earlier firmware that hotloaded. CC: Ashish Kalra CC: Tom Lendacky CC: John Allen CC: Herbert Xu CC: "David S. Miller" CC: Michael Roth CC: "Borislav Petkov (AMD)" Co-authored-by: Ashish Kalra Change-Id: Id28f9e80ea6eae565503493f874cca685c2b7f1b Signed-off-by: Dionna Glaze --- drivers/crypto/ccp/Kconfig | 2 + drivers/crypto/ccp/sev-dev.c | 398 ++++++++++++++++++++++++++++++++++- drivers/crypto/ccp/sev-dev.h | 14 ++ include/linux/psp-sev.h | 28 +++ include/uapi/linux/psp-sev.h | 5 + 5 files changed, 439 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig index f394e45e11ab4..cd9b667640e7c 100644 --- a/drivers/crypto/ccp/Kconfig +++ b/drivers/crypto/ccp/Kconfig @@ -39,6 +39,8 @@ config CRYPTO_DEV_SP_PSP bool "Platform Security Processor (PSP) device" default y depends on CRYPTO_DEV_CCP_DD && X86_64 && AMD_IOMMU + select FW_LOADER + select FW_UPLOAD help Provide support for the AMD Platform Security Processor (PSP). The PSP is a dedicated processor that provides support for key diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 9810edbb272d2..20232308b1b61 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -223,6 +223,7 @@ static int sev_cmd_buffer_len(int cmd) case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_= request); case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config); case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); + case SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX: return sizeof(struct sev_data_down= load_firmware_ex); default: return 0; } =20 @@ -829,6 +830,7 @@ static int snp_reclaim_cmd_buf(int cmd, void *cmd_buf) return 0; } =20 +static void snp_cmd_bookkeeping_locked(int cmd, struct sev_device *sev, vo= id *data); static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) { struct cmd_buf_desc desc_list[CMD_BUF_DESC_MAX] =3D {0}; @@ -852,6 +854,15 @@ static int __sev_do_cmd_locked(int cmd, void *data, in= t *psp_ret) if (WARN_ON_ONCE(!data !=3D !buf_len)) return -EINVAL; =20 + /* The firmware does not coordinate all GCTX page updates. Force an + * error to ensure that no new VM can be started and no active VM makes + * progress on guest requests until the firmware is rolled back. + */ + if (sev->synthetic_restore_required) { + *psp_ret =3D SEV_RET_RESTORE_REQUIRED; + return -EBUSY; + } + /* * Copy the incoming data to driver's scratch buffer as __pa() will not * work for some memory, e.g. vmalloc'd addresses, and @data may not be @@ -982,6 +993,9 @@ static int __sev_do_cmd_locked(int cmd, void *data, int= *psp_ret) print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data, buf_len, false); =20 + if (!ret) + snp_cmd_bookkeeping_locked(cmd, sev, data); + return ret; } =20 @@ -1082,6 +1096,7 @@ static int snp_filter_reserved_mem_regions(struct res= ource *rs, void *arg) return 0; } =20 +static int sev_snp_platform_init_firmware_upload(struct sev_device *sev); static int __sev_snp_init_locked(int *error) { struct psp_device *psp =3D psp_master; @@ -1179,6 +1194,8 @@ static int __sev_snp_init_locked(int *error) =20 sev_es_tmr_size =3D SNP_TMR_SIZE; =20 + rc =3D sev_snp_platform_init_firmware_upload(sev); + return rc; } =20 @@ -1326,6 +1343,13 @@ static int _sev_platform_init_locked(struct sev_plat= form_init_args *args) if (args->probe && !psp_init_on_probe) return 0; =20 + /* + * Defer legacy SEV/SEV-ES support if legacy VMs are not being launched + * and module psp_init_on_probe parameter is false. + */ + if (args->supports_download_firmware_ex && !psp_init_on_probe) + return 0; + return __sev_platform_init_locked(&args->error); } =20 @@ -1592,14 +1616,8 @@ static int sev_update_firmware(struct device *dev) return -1; } =20 - /* - * SEV FW expects the physical address given to it to be 32 - * byte aligned. Memory allocated has structure placed at the - * beginning followed by the firmware being passed to the SEV - * FW. Allocate enough memory for data structure + alignment - * padding + SEV FW. - */ - data_size =3D ALIGN(sizeof(struct sev_data_download_firmware), 32); + data_size =3D ALIGN(sizeof(struct sev_data_download_firmware), + SEV_FW_ALIGNMENT); =20 order =3D get_order(firmware->size + data_size); p =3D alloc_pages(GFP_KERNEL, order); @@ -2224,6 +2242,366 @@ static int sev_misc_init(struct sev_device *sev) return 0; } =20 +#ifdef CONFIG_FW_UPLOAD + +static enum fw_upload_err snp_dlfw_ex_prepare(struct fw_upload *fw_upload, + const u8 *data, u32 size) +{ + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err snp_dlfw_ex_poll_complete(struct fw_upload *fw_u= pload) +{ + return FW_UPLOAD_ERR_NONE; +} + +/* + * This may be called asynchronously with an on-going update. All other + * functions are called sequentially in a single thread. To avoid contenti= on on + * register accesses, only update the cancel_request flag. Other functions= will + * check this flag and handle the cancel request synchronously. + */ +static void snp_dlfw_ex_cancel(struct fw_upload *fw_upload) +{ + struct sev_device *sev =3D psp_master->sev_data; + + mutex_lock(&sev->fw_lock); + sev->fw_cancel =3D true; + mutex_unlock(&sev->fw_lock); +} + +static enum fw_upload_err snp_dlfw_ex_err_translate(struct sev_device *sev= , int psp_ret) +{ + dev_dbg(sev->dev, "Failed to update SEV firmware: %#x\n", psp_ret); + /* + * Operation error: + * HW_ERROR: Critical error. Machine needs repairs now. + * RW_ERROR: Severe error. Roll back to the prior version to recover. + * User error: + * FW_INVALID: Bad input for this interface. + * BUSY: Wrong machine state to run download_firmware_ex. + */ + switch (psp_ret) { + case SEV_RET_RESTORE_REQUIRED: + dev_warn(sev->dev, "Firmware updated but unusable\n"); + dev_warn(sev->dev, "Need to do manual firmware rollback!!!\n"); + return FW_UPLOAD_ERR_RW_ERROR; + case SEV_RET_SHUTDOWN_REQUIRED: + /* No state changes made. Not a hardware error. */ + dev_warn(sev->dev, "Firmware image cannot be live updated\n"); + return FW_UPLOAD_ERR_FW_INVALID; + case SEV_RET_BAD_VERSION: + /* No state changes made. Not a hardware error. */ + dev_warn(sev->dev, "Firmware image is not well formed\n"); + return FW_UPLOAD_ERR_FW_INVALID; + /* SEV-specific errors that can still happen. */ + case SEV_RET_BAD_SIGNATURE: + /* No state changes made. Not a hardware error. */ + dev_warn(sev->dev, "Firmware image signature is bad\n"); + return FW_UPLOAD_ERR_FW_INVALID; + case SEV_RET_INVALID_PLATFORM_STATE: + /* Calling at the wrong time. Not a hardware error. */ + dev_warn(sev->dev, "Firmware not updated as SEV in INIT state\n"); + return FW_UPLOAD_ERR_BUSY; + case SEV_RET_HWSEV_RET_UNSAFE: + dev_err(sev->dev, "Firmware is unstable. Reset your machine!!!\n"); + return FW_UPLOAD_ERR_HW_ERROR; + /* Kernel bug cases. */ + case SEV_RET_INVALID_PARAM: + dev_err(sev->dev, "Download-firmware-EX invalid parameter\n"); + return FW_UPLOAD_ERR_RW_ERROR; + case SEV_RET_INVALID_ADDRESS: + dev_err(sev->dev, "Download-firmware-EX invalid address\n"); + return FW_UPLOAD_ERR_RW_ERROR; + default: + dev_err(sev->dev, "Unhandled download_firmware_ex err %d\n", psp_ret); + return FW_UPLOAD_ERR_HW_ERROR; + } +} + +static enum fw_upload_err snp_dlfw_ex_write(struct fw_upload *fwl, const u= 8 *data, + u32 offset, u32 size, u32 *written) +{ + struct sev_data_download_firmware_ex *data_ex; + struct sev_data_snp_guest_status status_data; + struct sev_device *sev =3D fwl->dd_handle; + void *snp_guest_status, *fw_dest; + u8 api_major, api_minor, build; + int ret, error, order; + struct page *p; + u64 data_size; + bool cancel; + + if (!sev) + return FW_UPLOAD_ERR_HW_ERROR; + + mutex_lock(&sev->fw_lock); + cancel =3D sev->fw_cancel; + mutex_unlock(&sev->fw_lock); + + if (cancel) + return FW_UPLOAD_ERR_CANCELED; + + /* + * SEV firmware update is a one-shot update operation, the write() + * callback to be invoked multiple times for the same update is + * unexpected. + */ + if (offset) + return FW_UPLOAD_ERR_INVALID_SIZE; + + if (sev_get_api_version()) + return FW_UPLOAD_ERR_HW_ERROR; + + api_major =3D sev->api_major; + api_minor =3D sev->api_minor; + build =3D sev->build; + + data_size =3D ALIGN(sizeof(struct sev_data_download_firmware_ex), + SEV_FW_ALIGNMENT); + + order =3D get_order(size + data_size); + p =3D alloc_pages(GFP_KERNEL, order); + if (!p) { + ret =3D FW_UPLOAD_ERR_INVALID_SIZE; + goto fw_err; + } + + /* + * Copy firmware data to a kernel allocated contiguous + * memory region. + */ + data_ex =3D page_address(p); + fw_dest =3D page_address(p) + data_size; + memcpy(fw_dest, data, size); + + data_ex->address =3D __psp_pa(fw_dest); + data_ex->len =3D size; + data_ex->cmdlen =3D sizeof(struct sev_data_download_firmware_ex); + + /* + * SNP_COMMIT should be issued explicitly to commit the updated + * firmware after guest context pages have been updated. + */ + + ret =3D sev_do_cmd(SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX, data_ex, &error); + + if (ret) { + ret =3D snp_dlfw_ex_err_translate(sev, error); + goto free_err; + } + + __free_pages(p, order); + + /* Need to do a DF_FLUSH after live firmware update */ + wbinvd_on_all_cpus(); + ret =3D __sev_do_cmd_locked(SEV_CMD_SNP_DF_FLUSH, NULL, &error); + if (ret) { + dev_dbg(sev->dev, "DF_FLUSH error %d\n", error); + ret =3D FW_UPLOAD_ERR_HW_ERROR; + goto free_err; + } + + sev_get_api_version(); + + /* + * Force an update of guest context pages after SEV firmware + * live update by issuing SNP_GUEST_STATUS on all guest + * context pages. + */ + snp_guest_status =3D sev_fw_alloc(PAGE_SIZE); + if (!snp_guest_status) { + ret =3D FW_UPLOAD_ERR_INVALID_SIZE; + goto free_err; + } + + /* + * After the last bound asid-to-gctx page is snp_unbound_gctx_end-many + * unbound gctx pages that also need updating. + */ + for (int i =3D 1; i <=3D sev->last_snp_asid + sev->snp_unbound_gctx_end; = i++) { + if (sev->snp_asid_to_gctx_pages_map[i]) { + status_data.gctx_paddr =3D sev->snp_asid_to_gctx_pages_map[i]; + status_data.address =3D __psp_pa(snp_guest_status); + ret =3D sev_do_cmd(SEV_CMD_SNP_GUEST_STATUS, &status_data, &error); + if (ret) { + /* + * Handle race with SNP VM being destroyed/decommissoned, + * if guest context page invalid error is returned, + * assume guest has been destroyed. + */ + if (error =3D=3D SEV_RET_INVALID_GUEST) + continue; + sev->synthetic_restore_required =3D true; + dev_err(sev->dev, "Failed to update SNP GCTX after firmware update, %#= x\n", error); + dev_err(sev->dev, "Need to do manual SNP firmware rollback!!!\n"); + snp_free_firmware_page(snp_guest_status); + ret =3D FW_UPLOAD_ERR_RW_ERROR; + goto free_err; + } + } + } + snp_free_firmware_page(snp_guest_status); + + if (api_major !=3D sev->api_major || api_minor !=3D sev->api_minor || + build !=3D sev->build) { + dev_info(sev->dev, "SEV firmware updated from %d.%d.%d to %d.%d.%d\n", + api_major, api_minor, build, + sev->api_major, sev->api_minor, sev->build); + } else { + dev_info(sev->dev, "SEV firmware same as old %d.%d.%d\n", + api_major, api_minor, build); + } + + *written =3D size; + return FW_UPLOAD_ERR_NONE; + +free_err: + __free_pages(p, order); +fw_err: + return ret; +} + +static const struct fw_upload_ops snp_dlfw_ex_ops =3D { + .prepare =3D snp_dlfw_ex_prepare, + .write =3D snp_dlfw_ex_write, + .poll_complete =3D snp_dlfw_ex_poll_complete, + .cancel =3D snp_dlfw_ex_cancel, +}; + +static void sev_snp_dev_init_firmware_upload(struct sev_device *sev) +{ + struct fw_upload *fwl; + + fwl =3D firmware_upload_register(THIS_MODULE, sev->dev, "snp_dlfw_ex", &s= np_dlfw_ex_ops, sev); + + if (IS_ERR(fwl)) + dev_err(sev->dev, "SEV firmware upload failed to initialize, err %ld\n",= PTR_ERR(fwl)); + + sev->fwl =3D fwl; + mutex_init(&sev->fw_lock); +} + +static void sev_snp_destroy_firmware_upload(struct sev_device *sev) +{ + firmware_upload_unregister(sev->fwl); +} + +/* + * After a gctx is created, it is used by snp_launch_start before getting + * bound to an asid. The launch protocol allocates an asid before creating= a + * matching gctx page, so there should never be more unbound gctx pages th= an + * there are possible SNP asids. + * + * The unbound gctx pages must be updated after executing DOWNLOAD_FIRMWAR= E_EX + * and before committing the firmware. + */ +static void snp_gctx_create_track_locked(struct sev_device *sev, void *dat= a) +{ + struct sev_data_snp_addr *gctx_create =3D data; + + /* This condition should never happen, but is needed for memory safety. */ + if (sev->snp_unbound_gctx_end >=3D sev->last_snp_asid) { + dev_warn(sev->dev, "Too many unbound SNP GCTX pages to track\n"); + return; + } + + sev->snp_unbound_gctx_pages[sev->snp_unbound_gctx_end] =3D gctx_create->a= ddress; + sev->snp_unbound_gctx_end++; +} + +/* + * PREREQUISITE: The snp_activate command was successful, meaning the asid + * is in the acceptable range 1..sev->last_snp_asid. + * + * The gctx_paddr must be in the unbound gctx buffer. + */ +static void snp_activate_track_locked(struct sev_device *sev, void *data) +{ + struct sev_data_snp_activate *data_activate =3D data; + + sev->snp_asid_to_gctx_pages_map[data_activate->asid] =3D data_activate->g= ctx_paddr; + + for (int i =3D 0; i < sev->snp_unbound_gctx_end; i++) { + if (sev->snp_unbound_gctx_pages[i] =3D=3D data_activate->gctx_paddr) { + /* + * Swap the last unbound gctx page with the now-bound + * gctx page to shrink the buffer. + */ + sev->snp_unbound_gctx_end--; + sev->snp_unbound_gctx_pages[i] =3D sev->snp_unbound_gctx_pages[sev->snp= _unbound_gctx_end]; + sev->snp_unbound_gctx_pages[sev->snp_unbound_gctx_end] =3D 0; + break; + } + } +} + +static void snp_decommission_track_locked(struct sev_device *sev, void *da= ta) +{ + struct sev_data_snp_addr *data_decommission =3D data; + + for (int i =3D 1; i <=3D sev->last_snp_asid; i++) { + if (sev->snp_asid_to_gctx_pages_map[i] =3D=3D data_decommission->address= ) { + sev->snp_asid_to_gctx_pages_map[i] =3D 0; + break; + } + } +} + +static void snp_cmd_bookkeeping_locked(int cmd, struct sev_device *sev, vo= id *data) +{ + if (!sev->snp_asid_to_gctx_pages_map) + return; + + switch (cmd) + { + case SEV_CMD_SNP_GCTX_CREATE: + snp_gctx_create_track_locked(sev, data); + break; + case SEV_CMD_SNP_ACTIVATE: + snp_activate_track_locked(sev, data); + break; + case SEV_CMD_SNP_DECOMMISSION: + snp_decommission_track_locked(sev, data); + break; + default: + ; + } +} + +static int sev_snp_platform_init_firmware_upload(struct sev_device *sev) +{ + u32 max_snp_asid; + + /* + * cpuid_edx(0x8000001f) is the minimum SEV ASID, hence the exclusive + * maximum SEV-SNP ASID. Save the inclusive maximum to avoid confusing + * logic elsewhere. + */ + max_snp_asid =3D cpuid_edx(0x8000001f); + sev->last_snp_asid =3D max_snp_asid - 1; + if (sev->last_snp_asid) { + sev->snp_asid_to_gctx_pages_map =3D devm_kmalloc_array( + sev->dev, max_snp_asid * 2, sizeof(u64), GFP_KERNEL | __GFP_ZERO); + sev->snp_unbound_gctx_pages =3D &sev->snp_asid_to_gctx_pages_map[max_snp= _asid]; + if (!sev->snp_asid_to_gctx_pages_map) { + kfree(snp_range_list); + dev_err(sev->dev, + "SEV-SNP: snp_asid_to_gctx_pages_map memory allocation failed\n"); + return -ENOMEM; + } + } + return 0; +} + +#else + +static int sev_snp_platform_init_firmware_upload(struct sev_device *sev) {= return 0; } +static void sev_snp_dev_init_firmware_upload(struct sev_device *sev) { } +static void sev_snp_destroy_firmware_upload(struct sev_device *sev) { } +static void snp_cmd_bookkeeping_locked(int cmd, struct sev_device *sev, vo= id *data) { } +#endif + int sev_dev_init(struct psp_device *psp) { struct device *dev =3D psp->dev; @@ -2265,6 +2643,8 @@ int sev_dev_init(struct psp_device *psp) if (ret) goto e_irq; =20 + sev_snp_dev_init_firmware_upload(sev); + dev_notice(dev, "sev enabled\n"); =20 return 0; @@ -2343,6 +2723,8 @@ void sev_dev_destroy(struct psp_device *psp) kref_put(&misc_dev->refcount, sev_exit); =20 psp_clear_sev_irq_handler(psp); + + sev_snp_destroy_firmware_upload(sev); } =20 static int snp_shutdown_on_panic(struct notifier_block *nb, diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h index 3e4e5574e88a3..d6280688675d9 100644 --- a/drivers/crypto/ccp/sev-dev.h +++ b/drivers/crypto/ccp/sev-dev.h @@ -57,6 +57,20 @@ struct sev_device { bool cmd_buf_backup_active; =20 bool snp_initialized; + +#ifdef CONFIG_FW_UPLOAD + /* Lock to protect fw_cancel */ + struct mutex fw_lock; + struct fw_upload *fwl; + bool fw_cancel; + + /* Firmware update management. */ + u32 last_snp_asid; + bool synthetic_restore_required; + u64 *snp_asid_to_gctx_pages_map; + u64 *snp_unbound_gctx_pages; + u32 snp_unbound_gctx_end; +#endif /* CONFIG_FW_UPLOAD */ }; =20 int sev_dev_init(struct psp_device *psp); diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index 903ddfea85850..61ed2f8179946 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -16,6 +16,15 @@ =20 #define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ =20 +/* + * SEV FW expects the physical address given to it to be 32 + * byte aligned. Memory allocated has structure placed at the + * beginning followed by the firmware being passed to the SEV + * FW. Allocate enough memory for data structure + alignment + * padding + SEV FW. + */ +#define SEV_FW_ALIGNMENT 32 + /** * SEV platform state */ @@ -185,6 +194,22 @@ struct sev_data_download_firmware { u32 len; /* In */ } __packed; =20 +/** + * struct sev_data_download_firmware_ex - DOWNLOAD_FIRMWARE_EX command par= ameters + * + * @length: length of this command buffer + * @address: physical address of firmware image + * @len: len of the firmware image + * @commit: automatically commit the newly installed image + */ +struct sev_data_download_firmware_ex { + u32 cmdlen; /* In */ + u32 reserved; /* in */ + u64 address; /* In */ + u32 len; /* In */ + u32 commit:1; /* In */ +} __packed; + /** * struct sev_data_get_id - GET_ID command parameters * @@ -797,10 +822,13 @@ struct sev_data_snp_shutdown_ex { * @probe: True if this is being called as part of CCP module probe, which * will defer SEV_INIT/SEV_INIT_EX firmware initialization until needed * unless psp_init_on_probe module param is set + * @supports_download_firmware_ex: True if legacy SEV/SEV-ES guests are not + * being launched via KVM */ struct sev_platform_init_args { int error; bool probe; + bool supports_download_firmware_ex; }; =20 /** diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h index 832c15d9155bd..936464d4f282a 100644 --- a/include/uapi/linux/psp-sev.h +++ b/include/uapi/linux/psp-sev.h @@ -80,6 +80,11 @@ typedef enum { SEV_RET_INVALID_PAGE_OWNER, SEV_RET_INVALID_PAGE_AEAD_OFLOW, SEV_RET_RMP_INIT_REQUIRED, + SEV_RET_BAD_SVN, + SEV_RET_BAD_VERSION, + SEV_RET_SHUTDOWN_REQUIRED, + SEV_RET_UPDATE_FAILED, + SEV_RET_RESTORE_REQUIRED, SEV_RET_MAX, } sev_ret_code; =20 --=20 2.47.0.163.g1226f6d8fa-goog From nobody Mon Nov 25 05:01:01 2024 Received: from mail-yb1-f202.google.com (mail-yb1-f202.google.com [209.85.219.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 E4C9F20101B for ; Tue, 29 Oct 2024 18:39:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730227176; cv=none; b=L/sac6Hsfxs6owR8FumcwdPcg3e4DCU2F2A6gdGN3S14kzymnRLEIXpBKBP1sL6FsoLhciyAV28NkJSd5v3GWH/ys3liNnn5EAjuY1BwxIM1L9oZRJyR5VW+ftnlcOTxT57Ahn/79cFDfc5BniqY73Mtxik2X3lPuxwFaT3a/W4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730227176; c=relaxed/simple; bh=vT6UGaJCAHZQdweFlVmqsA0PbWlxvJ3lJa2y/UVhQX8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=LWGvV1fgJS81fL2k/WlH8V0lJQhSqq88OGxnElk8p8iJzOZvy6LMcIjgX3PNpXhNHrjvvyJTvoWEl2e3RA79gWPU660RfaDw7McDA05G+dykB0xKzQu7rfj0gTtxCbm8zwwbLG95SiUTgiFuxghUZPTRhFBlQ7EITM2r2tc6dhE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dionnaglaze.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Dwm81zay; arc=none smtp.client-ip=209.85.219.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--dionnaglaze.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Dwm81zay" Received: by mail-yb1-f202.google.com with SMTP id 3f1490d57ef6-e290b8b69f8so9581477276.2 for ; Tue, 29 Oct 2024 11:39:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1730227174; x=1730831974; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=nIzbr7zBh90Qk+4L+ha95UM8CI0cs/ioObBQO0IhCVc=; b=Dwm81zaycXRQq8ZUe56aUt0w2oAqC5/o0g0Qy4tSUYO0IpxPw/U9NQSzK7OEpqX7Kh HRANug3eagNeRfQqcAi23oc+LYOOu7QniXrGDroFq/vFGA05im+SBpwLj68iH6bwOtro /iggKnARKWrJitgHfugWNmzBDc0kVzfQerxjBtPBW8c8dcktAKIMgDNHKbrp4nXT94W9 Apw3F3xkIwz+U1C2QKtqTMV/+HyUo7ahcavHG/ZDuBn4GdgWXq9D/d4Apy8BZPh2W1KO 4Ph6XoXBT4Rbr5AAHQRDeZvzC6xQjwDkiKlV2mHhj4/kG4+LW8hvCzMYV4Chu+L+BVV3 YmSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730227174; x=1730831974; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=nIzbr7zBh90Qk+4L+ha95UM8CI0cs/ioObBQO0IhCVc=; b=vcmqs7Xdqk7OHPPPzHBgH9uBDkZTv84KQuTX/1okCfxGxaKhNmx/7ZH+x26UaLWglB 9l3oUejCRLOvRio7x7sEUI/5S/QkADeQqXedpyXzqGLICJwBHDe6sr9LB4rvNVb16xC6 g2qywPw2e910011sU+UsMl1swEUUW9/Xl0NGsyNyu0wOuuchmmQN+xjrYkfIcT8kklWE nPjsrXdIzge+Ux3b2c3cDFS65+c86XmXs2GCxznGuL4vVLI7iPy0mclxbTB0Db4gz+Nx vk9p5KECSMqHyRyZ0MfOUenc+GmOSgsrjBSzNngH0TUY4o/XdoT9ob70n1jLhBQxgIZQ b2tQ== X-Gm-Message-State: AOJu0YxwXFI0THxuu6cnqvp5VJaCuvXU/N0SyZ6GeMOySPkWc2+y5C0X m2EEKoosLWQckBiVJ/bAhG5pK7tBNxlzr17M351OVdJPgupHrfQL/CPpNzgdgy92Oil9Gv7czJs IUtHlEsrD10fH2ZFBwuBKW/txHv756mMsOkMdIiNZJc5OQFnnBZ3sL2R1VBV7uVRuaheyLNC5RE xuum8JFe6xw9sN3rk0Cttw7c7JsqwEvz0N9RyChqmd1+bv1ejvK5lMjHFaxThOtX44ejo= X-Google-Smtp-Source: AGHT+IHSZ9z1gKFuoLjow1B8gxL4DLpvVpticofCNjquLeMSvisfqXyLo4Rn8guu4cbEwZ/Xr0RyrrNg9xIAoplbLg== X-Received: from dionnaglaze.c.googlers.com ([fda3:e722:ac3:cc00:36:e7b8:ac13:c9e8]) (user=dionnaglaze job=sendgmr) by 2002:a25:18b:0:b0:e20:2502:be14 with SMTP id 3f1490d57ef6-e30cf49aefcmr320276.7.1730227173530; Tue, 29 Oct 2024 11:39:33 -0700 (PDT) Date: Tue, 29 Oct 2024 18:39:04 +0000 In-Reply-To: <20241029183907.3536683-1-dionnaglaze@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241029183907.3536683-1-dionnaglaze@google.com> X-Mailer: git-send-email 2.47.0.163.g1226f6d8fa-goog Message-ID: <20241029183907.3536683-5-dionnaglaze@google.com> Subject: [PATCH 4/4] KVM: SVM: Delay legacy platform initialization on SNP From: Dionna Glaze To: linux-kernel@vger.kernel.org, x86@kernel.org, Sean Christopherson , Paolo Bonzini , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" Cc: Dionna Glaze , Ashish Kalra , kvm@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When no SEV or SEV-ES guests are active, then the firmware can be updated while (SEV-SNP) VM guests are active. CC: Sean Christopherson CC: Paolo Bonzini CC: Thomas Gleixner CC: Ingo Molnar CC: Borislav Petkov CC: Dave Hansen Co-authored-by: Ashish Kalra Change-Id: I3efb5fbbd0da05ab29f85504a86693f5cdf49050 Signed-off-by: Dionna Glaze Reviewed-by: Ashish Kalra --- arch/x86/kvm/svm/sev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index f6e96ec0a5caa..8d365e2e3c1b1 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -445,6 +445,8 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm= _sev_cmd *argp, goto e_no_asid; =20 init_args.probe =3D false; + init_args.supports_download_firmware_ex =3D + vm_type !=3D KVM_X86_SEV_VM && vm_type !=3D KVM_X86_SEV_ES_VM; ret =3D sev_platform_init(&init_args); if (ret) goto e_free; --=20 2.47.0.163.g1226f6d8fa-goog