From patchwork Thu Nov 30 07:39:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Martinez Canillas X-Patchwork-Id: 10084303 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 07DFB60234 for ; Thu, 30 Nov 2017 07:39:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E726629EE6 for ; Thu, 30 Nov 2017 07:39:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D37E129EEC; Thu, 30 Nov 2017 07:39:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 311F229EE6 for ; Thu, 30 Nov 2017 07:39:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750800AbdK3HjN (ORCPT ); Thu, 30 Nov 2017 02:39:13 -0500 Received: from mail-wm0-f68.google.com ([74.125.82.68]:47077 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750783AbdK3HjL (ORCPT ); Thu, 30 Nov 2017 02:39:11 -0500 Received: by mail-wm0-f68.google.com with SMTP id r78so11089188wme.5 for ; Wed, 29 Nov 2017 23:39:11 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=5laPdGsuOxAe3lnM4NhOrjpYhPin+ZFXOUTk3KWybtI=; b=UIXWbFatqMdSjn637vZe0rU2wzakWnO8qcpPHLtHV1/aFIuCHqFLL1Z9H9V6MYusO6 UO/FftMlwrjfeyKU6ykrUlwCzu7T7hBKB261QvP6QKVjhZwlD4dqprVm5mF+Hu6s5kRf hX5Gp6V6/aCUV7YQjWGsHT4az/VQwj+5ko9QQZfr6g7Ividb2rpfjMJaBkCCfWv8AShJ 3x/37Nbos9Z/+sQ5Xdktx8MEATpWFjZ0nT7cUFfGrAaOa8wk0bTeHSoFRutviif/kMxh D71+hKzj8rlsBaqVgodwc3iIlwkS9+f7GgmUXZu4qhDIWLsuZQnK9TiTpKc83gYQLjKp UCnw== X-Gm-Message-State: AJaThX7OIMyZHquqwi5kMEIhIIQb0r4wgSw+Bfan4mN4CLpcCMXmTarg 5NlfTL9mC/J3e5TOPudQqIKVvQ== X-Google-Smtp-Source: AGs4zMaWhfqdZbklx+/+vhZ2H3aPyeezqMov8eV5SqTwfT24/uChs7wyqn+Y9vQAYgKPPARc4lv6zQ== X-Received: by 10.28.192.24 with SMTP id q24mr1037765wmf.98.1512027550612; Wed, 29 Nov 2017 23:39:10 -0800 (PST) Received: from minerva.redhat.com ([90.77.100.34]) by smtp.gmail.com with ESMTPSA id u33sm2733896wrb.68.2017.11.29.23.39.09 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 29 Nov 2017 23:39:10 -0800 (PST) From: Javier Martinez Canillas To: linux-kernel@vger.kernel.org Cc: Javier Martinez Canillas , Jarkko Sakkinen , Peter Huewe , Jerry Snitselaar , Jason Gunthorpe , Philip Tricca , linux-integrity@vger.kernel.org, William Roberts , James Bottomley Subject: [PATCH v3] tpm: return a TPM_RC_COMMAND_CODE response if command is not implemented Date: Thu, 30 Nov 2017 08:39:07 +0100 Message-Id: <20171130073907.20708-1-javierm@redhat.com> X-Mailer: git-send-email 2.14.3 Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP According to the TPM Library Specification, a TPM device must do a command header validation before processing and return a TPM_RC_COMMAND_CODE code if the command is not implemented. So user-space will expect to handle that response as an error. But if the in-kernel resource manager is used (/dev/tpmrm?), an -EINVAL errno code is returned instead if the command isn't implemented. This confuses userspace since it doesn't expect that error value. This also isn't consistent with the behavior when not using TPM spaces and accessing the TPM directly (/dev/tpm?). In this case, the command is sent to the TPM even when not implemented and the TPM responds with an error. Instead of returning an -EINVAL errno code when the tpm_validate_command() function fails, synthesize a TPM command response so user-space can get a TPM_RC_COMMAND_CODE as expected when a chip doesn't implement the command. The TPM only sets 12 of the 32 bits in the TPM_RC response, so the TSS and TAB specifications define that higher layers in the stack should use some of the unused 20 bits to specify from which level of the stack the error is coming from. Since the TPM_RC_COMMAND_CODE response code is sent by the kernel resource manager, set the error level to the TAB/RM layer so user-space is aware of this. Suggested-by: Jason Gunthorpe Signed-off-by: Javier Martinez Canillas Reviewed-by: Philip Tricca --- Changes since v2: - Use TSS2 as prefix instead of TPM2 to match the spec (suggested by Jarkko Sakkinen). - Add Philip's Reviewed-by tag as he asked and I missed in previous version. Changes since v1: - Remove the unused macros for the driver and resmgr RC layers (suggested by Philip Tricca). - Use naming conventions from the latest version of the TSS spec (suggested by Philip Tricca). Changes since RFCv2: - Set the error level to the TAB/RM layer so user-space is aware that the error is not coming from the TPM (suggested by Philip Tricca and Jarkko Sakkinen). Changes since RFCv1: - Don't pass not validated commands to the TPM, instead return a synthesized response with the correct TPM return code (suggested by Jason Gunthorpe). And example of user-space getting confused by the TPM chardev returning -EINVAL when sending a not supported TPM command can be seen in this tpm2-tools issue: https://github.com/intel/tpm2-tools/issues/621 Best regards, Javier drivers/char/tpm/tpm-interface.c | 28 ++++++++++++++++++++-------- drivers/char/tpm/tpm.h | 5 +++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 1d6729be4cd6..c5da6d3f7058 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -328,7 +328,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -static bool tpm_validate_command(struct tpm_chip *chip, +static int tpm_validate_command(struct tpm_chip *chip, struct tpm_space *space, const u8 *cmd, size_t len) @@ -340,10 +340,10 @@ static bool tpm_validate_command(struct tpm_chip *chip, unsigned int nr_handles; if (len < TPM_HEADER_SIZE) - return false; + return -EINVAL; if (!space) - return true; + return 0; if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) { cc = be32_to_cpu(header->ordinal); @@ -352,7 +352,7 @@ static bool tpm_validate_command(struct tpm_chip *chip, if (i < 0) { dev_dbg(&chip->dev, "0x%04X is an invalid command\n", cc); - return false; + return -EOPNOTSUPP; } attrs = chip->cc_attrs_tbl[i]; @@ -362,11 +362,11 @@ static bool tpm_validate_command(struct tpm_chip *chip, goto err_len; } - return true; + return 0; err_len: dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__, len); - return false; + return -EINVAL; } /** @@ -391,8 +391,20 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, unsigned long stop; bool need_locality; - if (!tpm_validate_command(chip, space, buf, bufsiz)) - return -EINVAL; + rc = tpm_validate_command(chip, space, buf, bufsiz); + if (rc == -EINVAL) + return rc; + /* + * If the command is not implemented by the TPM, synthesize a + * response with a TPM2_RC_COMMAND_CODE return for user-space. + */ + if (rc == -EOPNOTSUPP) { + header->length = cpu_to_be32(sizeof(*header)); + header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); + header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE | + TSS2_RESMGR_TPM_RC_LAYER); + return bufsiz; + } if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 2d5466a72e40..0b5b499f726a 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -93,12 +93,17 @@ enum tpm2_structures { TPM2_ST_SESSIONS = 0x8002, }; +/* Indicates from what layer of the software stack the error comes from */ +#define TSS2_RC_LAYER_SHIFT 16 +#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT) + enum tpm2_return_codes { TPM2_RC_SUCCESS = 0x0000, TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ TPM2_RC_HANDLE = 0x008B, TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ TPM2_RC_DISABLED = 0x0120, + TPM2_RC_COMMAND_CODE = 0x0143, TPM2_RC_TESTING = 0x090A, /* RC_WARN */ TPM2_RC_REFERENCE_H0 = 0x0910, };