From patchwork Tue Jun 20 12:44:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Loehle X-Patchwork-Id: 13285794 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 18C34EB64D7 for ; Tue, 20 Jun 2023 12:44:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230295AbjFTMor (ORCPT ); Tue, 20 Jun 2023 08:44:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60622 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229933AbjFTMoq (ORCPT ); Tue, 20 Jun 2023 08:44:46 -0400 Received: from mail5.swissbit.com (mail5.swissbit.com [148.251.244.252]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0D79E10DD; Tue, 20 Jun 2023 05:44:45 -0700 (PDT) Received: from mail5.swissbit.com (localhost [127.0.0.1]) by DDEI (Postfix) with ESMTP id 79E173A2694; Tue, 20 Jun 2023 14:44:43 +0200 (CEST) Received: from mail5.swissbit.com (localhost [127.0.0.1]) by DDEI (Postfix) with ESMTP id 58B873A25AA; Tue, 20 Jun 2023 14:44:43 +0200 (CEST) X-TM-AS-ERS: 10.181.10.103-127.5.254.253 X-TM-AS-SMTP: 1.0 bXgxLmRtei5zd2lzc2JpdC5jb20= Y2xvZWhsZUBoeXBlcnN0b25lLmNvb Q== X-DDEI-TLS-USAGE: Used Received: from mx1.dmz.swissbit.com (mx1.dmz.swissbit.com [10.181.10.103]) by mail5.swissbit.com (Postfix) with ESMTPS; Tue, 20 Jun 2023 14:44:43 +0200 (CEST) From: Christian Loehle To: "linux-mmc@vger.kernel.org" , "linux-kernel@vger.kernel.org" , Ulf Hansson , Adrian Hunter CC: Avri Altman Subject: [PATCHv3 1/1] mmc: block: ioctl: Add PROG-error aggregation Thread-Topic: [PATCHv3 1/1] mmc: block: ioctl: Add PROG-error aggregation Thread-Index: AdmjdCfpdU8NnQgrT4iRiz4+JBhVQw== Date: Tue, 20 Jun 2023 12:44:41 +0000 Message-ID: <26d178dcfc2f4b7d9010145d0c051394@hyperstone.com> Accept-Language: en-US, de-DE Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: MIME-Version: 1.0 X-TMASE-Version: DDEI-5.1-9.0.1002-27702.007 X-TMASE-Result: 10--14.337600-10.000000 X-TMASE-MatchedRID: U3PagEpWyqJvBOh2s92TSM2CuVPkCNzu2FA7wK9mP9fG5dXdQTj2OIGz z42T0DP5p3HiycuTwqB22LX9ExaXqivLSgqaAVoR9k0tWBWiOf/5UnqVnIHSz40nZyQtGDZRcQn 7AixVvVx72aKohPmGR8+cZr5skxwlUIGCvH0MbYudx4sU8R+eYNUEOicf335Wyuet65/g7pDwbY qNisklFI8eV9xXSOFA5p98cjyQCaIdj9vNGYhpkfZOZ2c2VQUgrzD8YrC59vwQRik6+J7XSekgE vppMdRRihBIRRThmIoXIQarK0WBEPTxGqS5mxwxSHCU59h5KrGc0xEjtkduy0Jv2xLgykjPrcmm D7/hK1+jDiEYA0mQt2c8Uo6La8PbOwBXM346/+zMw/TUDMCQo6lkWO1bfLIA5CAYYsadb/lnUw9 Y1e62m9Sq60+KNPxX X-TMASE-SNAP-Result: 1.821001.0001-0-1-22:0,33:0,34:0-0 X-TMASE-INERTIA: 0-0;;;; X-TMASE-XGENCLOUD: b4ac2a58-d29d-4cc3-b17b-fb2b7a638e28-0-0-200-0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org Userspace currently has no way of checking for error bits of detection mode X. These are error bits that are only detected by the card when executing the command. For e.g. a sanitize operation this may be minutes after the RSP was seen by the host. Currently userspace programs cannot see these error bits reliably. They could issue a multi ioctl cmd with a CMD13 immediately following it, but since errors of detection mode X are automatically cleared (they are all clear condition B). mmc_poll_for_busy of the first ioctl may have already hidden such an error flag. In case of the security operations: sanitize, secure erases and RPMB writes, this could lead to the operation not being performed successfully by the card with the user not knowing. If the user trusts that this operation is completed (e.g. their data is sanitized), this could be a security issue. An attacker could e.g. provoke a eMMC (VCC) flash fail, where a successful sanitize of a card is not possible. A card may move out of PROG state but issue a bit 19 R1 error. This patch therefore will also have the consequence of a mmc-utils patch, which enables the bit for the security-sensitive operations. Signed-off-by: Christian Loehle Acked-by: Avri Altman --- drivers/mmc/core/block.c | 26 +++++++++++++++----------- drivers/mmc/core/mmc_ops.c | 14 +++++++------- drivers/mmc/core/mmc_ops.h | 9 +++++++++ 3 files changed, 31 insertions(+), 18 deletions(-) -- 2.37.3 diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index e46330815484..c7e2b8ae58a9 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -470,7 +470,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct mmc_data data = {}; struct mmc_request mrq = {}; struct scatterlist sg; - bool r1b_resp, use_r1b_resp = false; + bool r1b_resp; unsigned int busy_timeout_ms; int err; unsigned int target_part; @@ -551,8 +551,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, busy_timeout_ms = idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS; r1b_resp = (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B; if (r1b_resp) - use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd, - busy_timeout_ms); + mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout_ms); mmc_wait_for_req(card->host, &mrq); memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp)); @@ -605,19 +604,24 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, if (idata->ic.postsleep_min_us) usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us); - /* No need to poll when using HW busy detection. */ - if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) - return 0; - if (mmc_host_is_spi(card->host)) { if (idata->ic.write_flag || r1b_resp || cmd.flags & MMC_RSP_SPI_BUSY) return mmc_spi_err_check(card); return err; } - /* Ensure RPMB/R1B command has completed by polling with CMD13. */ - if (idata->rpmb || r1b_resp) - err = mmc_poll_for_busy(card, busy_timeout_ms, false, - MMC_BUSY_IO); + /* Poll for RPMB/write/R1B execution errors */ + if (idata->rpmb || idata->ic.write_flag || r1b_resp) { + struct mmc_busy_data cb_data; + + cb_data.card = card; + cb_data.retry_crc_err = false; + cb_data.aggregate_err_flags = true; + cb_data.busy_cmd = MMC_BUSY_IO; + cb_data.status = &idata->ic.response[0]; + err = __mmc_poll_for_busy(card->host, 0, busy_timeout_ms, + &mmc_busy_cb, &cb_data); + + } return err; } diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 3b3adbddf664..15d8b806c670 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -54,11 +54,6 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -struct mmc_busy_data { - struct mmc_card *card; - bool retry_crc_err; - enum mmc_busy_cmd busy_cmd; -}; struct mmc_op_cond_busy_data { struct mmc_host *host; @@ -457,14 +452,15 @@ int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal) return mmc_switch_status_error(card->host, status); } -static int mmc_busy_cb(void *cb_data, bool *busy) +int mmc_busy_cb(void *cb_data, bool *busy) { struct mmc_busy_data *data = cb_data; struct mmc_host *host = data->card->host; u32 status = 0; int err; - if (data->busy_cmd != MMC_BUSY_IO && host->ops->card_busy) { + if (data->busy_cmd != MMC_BUSY_IO && host->ops->card_busy && + !data->aggregate_err_flags) { *busy = host->ops->card_busy(host); return 0; } @@ -477,6 +473,9 @@ static int mmc_busy_cb(void *cb_data, bool *busy) if (err) return err; + if (data->aggregate_err_flags) + *data->status = R1_STATUS(*data->status) | status; + switch (data->busy_cmd) { case MMC_BUSY_CMD6: err = mmc_switch_status_error(host, status); @@ -549,6 +548,7 @@ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, cb_data.card = card; cb_data.retry_crc_err = retry_crc_err; + cb_data.aggregate_err_flags = false; cb_data.busy_cmd = busy_cmd; return __mmc_poll_for_busy(host, 0, timeout_ms, &mmc_busy_cb, &cb_data); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 09ffbc00908b..a57751b83f19 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -18,6 +18,14 @@ enum mmc_busy_cmd { MMC_BUSY_IO, }; +struct mmc_busy_data { + struct mmc_card *card; + bool retry_crc_err; + bool aggregate_err_flags; + enum mmc_busy_cmd busy_cmd; + u32 *status; +}; + struct mmc_host; struct mmc_card; struct mmc_command; @@ -41,6 +49,7 @@ int mmc_can_ext_csd(struct mmc_card *card); int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal); bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd, unsigned int timeout_ms); +int mmc_busy_cb(void *cb_data, bool *busy); int __mmc_poll_for_busy(struct mmc_host *host, unsigned int period_us, unsigned int timeout_ms, int (*busy_cb)(void *cb_data, bool *busy),