2013-11-26 13:30:41 -07:00
/*
* Copyright ( C ) 2004 IBM Corporation
* Authors :
* Leendert van Doorn < leendert @ watson . ibm . com >
* Dave Safford < safford @ watson . ibm . com >
* Reiner Sailer < sailer @ watson . ibm . com >
* Kylene Hall < kjhall @ us . ibm . com >
*
2013-11-26 13:30:42 -07:00
* Copyright ( C ) 2013 Obsidian Research Corp
* Jason Gunthorpe < jgunthorpe @ obsidianresearch . com >
*
2013-11-26 13:30:41 -07:00
* sysfs filesystem inspection interface to the TPM
*
* 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 , version 2 of the
* License .
*
*/
# include <linux/device.h>
# include "tpm.h"
2017-06-20 11:38:03 +02:00
struct tpm_readpubek_out {
u8 algorithm [ 4 ] ;
u8 encscheme [ 2 ] ;
u8 sigscheme [ 2 ] ;
__be32 paramsize ;
u8 parameters [ 12 ] ;
__be32 keysize ;
u8 modulus [ 256 ] ;
u8 checksum [ 20 ] ;
} __packed ;
2017-01-19 07:19:12 -05:00
# define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
2017-05-03 18:19:10 +02:00
# define TPM_ORD_READPUBEK 124
2017-06-20 11:38:03 +02:00
2013-11-26 13:30:42 -07:00
static ssize_t pubek_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2013-11-26 13:30:41 -07:00
{
2017-06-20 11:38:03 +02:00
struct tpm_buf tpm_buf ;
struct tpm_readpubek_out * out ;
ssize_t rc ;
int i ;
2013-11-26 13:30:41 -07:00
char * str = buf ;
2016-04-18 13:26:13 -04:00
struct tpm_chip * chip = to_tpm_chip ( dev ) ;
2017-06-20 11:38:03 +02:00
char anti_replay [ 20 ] ;
2013-11-26 13:30:41 -07:00
2017-06-20 11:38:03 +02:00
memset ( & anti_replay , 0 , sizeof ( anti_replay ) ) ;
rc = tpm_buf_init ( & tpm_buf , TPM_TAG_RQU_COMMAND , TPM_ORD_READPUBEK ) ;
if ( rc )
return rc ;
2017-06-20 11:38:02 +02:00
2017-06-20 11:38:03 +02:00
tpm_buf_append ( & tpm_buf , anti_replay , sizeof ( anti_replay ) ) ;
2013-11-26 13:30:41 -07:00
2017-06-20 11:38:03 +02:00
rc = tpm_transmit_cmd ( chip , NULL , tpm_buf . data , PAGE_SIZE ,
READ_PUBEK_RESULT_MIN_BODY_SIZE , 0 ,
" attempting to read the PUBEK " ) ;
if ( rc ) {
tpm_buf_destroy ( & tpm_buf ) ;
return 0 ;
}
out = ( struct tpm_readpubek_out * ) & tpm_buf . data [ 10 ] ;
2013-11-26 13:30:41 -07:00
str + =
sprintf ( str ,
" Algorithm: %02X %02X %02X %02X \n "
" Encscheme: %02X %02X \n "
" Sigscheme: %02X %02X \n "
" Parameters: %02X %02X %02X %02X "
" %02X %02X %02X %02X "
" %02X %02X %02X %02X \n "
" Modulus length: %d \n "
" Modulus: \n " ,
2017-06-20 11:38:03 +02:00
out - > algorithm [ 0 ] , out - > algorithm [ 1 ] , out - > algorithm [ 2 ] ,
out - > algorithm [ 3 ] ,
out - > encscheme [ 0 ] , out - > encscheme [ 1 ] ,
out - > sigscheme [ 0 ] , out - > sigscheme [ 1 ] ,
out - > parameters [ 0 ] , out - > parameters [ 1 ] ,
out - > parameters [ 2 ] , out - > parameters [ 3 ] ,
out - > parameters [ 4 ] , out - > parameters [ 5 ] ,
out - > parameters [ 6 ] , out - > parameters [ 7 ] ,
out - > parameters [ 8 ] , out - > parameters [ 9 ] ,
out - > parameters [ 10 ] , out - > parameters [ 11 ] ,
be32_to_cpu ( out - > keysize ) ) ;
2013-11-26 13:30:41 -07:00
for ( i = 0 ; i < 256 ; i + + ) {
2017-06-20 11:38:03 +02:00
str + = sprintf ( str , " %02X " , out - > modulus [ i ] ) ;
2013-11-26 13:30:41 -07:00
if ( ( i + 1 ) % 16 = = 0 )
str + = sprintf ( str , " \n " ) ;
}
2017-06-20 11:38:03 +02:00
2013-11-26 13:30:41 -07:00
rc = str - buf ;
2017-06-20 11:38:03 +02:00
tpm_buf_destroy ( & tpm_buf ) ;
2013-11-26 13:30:41 -07:00
return rc ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( pubek ) ;
2013-11-26 13:30:41 -07:00
2013-11-26 13:30:42 -07:00
static ssize_t pcrs_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2013-11-26 13:30:41 -07:00
{
cap_t cap ;
u8 digest [ TPM_DIGEST_SIZE ] ;
ssize_t rc ;
int i , j , num_pcrs ;
char * str = buf ;
2016-04-18 13:26:13 -04:00
struct tpm_chip * chip = to_tpm_chip ( dev ) ;
2013-11-26 13:30:41 -07:00
2016-04-18 13:26:13 -04:00
rc = tpm_getcap ( chip , TPM_CAP_PROP_PCR , & cap ,
2017-01-19 07:19:12 -05:00
" attempting to determine the number of PCRS " ,
sizeof ( cap . num_pcrs ) ) ;
2013-11-26 13:30:41 -07:00
if ( rc )
return 0 ;
num_pcrs = be32_to_cpu ( cap . num_pcrs ) ;
for ( i = 0 ; i < num_pcrs ; i + + ) {
rc = tpm_pcr_read_dev ( chip , i , digest ) ;
if ( rc )
break ;
str + = sprintf ( str , " PCR-%02d: " , i ) ;
for ( j = 0 ; j < TPM_DIGEST_SIZE ; j + + )
str + = sprintf ( str , " %02X " , digest [ j ] ) ;
str + = sprintf ( str , " \n " ) ;
}
return str - buf ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( pcrs ) ;
2013-11-26 13:30:41 -07:00
2013-11-26 13:30:42 -07:00
static ssize_t enabled_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2013-11-26 13:30:41 -07:00
{
cap_t cap ;
ssize_t rc ;
2016-04-18 13:26:13 -04:00
rc = tpm_getcap ( to_tpm_chip ( dev ) , TPM_CAP_FLAG_PERM , & cap ,
2017-01-19 07:19:12 -05:00
" attempting to determine the permanent enabled state " ,
sizeof ( cap . perm_flags ) ) ;
2013-11-26 13:30:41 -07:00
if ( rc )
return 0 ;
rc = sprintf ( buf , " %d \n " , ! cap . perm_flags . disable ) ;
return rc ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( enabled ) ;
2013-11-26 13:30:41 -07:00
2013-12-07 16:10:26 +01:00
static ssize_t active_show ( struct device * dev , struct device_attribute * attr ,
2013-11-26 13:30:42 -07:00
char * buf )
2013-11-26 13:30:41 -07:00
{
cap_t cap ;
ssize_t rc ;
2016-04-18 13:26:13 -04:00
rc = tpm_getcap ( to_tpm_chip ( dev ) , TPM_CAP_FLAG_PERM , & cap ,
2017-01-19 07:19:12 -05:00
" attempting to determine the permanent active state " ,
sizeof ( cap . perm_flags ) ) ;
2013-11-26 13:30:41 -07:00
if ( rc )
return 0 ;
rc = sprintf ( buf , " %d \n " , ! cap . perm_flags . deactivated ) ;
return rc ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( active ) ;
2013-11-26 13:30:41 -07:00
2013-11-26 13:30:42 -07:00
static ssize_t owned_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2013-11-26 13:30:41 -07:00
{
cap_t cap ;
ssize_t rc ;
2016-04-18 13:26:13 -04:00
rc = tpm_getcap ( to_tpm_chip ( dev ) , TPM_CAP_PROP_OWNER , & cap ,
2017-01-19 07:19:12 -05:00
" attempting to determine the owner state " ,
sizeof ( cap . owned ) ) ;
2013-11-26 13:30:41 -07:00
if ( rc )
return 0 ;
rc = sprintf ( buf , " %d \n " , cap . owned ) ;
return rc ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( owned ) ;
2013-11-26 13:30:41 -07:00
2013-11-26 13:30:42 -07:00
static ssize_t temp_deactivated_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2013-11-26 13:30:41 -07:00
{
cap_t cap ;
ssize_t rc ;
2016-04-18 13:26:13 -04:00
rc = tpm_getcap ( to_tpm_chip ( dev ) , TPM_CAP_FLAG_VOL , & cap ,
2017-01-19 07:19:12 -05:00
" attempting to determine the temporary state " ,
sizeof ( cap . stclear_flags ) ) ;
2013-11-26 13:30:41 -07:00
if ( rc )
return 0 ;
rc = sprintf ( buf , " %d \n " , cap . stclear_flags . deactivated ) ;
return rc ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( temp_deactivated ) ;
2013-11-26 13:30:41 -07:00
2013-11-26 13:30:42 -07:00
static ssize_t caps_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2013-11-26 13:30:41 -07:00
{
2016-04-18 13:26:13 -04:00
struct tpm_chip * chip = to_tpm_chip ( dev ) ;
2013-11-26 13:30:41 -07:00
cap_t cap ;
ssize_t rc ;
char * str = buf ;
2016-04-18 13:26:13 -04:00
rc = tpm_getcap ( chip , TPM_CAP_PROP_MANUFACTURER , & cap ,
2017-01-19 07:19:12 -05:00
" attempting to determine the manufacturer " ,
sizeof ( cap . manufacturer_id ) ) ;
2013-11-26 13:30:41 -07:00
if ( rc )
return 0 ;
str + = sprintf ( str , " Manufacturer: 0x%x \n " ,
be32_to_cpu ( cap . manufacturer_id ) ) ;
/* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
2016-09-19 23:22:09 +03:00
rc = tpm_getcap ( chip , TPM_CAP_VERSION_1_2 , & cap ,
2017-01-19 07:19:12 -05:00
" attempting to determine the 1.2 version " ,
sizeof ( cap . tpm_version_1_2 ) ) ;
2013-11-26 13:30:41 -07:00
if ( ! rc ) {
str + = sprintf ( str ,
" TCG version: %d.%d \n Firmware version: %d.%d \n " ,
cap . tpm_version_1_2 . Major ,
cap . tpm_version_1_2 . Minor ,
cap . tpm_version_1_2 . revMajor ,
cap . tpm_version_1_2 . revMinor ) ;
} else {
/* Otherwise just use TPM_STRUCT_VER */
2016-09-19 23:22:09 +03:00
rc = tpm_getcap ( chip , TPM_CAP_VERSION_1_1 , & cap ,
2017-01-19 07:19:12 -05:00
" attempting to determine the 1.1 version " ,
sizeof ( cap . tpm_version ) ) ;
2013-11-26 13:30:41 -07:00
if ( rc )
return 0 ;
str + = sprintf ( str ,
" TCG version: %d.%d \n Firmware version: %d.%d \n " ,
cap . tpm_version . Major ,
cap . tpm_version . Minor ,
cap . tpm_version . revMajor ,
cap . tpm_version . revMinor ) ;
}
return str - buf ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( caps ) ;
2013-11-26 13:30:41 -07:00
2013-11-26 13:30:42 -07:00
static ssize_t cancel_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2013-11-26 13:30:41 -07:00
{
2016-04-18 13:26:13 -04:00
struct tpm_chip * chip = to_tpm_chip ( dev ) ;
2013-11-26 13:30:41 -07:00
if ( chip = = NULL )
return 0 ;
2013-11-26 13:30:44 -07:00
chip - > ops - > cancel ( chip ) ;
2013-11-26 13:30:41 -07:00
return count ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_WO ( cancel ) ;
2013-11-26 13:30:41 -07:00
2013-11-26 13:30:42 -07:00
static ssize_t durations_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2013-11-26 13:30:41 -07:00
{
2016-04-18 13:26:13 -04:00
struct tpm_chip * chip = to_tpm_chip ( dev ) ;
2013-11-26 13:30:41 -07:00
2016-03-31 22:56:59 +02:00
if ( chip - > duration [ TPM_LONG ] = = 0 )
2013-11-26 13:30:41 -07:00
return 0 ;
return sprintf ( buf , " %d %d %d [%s] \n " ,
2016-03-31 22:56:59 +02:00
jiffies_to_usecs ( chip - > duration [ TPM_SHORT ] ) ,
jiffies_to_usecs ( chip - > duration [ TPM_MEDIUM ] ) ,
jiffies_to_usecs ( chip - > duration [ TPM_LONG ] ) ,
chip - > duration_adjusted
2013-11-26 13:30:41 -07:00
? " adjusted " : " original " ) ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( durations ) ;
2013-11-26 13:30:41 -07:00
2013-11-26 13:30:42 -07:00
static ssize_t timeouts_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2013-11-26 13:30:41 -07:00
{
2016-04-18 13:26:13 -04:00
struct tpm_chip * chip = to_tpm_chip ( dev ) ;
2013-11-26 13:30:41 -07:00
return sprintf ( buf , " %d %d %d %d [%s] \n " ,
2016-03-31 22:56:59 +02:00
jiffies_to_usecs ( chip - > timeout_a ) ,
jiffies_to_usecs ( chip - > timeout_b ) ,
jiffies_to_usecs ( chip - > timeout_c ) ,
jiffies_to_usecs ( chip - > timeout_d ) ,
chip - > timeout_adjusted
2013-11-26 13:30:41 -07:00
? " adjusted " : " original " ) ;
}
2013-11-26 13:30:42 -07:00
static DEVICE_ATTR_RO ( timeouts ) ;
static struct attribute * tpm_dev_attrs [ ] = {
& dev_attr_pubek . attr ,
& dev_attr_pcrs . attr ,
& dev_attr_enabled . attr ,
& dev_attr_active . attr ,
& dev_attr_owned . attr ,
& dev_attr_temp_deactivated . attr ,
& dev_attr_caps . attr ,
& dev_attr_cancel . attr ,
& dev_attr_durations . attr ,
& dev_attr_timeouts . attr ,
NULL ,
} ;
static const struct attribute_group tpm_dev_group = {
. attrs = tpm_dev_attrs ,
} ;
2016-04-18 13:26:13 -04:00
void tpm_sysfs_add_device ( struct tpm_chip * chip )
2013-11-26 13:30:42 -07:00
{
2017-06-25 14:53:24 -07:00
/* XXX: If you wish to remove this restriction, you must first update
* tpm_sysfs to explicitly lock chip - > ops .
*/
2016-11-14 05:00:51 -05:00
if ( chip - > flags & TPM_CHIP_FLAG_TPM2 )
return ;
2016-04-18 13:26:13 -04:00
/* The sysfs routines rely on an implicit tpm_try_get_ops, device_del
* is called before ops is null ' d and the sysfs core synchronizes this
* removal so that no callbacks are running or can run again
2016-02-12 20:29:53 -07:00
*/
2016-04-18 13:26:13 -04:00
WARN_ON ( chip - > groups_cnt ! = 0 ) ;
chip - > groups [ chip - > groups_cnt + + ] = & tpm_dev_group ;
2013-11-26 13:30:42 -07:00
}