Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/jmorris/linux-security

Pull security layer fixes from James Morris:
 "Bugfixes for TPM and SELinux"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  IB/core: Fix static analysis warning in ib_policy_change_task
  IB/core: Fix uninitialized variable use in check_qp_port_pkey_settings
  tpm: do not suspend/resume if power stays on
  tpm: use tpm2_pcr_read() in tpm2_do_selftest()
  tpm: use tpm_buf functions in tpm2_pcr_read()
  tpm_tis: make ilb_base_addr static
  tpm: consolidate the TPM startup code
  tpm: Enable CLKRUN protocol for Braswell systems
  tpm/tpm_crb: fix priv->cmd_size initialisation
  tpm: fix a kernel memory leak in tpm-sysfs.c
  tpm: Issue a TPM2_Shutdown for TPM2 devices.
  Add "shutdown" to "struct class".
  • Loading branch information
torvalds committed Jul 8, 2017
2 parents 98ced88 + a750cfd commit a7d4026
Show file tree
Hide file tree
Showing 12 changed files with 261 additions and 133 deletions.
6 changes: 5 additions & 1 deletion drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2664,7 +2664,11 @@ void device_shutdown(void)
pm_runtime_get_noresume(dev);
pm_runtime_barrier(dev);

if (dev->bus && dev->bus->shutdown) {
if (dev->class && dev->class->shutdown) {
if (initcall_debug)
dev_info(dev, "shutdown\n");
dev->class->shutdown(dev);
} else if (dev->bus && dev->bus->shutdown) {
if (initcall_debug)
dev_info(dev, "shutdown\n");
dev->bus->shutdown(dev);
Expand Down
34 changes: 34 additions & 0 deletions drivers/char/tpm/tpm-chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,39 @@ static void tpm_devs_release(struct device *dev)
put_device(&chip->dev);
}

/**
* tpm_class_shutdown() - prepare the TPM device for loss of power.
* @dev: device to which the chip is associated.
*
* Issues a TPM2_Shutdown command prior to loss of power, as required by the
* TPM 2.0 spec.
* Then, calls bus- and device- specific shutdown code.
*
* XXX: This codepath relies on the fact that sysfs is not enabled for
* TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2
* has sysfs support enabled before TPM sysfs's implicit locking is fixed.
*/
static int tpm_class_shutdown(struct device *dev)
{
struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);

if (chip->flags & TPM_CHIP_FLAG_TPM2) {
down_write(&chip->ops_sem);
tpm2_shutdown(chip, TPM2_SU_CLEAR);
chip->ops = NULL;
up_write(&chip->ops_sem);
}
/* Allow bus- and device-specific code to run. Note: since chip->ops
* is NULL, more-specific shutdown code will not be able to issue TPM
* commands.
*/
if (dev->bus && dev->bus->shutdown)
dev->bus->shutdown(dev);
else if (dev->driver && dev->driver->shutdown)
dev->driver->shutdown(dev);
return 0;
}

/**
* tpm_chip_alloc() - allocate a new struct tpm_chip instance
* @pdev: device to which the chip is associated
Expand Down Expand Up @@ -181,6 +214,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
device_initialize(&chip->devs);

chip->dev.class = tpm_class;
chip->dev.class->shutdown = tpm_class_shutdown;
chip->dev.release = tpm_dev_release;
chip->dev.parent = pdev;
chip->dev.groups = chip->groups;
Expand Down
70 changes: 45 additions & 25 deletions drivers/char/tpm/tpm-interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,47 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
}
EXPORT_SYMBOL_GPL(tpm_transmit_cmd);

#define TPM_ORD_STARTUP 153
#define TPM_ST_CLEAR 1

/**
* tpm_startup - turn on the TPM
* @chip: TPM chip to use
*
* Normally the firmware should start the TPM. This function is provided as a
* workaround if this does not happen. A legal case for this could be for
* example when a TPM emulator is used.
*
* Return: same as tpm_transmit_cmd()
*/
int tpm_startup(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;

dev_info(&chip->dev, "starting up the TPM manually\n");

if (chip->flags & TPM_CHIP_FLAG_TPM2) {
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
if (rc < 0)
return rc;

tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
} else {
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
if (rc < 0)
return rc;

tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
}

rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
"attempting to start the TPM");

