Message ID | 20240115011546.21193-1-dpsmith@apertussolutions.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-25577-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:693c:2614:b0:101:6a76:bbe3 with SMTP id mm20csp1441820dyc; Sun, 14 Jan 2024 17:16:33 -0800 (PST) X-Google-Smtp-Source: AGHT+IGuAcCHnjcGM1Ki+s4t08blZu82MRpKejiBNZpaA2lNKYD9WTg3SJP1BvY7VYWp5+VS3I3x X-Received: by 2002:a17:902:c3d1:b0:1d4:ac2b:7601 with SMTP id j17-20020a170902c3d100b001d4ac2b7601mr5017314plj.38.1705281393141; Sun, 14 Jan 2024 17:16:33 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1705281393; cv=pass; d=google.com; s=arc-20160816; b=tF/gaIQ0ZlRQigs1xQM2+hVmtpq8dF9Im1DhIguirf0utD2Qy8/cY0vpO++DeuUjhx QgTSKS78mjxgLrl33L3vchfujUfN1LUl6ZZlpVkcIx/x92pk1wSTvuOUVMLqaci5zqUT FYrXO4r2wtrp0voXFOMxEIcqgbcs7vvdI7jY7PoQDT78AODKSLYvI4qIxZuaZ0Mql9j6 g+jjK0bxla5FUnAcXIBGbdMpHHLjwCymIUj9PUu16s1JfDEaVFVjDF1MIA1AcdmLeRto 9Z8eOneOhqYSWgROW2BcLNnpsMB8k7llLeX3ebiQ8mfWdhovMkWiaua5h9uMAnTcBpMm 6Hsw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:date:subject:cc:to :from:dkim-signature:delivered-to; bh=zLf9QVptryF0InKzR9EnfMAiKSvtoQon6fPnRpBNJf8=; fh=S2fiimOylfDN0P4urHkwN6aORERL4WEcK/vLqL941Zk=; b=PVW+x0fUV1E7c/pkY0dKkRH/JPmxhEDjdCF6l7weRuO6gE+F1dha+ndSaCOGKaJeAU 6cekhIEVFOERFajC9Vgl+Uf/b5aRggkr8ebJmf5DmkXf72mIMQB4JCREFP4ZJXKVFrxu WLdhHYmGr6dzcXRI0MHFV9Bxjdg6sf9I4tIHyAVnTfScn3RO0TPiKeJcGXRStDkEDvKy dJ8IxRzQSuco/StuyTGMkO/v3v+x9zHnXcgcHC+JVEUz2+QGyXBAIpFv7fr2WTxDPb/M BBI0S7uv5nBBjBhmFG2RlTG9pORnQliZdoD/1F0NCBXo82STSJepNb6xSLNEs0DExgUO FhCw== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@apertussolutions.com header.s=zoho header.b=REKN8IlM; arc=pass (i=1 spf=pass spfdomain=apertussolutions.com dkim=pass dkdomain=apertussolutions.com dmarc=pass fromdomain=apertussolutions.com>); spf=pass (google.com: domain of linux-kernel+bounces-25577-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-25577-ouuuleilei=gmail.com@vger.kernel.org" Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [2604:1380:45e3:2400::1]) by mx.google.com with ESMTPS id kg4-20020a170903060400b001cfba8ff230si7429865plb.268.2024.01.14.17.16.33 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 14 Jan 2024 17:16:33 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-25577-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) client-ip=2604:1380:45e3:2400::1; Authentication-Results: mx.google.com; dkim=pass header.i=@apertussolutions.com header.s=zoho header.b=REKN8IlM; arc=pass (i=1 spf=pass spfdomain=apertussolutions.com dkim=pass dkdomain=apertussolutions.com dmarc=pass fromdomain=apertussolutions.com>); spf=pass (google.com: domain of linux-kernel+bounces-25577-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-25577-ouuuleilei=gmail.com@vger.kernel.org" Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id E099D28155D for <ouuuleilei@gmail.com>; Mon, 15 Jan 2024 01:16:32 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id C24B9186A; Mon, 15 Jan 2024 01:16:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=apertussolutions.com header.i=dpsmith@apertussolutions.com header.b="REKN8IlM" Received: from sender4-of-o50.zoho.com (sender4-of-o50.zoho.com [136.143.188.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5B087137B; Mon, 15 Jan 2024 01:16:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=apertussolutions.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=apertussolutions.com Delivered-To: dpsmith@apertussolutions.com ARC-Seal: i=1; a=rsa-sha256; t=1705281357; cv=none; d=zohomail.com; s=zohoarc; b=jAuUvxVU8D23KdA/HZzdCYNvhAgM+U2WBQn/wpcFl3at/a7pKAY6U5Y8n9xcyCPfABMDNOCWj55cmjZ0rN7Xv3Mz2o8uWEOKV7WK7s9P+o8U7PB2PJh1e4SiPEDZcsJLE0SeAXhU0QIASsZFzZ4/HQTizxx6W1W2tWDTEZbbiCc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1705281357; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=zLf9QVptryF0InKzR9EnfMAiKSvtoQon6fPnRpBNJf8=; b=AVEbSNz512ykrZY1XLGhjtJNfbD1VYDoe/IzDbx8nOqrKSI982N6IdpKErV3vzquzvC5YSvCt7wgoeJ8hy91bhpPSAam46SC6qqxzz8F0igywFLcrCYAY/32OnEvMrmcaFKkbalL2qaTYZGtH6OmllNd1HB+fRPDfzeTHBDyoqQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=apertussolutions.com; spf=pass smtp.mailfrom=dpsmith@apertussolutions.com; dmarc=pass header.from=<dpsmith@apertussolutions.com> DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1705281357; s=zoho; d=apertussolutions.com; i=dpsmith@apertussolutions.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=zLf9QVptryF0InKzR9EnfMAiKSvtoQon6fPnRpBNJf8=; b=REKN8IlMTZyPV8JlO3ggYaFu6+/zE+z2855+XdJ+CJ4Z3kYVyBr1achSluEl8lQ3 z9w5VcizG8PhPrkirrcC+6XQ9+ri5dKUY9i76jpBff/Z5lN9ELhTrrb8nwXz4qTfx4S yN8E8gMManHaWMD9NRr2O//JG7ELgFWOA+jlzU0o= Received: from sisyou.hme. (static-72-81-132-2.bltmmd.fios.verizon.net [72.81.132.2]) by mx.zohomail.com with SMTPS id 1705281355612388.34342267689556; Sun, 14 Jan 2024 17:15:55 -0800 (PST) From: "Daniel P. Smith" <dpsmith@apertussolutions.com> To: Jason Gunthorpe <jgg@ziepe.ca>, Jarkko Sakkinen <jarkko@kernel.org>, Lino Sanfilippo <l.sanfilippo@kunbus.com>, Sasha Levin <sashal@kernel.org>, linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org Cc: "Daniel P. Smith" <dpsmith@apertussolutions.com>, Ross Philipson <ross.philipson@oracle.com>, Kanth Ghatraju <kanth.ghatraju@oracle.com>, Peter Huewe <peterhuewe@gmx.de> Subject: [PATCH] tpm: make locality handling resilient Date: Sun, 14 Jan 2024 20:15:44 -0500 Message-Id: <20240115011546.21193-1-dpsmith@apertussolutions.com> X-Mailer: git-send-email 2.30.2 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-ZohoMailClient: External X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1788117141985745870 X-GMAIL-MSGID: 1788117141985745870 |
Series |
tpm: make locality handling resilient
|
|
Commit Message
Daniel P. Smith
Jan. 15, 2024, 1:15 a.m. UTC
Commit 933bfc5ad213 introduced the use of a locality counter to control when locality request was actually sent to the TPM. This locality counter created a hard enforcement that the TPM had no active locality at the time of the driver initialization. The reality is that this may not always be the case coupled with the fact that the commit indiscriminately decremented the counter created the condition for integer underflow of the counter. The underflow was triggered by the first pair of request/relinquish calls made in tpm_tis_init_core and all subsequent calls to request/relinquished calls would have the counter flipping between the underflow value and 0. The result is that it appeared all calls to request/relinquish were successful, but they were not. The end result is that the locality that was active when the driver loaded would always remain active, to include after the driver shutdown. This creates a significant issue when using Intel TXT and Locality 2 is active at boot. After the GETSEC[SEXIT] instruction is called, the PCH will close access to Locality 2 MMIO address space, leaving the TPM locked in Locality 2 with no means to relinquish the locality until system reset. The commit seeks to address this situation through three changes. The first is to walk the localities during initialization and close any open localities to ensure the TPM is in the assumed state. Next is to put guards around the counter and the requested locality to ensure they remain within valid values. The last change is to make the request locality functions be consistent in their return values. The functions will either return the locality requested if successful or a negative error code. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Ross Philipson <ross.philipson@oracle.com> Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com> Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality") --- drivers/char/tpm/tpm-chip.c | 2 +- drivers/char/tpm/tpm_tis_core.c | 20 +++++++++++++++----- include/linux/tpm.h | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-)
Comments
On 15.01.2024 02:15, Daniel P. Smith wrote: > Commit 933bfc5ad213 introduced the use of a locality counter to control when > locality request was actually sent to the TPM. This locality counter created a > hard enforcement that the TPM had no active locality at the time of the driver > initialization. The reality is that this may not always be the case coupled > with the fact that the commit indiscriminately decremented the counter created > the condition for integer underflow of the counter. The underflow was triggered > by the first pair of request/relinquish calls made in tpm_tis_init_core and all > subsequent calls to request/relinquished calls would have the counter flipping > between the underflow value and 0. The result is that it appeared all calls to > request/relinquish were successful, but they were not. The end result is that > the locality that was active when the driver loaded would always remain active, > to include after the driver shutdown. This creates a significant issue when > using Intel TXT and Locality 2 is active at boot. After the GETSEC[SEXIT] > instruction is called, the PCH will close access to Locality 2 MMIO address > space, leaving the TPM locked in Locality 2 with no means to relinquish the > locality until system reset. > > The commit seeks to address this situation through three changes. Could you split this up into multiple patches then, so that they can be discussed separately? > The first is > to walk the localities during initialization and close any open localities to > ensure the TPM is in the assumed state. Next is to put guards around the > counter and the requested locality to ensure they remain within valid values. > The last change is to make the request locality functions be consistent in > their return values. The functions will either return the locality requested if > successful or a negative error code. > > Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> > Signed-off-by: Ross Philipson <ross.philipson@oracle.com> > Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com> > Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality") > --- > drivers/char/tpm/tpm-chip.c | 2 +- > drivers/char/tpm/tpm_tis_core.c | 20 +++++++++++++++----- > include/linux/tpm.h | 2 ++ > 3 files changed, 18 insertions(+), 6 deletions(-) > > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c > index 42b1062e33cd..e7293f85335a 100644 > --- a/drivers/char/tpm/tpm-chip.c > +++ b/drivers/char/tpm/tpm-chip.c > @@ -49,7 +49,7 @@ static int tpm_request_locality(struct tpm_chip *chip) > return rc; > > chip->locality = rc; > - return 0; > + return chip->locality; > } > > static void tpm_relinquish_locality(struct tpm_chip *chip) > diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c > index 1b350412d8a6..c8b9b0b199dc 100644 > --- a/drivers/char/tpm/tpm_tis_core.c > +++ b/drivers/char/tpm/tpm_tis_core.c > @@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l) > struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > > mutex_lock(&priv->locality_count_mutex); > - priv->locality_count--; > + if (priv->locality_count > 0) > + priv->locality_count--; > if (priv->locality_count == 0) > __tpm_tis_relinquish_locality(priv, l); > mutex_unlock(&priv->locality_count_mutex); > @@ -226,18 +227,21 @@ static int __tpm_tis_request_locality(struct tpm_chip *chip, int l) > tpm_msleep(TPM_TIMEOUT); > } while (time_before(jiffies, stop)); > } > - return -1; > + return -EBUSY; > } > > static int tpm_tis_request_locality(struct tpm_chip *chip, int l) > { > struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > - int ret = 0; > + int ret = -EIO; > + > + if (l > TPM_MAX_LOCALITY) > + return -EINVAL; > > mutex_lock(&priv->locality_count_mutex); > if (priv->locality_count == 0) > ret = __tpm_tis_request_locality(chip, l); > - if (!ret) > + if (ret >= 0) > priv->locality_count++; > mutex_unlock(&priv->locality_count_mutex); > return ret; This line seems to be the most important change, that fixes the locality_count handling for localities != 0. It could already be sufficient to fix your original problem. I'm not sure all the other changes are really necessary. > @@ -1108,7 +1112,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, > u32 intmask; > u32 clkrun_val; > u8 rid; > - int rc, probe; > + int rc, probe, locality; > struct tpm_chip *chip; > > chip = tpmm_chip_alloc(dev, &tpm_tis); > @@ -1169,6 +1173,12 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, > goto out_err; > } > > + /* It is not safe to assume localities are closed on startup */ > + for (locality = 0; locality <= TPM_MAX_LOCALITY; locality++) { > + if (check_locality(chip, locality)) > + tpm_tis_relinquish_locality(chip, locality); > + } > + > /* Take control of the TPM's interrupt hardware and shut it off */ > rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); > if (rc < 0) > diff --git a/include/linux/tpm.h b/include/linux/tpm.h > index 4ee9d13749ad..f2651281f02e 100644 > --- a/include/linux/tpm.h > +++ b/include/linux/tpm.h > @@ -116,6 +116,8 @@ struct tpm_chip_seqops { > const struct seq_operations *seqops; > }; > > +#define TPM_MAX_LOCALITY 4 > + > struct tpm_chip { > struct device dev; > struct device devs; > -- > 2.30.2 >
On Mon Jan 15, 2024 at 1:15 AM UTC, Daniel P. Smith wrote: > Commit 933bfc5ad213 introduced the use of a locality counter to control when > locality request was actually sent to the TPM. This locality counter created a > hard enforcement that the TPM had no active locality at the time of the driver > initialization. The reality is that this may not always be the case coupled > with the fact that the commit indiscriminately decremented the counter created > the condition for integer underflow of the counter. The underflow was triggered > by the first pair of request/relinquish calls made in tpm_tis_init_core and all > subsequent calls to request/relinquished calls would have the counter flipping > between the underflow value and 0. The result is that it appeared all calls to > request/relinquish were successful, but they were not. The end result is that > the locality that was active when the driver loaded would always remain active, > to include after the driver shutdown. This creates a significant issue when > using Intel TXT and Locality 2 is active at boot. After the GETSEC[SEXIT] > instruction is called, the PCH will close access to Locality 2 MMIO address > space, leaving the TPM locked in Locality 2 with no means to relinquish the > locality until system reset. > > The commit seeks to address this situation through three changes. The first is > to walk the localities during initialization and close any open localities to > ensure the TPM is in the assumed state. Next is to put guards around the > counter and the requested locality to ensure they remain within valid values. > The last change is to make the request locality functions be consistent in > their return values. The functions will either return the locality requested if > successful or a negative error code. > > Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> > Signed-off-by: Ross Philipson <ross.philipson@oracle.com> > Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com> > Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality") > --- > drivers/char/tpm/tpm-chip.c | 2 +- > drivers/char/tpm/tpm_tis_core.c | 20 +++++++++++++++----- > include/linux/tpm.h | 2 ++ > 3 files changed, 18 insertions(+), 6 deletions(-) > > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c > index 42b1062e33cd..e7293f85335a 100644 > --- a/drivers/char/tpm/tpm-chip.c > +++ b/drivers/char/tpm/tpm-chip.c > @@ -49,7 +49,7 @@ static int tpm_request_locality(struct tpm_chip *chip) > return rc; > > chip->locality = rc; > - return 0; > + return chip->locality; > } > > static void tpm_relinquish_locality(struct tpm_chip *chip) > diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c > index 1b350412d8a6..c8b9b0b199dc 100644 > --- a/drivers/char/tpm/tpm_tis_core.c > +++ b/drivers/char/tpm/tpm_tis_core.c > @@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l) > struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > > mutex_lock(&priv->locality_count_mutex); > - priv->locality_count--; > + if (priv->locality_count > 0) > + priv->locality_count--; > if (priv->locality_count == 0) > __tpm_tis_relinquish_locality(priv, l); > mutex_unlock(&priv->locality_count_mutex); > @@ -226,18 +227,21 @@ static int __tpm_tis_request_locality(struct tpm_chip *chip, int l) > tpm_msleep(TPM_TIMEOUT); > } while (time_before(jiffies, stop)); > } > - return -1; > + return -EBUSY; > } > > static int tpm_tis_request_locality(struct tpm_chip *chip, int l) > { > struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > - int ret = 0; > + int ret = -EIO; > + > + if (l > TPM_MAX_LOCALITY) > + return -EINVAL; > > mutex_lock(&priv->locality_count_mutex); > if (priv->locality_count == 0) > ret = __tpm_tis_request_locality(chip, l); > - if (!ret) > + if (ret >= 0) > priv->locality_count++; > mutex_unlock(&priv->locality_count_mutex); > return ret; > @@ -1108,7 +1112,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, > u32 intmask; > u32 clkrun_val; > u8 rid; > - int rc, probe; > + int rc, probe, locality; s/locality/i/ We don't use long names for loop indices generally. > struct tpm_chip *chip; > > chip = tpmm_chip_alloc(dev, &tpm_tis); > @@ -1169,6 +1173,12 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, > goto out_err; > } > > + /* It is not safe to assume localities are closed on startup */ This is somewhat useless comment. E.g. this would be way more useful: /* * Intel TXT starts with locality 2 active. Therefore, * localities cannot be assumed to be closed on startup. */ > + for (locality = 0; locality <= TPM_MAX_LOCALITY; locality++) { > + if (check_locality(chip, locality)) > + tpm_tis_relinquish_locality(chip, locality); > + } > + > /* Take control of the TPM's interrupt hardware and shut it off */ > rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); > if (rc < 0) > diff --git a/include/linux/tpm.h b/include/linux/tpm.h > index 4ee9d13749ad..f2651281f02e 100644 > --- a/include/linux/tpm.h > +++ b/include/linux/tpm.h > @@ -116,6 +116,8 @@ struct tpm_chip_seqops { > const struct seq_operations *seqops; > }; > > +#define TPM_MAX_LOCALITY 4 Not documented. > + > struct tpm_chip { > struct device dev; > struct device devs; Thanks for the fix. BR, Jarkko
On Wed Jan 17, 2024 at 8:44 AM UTC, Alexander Steffen wrote: > On 15.01.2024 02:15, Daniel P. Smith wrote: > > Commit 933bfc5ad213 introduced the use of a locality counter to control when > > locality request was actually sent to the TPM. This locality counter created a > > hard enforcement that the TPM had no active locality at the time of the driver > > initialization. The reality is that this may not always be the case coupled > > with the fact that the commit indiscriminately decremented the counter created > > the condition for integer underflow of the counter. The underflow was triggered > > by the first pair of request/relinquish calls made in tpm_tis_init_core and all > > subsequent calls to request/relinquished calls would have the counter flipping > > between the underflow value and 0. The result is that it appeared all calls to > > request/relinquish were successful, but they were not. The end result is that > > the locality that was active when the driver loaded would always remain active, > > to include after the driver shutdown. This creates a significant issue when > > using Intel TXT and Locality 2 is active at boot. After the GETSEC[SEXIT] > > instruction is called, the PCH will close access to Locality 2 MMIO address > > space, leaving the TPM locked in Locality 2 with no means to relinquish the > > locality until system reset. > > > > The commit seeks to address this situation through three changes. > > Could you split this up into multiple patches then, so that they can be > discussed separately? I have to agree with you ttly. Yeah also the text above is not exactly in the ballpark. I did not understand what I read. I had to read the code change instead to get an idea. A huge pile of text does not equal to stronger story. Like for any essay, scientific paper or a kernel message one should do also few edit rounds. The commit message is more important than the code change itself in bug fixes... There is trigger (TXT) and solution. A great commit message should have motivation and implementation parts and somewhat concise story where things lead to another. It should essentially make *any* reader who knows the basics of kernel code base convinced, not confused. This is at leat a good aim even tho sometimes unreachable. BR, Jarkko
On 1/17/24 03:44, Alexander Steffen wrote: > On 15.01.2024 02:15, Daniel P. Smith wrote: >> Commit 933bfc5ad213 introduced the use of a locality counter to >> control when >> locality request was actually sent to the TPM. This locality counter >> created a >> hard enforcement that the TPM had no active locality at the time of >> the driver >> initialization. The reality is that this may not always be the case >> coupled >> with the fact that the commit indiscriminately decremented the counter >> created >> the condition for integer underflow of the counter. The underflow was >> triggered >> by the first pair of request/relinquish calls made in >> tpm_tis_init_core and all >> subsequent calls to request/relinquished calls would have the counter >> flipping >> between the underflow value and 0. The result is that it appeared all >> calls to >> request/relinquish were successful, but they were not. The end result >> is that >> the locality that was active when the driver loaded would always >> remain active, >> to include after the driver shutdown. This creates a significant issue >> when >> using Intel TXT and Locality 2 is active at boot. After the GETSEC[SEXIT] >> instruction is called, the PCH will close access to Locality 2 MMIO >> address >> space, leaving the TPM locked in Locality 2 with no means to >> relinquish the >> locality until system reset. >> >> The commit seeks to address this situation through three changes. > > Could you split this up into multiple patches then, so that they can be > discussed separately? Gladly, but individually none of these fully address the situation. >> The first is >> to walk the localities during initialization and close any open >> localities to >> ensure the TPM is in the assumed state. Next is to put guards around the >> counter and the requested locality to ensure they remain within valid >> values. >> The last change is to make the request locality functions be >> consistent in >> their return values. The functions will either return the locality >> requested if >> successful or a negative error code. >> >> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> >> Signed-off-by: Ross Philipson <ross.philipson@oracle.com> >> Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com> >> Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality") >> --- >> drivers/char/tpm/tpm-chip.c | 2 +- >> drivers/char/tpm/tpm_tis_core.c | 20 +++++++++++++++----- >> include/linux/tpm.h | 2 ++ >> 3 files changed, 18 insertions(+), 6 deletions(-) >> >> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c >> index 42b1062e33cd..e7293f85335a 100644 >> --- a/drivers/char/tpm/tpm-chip.c >> +++ b/drivers/char/tpm/tpm-chip.c >> @@ -49,7 +49,7 @@ static int tpm_request_locality(struct tpm_chip *chip) >> return rc; >> >> chip->locality = rc; >> - return 0; >> + return chip->locality; >> } >> >> static void tpm_relinquish_locality(struct tpm_chip *chip) >> diff --git a/drivers/char/tpm/tpm_tis_core.c >> b/drivers/char/tpm/tpm_tis_core.c >> index 1b350412d8a6..c8b9b0b199dc 100644 >> --- a/drivers/char/tpm/tpm_tis_core.c >> +++ b/drivers/char/tpm/tpm_tis_core.c >> @@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct >> tpm_chip *chip, int l) >> struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); >> >> mutex_lock(&priv->locality_count_mutex); >> - priv->locality_count--; >> + if (priv->locality_count > 0) >> + priv->locality_count--; >> if (priv->locality_count == 0) >> __tpm_tis_relinquish_locality(priv, l); >> mutex_unlock(&priv->locality_count_mutex); >> @@ -226,18 +227,21 @@ static int __tpm_tis_request_locality(struct >> tpm_chip *chip, int l) >> tpm_msleep(TPM_TIMEOUT); >> } while (time_before(jiffies, stop)); >> } >> - return -1; >> + return -EBUSY; >> } >> >> static int tpm_tis_request_locality(struct tpm_chip *chip, int l) >> { >> struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); >> - int ret = 0; >> + int ret = -EIO; >> + >> + if (l > TPM_MAX_LOCALITY) >> + return -EINVAL; >> >> mutex_lock(&priv->locality_count_mutex); >> if (priv->locality_count == 0) >> ret = __tpm_tis_request_locality(chip, l); >> - if (!ret) >> + if (ret >= 0) >> priv->locality_count++; >> mutex_unlock(&priv->locality_count_mutex); >> return ret; > > This line seems to be the most important change, that fixes the > locality_count handling for localities != 0. It could already be > sufficient to fix your original problem. I'm not sure all the other > changes are really necessary. It do not believe this fully address the issue. It does stop the underflow but locality still is not being properly tracked. >> @@ -1108,7 +1112,7 @@ int tpm_tis_core_init(struct device *dev, struct >> tpm_tis_data *priv, int irq, >> u32 intmask; >> u32 clkrun_val; >> u8 rid; >> - int rc, probe; >> + int rc, probe, locality; >> struct tpm_chip *chip; >> >> chip = tpmm_chip_alloc(dev, &tpm_tis); >> @@ -1169,6 +1173,12 @@ int tpm_tis_core_init(struct device *dev, >> struct tpm_tis_data *priv, int irq, >> goto out_err; >> } >> >> + /* It is not safe to assume localities are closed on startup */ >> + for (locality = 0; locality <= TPM_MAX_LOCALITY; locality++) { >> + if (check_locality(chip, locality)) >> + tpm_tis_relinquish_locality(chip, locality); >> + } >> + >> /* Take control of the TPM's interrupt hardware and shut it >> off */ >> rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), >> &intmask); >> if (rc < 0) >> diff --git a/include/linux/tpm.h b/include/linux/tpm.h >> index 4ee9d13749ad..f2651281f02e 100644 >> --- a/include/linux/tpm.h >> +++ b/include/linux/tpm.h >> @@ -116,6 +116,8 @@ struct tpm_chip_seqops { >> const struct seq_operations *seqops; >> }; >> >> +#define TPM_MAX_LOCALITY 4 >> + >> struct tpm_chip { >> struct device dev; >> struct device devs; >> -- >> 2.30.2 >>
On 1/19/24 16:28, Jarkko Sakkinen wrote: > On Mon Jan 15, 2024 at 1:15 AM UTC, Daniel P. Smith wrote: >> Commit 933bfc5ad213 introduced the use of a locality counter to control when >> locality request was actually sent to the TPM. This locality counter created a >> hard enforcement that the TPM had no active locality at the time of the driver >> initialization. The reality is that this may not always be the case coupled >> with the fact that the commit indiscriminately decremented the counter created >> the condition for integer underflow of the counter. The underflow was triggered >> by the first pair of request/relinquish calls made in tpm_tis_init_core and all >> subsequent calls to request/relinquished calls would have the counter flipping >> between the underflow value and 0. The result is that it appeared all calls to >> request/relinquish were successful, but they were not. The end result is that >> the locality that was active when the driver loaded would always remain active, >> to include after the driver shutdown. This creates a significant issue when >> using Intel TXT and Locality 2 is active at boot. After the GETSEC[SEXIT] >> instruction is called, the PCH will close access to Locality 2 MMIO address >> space, leaving the TPM locked in Locality 2 with no means to relinquish the >> locality until system reset. >> >> The commit seeks to address this situation through three changes. The first is >> to walk the localities during initialization and close any open localities to >> ensure the TPM is in the assumed state. Next is to put guards around the >> counter and the requested locality to ensure they remain within valid values. >> The last change is to make the request locality functions be consistent in >> their return values. The functions will either return the locality requested if >> successful or a negative error code. >> >> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> >> Signed-off-by: Ross Philipson <ross.philipson@oracle.com> >> Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com> >> Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality") >> --- >> drivers/char/tpm/tpm-chip.c | 2 +- >> drivers/char/tpm/tpm_tis_core.c | 20 +++++++++++++++----- >> include/linux/tpm.h | 2 ++ >> 3 files changed, 18 insertions(+), 6 deletions(-) >> >> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c >> index 42b1062e33cd..e7293f85335a 100644 >> --- a/drivers/char/tpm/tpm-chip.c >> +++ b/drivers/char/tpm/tpm-chip.c >> @@ -49,7 +49,7 @@ static int tpm_request_locality(struct tpm_chip *chip) >> return rc; >> >> chip->locality = rc; >> - return 0; >> + return chip->locality; >> } >> >> static void tpm_relinquish_locality(struct tpm_chip *chip) >> diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c >> index 1b350412d8a6..c8b9b0b199dc 100644 >> --- a/drivers/char/tpm/tpm_tis_core.c >> +++ b/drivers/char/tpm/tpm_tis_core.c >> @@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l) >> struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); >> >> mutex_lock(&priv->locality_count_mutex); >> - priv->locality_count--; >> + if (priv->locality_count > 0) >> + priv->locality_count--; >> if (priv->locality_count == 0) >> __tpm_tis_relinquish_locality(priv, l); >> mutex_unlock(&priv->locality_count_mutex); >> @@ -226,18 +227,21 @@ static int __tpm_tis_request_locality(struct tpm_chip *chip, int l) >> tpm_msleep(TPM_TIMEOUT); >> } while (time_before(jiffies, stop)); >> } >> - return -1; >> + return -EBUSY; >> } >> >> static int tpm_tis_request_locality(struct tpm_chip *chip, int l) >> { >> struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); >> - int ret = 0; >> + int ret = -EIO; >> + >> + if (l > TPM_MAX_LOCALITY) >> + return -EINVAL; >> >> mutex_lock(&priv->locality_count_mutex); >> if (priv->locality_count == 0) >> ret = __tpm_tis_request_locality(chip, l); >> - if (!ret) >> + if (ret >= 0) >> priv->locality_count++; >> mutex_unlock(&priv->locality_count_mutex); >> return ret; >> @@ -1108,7 +1112,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, >> u32 intmask; >> u32 clkrun_val; >> u8 rid; >> - int rc, probe; >> + int rc, probe, locality; > > s/locality/i/ > > We don't use long names for loop indices generally. No problem, will change. >> struct tpm_chip *chip; >> >> chip = tpmm_chip_alloc(dev, &tpm_tis); >> @@ -1169,6 +1173,12 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, >> goto out_err; >> } >> >> + /* It is not safe to assume localities are closed on startup */ > > This is somewhat useless comment. > > E.g. this would be way more useful: > > /* > * Intel TXT starts with locality 2 active. Therefore, > * localities cannot be assumed to be closed on startup. > */ Okay, will expand. >> + for (locality = 0; locality <= TPM_MAX_LOCALITY; locality++) { >> + if (check_locality(chip, locality)) >> + tpm_tis_relinquish_locality(chip, locality); >> + } >> + >> /* Take control of the TPM's interrupt hardware and shut it off */ >> rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); >> if (rc < 0) >> diff --git a/include/linux/tpm.h b/include/linux/tpm.h >> index 4ee9d13749ad..f2651281f02e 100644 >> --- a/include/linux/tpm.h >> +++ b/include/linux/tpm.h >> @@ -116,6 +116,8 @@ struct tpm_chip_seqops { >> const struct seq_operations *seqops; >> }; >> >> +#define TPM_MAX_LOCALITY 4 > > Not documented. Okay, will add spec ref. >> + >> struct tpm_chip { >> struct device dev; >> struct device devs; > > Thanks for the fix. Your welcome. > BR, Jarkko V/r, DPS
On Thu Jan 25, 2024 at 2:01 AM EET, Daniel P. Smith wrote: > > Could you split this up into multiple patches then, so that they can be > > discussed separately? > > Gladly, but individually none of these fully address the situation. The total number of scenarios described was exactly zero meaning for us that a situation does not exist with our current pool of knowledge :-) I wonder what sort of scenario requires all those changes applied at once in order to get fixed. BR, Jarkko
Hi, On 15.01.24 02:15, Daniel P. Smith wrote: > Commit 933bfc5ad213 introduced the use of a locality counter to control when > locality request was actually sent to the TPM. This locality counter created a > hard enforcement that the TPM had no active locality at the time of the driver > initialization. The reality is that this may not always be the case coupled > with the fact that the commit indiscriminately decremented the counter created > the condition for integer underflow of the counter. The underflow was triggered > by the first pair of request/relinquish calls made in tpm_tis_init_core and all > subsequent calls to request/relinquished calls would have the counter flipping > between the underflow value and 0. The result is that it appeared all calls to > request/relinquish were successful, but they were not. The end result is that > the locality that was active when the driver loaded would always remain active, > to include after the driver shutdown. This creates a significant issue when > using Intel TXT and Locality 2 is active at boot. After the GETSEC[SEXIT] > instruction is called, the PCH will close access to Locality 2 MMIO address > space, leaving the TPM locked in Locality 2 with no means to relinquish the > locality until system reset. > > The commit seeks to address this situation through three changes. The first is > to walk the localities during initialization and close any open localities to > ensure the TPM is in the assumed state. Next is to put guards around the > counter and the requested locality to ensure they remain within valid values. > The last change is to make the request locality functions be consistent in > their return values. The functions will either return the locality requested if > successful or a negative error code. > > Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> > Signed-off-by: Ross Philipson <ross.philipson@oracle.com> > Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com> > Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality") > --- > drivers/char/tpm/tpm-chip.c | 2 +- > drivers/char/tpm/tpm_tis_core.c | 20 +++++++++++++++----- > include/linux/tpm.h | 2 ++ > 3 files changed, 18 insertions(+), 6 deletions(-) > > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c > index 42b1062e33cd..e7293f85335a 100644 > --- a/drivers/char/tpm/tpm-chip.c > +++ b/drivers/char/tpm/tpm-chip.c > @@ -49,7 +49,7 @@ static int tpm_request_locality(struct tpm_chip *chip) > return rc; > > chip->locality = rc; > - return 0; > + return chip->locality; > } > > static void tpm_relinquish_locality(struct tpm_chip *chip) > diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c > index 1b350412d8a6..c8b9b0b199dc 100644 > --- a/drivers/char/tpm/tpm_tis_core.c > +++ b/drivers/char/tpm/tpm_tis_core.c > @@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l) > struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > > mutex_lock(&priv->locality_count_mutex); > - priv->locality_count--; > + if (priv->locality_count > 0) > + priv->locality_count--; > if (priv->locality_count == 0) > __tpm_tis_relinquish_locality(priv, l); > mutex_unlock(&priv->locality_count_mutex); > @@ -226,18 +227,21 @@ static int __tpm_tis_request_locality(struct tpm_chip *chip, int l) > tpm_msleep(TPM_TIMEOUT); > } while (time_before(jiffies, stop)); > } > - return -1; > + return -EBUSY; Why do we want to return -EBUSY now? This does not seem to have anything to do with the issue you are trying to solve. > } > > static int tpm_tis_request_locality(struct tpm_chip *chip, int l) > { > struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > - int ret = 0; > + int ret = -EIO; > + > + if (l > TPM_MAX_LOCALITY) > + return -EINVAL; How can it happen that l > TPM_MAX_LOCALITY? > > mutex_lock(&priv->locality_count_mutex); > if (priv->locality_count == 0) > ret = __tpm_tis_request_locality(chip, l); > - if (!ret) > + if (ret >= 0) > priv->locality_count++; > mutex_unlock(&priv->locality_count_mutex); > return ret; > @@ -1108,7 +1112,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, > u32 intmask; > u32 clkrun_val; > u8 rid; > - int rc, probe; > + int rc, probe, locality; > struct tpm_chip *chip; > > chip = tpmm_chip_alloc(dev, &tpm_tis); > @@ -1169,6 +1173,12 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, > goto out_err; > } > > + /* It is not safe to assume localities are closed on startup */ > + for (locality = 0; locality <= TPM_MAX_LOCALITY; locality++) { > + if (check_locality(chip, locality)) > + tpm_tis_relinquish_locality(chip, locality); > + } > + wait_startup() already needs a locality, so this has to be done before that function. Furthermore you can simply use __tpm_tis_relinquish_locality() as there is not concurrency involved at this point. With that you can IMHO spare everything else and the complete fix can be broken down to: for (i = 0; i <= MAX_LOCALITY; i++) __tpm_tis_relinquish_locality(priv, i); > /* Take control of the TPM's interrupt hardware and shut it off */ > rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); > if (rc < 0) > diff --git a/include/linux/tpm.h b/include/linux/tpm.h > index 4ee9d13749ad..f2651281f02e 100644 > --- a/include/linux/tpm.h > +++ b/include/linux/tpm.h > @@ -116,6 +116,8 @@ struct tpm_chip_seqops { > const struct seq_operations *seqops; > }; > > +#define TPM_MAX_LOCALITY 4 > + > struct tpm_chip { > struct device dev; > struct device devs; > -- > 2.30.2 > Regards, Lino
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 42b1062e33cd..e7293f85335a 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -49,7 +49,7 @@ static int tpm_request_locality(struct tpm_chip *chip) return rc; chip->locality = rc; - return 0; + return chip->locality; } static void tpm_relinquish_locality(struct tpm_chip *chip) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 1b350412d8a6..c8b9b0b199dc 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l) struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); mutex_lock(&priv->locality_count_mutex); - priv->locality_count--; + if (priv->locality_count > 0) + priv->locality_count--; if (priv->locality_count == 0) __tpm_tis_relinquish_locality(priv, l); mutex_unlock(&priv->locality_count_mutex); @@ -226,18 +227,21 @@ static int __tpm_tis_request_locality(struct tpm_chip *chip, int l) tpm_msleep(TPM_TIMEOUT); } while (time_before(jiffies, stop)); } - return -1; + return -EBUSY; } static int tpm_tis_request_locality(struct tpm_chip *chip, int l) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); - int ret = 0; + int ret = -EIO; + + if (l > TPM_MAX_LOCALITY) + return -EINVAL; mutex_lock(&priv->locality_count_mutex); if (priv->locality_count == 0) ret = __tpm_tis_request_locality(chip, l); - if (!ret) + if (ret >= 0) priv->locality_count++; mutex_unlock(&priv->locality_count_mutex); return ret; @@ -1108,7 +1112,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, u32 intmask; u32 clkrun_val; u8 rid; - int rc, probe; + int rc, probe, locality; struct tpm_chip *chip; chip = tpmm_chip_alloc(dev, &tpm_tis); @@ -1169,6 +1173,12 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, goto out_err; } + /* It is not safe to assume localities are closed on startup */ + for (locality = 0; locality <= TPM_MAX_LOCALITY; locality++) { + if (check_locality(chip, locality)) + tpm_tis_relinquish_locality(chip, locality); + } + /* Take control of the TPM's interrupt hardware and shut it off */ rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); if (rc < 0) diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 4ee9d13749ad..f2651281f02e 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -116,6 +116,8 @@ struct tpm_chip_seqops { const struct seq_operations *seqops; }; +#define TPM_MAX_LOCALITY 4 + struct tpm_chip { struct device dev; struct device devs;