From patchwork Tue Aug 30 04:50:19 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nayna X-Patchwork-Id: 9304841 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 F3997607F0 for ; Tue, 30 Aug 2016 04:51:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DCAE828AB5 for ; Tue, 30 Aug 2016 04:51:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D185228AC1; Tue, 30 Aug 2016 04:51:26 +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 lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id A322A28AB5 for ; Tue, 30 Aug 2016 04:51:25 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1beb19-0003SK-Gg; Tue, 30 Aug 2016 04:51:23 +0000 Received: from sog-mx-1.v43.ch3.sourceforge.com ([172.29.43.191] helo=mx.sourceforge.net) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1beb18-0003SE-PI for tpmdd-devel@lists.sourceforge.net; Tue, 30 Aug 2016 04:51:22 +0000 X-ACL-Warn: Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by sog-mx-1.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.76) id 1beb17-0000jC-6e for tpmdd-devel@lists.sourceforge.net; Tue, 30 Aug 2016 04:51:22 +0000 Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id u7U4hwKB147073 for ; Tue, 30 Aug 2016 00:51:15 -0400 Received: from e28smtp09.in.ibm.com (e28smtp09.in.ibm.com [125.16.236.9]) by mx0a-001b2d01.pphosted.com with ESMTP id 2553638jt8-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Tue, 30 Aug 2016 00:51:15 -0400 Received: from localhost by e28smtp09.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 30 Aug 2016 10:21:11 +0530 Received: from d28dlp01.in.ibm.com (9.184.220.126) by e28smtp09.in.ibm.com (192.168.1.139) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 30 Aug 2016 10:21:10 +0530 X-IBM-Helo: d28dlp01.in.ibm.com X-IBM-MailFrom: nayna@linux.vnet.ibm.com X-IBM-RcptTo: tpmdd-devel@lists.sourceforge.net Received: from d28relay02.in.ibm.com (d28relay02.in.ibm.com [9.184.220.59]) by d28dlp01.in.ibm.com (Postfix) with ESMTP id B9F64E005A for ; Tue, 30 Aug 2016 10:20:11 +0530 (IST) Received: from d28av03.in.ibm.com (d28av03.in.ibm.com [9.184.220.65]) by d28relay02.in.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u7U4p9Di22085642 for ; Tue, 30 Aug 2016 10:21:09 +0530 Received: from d28av03.in.ibm.com (localhost [127.0.0.1]) by d28av03.in.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u7U4p78q022391 for ; Tue, 30 Aug 2016 10:21:08 +0530 Received: from c365f16u1b3.pok.stglabs.ibm.com (c365f16u1b3.pok.stglabs.ibm.com [9.47.77.42]) by d28av03.in.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u7U4oRiB020851; Tue, 30 Aug 2016 10:21:05 +0530 From: Nayna Jain To: tpmdd-devel@lists.sourceforge.net Date: Tue, 30 Aug 2016 00:50:19 -0400 X-Mailer: git-send-email 2.5.0 In-Reply-To: <1472532619-22170-1-git-send-email-nayna@linux.vnet.ibm.com> References: <1472532619-22170-1-git-send-email-nayna@linux.vnet.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16083004-0060-0000-0000-000001183C72 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16083004-0061-0000-0000-00000F35A6E7 Message-Id: <1472532619-22170-8-git-send-email-nayna@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-08-30_02:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=1 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1604210000 definitions=main-1608300044 X-Headers-End: 1beb17-0000jC-6e Subject: [tpmdd-devel] [PATCH v3 7/7] tpm: Adds securityfs support for TPM2.0 eventlog X-BeenThere: tpmdd-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Tpm Device Driver maintainance List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: tpmdd-devel-bounces@lists.sourceforge.net X-Virus-Scanned: ClamAV using ClamSMTP Adds securityfs support for TPM2.0. This patch add supports only for binary_bios_measurements. Signed-off-by: Nayna Jain --- drivers/char/tpm/Makefile | 2 +- drivers/char/tpm/tpm2.h | 85 +++++++++++++ drivers/char/tpm/tpm2_eventlog.c | 224 +++++++++++++++++++++++++++++++++++ drivers/char/tpm/tpm_eventlog_init.c | 28 +++-- drivers/char/tpm/tpm_of.c | 42 ++++--- 5 files changed, 357 insertions(+), 24 deletions(-) create mode 100644 drivers/char/tpm/tpm2.h create mode 100644 drivers/char/tpm/tpm2_eventlog.c diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 200b957..b10316d 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_TCG_TPM) += tpm.o tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ - tpm_eventlog.o tpm_eventlog_init.o + tpm_eventlog.o tpm_eventlog_init.o tpm2_eventlog.o tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o tpm-$(CONFIG_OF) += tpm_of.o diff --git a/drivers/char/tpm/tpm2.h b/drivers/char/tpm/tpm2.h new file mode 100644 index 0000000..38a8073 --- /dev/null +++ b/drivers/char/tpm/tpm2.h @@ -0,0 +1,85 @@ +#ifndef __TPM2_H__ +#define __TPM2_H__ + +#define TPM_ALG_SHA1_DIGEST_SIZE 20 +#define TPM_ALG_SHA256_DIGEST_SIZE 32 +#define TPM_ALG_SHA384_DIGEST_SIZE 48 + +#define HASH_COUNT 3 +#define MAX_TPM_LOG_MSG 128 + +/** + * All the structures related to Event Log are taken from TCG EFI Protocol + * Specification, Family "2.0". Document is available on link + * http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ + * Information is also available on TCG PC Client Platform Firmware Profile + * Specification, Family "2.0" + * Detailed digest structures for TPM2.0 are defined in document + * Trusted Platform Module Library Part 2: Structures, Family "2.0". + */ + +/* Event log header algorithm spec. */ +struct tcg_efispecideventalgorithmsize { + u16 algorithm_id; + u16 digest_size; +} __packed; + +/* Event log header data. */ +struct tcg_efispecideventstruct { + u8 signature[16]; + u32 platform_class; + u8 spec_version_minor; + u8 spec_version_major; + u8 spec_errata; + u8 uintnsize; + u32 num_algs; + struct tcg_efispecideventalgorithmsize digest_sizes[HASH_COUNT]; + u8 vendor_info_size; + u8 vendor_info[0]; +} __packed; + +/* Header entry for eventlog. */ +struct tcg_pcr_event { + u32 pcr_index; + u32 event_type; + u8 digest[20]; + u32 event_size; + u8 event[MAX_TPM_LOG_MSG]; +} __packed; + +/* Digest union for crypto agility. */ +union tpmu_ha { + u8 sha1[TPM_ALG_SHA1_DIGEST_SIZE]; + u8 sha256[TPM_ALG_SHA256_DIGEST_SIZE]; + u8 sha384[TPM_ALG_SHA384_DIGEST_SIZE]; +} __packed; + +/* Crypto Agile algorithm and respective digest. */ +struct tpmt_ha { + u16 algorithm_id; + union tpmu_ha digest; +} __packed; + +/* Crypto agile digests list. */ +struct tpml_digest_values { + u32 count; + struct tpmt_ha digests[HASH_COUNT]; +} __packed; + +/* Event field structure. */ +struct tcg_event_field { + u32 event_size; + u8 event[MAX_TPM_LOG_MSG]; +} __packed; + +/* Crypto agile log entry format for TPM 2.0. */ +struct tcg_pcr_event2 { + u32 pcr_index; + u32 event_type; + struct tpml_digest_values digests; + struct tcg_event_field event; +} __packed; + +extern const struct seq_operations tpm2_binary_b_measurments_seqops; + +#endif diff --git a/drivers/char/tpm/tpm2_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c new file mode 100644 index 0000000..f1e8c4a --- /dev/null +++ b/drivers/char/tpm/tpm2_eventlog.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2016 IBM Corporation + * + * Authors: + * Nayna Jain + + * Access to TPM2.0 event log as written by Firmware. + * It assumes that writer of event log has followed TCG Spec 2.0 + * has written the event struct data in little endian. With that, + * it doesn't need any endian conversion for structure content. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include "tpm.h" +#include "tpm2.h" +#include "tpm_eventlog.h" + + +static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, + struct tcg_pcr_event *event_header) +{ + struct tcg_efispecideventstruct *efispecid; + struct tcg_event_field *event_field; + void *marker, *marker_start; + int j; + size_t size = 0; + + /* + * NOTE: TPM2.0 allows support for extend to multiple PCR Banks. + * This implies that eventlog also has multiple digest values + * one for each PCR Bank. This is called Crypto Agile Log Entry + * Format. Current support implementation is for SHA1 and SHA256. + * Number of digest values are identified by parsing first + * structure stored in event log also called event header. + * Further, the eventlog is written in packed form so to calculate + * offset it is important to know the type of algorithm used. + * Eg. 1: + * digest_values.count = 1; + * digest_values.digest[0].algorithm_id = sha1; + * digest_values.digest[0].digest.sha1 = {20 bytes raw data}; + * Offset of eventsize is sizeof(count) + sizeof(algorithm_id) + 20 + * + * Eg. 2: + * digest_values.count = 1; + * digest_values.digest[0].algorithm_id = sha256; + * digest_values.digest[0].digest.sha1 = {32 bytes raw data}; + * Offset of eventsize is sizeof(count) + sizeof(algorithm_id) + 32 + + * Eg. 3: + * digest_values.count = 2; + * digest_values.digest[0].algorithm_id = sha1; + * digest_values.digest[0].digest.sha1 = {20 bytes raw data}; + * digest_values.digest[1].algorithm_id = sha256; + * digest_values.digest[1].digest.sha256 = {32 bytes raw data}; + * Offset of eventsize is sizeof(count) + sizeof(algorithm_id) + 20 + * + sizeof(algorithm_id) + 32; + * + * So, it implies that offset of event_size can vary based on digest + * values as defined by vendor. And so we have to calculate the + * offset by parsing through number and type of digests being used. + * And this is the purpose of using *marker to traverse the structure + * and calculate the offset of event_size. This function uses *marker + * to parse and calculate the dynamic size of the whole event structure. + */ + + marker = event; + marker_start = marker; + marker = marker + sizeof(event->pcr_index) + sizeof(event->event_type) + + sizeof(event->digests.count); + + efispecid = (struct tcg_efispecideventstruct *) event_header->event; + + for (j = 0; (j < efispecid->num_algs) && (j < HASH_COUNT); j++) { + marker = marker + + sizeof(efispecid->digest_sizes[j].algorithm_id); + marker = marker + efispecid->digest_sizes[j].digest_size; + } + + event_field = (struct tcg_event_field *) marker; + marker = marker + sizeof(event_field->event_size) + + event_field->event_size; + size = marker - marker_start; + + if ((event->event_type == 0) && (event_field->event_size == 0)) + return 0; + + return size; +} + +static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) +{ + struct tpm_bios_log *log = m->private; + void *addr = log->bios_event_log; + void *limit = log->bios_event_log_end; + struct tcg_pcr_event *event_header; + struct tcg_pcr_event2 *event; + int i; + size_t size = 0; + + event_header = addr; + + size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event) + + event_header->event_size; + + + if (*pos == 0) { + if (addr + size < limit) { + if ((event_header->event_type == 0) && + (event_header->event_size == 0)) + return NULL; + return SEQ_START_TOKEN; + } + } + + if (*pos > 0) { + addr += size; + event = addr; + size = calc_tpm2_event_size(event, event_header); + if ((addr + size >= limit) || (size == 0)) + return NULL; + } + + /* read over *pos measurements */ + for (i = 0; i < (*pos - 1); i++) { + event = addr; + size = calc_tpm2_event_size(event, event_header); + + if ((addr + size >= limit) || (size == 0)) + return NULL; + addr += size; + } + + return addr; +} + +static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, + loff_t *pos) +{ + struct tcg_pcr_event *event_header; + struct tcg_pcr_event2 *event; + struct tpm_bios_log *log = m->private; + void *limit = log->bios_event_log_end; + void *marker; + size_t event_size = 0; + + event_header = log->bios_event_log; + + if (v == SEQ_START_TOKEN) { + event_size = sizeof(struct tcg_pcr_event) + - sizeof(event_header->event) + + event_header->event_size; + marker = event_header; + } else { + event = v; + event_size = calc_tpm2_event_size(event, event_header); + if (event_size == 0) + return NULL; + marker = event; + } + + marker = marker + event_size; + if (marker >= limit) + return NULL; + v = marker; + event = v; + + event_size = calc_tpm2_event_size(event, event_header); + if (((v + event_size) >= limit) || (event_size == 0)) + return NULL; + + (*pos)++; + return v; +} + +static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) +{ +} + +static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) +{ + struct tpm_bios_log *log = m->private; + struct tcg_pcr_event *event_header = log->bios_event_log; + struct tcg_pcr_event2 *event = v; + void *temp_ptr; + size_t size = 0; + + if (v == SEQ_START_TOKEN) { + + size = sizeof(struct tcg_pcr_event) + - sizeof(event_header->event) + + event_header->event_size; + + temp_ptr = event_header; + + if (size > 0) + seq_write(m, temp_ptr, size); + } else { + + size = calc_tpm2_event_size(event, event_header); + + temp_ptr = event; + if (size > 0) + seq_write(m, temp_ptr, size); + } + + return 0; +} + +const struct seq_operations tpm2_binary_b_measurments_seqops = { + .start = tpm2_bios_measurements_start, + .next = tpm2_bios_measurements_next, + .stop = tpm2_bios_measurements_stop, + .show = tpm2_binary_bios_measurements_show, +}; diff --git a/drivers/char/tpm/tpm_eventlog_init.c b/drivers/char/tpm/tpm_eventlog_init.c index 038771a..9afeb3d 100644 --- a/drivers/char/tpm/tpm_eventlog_init.c +++ b/drivers/char/tpm/tpm_eventlog_init.c @@ -28,6 +28,7 @@ #include #include "tpm.h" +#include "tpm2.h" #include "tpm_eventlog.h" static int tpm_bios_measurements_release(struct inode *inode, @@ -94,6 +95,7 @@ int read_log(struct tpm_chip *chip) void tpm_bios_log_setup(struct tpm_chip *chip) { const char *name = dev_name(&chip->dev); + void *seq_ops; int rc = 0; rc = read_log(chip); @@ -108,23 +110,31 @@ void tpm_bios_log_setup(struct tpm_chip *chip) chip->bios_dir[chip->bios_dir_count]->d_inode->i_private = chip; chip->bios_dir_count++; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + seq_ops = (void *)&tpm2_binary_b_measurments_seqops; + else + seq_ops = (void *)&tpm_binary_b_measurments_seqops; + + chip->bios_dir[chip->bios_dir_count] = securityfs_create_file("binary_bios_measurements", S_IRUSR | S_IRGRP, chip->bios_dir[0], - (void *)&tpm_binary_b_measurments_seqops, + seq_ops, &tpm_bios_measurements_ops); if (is_bad(chip->bios_dir[chip->bios_dir_count])) goto err; chip->bios_dir_count++; - chip->bios_dir[chip->bios_dir_count] = - securityfs_create_file("ascii_bios_measurements", - S_IRUSR | S_IRGRP, chip->bios_dir[0], - (void *)&tpm_ascii_b_measurments_seqops, - &tpm_bios_measurements_ops); - if (is_bad(chip->bios_dir[chip->bios_dir_count])) - goto err; - chip->bios_dir_count++; + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + chip->bios_dir[chip->bios_dir_count] = + securityfs_create_file("ascii_bios_measurements", + S_IRUSR | S_IRGRP, chip->bios_dir[0], + (void *)&tpm_ascii_b_measurments_seqops, + &tpm_bios_measurements_ops); + if (is_bad(chip->bios_dir[chip->bios_dir_count])) + goto err; + chip->bios_dir_count++; + } return; diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 4e4eed7..2fc58fe 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -15,12 +15,10 @@ * */ -#include -#include -#include -#include #include +#include #include +#include #include "tpm.h" #include "tpm_eventlog.h" @@ -30,44 +28,60 @@ int read_log_of(struct tpm_chip *chip) struct device_node *np; const u32 *sizep; const u64 *basep; + const struct of_device_id *of_id; + const char *compat; + u32 log_size; if (chip->dev.of_node) np = chip->dev.of_node; if (!np) { - dev_dbg(&chip->dev, "%s: ERROR - IBMVTPM not supported\n", + dev_dbg(&chip->dev, "%s: ERROR - TPM not supported\n", __func__); return -ENODEV; } + compat = of_get_property(np, "compatible", NULL); + if (compat == NULL) { + dev_dbg(&chip->dev, "%s: ERROR - Compatible device not found", + __func__); + return -EIO; + } + sizep = of_get_property(np, "linux,sml-size", NULL); if (sizep == NULL) { dev_dbg(&chip->dev, "%s: ERROR - SML size not found\n", __func__); - goto cleanup_eio; + return -EIO; } if (*sizep == 0) { dev_dbg(&chip->dev, "%s: ERROR - event log area empty\n", __func__); - goto cleanup_eio; + return -EIO; } + if (!strcasecmp(compat, "IBM,vtpm")) + log_size = *sizep; + else + log_size = be32_to_cpup(sizep); + basep = of_get_property(np, "linux,sml-base", NULL); if (basep == NULL) { dev_dbg(&chip->dev, "%s: ERROR - SML not found\n", __func__); - goto cleanup_eio; + return -EIO; } - chip->log.bios_event_log = kmalloc(*sizep, GFP_KERNEL); + chip->log.bios_event_log = kmalloc(log_size, GFP_KERNEL); if (!chip->log.bios_event_log) { return -ENOMEM; } - chip->log.bios_event_log_end = chip->log.bios_event_log + *sizep; + chip->log.bios_event_log_end = chip->log.bios_event_log + log_size; - memcpy(chip->log.bios_event_log, __va(*basep), *sizep); + if (!strcasecmp(compat, "IBM,vtpm")) + memcpy(chip->log.bios_event_log, __va(*basep), log_size); + else + memcpy(chip->log.bios_event_log, __va(be64_to_cpup(basep)), + log_size); return 0; - -cleanup_eio: - return -EIO; }