tpm_buf_destroy(&buf);
return rc;
}

#define TPM_DIGEST_SIZE 20
#define TPM_RET_CODE_IDX 6
#define TPM_INTERNAL_RESULT_SIZE 200
Expand Down Expand Up @@ -586,27 +627,6 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
}
EXPORT_SYMBOL_GPL(tpm_getcap);

#define TPM_ORD_STARTUP 153
#define TPM_ST_CLEAR cpu_to_be16(1)
#define TPM_ST_STATE cpu_to_be16(2)
#define TPM_ST_DEACTIVATED cpu_to_be16(3)
static const struct tpm_input_header tpm_startup_header = {
.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(12),
.ordinal = cpu_to_be32(TPM_ORD_STARTUP)
};

static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
{
struct tpm_cmd_t start_cmd;
start_cmd.header.in = tpm_startup_header;

start_cmd.params.startup_in.startup_type = startup_type;
return tpm_transmit_cmd(chip, NULL, &start_cmd,
TPM_INTERNAL_RESULT_SIZE, 0,
0, "attempting to start the TPM");
}

int tpm_get_timeouts(struct tpm_chip *chip)
{
cap_t cap;
Expand Down Expand Up @@ -636,10 +656,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL,
sizeof(cap.timeout));
if (rc == TPM_ERR_INVALID_POSTINIT) {
/* The TPM is not started, we are the first to talk to it.
Execute a startup command. */
dev_info(&chip->dev, "Issuing TPM_STARTUP\n");
if (tpm_startup(chip, TPM_ST_CLEAR))
if (tpm_startup(chip))
return rc;

rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
Expand Down Expand Up @@ -1102,6 +1119,9 @@ int tpm_pm_suspend(struct device *dev)
if (chip == NULL)
return -ENODEV;

if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
return 0;

if (chip->flags & TPM_CHIP_FLAG_TPM2) {
tpm2_shutdown(chip, TPM2_SU_STATE);
return 0;
Expand Down
6 changes: 5 additions & 1 deletion drivers/char/tpm/tpm-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
ssize_t err;
int i, rc;
char *str = buf;

struct tpm_chip *chip = to_tpm_chip(dev);

memset(&tpm_cmd, 0, sizeof(tpm_cmd));

tpm_cmd.header.in = tpm_readpubek_header;
err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
Expand Down Expand Up @@ -294,6 +295,9 @@ static const struct attribute_group tpm_dev_group = {

void tpm_sysfs_add_device(struct tpm_chip *chip)
{
/* XXX: If you wish to remove this restriction, you must first update
* tpm_sysfs to explicitly lock chip->ops.
*/
if (chip->flags & TPM_CHIP_FLAG_TPM2)
return;

Expand Down
11 changes: 6 additions & 5 deletions drivers/char/tpm/tpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
#include <linux/highmem.h>
#include <crypto/hash_info.h>

#ifdef CONFIG_X86
#include <asm/intel-family.h>
#endif

enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
TPM_BUFSIZE = 4096,
Expand Down Expand Up @@ -170,6 +174,7 @@ enum tpm_chip_flags {
TPM_CHIP_FLAG_IRQ = BIT(2),
TPM_CHIP_FLAG_VIRTUAL = BIT(3),
TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4),
TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
};

struct tpm_bios_log {
Expand Down Expand Up @@ -378,18 +383,13 @@ struct tpm_getrandom_in {
__be32 num_bytes;
} __packed;

struct tpm_startup_in {
__be16 startup_type;
} __packed;

typedef union {
struct tpm_readpubek_params_out readpubek_out;
u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
struct tpm_pcrread_in pcrread_in;
struct tpm_pcrread_out pcrread_out;
struct tpm_getrandom_in getrandom_in;
struct tpm_getrandom_out getrandom_out;
struct tpm_startup_in startup_in;
} tpm_cmd_params;

struct tpm_cmd_t {
Expand Down Expand Up @@ -515,6 +515,7 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
const void *buf, size_t bufsiz,
size_t min_rsp_body_length, unsigned int flags,
const char *desc);
int tpm_startup(struct tpm_chip *chip);
ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length);
int tpm_get_timeouts(struct tpm_chip *);
Expand Down
Loading

0 comments on commit a7d4026

Please sign in to comment.