Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris: "Highlights: - Smack adds secmark support for Netfilter - /proc/keys is now mandatory if CONFIG_KEYS=y - TPM gets its own device class - Added TPM 2.0 support - Smack file hook rework (all Smack users should review this!)" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (64 commits) cipso: don't use IPCB() to locate the CIPSO IP option SELinux: fix error code in policydb_init() selinux: add security in-core xattr support for pstore and debugfs selinux: quiet the filesystem labeling behavior message selinux: Remove unused function avc_sidcmp() ima: /proc/keys is now mandatory Smack: Repair netfilter dependency X.509: silence asn1 compiler debug output X.509: shut up about included cert for silent build KEYS: Make /proc/keys unconditional if CONFIG_KEYS=y MAINTAINERS: email update tpm/tpm_tis: Add missing ifdef CONFIG_ACPI for pnp_acpi_device smack: fix possible use after frees in task_security() callers smack: Add missing logging in bidirectional UDS connect check Smack: secmark support for netfilter Smack: Rework file hooks tpm: fix format string error in tpm-chip.c char/tpm/tpm_crb: fix build error smack: Fix a bidirectional UDS connect check typo smack: introduce a special case for tmpfs in smack_d_instantiate() ...
This commit is contained in:
commit
8cc748aa76
|
@ -1,4 +1,4 @@
|
||||||
What: /sys/class/misc/tpmX/device/
|
What: /sys/class/tpm/tpmX/device/
|
||||||
Date: April 2005
|
Date: April 2005
|
||||||
KernelVersion: 2.6.12
|
KernelVersion: 2.6.12
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -6,7 +6,7 @@ Description: The device/ directory under a specific TPM instance exposes
|
||||||
the properties of that TPM chip
|
the properties of that TPM chip
|
||||||
|
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/active
|
What: /sys/class/tpm/tpmX/device/active
|
||||||
Date: April 2006
|
Date: April 2006
|
||||||
KernelVersion: 2.6.17
|
KernelVersion: 2.6.17
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -18,7 +18,7 @@ Description: The "active" property prints a '1' if the TPM chip is accepting
|
||||||
section 17 for more information on which commands are
|
section 17 for more information on which commands are
|
||||||
available.
|
available.
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/cancel
|
What: /sys/class/tpm/tpmX/device/cancel
|
||||||
Date: June 2005
|
Date: June 2005
|
||||||
KernelVersion: 2.6.13
|
KernelVersion: 2.6.13
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -26,7 +26,7 @@ Description: The "cancel" property allows you to cancel the currently
|
||||||
pending TPM command. Writing any value to cancel will call the
|
pending TPM command. Writing any value to cancel will call the
|
||||||
TPM vendor specific cancel operation.
|
TPM vendor specific cancel operation.
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/caps
|
What: /sys/class/tpm/tpmX/device/caps
|
||||||
Date: April 2005
|
Date: April 2005
|
||||||
KernelVersion: 2.6.12
|
KernelVersion: 2.6.12
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -43,7 +43,7 @@ Description: The "caps" property contains TPM manufacturer and version info.
|
||||||
the chip supports. Firmware version is that of the chip and
|
the chip supports. Firmware version is that of the chip and
|
||||||
is manufacturer specific.
|
is manufacturer specific.
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/durations
|
What: /sys/class/tpm/tpmX/device/durations
|
||||||
Date: March 2011
|
Date: March 2011
|
||||||
KernelVersion: 3.1
|
KernelVersion: 3.1
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -66,7 +66,7 @@ Description: The "durations" property shows the 3 vendor-specific values
|
||||||
scaled to be displayed in usecs. In this case "[adjusted]"
|
scaled to be displayed in usecs. In this case "[adjusted]"
|
||||||
will be displayed in place of "[original]".
|
will be displayed in place of "[original]".
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/enabled
|
What: /sys/class/tpm/tpmX/device/enabled
|
||||||
Date: April 2006
|
Date: April 2006
|
||||||
KernelVersion: 2.6.17
|
KernelVersion: 2.6.17
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -75,7 +75,7 @@ Description: The "enabled" property prints a '1' if the TPM chip is enabled,
|
||||||
may be visible but produce a '0' after some operation that
|
may be visible but produce a '0' after some operation that
|
||||||
disables the TPM.
|
disables the TPM.
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/owned
|
What: /sys/class/tpm/tpmX/device/owned
|
||||||
Date: April 2006
|
Date: April 2006
|
||||||
KernelVersion: 2.6.17
|
KernelVersion: 2.6.17
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -83,7 +83,7 @@ Description: The "owned" property produces a '1' if the TPM_TakeOwnership
|
||||||
ordinal has been executed successfully in the chip. A '0'
|
ordinal has been executed successfully in the chip. A '0'
|
||||||
indicates that ownership hasn't been taken.
|
indicates that ownership hasn't been taken.
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/pcrs
|
What: /sys/class/tpm/tpmX/device/pcrs
|
||||||
Date: April 2005
|
Date: April 2005
|
||||||
KernelVersion: 2.6.12
|
KernelVersion: 2.6.12
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -106,7 +106,7 @@ Description: The "pcrs" property will dump the current value of all Platform
|
||||||
1.2 chips, PCRs represent SHA-1 hashes, which are 20 bytes
|
1.2 chips, PCRs represent SHA-1 hashes, which are 20 bytes
|
||||||
long. Use the "caps" property to determine TPM version.
|
long. Use the "caps" property to determine TPM version.
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/pubek
|
What: /sys/class/tpm/tpmX/device/pubek
|
||||||
Date: April 2005
|
Date: April 2005
|
||||||
KernelVersion: 2.6.12
|
KernelVersion: 2.6.12
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -158,7 +158,7 @@ Description: The "pubek" property will return the TPM's public endorsement
|
||||||
Modulus Length: 256 (bytes)
|
Modulus Length: 256 (bytes)
|
||||||
Modulus: The 256 byte Endorsement Key modulus
|
Modulus: The 256 byte Endorsement Key modulus
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/temp_deactivated
|
What: /sys/class/tpm/tpmX/device/temp_deactivated
|
||||||
Date: April 2006
|
Date: April 2006
|
||||||
KernelVersion: 2.6.17
|
KernelVersion: 2.6.17
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
@ -167,7 +167,7 @@ Description: The "temp_deactivated" property returns a '1' if the chip has
|
||||||
cycle. Whether a warm boot (reboot) will clear a TPM chip
|
cycle. Whether a warm boot (reboot) will clear a TPM chip
|
||||||
from a temp_deactivated state is platform specific.
|
from a temp_deactivated state is platform specific.
|
||||||
|
|
||||||
What: /sys/class/misc/tpmX/device/timeouts
|
What: /sys/class/tpm/tpmX/device/timeouts
|
||||||
Date: March 2011
|
Date: March 2011
|
||||||
KernelVersion: 3.1
|
KernelVersion: 3.1
|
||||||
Contact: tpmdd-devel@lists.sf.net
|
Contact: tpmdd-devel@lists.sf.net
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
* STMicroelectronics SAS. ST33ZP24 TPM SoC
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should be "st,st33zp24-i2c".
|
||||||
|
- clock-frequency: I²C work frequency.
|
||||||
|
- reg: address on the bus
|
||||||
|
|
||||||
|
Optional ST33ZP24 Properties:
|
||||||
|
- interrupt-parent: phandle for the interrupt gpio controller
|
||||||
|
- interrupts: GPIO interrupt to which the chip is connected
|
||||||
|
- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state.
|
||||||
|
If set, power must be present when the platform is going into sleep/hibernate mode.
|
||||||
|
|
||||||
|
Optional SoC Specific Properties:
|
||||||
|
- pinctrl-names: Contains only one value - "default".
|
||||||
|
- pintctrl-0: Specifies the pin control groups used for this controller.
|
||||||
|
|
||||||
|
Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2):
|
||||||
|
|
||||||
|
&i2c2 {
|
||||||
|
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
st33zp24: st33zp24@13 {
|
||||||
|
|
||||||
|
compatible = "st,st33zp24-i2c";
|
||||||
|
|
||||||
|
reg = <0x13>;
|
||||||
|
clock-frequency = <400000>;
|
||||||
|
|
||||||
|
interrupt-parent = <&gpio5>;
|
||||||
|
interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
|
||||||
|
lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -323,8 +323,6 @@ about the status of the key service:
|
||||||
U Under construction by callback to userspace
|
U Under construction by callback to userspace
|
||||||
N Negative key
|
N Negative key
|
||||||
|
|
||||||
This file must be enabled at kernel configuration time as it allows anyone
|
|
||||||
to list the keys database.
|
|
||||||
|
|
||||||
(*) /proc/key-users
|
(*) /proc/key-users
|
||||||
|
|
||||||
|
|
12
MAINTAINERS
12
MAINTAINERS
|
@ -4917,7 +4917,7 @@ F: drivers/ipack/
|
||||||
|
|
||||||
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
|
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
|
||||||
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
||||||
M: Dmitry Kasatkin <d.kasatkin@samsung.com>
|
M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
|
||||||
L: linux-ima-devel@lists.sourceforge.net
|
L: linux-ima-devel@lists.sourceforge.net
|
||||||
L: linux-ima-user@lists.sourceforge.net
|
L: linux-ima-user@lists.sourceforge.net
|
||||||
L: linux-security-module@vger.kernel.org
|
L: linux-security-module@vger.kernel.org
|
||||||
|
@ -9817,13 +9817,21 @@ F: drivers/media/pci/tw68/
|
||||||
|
|
||||||
TPM DEVICE DRIVER
|
TPM DEVICE DRIVER
|
||||||
M: Peter Huewe <peterhuewe@gmx.de>
|
M: Peter Huewe <peterhuewe@gmx.de>
|
||||||
M: Ashley Lai <ashley@ashleylai.com>
|
|
||||||
M: Marcel Selhorst <tpmdd@selhorst.net>
|
M: Marcel Selhorst <tpmdd@selhorst.net>
|
||||||
W: http://tpmdd.sourceforge.net
|
W: http://tpmdd.sourceforge.net
|
||||||
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
|
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||||
|
Q: git git://github.com/PeterHuewe/linux-tpmdd.git
|
||||||
|
T: https://github.com/PeterHuewe/linux-tpmdd
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/char/tpm/
|
F: drivers/char/tpm/
|
||||||
|
|
||||||
|
TPM IBM_VTPM DEVICE DRIVER
|
||||||
|
M: Ashley Lai <ashleydlai@gmail.com>
|
||||||
|
W: http://tpmdd.sourceforge.net
|
||||||
|
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/char/tpm/tpm_ibmvtpm*
|
||||||
|
|
||||||
TRACING
|
TRACING
|
||||||
M: Steven Rostedt <rostedt@goodmis.org>
|
M: Steven Rostedt <rostedt@goodmis.org>
|
||||||
M: Ingo Molnar <mingo@redhat.com>
|
M: Ingo Molnar <mingo@redhat.com>
|
||||||
|
|
|
@ -100,15 +100,15 @@ config TCG_IBMVTPM
|
||||||
will be accessible from within Linux. To compile this driver
|
will be accessible from within Linux. To compile this driver
|
||||||
as a module, choose M here; the module will be called tpm_ibmvtpm.
|
as a module, choose M here; the module will be called tpm_ibmvtpm.
|
||||||
|
|
||||||
config TCG_ST33_I2C
|
config TCG_TIS_I2C_ST33
|
||||||
tristate "STMicroelectronics ST33 I2C TPM"
|
tristate "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
depends on GPIOLIB
|
depends on GPIOLIB
|
||||||
---help---
|
---help---
|
||||||
If you have a TPM security chip from STMicroelectronics working with
|
If you have a TPM security chip from STMicroelectronics working with
|
||||||
an I2C bus say Yes and it will be accessible from within Linux.
|
an I2C bus say Yes and it will be accessible from within Linux.
|
||||||
To compile this driver as a module, choose M here; the module will be
|
To compile this driver as a module, choose M here; the module will be
|
||||||
called tpm_stm_st33_i2c.
|
called tpm_i2c_stm_st33.
|
||||||
|
|
||||||
config TCG_XEN
|
config TCG_XEN
|
||||||
tristate "XEN TPM Interface"
|
tristate "XEN TPM Interface"
|
||||||
|
@ -122,4 +122,13 @@ config TCG_XEN
|
||||||
To compile this driver as a module, choose M here; the module
|
To compile this driver as a module, choose M here; the module
|
||||||
will be called xen-tpmfront.
|
will be called xen-tpmfront.
|
||||||
|
|
||||||
|
config TCG_CRB
|
||||||
|
tristate "TPM 2.0 CRB Interface"
|
||||||
|
depends on X86 && ACPI
|
||||||
|
---help---
|
||||||
|
If you have a TPM security chip that is compliant with the
|
||||||
|
TCG CRB 2.0 TPM specification say Yes and it will be accessible
|
||||||
|
from within Linux. To compile this driver as a module, choose
|
||||||
|
M here; the module will be called tpm_crb.
|
||||||
|
|
||||||
endif # TCG_TPM
|
endif # TCG_TPM
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Makefile for the kernel tpm device drivers.
|
# Makefile for the kernel tpm device drivers.
|
||||||
#
|
#
|
||||||
obj-$(CONFIG_TCG_TPM) += tpm.o
|
obj-$(CONFIG_TCG_TPM) += tpm.o
|
||||||
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o
|
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
|
||||||
tpm-$(CONFIG_ACPI) += tpm_ppi.o
|
tpm-$(CONFIG_ACPI) += tpm_ppi.o
|
||||||
|
|
||||||
ifdef CONFIG_ACPI
|
ifdef CONFIG_ACPI
|
||||||
|
@ -20,5 +20,6 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
|
||||||
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
|
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
|
||||||
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
|
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
|
||||||
obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
|
obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
|
||||||
obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
|
obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o
|
||||||
obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
|
obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
|
||||||
|
obj-$(CONFIG_TCG_CRB) += tpm_crb.o
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2004 IBM Corporation
|
||||||
|
* Copyright (C) 2014 Intel Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
||||||
|
* 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>
|
||||||
|
*
|
||||||
|
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
||||||
|
*
|
||||||
|
* TPM chip management routines.
|
||||||
|
*
|
||||||
|
* 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/poll.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/freezer.h>
|
||||||
|
#include <linux/major.h>
|
||||||
|
#include "tpm.h"
|
||||||
|
#include "tpm_eventlog.h"
|
||||||
|
|
||||||
|
static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
|
||||||
|
static LIST_HEAD(tpm_chip_list);
|
||||||
|
static DEFINE_SPINLOCK(driver_lock);
|
||||||
|
|
||||||
|
struct class *tpm_class;
|
||||||
|
dev_t tpm_devt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tpm_chip_find_get - return tpm_chip for a given chip number
|
||||||
|
* @chip_num the device number for the chip
|
||||||
|
*/
|
||||||
|
struct tpm_chip *tpm_chip_find_get(int chip_num)
|
||||||
|
{
|
||||||
|
struct tpm_chip *pos, *chip = NULL;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
|
||||||
|
if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (try_module_get(pos->pdev->driver->owner)) {
|
||||||
|
chip = pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
return chip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm_dev_release() - free chip memory and the device number
|
||||||
|
* @dev: the character device for the TPM chip
|
||||||
|
*
|
||||||
|
* This is used as the release function for the character device.
|
||||||
|
*/
|
||||||
|
static void tpm_dev_release(struct device *dev)
|
||||||
|
{
|
||||||
|
struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
|
||||||
|
|
||||||
|
spin_lock(&driver_lock);
|
||||||
|
clear_bit(chip->dev_num, dev_mask);
|
||||||
|
spin_unlock(&driver_lock);
|
||||||
|
kfree(chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpmm_chip_alloc() - allocate a new struct tpm_chip instance
|
||||||
|
* @dev: device to which the chip is associated
|
||||||
|
* @ops: struct tpm_class_ops instance
|
||||||
|
*
|
||||||
|
* Allocates a new struct tpm_chip instance and assigns a free
|
||||||
|
* device number for it. Caller does not have to worry about
|
||||||
|
* freeing the allocated resources. When the devices is removed
|
||||||
|
* devres calls tpmm_chip_remove() to do the job.
|
||||||
|
*/
|
||||||
|
struct tpm_chip *tpmm_chip_alloc(struct device *dev,
|
||||||
|
const struct tpm_class_ops *ops)
|
||||||
|
{
|
||||||
|
struct tpm_chip *chip;
|
||||||
|
|
||||||
|
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||||
|
if (chip == NULL)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
mutex_init(&chip->tpm_mutex);
|
||||||
|
INIT_LIST_HEAD(&chip->list);
|
||||||
|
|
||||||
|
chip->ops = ops;
|
||||||
|
|
||||||
|
spin_lock(&driver_lock);
|
||||||
|
chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
|
||||||
|
spin_unlock(&driver_lock);
|
||||||
|
|
||||||
|
if (chip->dev_num >= TPM_NUM_DEVICES) {
|
||||||
|
dev_err(dev, "No available tpm device numbers\n");
|
||||||
|
kfree(chip);
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_bit(chip->dev_num, dev_mask);
|
||||||
|
|
||||||
|
scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num);
|
||||||
|
|
||||||
|
chip->pdev = dev;
|
||||||
|
|
||||||
|
dev_set_drvdata(dev, chip);
|
||||||
|
|
||||||
|
chip->dev.class = tpm_class;
|
||||||
|
chip->dev.release = tpm_dev_release;
|
||||||
|
chip->dev.parent = chip->pdev;
|
||||||
|
|
||||||
|
if (chip->dev_num == 0)
|
||||||
|
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
|
||||||
|
else
|
||||||
|
chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
|
||||||
|
|
||||||
|
dev_set_name(&chip->dev, "%s", chip->devname);
|
||||||
|
|
||||||
|
device_initialize(&chip->dev);
|
||||||
|
|
||||||
|
chip->cdev.owner = chip->pdev->driver->owner;
|
||||||
|
cdev_init(&chip->cdev, &tpm_fops);
|
||||||
|
|
||||||
|
return chip;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
|
||||||
|
|
||||||
|
static int tpm_dev_add_device(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = device_add(&chip->dev);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(&chip->dev,
|
||||||
|
"unable to device_register() %s, major %d, minor %d, err=%d\n",
|
||||||
|
chip->devname, MAJOR(chip->dev.devt),
|
||||||
|
MINOR(chip->dev.devt), rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(&chip->dev,
|
||||||
|
"unable to cdev_add() %s, major %d, minor %d, err=%d\n",
|
||||||
|
chip->devname, MAJOR(chip->dev.devt),
|
||||||
|
MINOR(chip->dev.devt), rc);
|
||||||
|
|
||||||
|
device_unregister(&chip->dev);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tpm_dev_del_device(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
cdev_del(&chip->cdev);
|
||||||
|
device_unregister(&chip->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tpm_chip_register() - create a character device for the TPM chip
|
||||||
|
* @chip: TPM chip to use.
|
||||||
|
*
|
||||||
|
* Creates a character device for the TPM chip and adds sysfs interfaces for
|
||||||
|
* the device, PPI and TCPA. As the last step this function adds the
|
||||||
|
* chip to the list of TPM chips available for use.
|
||||||
|
*
|
||||||
|
* NOTE: This function should be only called after the chip initialization
|
||||||
|
* is complete.
|
||||||
|
*
|
||||||
|
* Called from tpm_<specific>.c probe function only for devices
|
||||||
|
* the driver has determined it should claim. Prior to calling
|
||||||
|
* this function the specific probe function has called pci_enable_device
|
||||||
|
* upon errant exit from this function specific probe function should call
|
||||||
|
* pci_disable_device
|
||||||
|
*/
|
||||||
|
int tpm_chip_register(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = tpm_dev_add_device(chip);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Populate sysfs for TPM1 devices. */
|
||||||
|
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
|
||||||
|
rc = tpm_sysfs_add_device(chip);
|
||||||
|
if (rc)
|
||||||
|
goto del_misc;
|
||||||
|
|
||||||
|
rc = tpm_add_ppi(chip);
|
||||||
|
if (rc)
|
||||||
|
goto del_sysfs;
|
||||||
|
|
||||||
|
chip->bios_dir = tpm_bios_log_setup(chip->devname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the chip available. */
|
||||||
|
spin_lock(&driver_lock);
|
||||||
|
list_add_rcu(&chip->list, &tpm_chip_list);
|
||||||
|
spin_unlock(&driver_lock);
|
||||||
|
|
||||||
|
chip->flags |= TPM_CHIP_FLAG_REGISTERED;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
del_sysfs:
|
||||||
|
tpm_sysfs_del_device(chip);
|
||||||
|
del_misc:
|
||||||
|
tpm_dev_del_device(chip);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm_chip_register);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tpm_chip_unregister() - release the TPM driver
|
||||||
|
* @chip: TPM chip to use.
|
||||||
|
*
|
||||||
|
* Takes the chip first away from the list of available TPM chips and then
|
||||||
|
* cleans up all the resources reserved by tpm_chip_register().
|
||||||
|
*
|
||||||
|
* NOTE: This function should be only called before deinitializing chip
|
||||||
|
* resources.
|
||||||
|
*/
|
||||||
|
void tpm_chip_unregister(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED))
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock(&driver_lock);
|
||||||
|
list_del_rcu(&chip->list);
|
||||||
|
spin_unlock(&driver_lock);
|
||||||
|
synchronize_rcu();
|
||||||
|
|
||||||
|
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
|
||||||
|
if (chip->bios_dir)
|
||||||
|
tpm_bios_log_teardown(chip->bios_dir);
|
||||||
|
tpm_remove_ppi(chip);
|
||||||
|
tpm_sysfs_del_device(chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
tpm_dev_del_device(chip);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm_chip_unregister);
|
|
@ -17,7 +17,6 @@
|
||||||
* License.
|
* License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <linux/miscdevice.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
|
@ -54,16 +53,15 @@ static void timeout_work(struct work_struct *work)
|
||||||
|
|
||||||
static int tpm_open(struct inode *inode, struct file *file)
|
static int tpm_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct miscdevice *misc = file->private_data;
|
struct tpm_chip *chip =
|
||||||
struct tpm_chip *chip = container_of(misc, struct tpm_chip,
|
container_of(inode->i_cdev, struct tpm_chip, cdev);
|
||||||
vendor.miscdev);
|
|
||||||
struct file_priv *priv;
|
struct file_priv *priv;
|
||||||
|
|
||||||
/* It's assured that the chip will be opened just once,
|
/* It's assured that the chip will be opened just once,
|
||||||
* by the check of is_open variable, which is protected
|
* by the check of is_open variable, which is protected
|
||||||
* by driver_lock. */
|
* by driver_lock. */
|
||||||
if (test_and_set_bit(0, &chip->is_open)) {
|
if (test_and_set_bit(0, &chip->is_open)) {
|
||||||
dev_dbg(chip->dev, "Another process owns this TPM\n");
|
dev_dbg(chip->pdev, "Another process owns this TPM\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +79,7 @@ static int tpm_open(struct inode *inode, struct file *file)
|
||||||
INIT_WORK(&priv->work, timeout_work);
|
INIT_WORK(&priv->work, timeout_work);
|
||||||
|
|
||||||
file->private_data = priv;
|
file->private_data = priv;
|
||||||
get_device(chip->dev);
|
get_device(chip->pdev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,12 +166,12 @@ static int tpm_release(struct inode *inode, struct file *file)
|
||||||
file->private_data = NULL;
|
file->private_data = NULL;
|
||||||
atomic_set(&priv->data_pending, 0);
|
atomic_set(&priv->data_pending, 0);
|
||||||
clear_bit(0, &priv->chip->is_open);
|
clear_bit(0, &priv->chip->is_open);
|
||||||
put_device(priv->chip->dev);
|
put_device(priv->chip->pdev);
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations tpm_fops = {
|
const struct file_operations tpm_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.llseek = no_llseek,
|
.llseek = no_llseek,
|
||||||
.open = tpm_open,
|
.open = tpm_open,
|
||||||
|
@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = {
|
||||||
.release = tpm_release,
|
.release = tpm_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
int tpm_dev_add_device(struct tpm_chip *chip)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
chip->vendor.miscdev.fops = &tpm_fops;
|
|
||||||
if (chip->dev_num == 0)
|
|
||||||
chip->vendor.miscdev.minor = TPM_MINOR;
|
|
||||||
else
|
|
||||||
chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
|
|
||||||
|
|
||||||
chip->vendor.miscdev.name = chip->devname;
|
|
||||||
chip->vendor.miscdev.parent = chip->dev;
|
|
||||||
|
|
||||||
rc = misc_register(&chip->vendor.miscdev);
|
|
||||||
if (rc) {
|
|
||||||
chip->vendor.miscdev.name = NULL;
|
|
||||||
dev_err(chip->dev,
|
|
||||||
"unable to misc_register %s, minor %d err=%d\n",
|
|
||||||
chip->vendor.miscdev.name,
|
|
||||||
chip->vendor.miscdev.minor, rc);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tpm_dev_del_device(struct tpm_chip *chip)
|
|
||||||
{
|
|
||||||
if (chip->vendor.miscdev.name)
|
|
||||||
misc_deregister(&chip->vendor.miscdev);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2004 IBM Corporation
|
* Copyright (C) 2004 IBM Corporation
|
||||||
|
* Copyright (C) 2014 Intel Corporation
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Leendert van Doorn <leendert@watson.ibm.com>
|
* Leendert van Doorn <leendert@watson.ibm.com>
|
||||||
|
@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
|
||||||
MODULE_PARM_DESC(suspend_pcr,
|
MODULE_PARM_DESC(suspend_pcr,
|
||||||
"PCR to use for dummy writes to faciltate flush on suspend.");
|
"PCR to use for dummy writes to faciltate flush on suspend.");
|
||||||
|
|
||||||
static LIST_HEAD(tpm_chip_list);
|
|
||||||
static DEFINE_SPINLOCK(driver_lock);
|
|
||||||
static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Array with one entry per ordinal defining the maximum amount
|
* Array with one entry per ordinal defining the maximum amount
|
||||||
* of time the chip could take to return the result. The ordinal
|
* of time the chip could take to return the result. The ordinal
|
||||||
|
@ -346,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
if (count > bufsiz) {
|
if (count > bufsiz) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"invalid count value %x %zx\n", count, bufsiz);
|
"invalid count value %x %zx\n", count, bufsiz);
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
}
|
}
|
||||||
|
@ -355,7 +352,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
|
|
||||||
rc = chip->ops->send(chip, (u8 *) buf, count);
|
rc = chip->ops->send(chip, (u8 *) buf, count);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"tpm_transmit: tpm_send: error %zd\n", rc);
|
"tpm_transmit: tpm_send: error %zd\n", rc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -363,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
if (chip->vendor.irq)
|
if (chip->vendor.irq)
|
||||||
goto out_recv;
|
goto out_recv;
|
||||||
|
|
||||||
stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
|
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||||
|
stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
|
||||||
|
else
|
||||||
|
stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
|
||||||
do {
|
do {
|
||||||
u8 status = chip->ops->status(chip);
|
u8 status = chip->ops->status(chip);
|
||||||
if ((status & chip->ops->req_complete_mask) ==
|
if ((status & chip->ops->req_complete_mask) ==
|
||||||
|
@ -371,7 +371,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
goto out_recv;
|
goto out_recv;
|
||||||
|
|
||||||
if (chip->ops->req_canceled(chip, status)) {
|
if (chip->ops->req_canceled(chip, status)) {
|
||||||
dev_err(chip->dev, "Operation Canceled\n");
|
dev_err(chip->pdev, "Operation Canceled\n");
|
||||||
rc = -ECANCELED;
|
rc = -ECANCELED;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -381,14 +381,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
} while (time_before(jiffies, stop));
|
} while (time_before(jiffies, stop));
|
||||||
|
|
||||||
chip->ops->cancel(chip);
|
chip->ops->cancel(chip);
|
||||||
dev_err(chip->dev, "Operation Timed out\n");
|
dev_err(chip->pdev, "Operation Timed out\n");
|
||||||
rc = -ETIME;
|
rc = -ETIME;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
out_recv:
|
out_recv:
|
||||||
rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
|
rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"tpm_transmit: tpm_recv: error %zd\n", rc);
|
"tpm_transmit: tpm_recv: error %zd\n", rc);
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&chip->tpm_mutex);
|
mutex_unlock(&chip->tpm_mutex);
|
||||||
|
@ -398,9 +398,10 @@ out:
|
||||||
#define TPM_DIGEST_SIZE 20
|
#define TPM_DIGEST_SIZE 20
|
||||||
#define TPM_RET_CODE_IDX 6
|
#define TPM_RET_CODE_IDX 6
|
||||||
|
|
||||||
static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
|
||||||
int len, const char *desc)
|
int len, const char *desc)
|
||||||
{
|
{
|
||||||
|
struct tpm_output_header *header;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
len = tpm_transmit(chip, (u8 *) cmd, len);
|
len = tpm_transmit(chip, (u8 *) cmd, len);
|
||||||
|
@ -409,9 +410,12 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
||||||
else if (len < TPM_HEADER_SIZE)
|
else if (len < TPM_HEADER_SIZE)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
err = be32_to_cpu(cmd->header.out.return_code);
|
header = cmd;
|
||||||
|
|
||||||
|
err = be32_to_cpu(header->return_code);
|
||||||
if (err != 0 && desc)
|
if (err != 0 && desc)
|
||||||
dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
|
dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err,
|
||||||
|
desc);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -448,7 +452,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
|
||||||
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
||||||
tpm_cmd.params.getcap_in.subcap = subcap_id;
|
tpm_cmd.params.getcap_in.subcap = subcap_id;
|
||||||
}
|
}
|
||||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
|
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
*cap = tpm_cmd.params.getcap_out.cap;
|
*cap = tpm_cmd.params.getcap_out.cap;
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -464,8 +468,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
|
||||||
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
||||||
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
|
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
|
||||||
|
|
||||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||||
"attempting to determine the timeouts");
|
"attempting to determine the timeouts");
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
|
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
|
||||||
|
|
||||||
|
@ -483,9 +487,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
|
||||||
{
|
{
|
||||||
struct tpm_cmd_t start_cmd;
|
struct tpm_cmd_t start_cmd;
|
||||||
start_cmd.header.in = tpm_startup_header;
|
start_cmd.header.in = tpm_startup_header;
|
||||||
|
|
||||||
start_cmd.params.startup_in.startup_type = startup_type;
|
start_cmd.params.startup_in.startup_type = startup_type;
|
||||||
return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
|
return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||||
"attempting to start the TPM");
|
"attempting to start the TPM");
|
||||||
}
|
}
|
||||||
|
|
||||||
int tpm_get_timeouts(struct tpm_chip *chip)
|
int tpm_get_timeouts(struct tpm_chip *chip)
|
||||||
|
@ -500,12 +505,12 @@ int tpm_get_timeouts(struct tpm_chip *chip)
|
||||||
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
|
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
|
||||||
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
||||||
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
|
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
|
||||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
|
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
|
||||||
|
|
||||||
if (rc == TPM_ERR_INVALID_POSTINIT) {
|
if (rc == TPM_ERR_INVALID_POSTINIT) {
|
||||||
/* The TPM is not started, we are the first to talk to it.
|
/* The TPM is not started, we are the first to talk to it.
|
||||||
Execute a startup command. */
|
Execute a startup command. */
|
||||||
dev_info(chip->dev, "Issuing TPM_STARTUP");
|
dev_info(chip->pdev, "Issuing TPM_STARTUP");
|
||||||
if (tpm_startup(chip, TPM_ST_CLEAR))
|
if (tpm_startup(chip, TPM_ST_CLEAR))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -513,11 +518,11 @@ int tpm_get_timeouts(struct tpm_chip *chip)
|
||||||
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
|
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
|
||||||
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
||||||
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
|
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
|
||||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"A TPM error (%zd) occurred attempting to determine the timeouts\n",
|
"A TPM error (%zd) occurred attempting to determine the timeouts\n",
|
||||||
rc);
|
rc);
|
||||||
goto duration;
|
goto duration;
|
||||||
|
@ -556,7 +561,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
|
||||||
|
|
||||||
/* Report adjusted timeouts */
|
/* Report adjusted timeouts */
|
||||||
if (chip->vendor.timeout_adjusted) {
|
if (chip->vendor.timeout_adjusted) {
|
||||||
dev_info(chip->dev,
|
dev_info(chip->pdev,
|
||||||
HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
|
HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
|
||||||
old_timeout[0], new_timeout[0],
|
old_timeout[0], new_timeout[0],
|
||||||
old_timeout[1], new_timeout[1],
|
old_timeout[1], new_timeout[1],
|
||||||
|
@ -575,8 +580,8 @@ duration:
|
||||||
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
||||||
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
|
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
|
||||||
|
|
||||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||||
"attempting to determine the durations");
|
"attempting to determine the durations");
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -603,7 +608,7 @@ duration:
|
||||||
chip->vendor.duration[TPM_MEDIUM] *= 1000;
|
chip->vendor.duration[TPM_MEDIUM] *= 1000;
|
||||||
chip->vendor.duration[TPM_LONG] *= 1000;
|
chip->vendor.duration[TPM_LONG] *= 1000;
|
||||||
chip->vendor.duration_adjusted = true;
|
chip->vendor.duration_adjusted = true;
|
||||||
dev_info(chip->dev, "Adjusting TPM timeout parameters.");
|
dev_info(chip->pdev, "Adjusting TPM timeout parameters.");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -631,32 +636,11 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
|
||||||
struct tpm_cmd_t cmd;
|
struct tpm_cmd_t cmd;
|
||||||
|
|
||||||
cmd.header.in = continue_selftest_header;
|
cmd.header.in = continue_selftest_header;
|
||||||
rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
|
rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
|
||||||
"continue selftest");
|
"continue selftest");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* tpm_chip_find_get - return tpm_chip for given chip number
|
|
||||||
*/
|
|
||||||
static struct tpm_chip *tpm_chip_find_get(int chip_num)
|
|
||||||
{
|
|
||||||
struct tpm_chip *pos, *chip = NULL;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
|
|
||||||
if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (try_module_get(pos->dev->driver->owner)) {
|
|
||||||
chip = pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
return chip;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
|
#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
|
||||||
#define READ_PCR_RESULT_SIZE 30
|
#define READ_PCR_RESULT_SIZE 30
|
||||||
static struct tpm_input_header pcrread_header = {
|
static struct tpm_input_header pcrread_header = {
|
||||||
|
@ -672,8 +656,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||||
|
|
||||||
cmd.header.in = pcrread_header;
|
cmd.header.in = pcrread_header;
|
||||||
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
|
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
|
||||||
rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
|
rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
|
||||||
"attempting to read a pcr value");
|
"attempting to read a pcr value");
|
||||||
|
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
|
memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
|
||||||
|
@ -700,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
|
||||||
chip = tpm_chip_find_get(chip_num);
|
chip = tpm_chip_find_get(chip_num);
|
||||||
if (chip == NULL)
|
if (chip == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
|
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||||
|
rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
|
||||||
|
else
|
||||||
|
rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
|
||||||
tpm_chip_put(chip);
|
tpm_chip_put(chip);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -734,11 +721,17 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
|
||||||
if (chip == NULL)
|
if (chip == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||||
|
rc = tpm2_pcr_extend(chip, pcr_idx, hash);
|
||||||
|
tpm_chip_put(chip);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
cmd.header.in = pcrextend_header;
|
cmd.header.in = pcrextend_header;
|
||||||
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
|
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
|
||||||
memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
|
memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
|
||||||
rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
|
rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
|
||||||
"attempting extend a PCR value");
|
"attempting extend a PCR value");
|
||||||
|
|
||||||
tpm_chip_put(chip);
|
tpm_chip_put(chip);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -781,7 +774,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
|
||||||
* around 300ms while the self test is ongoing, keep trying
|
* around 300ms while the self test is ongoing, keep trying
|
||||||
* until the self test duration expires. */
|
* until the self test duration expires. */
|
||||||
if (rc == -ETIME) {
|
if (rc == -ETIME) {
|
||||||
dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test");
|
dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test");
|
||||||
msleep(delay_msec);
|
msleep(delay_msec);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -791,7 +784,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
|
||||||
|
|
||||||
rc = be32_to_cpu(cmd.header.out.return_code);
|
rc = be32_to_cpu(cmd.header.out.return_code);
|
||||||
if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
|
if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
|
||||||
dev_info(chip->dev,
|
dev_info(chip->pdev,
|
||||||
"TPM is disabled/deactivated (0x%X)\n", rc);
|
"TPM is disabled/deactivated (0x%X)\n", rc);
|
||||||
/* TPM is disabled and/or deactivated; driver can
|
/* TPM is disabled and/or deactivated; driver can
|
||||||
* proceed and TPM does handle commands for
|
* proceed and TPM does handle commands for
|
||||||
|
@ -817,7 +810,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
|
||||||
if (chip == NULL)
|
if (chip == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
|
rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
|
||||||
|
|
||||||
tpm_chip_put(chip);
|
tpm_chip_put(chip);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -884,30 +877,6 @@ again:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
|
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
|
||||||
|
|
||||||
void tpm_remove_hardware(struct device *dev)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
if (chip == NULL) {
|
|
||||||
dev_err(dev, "No device data found\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock(&driver_lock);
|
|
||||||
list_del_rcu(&chip->list);
|
|
||||||
spin_unlock(&driver_lock);
|
|
||||||
synchronize_rcu();
|
|
||||||
|
|
||||||
tpm_dev_del_device(chip);
|
|
||||||
tpm_sysfs_del_device(chip);
|
|
||||||
tpm_remove_ppi(&dev->kobj);
|
|
||||||
tpm_bios_log_teardown(chip->bios_dir);
|
|
||||||
|
|
||||||
/* write it this way to be explicit (chip->dev == dev) */
|
|
||||||
put_device(chip->dev);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_remove_hardware);
|
|
||||||
|
|
||||||
#define TPM_ORD_SAVESTATE cpu_to_be32(152)
|
#define TPM_ORD_SAVESTATE cpu_to_be32(152)
|
||||||
#define SAVESTATE_RESULT_SIZE 10
|
#define SAVESTATE_RESULT_SIZE 10
|
||||||
|
|
||||||
|
@ -932,20 +901,23 @@ int tpm_pm_suspend(struct device *dev)
|
||||||
if (chip == NULL)
|
if (chip == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||||
|
return tpm2_shutdown(chip, TPM2_SU_CLEAR);
|
||||||
|
|
||||||
/* for buggy tpm, flush pcrs with extend to selected dummy */
|
/* for buggy tpm, flush pcrs with extend to selected dummy */
|
||||||
if (tpm_suspend_pcr) {
|
if (tpm_suspend_pcr) {
|
||||||
cmd.header.in = pcrextend_header;
|
cmd.header.in = pcrextend_header;
|
||||||
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
|
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
|
||||||
memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
|
memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
|
||||||
TPM_DIGEST_SIZE);
|
TPM_DIGEST_SIZE);
|
||||||
rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
|
rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
|
||||||
"extending dummy pcr before suspend");
|
"extending dummy pcr before suspend");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now do the actual savestate */
|
/* now do the actual savestate */
|
||||||
for (try = 0; try < TPM_RETRY; try++) {
|
for (try = 0; try < TPM_RETRY; try++) {
|
||||||
cmd.header.in = savestate_header;
|
cmd.header.in = savestate_header;
|
||||||
rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
|
rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the TPM indicates that it is too busy to respond to
|
* If the TPM indicates that it is too busy to respond to
|
||||||
|
@ -963,10 +935,10 @@ int tpm_pm_suspend(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"Error (%d) sending savestate before suspend\n", rc);
|
"Error (%d) sending savestate before suspend\n", rc);
|
||||||
else if (try > 0)
|
else if (try > 0)
|
||||||
dev_warn(chip->dev, "TPM savestate took %dms\n",
|
dev_warn(chip->pdev, "TPM savestate took %dms\n",
|
||||||
try * TPM_TIMEOUT_RETRY);
|
try * TPM_TIMEOUT_RETRY);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -1018,11 +990,17 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
|
||||||
if (chip == NULL)
|
if (chip == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||||
|
err = tpm2_get_random(chip, out, max);
|
||||||
|
tpm_chip_put(chip);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
tpm_cmd.header.in = tpm_getrandom_header;
|
tpm_cmd.header.in = tpm_getrandom_header;
|
||||||
tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
|
tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
|
||||||
|
|
||||||
err = transmit_cmd(chip, &tpm_cmd,
|
err = tpm_transmit_cmd(chip, &tpm_cmd,
|
||||||
TPM_GETRANDOM_RESULT_SIZE + num_bytes,
|
TPM_GETRANDOM_RESULT_SIZE + num_bytes,
|
||||||
"attempting get random");
|
"attempting get random");
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1041,103 +1019,34 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_get_random);
|
EXPORT_SYMBOL_GPL(tpm_get_random);
|
||||||
|
|
||||||
/* In case vendor provided release function, call it too.*/
|
static int __init tpm_init(void)
|
||||||
|
|
||||||
void tpm_dev_vendor_release(struct tpm_chip *chip)
|
|
||||||
{
|
{
|
||||||
if (!chip)
|
int rc;
|
||||||
return;
|
|
||||||
|
|
||||||
clear_bit(chip->dev_num, dev_mask);
|
tpm_class = class_create(THIS_MODULE, "tpm");
|
||||||
}
|
if (IS_ERR(tpm_class)) {
|
||||||
EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
|
pr_err("couldn't create tpm class\n");
|
||||||
|
return PTR_ERR(tpm_class);
|
||||||
|
|
||||||
/*
|
|
||||||
* Once all references to platform device are down to 0,
|
|
||||||
* release all allocated structures.
|
|
||||||
*/
|
|
||||||
static void tpm_dev_release(struct device *dev)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
if (!chip)
|
|
||||||
return;
|
|
||||||
|
|
||||||
tpm_dev_vendor_release(chip);
|
|
||||||
|
|
||||||
chip->release(dev);
|
|
||||||
kfree(chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called from tpm_<specific>.c probe function only for devices
|
|
||||||
* the driver has determined it should claim. Prior to calling
|
|
||||||
* this function the specific probe function has called pci_enable_device
|
|
||||||
* upon errant exit from this function specific probe function should call
|
|
||||||
* pci_disable_device
|
|
||||||
*/
|
|
||||||
struct tpm_chip *tpm_register_hardware(struct device *dev,
|
|
||||||
const struct tpm_class_ops *ops)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip;
|
|
||||||
|
|
||||||
/* Driver specific per-device data */
|
|
||||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
|
||||||
|
|
||||||
if (chip == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
mutex_init(&chip->tpm_mutex);
|
|
||||||
INIT_LIST_HEAD(&chip->list);
|
|
||||||
|
|
||||||
chip->ops = ops;
|
|
||||||
chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
|
|
||||||
|
|
||||||
if (chip->dev_num >= TPM_NUM_DEVICES) {
|
|
||||||
dev_err(dev, "No available tpm device numbers\n");
|
|
||||||
goto out_free;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_bit(chip->dev_num, dev_mask);
|
rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("tpm: failed to allocate char dev region\n");
|
||||||
|
class_destroy(tpm_class);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
|
return 0;
|
||||||
chip->dev_num);
|
|
||||||
|
|
||||||
chip->dev = get_device(dev);
|
|
||||||
chip->release = dev->release;
|
|
||||||
dev->release = tpm_dev_release;
|
|
||||||
dev_set_drvdata(dev, chip);
|
|
||||||
|
|
||||||
if (tpm_dev_add_device(chip))
|
|
||||||
goto put_device;
|
|
||||||
|
|
||||||
if (tpm_sysfs_add_device(chip))
|
|
||||||
goto del_misc;
|
|
||||||
|
|
||||||
if (tpm_add_ppi(&dev->kobj))
|
|
||||||
goto del_sysfs;
|
|
||||||
|
|
||||||
chip->bios_dir = tpm_bios_log_setup(chip->devname);
|
|
||||||
|
|
||||||
/* Make chip available */
|
|
||||||
spin_lock(&driver_lock);
|
|
||||||
list_add_rcu(&chip->list, &tpm_chip_list);
|
|
||||||
spin_unlock(&driver_lock);
|
|
||||||
|
|
||||||
return chip;
|
|
||||||
|
|
||||||
del_sysfs:
|
|
||||||
tpm_sysfs_del_device(chip);
|
|
||||||
del_misc:
|
|
||||||
tpm_dev_del_device(chip);
|
|
||||||
put_device:
|
|
||||||
put_device(chip->dev);
|
|
||||||
out_free:
|
|
||||||
kfree(chip);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_register_hardware);
|
|
||||||
|
static void __exit tpm_exit(void)
|
||||||
|
{
|
||||||
|
class_destroy(tpm_class);
|
||||||
|
unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
|
||||||
|
}
|
||||||
|
|
||||||
|
subsys_initcall(tpm_init);
|
||||||
|
module_exit(tpm_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
|
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
|
||||||
MODULE_DESCRIPTION("TPM Driver");
|
MODULE_DESCRIPTION("TPM Driver");
|
||||||
|
|
|
@ -20,25 +20,6 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
|
|
||||||
/* XXX for now this helper is duplicated in tpm-interface.c */
|
|
||||||
static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
|
||||||
int len, const char *desc)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
len = tpm_transmit(chip, (u8 *) cmd, len);
|
|
||||||
if (len < 0)
|
|
||||||
return len;
|
|
||||||
else if (len < TPM_HEADER_SIZE)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
err = be32_to_cpu(cmd->header.out.return_code);
|
|
||||||
if (err != 0 && desc)
|
|
||||||
dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define READ_PUBEK_RESULT_SIZE 314
|
#define READ_PUBEK_RESULT_SIZE 314
|
||||||
#define TPM_ORD_READPUBEK cpu_to_be32(124)
|
#define TPM_ORD_READPUBEK cpu_to_be32(124)
|
||||||
static struct tpm_input_header tpm_readpubek_header = {
|
static struct tpm_input_header tpm_readpubek_header = {
|
||||||
|
@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
tpm_cmd.header.in = tpm_readpubek_header;
|
tpm_cmd.header.in = tpm_readpubek_header;
|
||||||
err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
|
err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
|
||||||
"attempting to read the PUBEK");
|
"attempting to read the PUBEK");
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -303,16 +284,16 @@ static const struct attribute_group tpm_dev_group = {
|
||||||
int tpm_sysfs_add_device(struct tpm_chip *chip)
|
int tpm_sysfs_add_device(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
err = sysfs_create_group(&chip->dev->kobj,
|
err = sysfs_create_group(&chip->pdev->kobj,
|
||||||
&tpm_dev_group);
|
&tpm_dev_group);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"failed to create sysfs attributes, %d\n", err);
|
"failed to create sysfs attributes, %d\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tpm_sysfs_del_device(struct tpm_chip *chip)
|
void tpm_sysfs_del_device(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group);
|
sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,23 +10,24 @@
|
||||||
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
||||||
*
|
*
|
||||||
* Device driver for TCG/TCPA TPM (trusted platform module).
|
* Device driver for TCG/TCPA TPM (trusted platform module).
|
||||||
* Specifications at www.trustedcomputinggroup.org
|
* Specifications at www.trustedcomputinggroup.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
* published by the Free Software Foundation, version 2 of the
|
* published by the Free Software Foundation, version 2 of the
|
||||||
* License.
|
* License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/miscdevice.h>
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/tpm.h>
|
#include <linux/tpm.h>
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
|
||||||
enum tpm_const {
|
enum tpm_const {
|
||||||
TPM_MINOR = 224, /* officially assigned */
|
TPM_MINOR = 224, /* officially assigned */
|
||||||
|
@ -61,6 +62,59 @@ enum tpm_duration {
|
||||||
#define TPM_ERR_INVALID_POSTINIT 38
|
#define TPM_ERR_INVALID_POSTINIT 38
|
||||||
|
|
||||||
#define TPM_HEADER_SIZE 10
|
#define TPM_HEADER_SIZE 10
|
||||||
|
|
||||||
|
enum tpm2_const {
|
||||||
|
TPM2_PLATFORM_PCR = 24,
|
||||||
|
TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
|
||||||
|
TPM2_TIMEOUT_A = 750,
|
||||||
|
TPM2_TIMEOUT_B = 2000,
|
||||||
|
TPM2_TIMEOUT_C = 200,
|
||||||
|
TPM2_TIMEOUT_D = 30,
|
||||||
|
TPM2_DURATION_SHORT = 20,
|
||||||
|
TPM2_DURATION_MEDIUM = 750,
|
||||||
|
TPM2_DURATION_LONG = 2000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tpm2_structures {
|
||||||
|
TPM2_ST_NO_SESSIONS = 0x8001,
|
||||||
|
TPM2_ST_SESSIONS = 0x8002,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tpm2_return_codes {
|
||||||
|
TPM2_RC_INITIALIZE = 0x0100,
|
||||||
|
TPM2_RC_TESTING = 0x090A,
|
||||||
|
TPM2_RC_DISABLED = 0x0120,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tpm2_algorithms {
|
||||||
|
TPM2_ALG_SHA1 = 0x0004,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tpm2_command_codes {
|
||||||
|
TPM2_CC_FIRST = 0x011F,
|
||||||
|
TPM2_CC_SELF_TEST = 0x0143,
|
||||||
|
TPM2_CC_STARTUP = 0x0144,
|
||||||
|
TPM2_CC_SHUTDOWN = 0x0145,
|
||||||
|
TPM2_CC_GET_CAPABILITY = 0x017A,
|
||||||
|
TPM2_CC_GET_RANDOM = 0x017B,
|
||||||
|
TPM2_CC_PCR_READ = 0x017E,
|
||||||
|
TPM2_CC_PCR_EXTEND = 0x0182,
|
||||||
|
TPM2_CC_LAST = 0x018F,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tpm2_permanent_handles {
|
||||||
|
TPM2_RS_PW = 0x40000009,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tpm2_capabilities {
|
||||||
|
TPM2_CAP_TPM_PROPERTIES = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tpm2_startup_types {
|
||||||
|
TPM2_SU_CLEAR = 0x0000,
|
||||||
|
TPM2_SU_STATE = 0x0001,
|
||||||
|
};
|
||||||
|
|
||||||
struct tpm_chip;
|
struct tpm_chip;
|
||||||
|
|
||||||
struct tpm_vendor_specific {
|
struct tpm_vendor_specific {
|
||||||
|
@ -73,7 +127,6 @@ struct tpm_vendor_specific {
|
||||||
int region_size;
|
int region_size;
|
||||||
int have_region;
|
int have_region;
|
||||||
|
|
||||||
struct miscdevice miscdev;
|
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
int locality;
|
int locality;
|
||||||
unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
|
unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
|
||||||
|
@ -88,15 +141,27 @@ struct tpm_vendor_specific {
|
||||||
u16 manufacturer_id;
|
u16 manufacturer_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TPM_VPRIV(c) (c)->vendor.priv
|
#define TPM_VPRIV(c) ((c)->vendor.priv)
|
||||||
|
|
||||||
#define TPM_VID_INTEL 0x8086
|
#define TPM_VID_INTEL 0x8086
|
||||||
#define TPM_VID_WINBOND 0x1050
|
#define TPM_VID_WINBOND 0x1050
|
||||||
#define TPM_VID_STM 0x104A
|
#define TPM_VID_STM 0x104A
|
||||||
|
|
||||||
|
#define TPM_PPI_VERSION_LEN 3
|
||||||
|
|
||||||
|
enum tpm_chip_flags {
|
||||||
|
TPM_CHIP_FLAG_REGISTERED = BIT(0),
|
||||||
|
TPM_CHIP_FLAG_PPI = BIT(1),
|
||||||
|
TPM_CHIP_FLAG_TPM2 = BIT(2),
|
||||||
|
};
|
||||||
|
|
||||||
struct tpm_chip {
|
struct tpm_chip {
|
||||||
struct device *dev; /* Device stuff */
|
struct device *pdev; /* Device stuff */
|
||||||
|
struct device dev;
|
||||||
|
struct cdev cdev;
|
||||||
|
|
||||||
const struct tpm_class_ops *ops;
|
const struct tpm_class_ops *ops;
|
||||||
|
unsigned int flags;
|
||||||
|
|
||||||
int dev_num; /* /dev/tpm# */
|
int dev_num; /* /dev/tpm# */
|
||||||
char devname[7];
|
char devname[7];
|
||||||
|
@ -109,15 +174,19 @@ struct tpm_chip {
|
||||||
|
|
||||||
struct dentry **bios_dir;
|
struct dentry **bios_dir;
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
acpi_handle acpi_dev_handle;
|
||||||
|
char ppi_version[TPM_PPI_VERSION_LEN + 1];
|
||||||
|
#endif /* CONFIG_ACPI */
|
||||||
|
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
void (*release) (struct device *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
|
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
|
||||||
|
|
||||||
static inline void tpm_chip_put(struct tpm_chip *chip)
|
static inline void tpm_chip_put(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
module_put(chip->dev->driver->owner);
|
module_put(chip->pdev->driver->owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int tpm_read_index(int base, int index)
|
static inline int tpm_read_index(int base, int index)
|
||||||
|
@ -313,40 +382,57 @@ struct tpm_cmd_t {
|
||||||
tpm_cmd_params params;
|
tpm_cmd_params params;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
|
extern struct class *tpm_class;
|
||||||
|
extern dev_t tpm_devt;
|
||||||
|
extern const struct file_operations tpm_fops;
|
||||||
|
|
||||||
|
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
|
||||||
ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
size_t bufsiz);
|
size_t bufsiz);
|
||||||
|
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
|
||||||
|
const char *desc);
|
||||||
extern int tpm_get_timeouts(struct tpm_chip *);
|
extern int tpm_get_timeouts(struct tpm_chip *);
|
||||||
extern void tpm_gen_interrupt(struct tpm_chip *);
|
extern void tpm_gen_interrupt(struct tpm_chip *);
|
||||||
extern int tpm_do_selftest(struct tpm_chip *);
|
extern int tpm_do_selftest(struct tpm_chip *);
|
||||||
extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
|
extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
|
||||||
extern struct tpm_chip* tpm_register_hardware(struct device *,
|
|
||||||
const struct tpm_class_ops *ops);
|
|
||||||
extern void tpm_dev_vendor_release(struct tpm_chip *);
|
|
||||||
extern void tpm_remove_hardware(struct device *);
|
|
||||||
extern int tpm_pm_suspend(struct device *);
|
extern int tpm_pm_suspend(struct device *);
|
||||||
extern int tpm_pm_resume(struct device *);
|
extern int tpm_pm_resume(struct device *);
|
||||||
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
|
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
|
||||||
wait_queue_head_t *, bool);
|
wait_queue_head_t *, bool);
|
||||||
|
|
||||||
int tpm_dev_add_device(struct tpm_chip *chip);
|
struct tpm_chip *tpm_chip_find_get(int chip_num);
|
||||||
void tpm_dev_del_device(struct tpm_chip *chip);
|
extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
|
||||||
|
const struct tpm_class_ops *ops);
|
||||||
|
extern int tpm_chip_register(struct tpm_chip *chip);
|
||||||
|
extern void tpm_chip_unregister(struct tpm_chip *chip);
|
||||||
|
|
||||||
int tpm_sysfs_add_device(struct tpm_chip *chip);
|
int tpm_sysfs_add_device(struct tpm_chip *chip);
|
||||||
void tpm_sysfs_del_device(struct tpm_chip *chip);
|
void tpm_sysfs_del_device(struct tpm_chip *chip);
|
||||||
|
|
||||||
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
|
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
extern int tpm_add_ppi(struct kobject *);
|
extern int tpm_add_ppi(struct tpm_chip *chip);
|
||||||
extern void tpm_remove_ppi(struct kobject *);
|
extern void tpm_remove_ppi(struct tpm_chip *chip);
|
||||||
#else
|
#else
|
||||||
static inline int tpm_add_ppi(struct kobject *parent)
|
static inline int tpm_add_ppi(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void tpm_remove_ppi(struct kobject *parent)
|
static inline void tpm_remove_ppi(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
|
||||||
|
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
|
||||||
|
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
|
||||||
|
ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
|
||||||
|
u32 *value, const char *desc);
|
||||||
|
|
||||||
|
extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type);
|
||||||
|
extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
|
||||||
|
extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32);
|
||||||
|
extern int tpm2_do_selftest(struct tpm_chip *chip);
|
||||||
|
extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet);
|
||||||
|
|
|
@ -0,0 +1,617 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Intel Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
||||||
|
*
|
||||||
|
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
||||||
|
*
|
||||||
|
* This file contains TPM2 protocol implementations of the commands
|
||||||
|
* used by the kernel internally.
|
||||||
|
*
|
||||||
|
* 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 "tpm.h"
|
||||||
|
|
||||||
|
struct tpm2_startup_in {
|
||||||
|
__be16 startup_type;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_self_test_in {
|
||||||
|
u8 full_test;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_pcr_read_in {
|
||||||
|
__be32 pcr_selects_cnt;
|
||||||
|
__be16 hash_alg;
|
||||||
|
u8 pcr_select_size;
|
||||||
|
u8 pcr_select[TPM2_PCR_SELECT_MIN];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_pcr_read_out {
|
||||||
|
__be32 update_cnt;
|
||||||
|
__be32 pcr_selects_cnt;
|
||||||
|
__be16 hash_alg;
|
||||||
|
u8 pcr_select_size;
|
||||||
|
u8 pcr_select[TPM2_PCR_SELECT_MIN];
|
||||||
|
__be32 digests_cnt;
|
||||||
|
__be16 digest_size;
|
||||||
|
u8 digest[TPM_DIGEST_SIZE];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_null_auth_area {
|
||||||
|
__be32 handle;
|
||||||
|
__be16 nonce_size;
|
||||||
|
u8 attributes;
|
||||||
|
__be16 auth_size;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_pcr_extend_in {
|
||||||
|
__be32 pcr_idx;
|
||||||
|
__be32 auth_area_size;
|
||||||
|
struct tpm2_null_auth_area auth_area;
|
||||||
|
__be32 digest_cnt;
|
||||||
|
__be16 hash_alg;
|
||||||
|
u8 digest[TPM_DIGEST_SIZE];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_get_tpm_pt_in {
|
||||||
|
__be32 cap_id;
|
||||||
|
__be32 property_id;
|
||||||
|
__be32 property_cnt;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_get_tpm_pt_out {
|
||||||
|
u8 more_data;
|
||||||
|
__be32 subcap_id;
|
||||||
|
__be32 property_cnt;
|
||||||
|
__be32 property_id;
|
||||||
|
__be32 value;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_get_random_in {
|
||||||
|
__be16 size;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_get_random_out {
|
||||||
|
__be16 size;
|
||||||
|
u8 buffer[TPM_MAX_RNG_DATA];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
union tpm2_cmd_params {
|
||||||
|
struct tpm2_startup_in startup_in;
|
||||||
|
struct tpm2_self_test_in selftest_in;
|
||||||
|
struct tpm2_pcr_read_in pcrread_in;
|
||||||
|
struct tpm2_pcr_read_out pcrread_out;
|
||||||
|
struct tpm2_pcr_extend_in pcrextend_in;
|
||||||
|
struct tpm2_get_tpm_pt_in get_tpm_pt_in;
|
||||||
|
struct tpm2_get_tpm_pt_out get_tpm_pt_out;
|
||||||
|
struct tpm2_get_random_in getrandom_in;
|
||||||
|
struct tpm2_get_random_out getrandom_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tpm2_cmd {
|
||||||
|
tpm_cmd_header header;
|
||||||
|
union tpm2_cmd_params params;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Array with one entry per ordinal defining the maximum amount
|
||||||
|
* of time the chip could take to return the result. The values
|
||||||
|
* of the SHORT, MEDIUM, and LONG durations are taken from the
|
||||||
|
* PC Client Profile (PTP) specification.
|
||||||
|
*/
|
||||||
|
static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = {
|
||||||
|
TPM_UNDEFINED, /* 11F */
|
||||||
|
TPM_UNDEFINED, /* 120 */
|
||||||
|
TPM_LONG, /* 121 */
|
||||||
|
TPM_UNDEFINED, /* 122 */
|
||||||
|
TPM_UNDEFINED, /* 123 */
|
||||||
|
TPM_UNDEFINED, /* 124 */
|
||||||
|
TPM_UNDEFINED, /* 125 */
|
||||||
|
TPM_UNDEFINED, /* 126 */
|
||||||
|
TPM_UNDEFINED, /* 127 */
|
||||||
|
TPM_UNDEFINED, /* 128 */
|
||||||
|
TPM_LONG, /* 129 */
|
||||||
|
TPM_UNDEFINED, /* 12a */
|
||||||
|
TPM_UNDEFINED, /* 12b */
|
||||||
|
TPM_UNDEFINED, /* 12c */
|
||||||
|
TPM_UNDEFINED, /* 12d */
|
||||||
|
TPM_UNDEFINED, /* 12e */
|
||||||
|
TPM_UNDEFINED, /* 12f */
|
||||||
|
TPM_UNDEFINED, /* 130 */
|
||||||
|
TPM_UNDEFINED, /* 131 */
|
||||||
|
TPM_UNDEFINED, /* 132 */
|
||||||
|
TPM_UNDEFINED, /* 133 */
|
||||||
|
TPM_UNDEFINED, /* 134 */
|
||||||
|
TPM_UNDEFINED, /* 135 */
|
||||||
|
TPM_UNDEFINED, /* 136 */
|
||||||
|
TPM_UNDEFINED, /* 137 */
|
||||||
|
TPM_UNDEFINED, /* 138 */
|
||||||
|
TPM_UNDEFINED, /* 139 */
|
||||||
|
TPM_UNDEFINED, /* 13a */
|
||||||
|
TPM_UNDEFINED, /* 13b */
|
||||||
|
TPM_UNDEFINED, /* 13c */
|
||||||
|
TPM_UNDEFINED, /* 13d */
|
||||||
|
TPM_MEDIUM, /* 13e */
|
||||||
|
TPM_UNDEFINED, /* 13f */
|
||||||
|
TPM_UNDEFINED, /* 140 */
|
||||||
|
TPM_UNDEFINED, /* 141 */
|
||||||
|
TPM_UNDEFINED, /* 142 */
|
||||||
|
TPM_LONG, /* 143 */
|
||||||
|
TPM_MEDIUM, /* 144 */
|
||||||
|
TPM_UNDEFINED, /* 145 */
|
||||||
|
TPM_UNDEFINED, /* 146 */
|
||||||
|
TPM_UNDEFINED, /* 147 */
|
||||||
|
TPM_UNDEFINED, /* 148 */
|
||||||
|
TPM_UNDEFINED, /* 149 */
|
||||||
|
TPM_UNDEFINED, /* 14a */
|
||||||
|
TPM_UNDEFINED, /* 14b */
|
||||||
|
TPM_UNDEFINED, /* 14c */
|
||||||
|
TPM_UNDEFINED, /* 14d */
|
||||||
|
TPM_LONG, /* 14e */
|
||||||
|
TPM_UNDEFINED, /* 14f */
|
||||||
|
TPM_UNDEFINED, /* 150 */
|
||||||
|
TPM_UNDEFINED, /* 151 */
|
||||||
|
TPM_UNDEFINED, /* 152 */
|
||||||
|
TPM_UNDEFINED, /* 153 */
|
||||||
|
TPM_UNDEFINED, /* 154 */
|
||||||
|
TPM_UNDEFINED, /* 155 */
|
||||||
|
TPM_UNDEFINED, /* 156 */
|
||||||
|
TPM_UNDEFINED, /* 157 */
|
||||||
|
TPM_UNDEFINED, /* 158 */
|
||||||
|
TPM_UNDEFINED, /* 159 */
|
||||||
|
TPM_UNDEFINED, /* 15a */
|
||||||
|
TPM_UNDEFINED, /* 15b */
|
||||||
|
TPM_MEDIUM, /* 15c */
|
||||||
|
TPM_UNDEFINED, /* 15d */
|
||||||
|
TPM_UNDEFINED, /* 15e */
|
||||||
|
TPM_UNDEFINED, /* 15f */
|
||||||
|
TPM_UNDEFINED, /* 160 */
|
||||||
|
TPM_UNDEFINED, /* 161 */
|
||||||
|
TPM_UNDEFINED, /* 162 */
|
||||||
|
TPM_UNDEFINED, /* 163 */
|
||||||
|
TPM_UNDEFINED, /* 164 */
|
||||||
|
TPM_UNDEFINED, /* 165 */
|
||||||
|
TPM_UNDEFINED, /* 166 */
|
||||||
|
TPM_UNDEFINED, /* 167 */
|
||||||
|
TPM_UNDEFINED, /* 168 */
|
||||||
|
TPM_UNDEFINED, /* 169 */
|
||||||
|
TPM_UNDEFINED, /* 16a */
|
||||||
|
TPM_UNDEFINED, /* 16b */
|
||||||
|
TPM_UNDEFINED, /* 16c */
|
||||||
|
TPM_UNDEFINED, /* 16d */
|
||||||
|
TPM_UNDEFINED, /* 16e */
|
||||||
|
TPM_UNDEFINED, /* 16f */
|
||||||
|
TPM_UNDEFINED, /* 170 */
|
||||||
|
TPM_UNDEFINED, /* 171 */
|
||||||
|
TPM_UNDEFINED, /* 172 */
|
||||||
|
TPM_UNDEFINED, /* 173 */
|
||||||
|
TPM_UNDEFINED, /* 174 */
|
||||||
|
TPM_UNDEFINED, /* 175 */
|
||||||
|
TPM_UNDEFINED, /* 176 */
|
||||||
|
TPM_LONG, /* 177 */
|
||||||
|
TPM_UNDEFINED, /* 178 */
|
||||||
|
TPM_UNDEFINED, /* 179 */
|
||||||
|
TPM_MEDIUM, /* 17a */
|
||||||
|
TPM_LONG, /* 17b */
|
||||||
|
TPM_UNDEFINED, /* 17c */
|
||||||
|
TPM_UNDEFINED, /* 17d */
|
||||||
|
TPM_UNDEFINED, /* 17e */
|
||||||
|
TPM_UNDEFINED, /* 17f */
|
||||||
|
TPM_UNDEFINED, /* 180 */
|
||||||
|
TPM_UNDEFINED, /* 181 */
|
||||||
|
TPM_MEDIUM, /* 182 */
|
||||||
|
TPM_UNDEFINED, /* 183 */
|
||||||
|
TPM_UNDEFINED, /* 184 */
|
||||||
|
TPM_MEDIUM, /* 185 */
|
||||||
|
TPM_MEDIUM, /* 186 */
|
||||||
|
TPM_UNDEFINED, /* 187 */
|
||||||
|
TPM_UNDEFINED, /* 188 */
|
||||||
|
TPM_UNDEFINED, /* 189 */
|
||||||
|
TPM_UNDEFINED, /* 18a */
|
||||||
|
TPM_UNDEFINED, /* 18b */
|
||||||
|
TPM_UNDEFINED, /* 18c */
|
||||||
|
TPM_UNDEFINED, /* 18d */
|
||||||
|
TPM_UNDEFINED, /* 18e */
|
||||||
|
TPM_UNDEFINED /* 18f */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TPM2_PCR_READ_IN_SIZE \
|
||||||
|
(sizeof(struct tpm_input_header) + \
|
||||||
|
sizeof(struct tpm2_pcr_read_in))
|
||||||
|
|
||||||
|
static const struct tpm_input_header tpm2_pcrread_header = {
|
||||||
|
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
|
||||||
|
.length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE),
|
||||||
|
.ordinal = cpu_to_be32(TPM2_CC_PCR_READ)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_pcr_read() - read a PCR value
|
||||||
|
* @chip: TPM chip to use.
|
||||||
|
* @pcr_idx: index of the PCR to read.
|
||||||
|
* @ref_buf: buffer to store the resulting hash,
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct tpm2_cmd cmd;
|
||||||
|
u8 *buf;
|
||||||
|
|
||||||
|
if (pcr_idx >= TPM2_PLATFORM_PCR)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
cmd.header.in = tpm2_pcrread_header;
|
||||||
|
cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
|
||||||
|
cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
|
||||||
|
cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
|
||||||
|
|
||||||
|
memset(cmd.params.pcrread_in.pcr_select, 0,
|
||||||
|
sizeof(cmd.params.pcrread_in.pcr_select));
|
||||||
|
cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
|
||||||
|
|
||||||
|
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
|
||||||
|
"attempting to read a pcr value");
|
||||||
|
if (rc == 0) {
|
||||||
|
buf = cmd.params.pcrread_out.digest;
|
||||||
|
memcpy(res_buf, buf, TPM_DIGEST_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TPM2_GET_PCREXTEND_IN_SIZE \
|
||||||
|
(sizeof(struct tpm_input_header) + \
|
||||||
|
sizeof(struct tpm2_pcr_extend_in))
|
||||||
|
|
||||||
|
static const struct tpm_input_header tpm2_pcrextend_header = {
|
||||||
|
.tag = cpu_to_be16(TPM2_ST_SESSIONS),
|
||||||
|
.length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE),
|
||||||
|
.ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_pcr_extend() - extend a PCR value
|
||||||
|
* @chip: TPM chip to use.
|
||||||
|
* @pcr_idx: index of the PCR.
|
||||||
|
* @hash: hash value to use for the extend operation.
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
|
||||||
|
{
|
||||||
|
struct tpm2_cmd cmd;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
cmd.header.in = tpm2_pcrextend_header;
|
||||||
|
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
|
||||||
|
cmd.params.pcrextend_in.auth_area_size =
|
||||||
|
cpu_to_be32(sizeof(struct tpm2_null_auth_area));
|
||||||
|
cmd.params.pcrextend_in.auth_area.handle =
|
||||||
|
cpu_to_be32(TPM2_RS_PW);
|
||||||
|
cmd.params.pcrextend_in.auth_area.nonce_size = 0;
|
||||||
|
cmd.params.pcrextend_in.auth_area.attributes = 0;
|
||||||
|
cmd.params.pcrextend_in.auth_area.auth_size = 0;
|
||||||
|
cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1);
|
||||||
|
cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
|
||||||
|
memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
|
||||||
|
|
||||||
|
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
|
||||||
|
"attempting extend a PCR value");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TPM2_GETRANDOM_IN_SIZE \
|
||||||
|
(sizeof(struct tpm_input_header) + \
|
||||||
|
sizeof(struct tpm2_get_random_in))
|
||||||
|
|
||||||
|
static const struct tpm_input_header tpm2_getrandom_header = {
|
||||||
|
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
|
||||||
|
.length = cpu_to_be32(TPM2_GETRANDOM_IN_SIZE),
|
||||||
|
.ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_get_random() - get random bytes from the TPM RNG
|
||||||
|
* @chip: TPM chip to use
|
||||||
|
* @out: destination buffer for the random bytes
|
||||||
|
* @max: the max number of bytes to write to @out
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
|
||||||
|
{
|
||||||
|
struct tpm2_cmd cmd;
|
||||||
|
u32 recd;
|
||||||
|
u32 num_bytes;
|
||||||
|
int err;
|
||||||
|
int total = 0;
|
||||||
|
int retries = 5;
|
||||||
|
u8 *dest = out;
|
||||||
|
|
||||||
|
num_bytes = min_t(u32, max, sizeof(cmd.params.getrandom_out.buffer));
|
||||||
|
|
||||||
|
if (!out || !num_bytes ||
|
||||||
|
max > sizeof(cmd.params.getrandom_out.buffer))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
do {
|
||||||
|
cmd.header.in = tpm2_getrandom_header;
|
||||||
|
cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
|
||||||
|
|
||||||
|
err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
|
||||||
|
"attempting get random");
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
|
||||||
|
recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size),
|
||||||
|
num_bytes);
|
||||||
|
memcpy(dest, cmd.params.getrandom_out.buffer, recd);
|
||||||
|
|
||||||
|
dest += recd;
|
||||||
|
total += recd;
|
||||||
|
num_bytes -= recd;
|
||||||
|
} while (retries-- && total < max);
|
||||||
|
|
||||||
|
return total ? total : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TPM2_GET_TPM_PT_IN_SIZE \
|
||||||
|
(sizeof(struct tpm_input_header) + \
|
||||||
|
sizeof(struct tpm2_get_tpm_pt_in))
|
||||||
|
|
||||||
|
static const struct tpm_input_header tpm2_get_tpm_pt_header = {
|
||||||
|
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
|
||||||
|
.length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE),
|
||||||
|
.ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
|
||||||
|
* @chip: TPM chip to use.
|
||||||
|
* @property_id: property ID.
|
||||||
|
* @value: output variable.
|
||||||
|
* @desc: passed to tpm_transmit_cmd()
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
|
||||||
|
const char *desc)
|
||||||
|
{
|
||||||
|
struct tpm2_cmd cmd;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
cmd.header.in = tpm2_get_tpm_pt_header;
|
||||||
|
cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
|
||||||
|
cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
|
||||||
|
cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
|
||||||
|
|
||||||
|
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc);
|
||||||
|
if (!rc)
|
||||||
|
*value = cmd.params.get_tpm_pt_out.value;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TPM2_STARTUP_IN_SIZE \
|
||||||
|
(sizeof(struct tpm_input_header) + \
|
||||||
|
sizeof(struct tpm2_startup_in))
|
||||||
|
|
||||||
|
static const struct tpm_input_header tpm2_startup_header = {
|
||||||
|
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
|
||||||
|
.length = cpu_to_be32(TPM2_STARTUP_IN_SIZE),
|
||||||
|
.ordinal = cpu_to_be32(TPM2_CC_STARTUP)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_startup() - send startup command to the TPM chip
|
||||||
|
* @chip: TPM chip to use.
|
||||||
|
* @startup_type startup type. The value is either
|
||||||
|
* TPM_SU_CLEAR or TPM_SU_STATE.
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
|
||||||
|
{
|
||||||
|
struct tpm2_cmd cmd;
|
||||||
|
|
||||||
|
cmd.header.in = tpm2_startup_header;
|
||||||
|
|
||||||
|
cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
|
||||||
|
return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
|
||||||
|
"attempting to start the TPM");
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm2_startup);
|
||||||
|
|
||||||
|
#define TPM2_SHUTDOWN_IN_SIZE \
|
||||||
|
(sizeof(struct tpm_input_header) + \
|
||||||
|
sizeof(struct tpm2_startup_in))
|
||||||
|
|
||||||
|
static const struct tpm_input_header tpm2_shutdown_header = {
|
||||||
|
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
|
||||||
|
.length = cpu_to_be32(TPM2_SHUTDOWN_IN_SIZE),
|
||||||
|
.ordinal = cpu_to_be32(TPM2_CC_SHUTDOWN)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_shutdown() - send shutdown command to the TPM chip
|
||||||
|
* @chip: TPM chip to use.
|
||||||
|
* @shutdown_type shutdown type. The value is either
|
||||||
|
* TPM_SU_CLEAR or TPM_SU_STATE.
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
|
||||||
|
{
|
||||||
|
struct tpm2_cmd cmd;
|
||||||
|
|
||||||
|
cmd.header.in = tpm2_shutdown_header;
|
||||||
|
|
||||||
|
cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
|
||||||
|
return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
|
||||||
|
"stopping the TPM");
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm2_shutdown);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tpm2_calc_ordinal_duration() - maximum duration for a command
|
||||||
|
* @chip: TPM chip to use.
|
||||||
|
* @ordinal: command code number.
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
|
||||||
|
{
|
||||||
|
int index = TPM_UNDEFINED;
|
||||||
|
int duration = 0;
|
||||||
|
|
||||||
|
if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST)
|
||||||
|
index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST];
|
||||||
|
|
||||||
|
if (index != TPM_UNDEFINED)
|
||||||
|
duration = chip->vendor.duration[index];
|
||||||
|
|
||||||
|
if (duration <= 0)
|
||||||
|
duration = 2 * 60 * HZ;
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
|
||||||
|
|
||||||
|
#define TPM2_SELF_TEST_IN_SIZE \
|
||||||
|
(sizeof(struct tpm_input_header) + \
|
||||||
|
sizeof(struct tpm2_self_test_in))
|
||||||
|
|
||||||
|
static const struct tpm_input_header tpm2_selftest_header = {
|
||||||
|
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
|
||||||
|
.length = cpu_to_be32(TPM2_SELF_TEST_IN_SIZE),
|
||||||
|
.ordinal = cpu_to_be32(TPM2_CC_SELF_TEST)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_continue_selftest() - start a self test
|
||||||
|
* @chip: TPM chip to use
|
||||||
|
* @full: test all commands instead of testing only those that were not
|
||||||
|
* previously tested.
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct tpm2_cmd cmd;
|
||||||
|
|
||||||
|
cmd.header.in = tpm2_selftest_header;
|
||||||
|
cmd.params.selftest_in.full_test = full;
|
||||||
|
|
||||||
|
rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE,
|
||||||
|
"continue selftest");
|
||||||
|
|
||||||
|
/* At least some prototype chips seem to give RC_TESTING error
|
||||||
|
* immediately. This is a workaround for that.
|
||||||
|
*/
|
||||||
|
if (rc == TPM2_RC_TESTING) {
|
||||||
|
dev_warn(chip->pdev, "Got RC_TESTING, ignoring\n");
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_do_selftest() - run a full self test
|
||||||
|
* @chip: TPM chip to use
|
||||||
|
*
|
||||||
|
* During the self test TPM2 commands return with the error code RC_TESTING.
|
||||||
|
* Waiting is done by issuing PCR read until it executes successfully.
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
int tpm2_do_selftest(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
unsigned int loops;
|
||||||
|
unsigned int delay_msec = 100;
|
||||||
|
unsigned long duration;
|
||||||
|
struct tpm2_cmd cmd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST);
|
||||||
|
|
||||||
|
loops = jiffies_to_msecs(duration) / delay_msec;
|
||||||
|
|
||||||
|
rc = tpm2_start_selftest(chip, true);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
for (i = 0; i < loops; i++) {
|
||||||
|
/* Attempt to read a PCR value */
|
||||||
|
cmd.header.in = tpm2_pcrread_header;
|
||||||
|
cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
|
||||||
|
cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
|
||||||
|
cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
|
||||||
|
cmd.params.pcrread_in.pcr_select[0] = 0x01;
|
||||||
|
cmd.params.pcrread_in.pcr_select[1] = 0x00;
|
||||||
|
cmd.params.pcrread_in.pcr_select[2] = 0x00;
|
||||||
|
|
||||||
|
rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL);
|
||||||
|
if (rc < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rc = be32_to_cpu(cmd.header.out.return_code);
|
||||||
|
if (rc != TPM2_RC_TESTING)
|
||||||
|
break;
|
||||||
|
|
||||||
|
msleep(delay_msec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm2_do_selftest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_gen_interrupt() - generate an interrupt
|
||||||
|
* @chip: TPM chip to use
|
||||||
|
* @quiet: surpress the error message
|
||||||
|
*
|
||||||
|
* 0 is returned when the operation is successful. If a negative number is
|
||||||
|
* returned it remarks a POSIX error code. If a positive number is returned
|
||||||
|
* it remarks a TPM error.
|
||||||
|
*/
|
||||||
|
int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet)
|
||||||
|
{
|
||||||
|
const char *desc = NULL;
|
||||||
|
u32 dummy;
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
desc = "attempting to generate an interrupt";
|
||||||
|
|
||||||
|
return tpm2_get_tpm_pt(chip, TPM2_CAP_TPM_PROPERTIES, &dummy, desc);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);
|
|
@ -49,7 +49,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
for (i = 0; i < 6; i++) {
|
for (i = 0; i < 6; i++) {
|
||||||
status = ioread8(chip->vendor.iobase + 1);
|
status = ioread8(chip->vendor.iobase + 1);
|
||||||
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
|
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
|
||||||
dev_err(chip->dev, "error reading header\n");
|
dev_err(chip->pdev, "error reading header\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
*buf++ = ioread8(chip->vendor.iobase);
|
*buf++ = ioread8(chip->vendor.iobase);
|
||||||
|
@ -60,12 +60,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
size = be32_to_cpu(*native_size);
|
size = be32_to_cpu(*native_size);
|
||||||
|
|
||||||
if (count < size) {
|
if (count < size) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"Recv size(%d) less than available space\n", size);
|
"Recv size(%d) less than available space\n", size);
|
||||||
for (; i < size; i++) { /* clear the waiting data anyway */
|
for (; i < size; i++) { /* clear the waiting data anyway */
|
||||||
status = ioread8(chip->vendor.iobase + 1);
|
status = ioread8(chip->vendor.iobase + 1);
|
||||||
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
|
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
|
||||||
dev_err(chip->dev, "error reading data\n");
|
dev_err(chip->pdev, "error reading data\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
for (; i < size; i++) {
|
for (; i < size; i++) {
|
||||||
status = ioread8(chip->vendor.iobase + 1);
|
status = ioread8(chip->vendor.iobase + 1);
|
||||||
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
|
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
|
||||||
dev_err(chip->dev, "error reading data\n");
|
dev_err(chip->pdev, "error reading data\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
*buf++ = ioread8(chip->vendor.iobase);
|
*buf++ = ioread8(chip->vendor.iobase);
|
||||||
|
@ -86,7 +86,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
status = ioread8(chip->vendor.iobase + 1);
|
status = ioread8(chip->vendor.iobase + 1);
|
||||||
|
|
||||||
if (status & ATML_STATUS_DATA_AVAIL) {
|
if (status & ATML_STATUS_DATA_AVAIL) {
|
||||||
dev_err(chip->dev, "data available is stuck\n");
|
dev_err(chip->pdev, "data available is stuck\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,9 +97,9 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
dev_dbg(chip->dev, "tpm_atml_send:\n");
|
dev_dbg(chip->pdev, "tpm_atml_send:\n");
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
|
dev_dbg(chip->pdev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
|
||||||
iowrite8(buf[i], chip->vendor.iobase);
|
iowrite8(buf[i], chip->vendor.iobase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,11 +138,11 @@ static void atml_plat_remove(void)
|
||||||
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
|
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
if (chip) {
|
if (chip) {
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
if (chip->vendor.have_region)
|
if (chip->vendor.have_region)
|
||||||
atmel_release_region(chip->vendor.base,
|
atmel_release_region(chip->vendor.base,
|
||||||
chip->vendor.region_size);
|
chip->vendor.region_size);
|
||||||
atmel_put_base_addr(chip->vendor.iobase);
|
atmel_put_base_addr(chip->vendor.iobase);
|
||||||
tpm_remove_hardware(chip->dev);
|
|
||||||
platform_device_unregister(pdev);
|
platform_device_unregister(pdev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,8 +183,9 @@ static int __init init_atmel(void)
|
||||||
goto err_rel_reg;
|
goto err_rel_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
|
chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
|
||||||
rc = -ENODEV;
|
if (IS_ERR(chip)) {
|
||||||
|
rc = PTR_ERR(chip);
|
||||||
goto err_unreg_dev;
|
goto err_unreg_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +194,10 @@ static int __init init_atmel(void)
|
||||||
chip->vendor.have_region = have_region;
|
chip->vendor.have_region = have_region;
|
||||||
chip->vendor.region_size = region_size;
|
chip->vendor.region_size = region_size;
|
||||||
|
|
||||||
|
rc = tpm_chip_register(chip);
|
||||||
|
if (rc)
|
||||||
|
goto err_unreg_dev;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_unreg_dev:
|
err_unreg_dev:
|
||||||
|
|
|
@ -0,0 +1,354 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Intel Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
||||||
|
*
|
||||||
|
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
||||||
|
*
|
||||||
|
* This device driver implements the TPM interface as defined in
|
||||||
|
* the TCG CRB 2.0 TPM specification.
|
||||||
|
*
|
||||||
|
* 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/acpi.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
#include <linux/rculist.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include "tpm.h"
|
||||||
|
|
||||||
|
#define ACPI_SIG_TPM2 "TPM2"
|
||||||
|
|
||||||
|
static const u8 CRB_ACPI_START_UUID[] = {
|
||||||
|
/* 0000 */ 0xAB, 0x6C, 0xBF, 0x6B, 0x63, 0x54, 0x14, 0x47,
|
||||||
|
/* 0008 */ 0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum crb_defaults {
|
||||||
|
CRB_ACPI_START_REVISION_ID = 1,
|
||||||
|
CRB_ACPI_START_INDEX = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum crb_start_method {
|
||||||
|
CRB_SM_ACPI_START = 2,
|
||||||
|
CRB_SM_CRB = 7,
|
||||||
|
CRB_SM_CRB_WITH_ACPI_START = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct acpi_tpm2 {
|
||||||
|
struct acpi_table_header hdr;
|
||||||
|
u16 platform_class;
|
||||||
|
u16 reserved;
|
||||||
|
u64 control_area_pa;
|
||||||
|
u32 start_method;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
enum crb_ca_request {
|
||||||
|
CRB_CA_REQ_GO_IDLE = BIT(0),
|
||||||
|
CRB_CA_REQ_CMD_READY = BIT(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum crb_ca_status {
|
||||||
|
CRB_CA_STS_ERROR = BIT(0),
|
||||||
|
CRB_CA_STS_TPM_IDLE = BIT(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum crb_start {
|
||||||
|
CRB_START_INVOKE = BIT(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum crb_cancel {
|
||||||
|
CRB_CANCEL_INVOKE = BIT(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crb_control_area {
|
||||||
|
u32 req;
|
||||||
|
u32 sts;
|
||||||
|
u32 cancel;
|
||||||
|
u32 start;
|
||||||
|
u32 int_enable;
|
||||||
|
u32 int_sts;
|
||||||
|
u32 cmd_size;
|
||||||
|
u64 cmd_pa;
|
||||||
|
u32 rsp_size;
|
||||||
|
u64 rsp_pa;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
enum crb_status {
|
||||||
|
CRB_STS_COMPLETE = BIT(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum crb_flags {
|
||||||
|
CRB_FL_ACPI_START = BIT(0),
|
||||||
|
CRB_FL_CRB_START = BIT(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crb_priv {
|
||||||
|
unsigned int flags;
|
||||||
|
struct crb_control_area __iomem *cca;
|
||||||
|
u8 __iomem *cmd;
|
||||||
|
u8 __iomem *rsp;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int crb_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
rc = tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||||
|
if (!rc)
|
||||||
|
rc = tpm2_do_selftest(chip);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume);
|
||||||
|
|
||||||
|
static u8 crb_status(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
struct crb_priv *priv = chip->vendor.priv;
|
||||||
|
u8 sts = 0;
|
||||||
|
|
||||||
|
if ((le32_to_cpu(ioread32(&priv->cca->start)) & CRB_START_INVOKE) !=
|
||||||
|
CRB_START_INVOKE)
|
||||||
|
sts |= CRB_STS_COMPLETE;
|
||||||
|
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct crb_priv *priv = chip->vendor.priv;
|
||||||
|
unsigned int expected;
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (count < 6)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (le32_to_cpu(ioread32(&priv->cca->sts)) & CRB_CA_STS_ERROR)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
memcpy_fromio(buf, priv->rsp, 6);
|
||||||
|
expected = be32_to_cpup((__be32 *) &buf[2]);
|
||||||
|
|
||||||
|
if (expected > count)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
|
||||||
|
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crb_do_acpi_start(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
union acpi_object *obj;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
obj = acpi_evaluate_dsm(chip->acpi_dev_handle,
|
||||||
|
CRB_ACPI_START_UUID,
|
||||||
|
CRB_ACPI_START_REVISION_ID,
|
||||||
|
CRB_ACPI_START_INDEX,
|
||||||
|
NULL);
|
||||||
|
if (!obj)
|
||||||
|
return -ENXIO;
|
||||||
|
rc = obj->integer.value == 0 ? 0 : -ENXIO;
|
||||||
|
ACPI_FREE(obj);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct crb_priv *priv = chip->vendor.priv;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) {
|
||||||
|
dev_err(&chip->dev,
|
||||||
|
"invalid command count value %x %zx\n",
|
||||||
|
(unsigned int) len,
|
||||||
|
(size_t) le32_to_cpu(ioread32(&priv->cca->cmd_size)));
|
||||||
|
return -E2BIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy_toio(priv->cmd, buf, len);
|
||||||
|
|
||||||
|
/* Make sure that cmd is populated before issuing start. */
|
||||||
|
wmb();
|
||||||
|
|
||||||
|
if (priv->flags & CRB_FL_CRB_START)
|
||||||
|
iowrite32(cpu_to_le32(CRB_START_INVOKE), &priv->cca->start);
|
||||||
|
|
||||||
|
if (priv->flags & CRB_FL_ACPI_START)
|
||||||
|
rc = crb_do_acpi_start(chip);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void crb_cancel(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
struct crb_priv *priv = chip->vendor.priv;
|
||||||
|
|
||||||
|
iowrite32(cpu_to_le32(CRB_CANCEL_INVOKE), &priv->cca->cancel);
|
||||||
|
|
||||||
|
/* Make sure that cmd is populated before issuing cancel. */
|
||||||
|
wmb();
|
||||||
|
|
||||||
|
if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip))
|
||||||
|
dev_err(&chip->dev, "ACPI Start failed\n");
|
||||||
|
|
||||||
|
iowrite32(0, &priv->cca->cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
|
{
|
||||||
|
struct crb_priv *priv = chip->vendor.priv;
|
||||||
|
u32 cancel = le32_to_cpu(ioread32(&priv->cca->cancel));
|
||||||
|
|
||||||
|
return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct tpm_class_ops tpm_crb = {
|
||||||
|
.status = crb_status,
|
||||||
|
.recv = crb_recv,
|
||||||
|
.send = crb_send,
|
||||||
|
.cancel = crb_cancel,
|
||||||
|
.req_canceled = crb_req_canceled,
|
||||||
|
.req_complete_mask = CRB_STS_COMPLETE,
|
||||||
|
.req_complete_val = CRB_STS_COMPLETE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int crb_acpi_add(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
struct tpm_chip *chip;
|
||||||
|
struct acpi_tpm2 *buf;
|
||||||
|
struct crb_priv *priv;
|
||||||
|
struct device *dev = &device->dev;
|
||||||
|
acpi_status status;
|
||||||
|
u32 sm;
|
||||||
|
u64 pa;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
chip = tpmm_chip_alloc(dev, &tpm_crb);
|
||||||
|
if (IS_ERR(chip))
|
||||||
|
return PTR_ERR(chip);
|
||||||
|
|
||||||
|
chip->flags = TPM_CHIP_FLAG_TPM2;
|
||||||
|
|
||||||
|
status = acpi_get_table(ACPI_SIG_TPM2, 1,
|
||||||
|
(struct acpi_table_header **) &buf);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
dev_err(dev, "failed to get TPM2 ACPI table\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
|
||||||
|
dev_err(dev, "TPM2 ACPI table has wrong size");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = (struct crb_priv *) devm_kzalloc(dev, sizeof(struct crb_priv),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!priv) {
|
||||||
|
dev_err(dev, "failed to devm_kzalloc for private data\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
sm = le32_to_cpu(buf->start_method);
|
||||||
|
|
||||||
|
/* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
|
||||||
|
* report only ACPI start but in practice seems to require both
|
||||||
|
* ACPI start and CRB start.
|
||||||
|
*/
|
||||||
|
if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START ||
|
||||||
|
!strcmp(acpi_device_hid(device), "MSFT0101"))
|
||||||
|
priv->flags |= CRB_FL_CRB_START;
|
||||||
|
|
||||||
|
if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
|
||||||
|
priv->flags |= CRB_FL_ACPI_START;
|
||||||
|
|
||||||
|
priv->cca = (struct crb_control_area __iomem *)
|
||||||
|
devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
|
||||||
|
if (!priv->cca) {
|
||||||
|
dev_err(dev, "ioremap of the control area failed\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy_fromio(&pa, &priv->cca->cmd_pa, 8);
|
||||||
|
pa = le64_to_cpu(pa);
|
||||||
|
priv->cmd = devm_ioremap_nocache(dev, le64_to_cpu(pa),
|
||||||
|
ioread32(&priv->cca->cmd_size));
|
||||||
|
if (!priv->cmd) {
|
||||||
|
dev_err(dev, "ioremap of the command buffer failed\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
|
||||||
|
pa = le64_to_cpu(pa);
|
||||||
|
priv->rsp = devm_ioremap_nocache(dev, le64_to_cpu(pa),
|
||||||
|
ioread32(&priv->cca->rsp_size));
|
||||||
|
if (!priv->rsp) {
|
||||||
|
dev_err(dev, "ioremap of the response buffer failed\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip->vendor.priv = priv;
|
||||||
|
|
||||||
|
/* Default timeouts and durations */
|
||||||
|
chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
|
||||||
|
chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
|
||||||
|
chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
|
||||||
|
chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
|
||||||
|
chip->vendor.duration[TPM_SHORT] =
|
||||||
|
msecs_to_jiffies(TPM2_DURATION_SHORT);
|
||||||
|
chip->vendor.duration[TPM_MEDIUM] =
|
||||||
|
msecs_to_jiffies(TPM2_DURATION_MEDIUM);
|
||||||
|
chip->vendor.duration[TPM_LONG] =
|
||||||
|
msecs_to_jiffies(TPM2_DURATION_LONG);
|
||||||
|
|
||||||
|
chip->acpi_dev_handle = device->handle;
|
||||||
|
|
||||||
|
rc = tpm2_do_selftest(chip);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return tpm_chip_register(chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crb_acpi_remove(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
struct device *dev = &device->dev;
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct acpi_device_id crb_device_ids[] = {
|
||||||
|
{"MSFT0101", 0},
|
||||||
|
{"", 0},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, crb_device_ids);
|
||||||
|
|
||||||
|
static struct acpi_driver crb_acpi_driver = {
|
||||||
|
.name = "tpm_crb",
|
||||||
|
.ids = crb_device_ids,
|
||||||
|
.ops = {
|
||||||
|
.add = crb_acpi_add,
|
||||||
|
.remove = crb_acpi_remove,
|
||||||
|
},
|
||||||
|
.drv = {
|
||||||
|
.pm = &crb_pm,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_acpi_driver(crb_acpi_driver);
|
||||||
|
MODULE_AUTHOR("Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>");
|
||||||
|
MODULE_DESCRIPTION("TPM2 Driver");
|
||||||
|
MODULE_VERSION("0.1");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -52,7 +52,7 @@ struct priv_data {
|
||||||
static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct priv_data *priv = chip->vendor.priv;
|
struct priv_data *priv = chip->vendor.priv;
|
||||||
struct i2c_client *client = to_i2c_client(chip->dev);
|
struct i2c_client *client = to_i2c_client(chip->pdev);
|
||||||
s32 status;
|
s32 status;
|
||||||
|
|
||||||
priv->len = 0;
|
priv->len = 0;
|
||||||
|
@ -62,7 +62,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
|
|
||||||
status = i2c_master_send(client, buf, len);
|
status = i2c_master_send(client, buf, len);
|
||||||
|
|
||||||
dev_dbg(chip->dev,
|
dev_dbg(chip->pdev,
|
||||||
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
|
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
|
||||||
(int)min_t(size_t, 64, len), buf, len, status);
|
(int)min_t(size_t, 64, len), buf, len, status);
|
||||||
return status;
|
return status;
|
||||||
|
@ -71,7 +71,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct priv_data *priv = chip->vendor.priv;
|
struct priv_data *priv = chip->vendor.priv;
|
||||||
struct i2c_client *client = to_i2c_client(chip->dev);
|
struct i2c_client *client = to_i2c_client(chip->pdev);
|
||||||
struct tpm_output_header *hdr =
|
struct tpm_output_header *hdr =
|
||||||
(struct tpm_output_header *)priv->buffer;
|
(struct tpm_output_header *)priv->buffer;
|
||||||
u32 expected_len;
|
u32 expected_len;
|
||||||
|
@ -88,7 +88,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (priv->len >= expected_len) {
|
if (priv->len >= expected_len) {
|
||||||
dev_dbg(chip->dev,
|
dev_dbg(chip->pdev,
|
||||||
"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
|
"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
|
||||||
(int)min_t(size_t, 64, expected_len), buf, count,
|
(int)min_t(size_t, 64, expected_len), buf, count,
|
||||||
expected_len);
|
expected_len);
|
||||||
|
@ -97,7 +97,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = i2c_master_recv(client, buf, expected_len);
|
rc = i2c_master_recv(client, buf, expected_len);
|
||||||
dev_dbg(chip->dev,
|
dev_dbg(chip->pdev,
|
||||||
"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
|
"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
|
||||||
(int)min_t(size_t, 64, expected_len), buf, count,
|
(int)min_t(size_t, 64, expected_len), buf, count,
|
||||||
expected_len);
|
expected_len);
|
||||||
|
@ -106,13 +106,13 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
|
|
||||||
static void i2c_atmel_cancel(struct tpm_chip *chip)
|
static void i2c_atmel_cancel(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported");
|
dev_err(chip->pdev, "TPM operation cancellation was requested, but is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 i2c_atmel_read_status(struct tpm_chip *chip)
|
static u8 i2c_atmel_read_status(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
struct priv_data *priv = chip->vendor.priv;
|
struct priv_data *priv = chip->vendor.priv;
|
||||||
struct i2c_client *client = to_i2c_client(chip->dev);
|
struct i2c_client *client = to_i2c_client(chip->pdev);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* The TPM fails the I2C read until it is ready, so we do the entire
|
/* The TPM fails the I2C read until it is ready, so we do the entire
|
||||||
|
@ -125,7 +125,7 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip)
|
||||||
/* Once the TPM has completed the command the command remains readable
|
/* Once the TPM has completed the command the command remains readable
|
||||||
* until another command is issued. */
|
* until another command is issued. */
|
||||||
rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
|
rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
|
||||||
dev_dbg(chip->dev,
|
dev_dbg(chip->pdev,
|
||||||
"%s: sts=%d", __func__, rc);
|
"%s: sts=%d", __func__, rc);
|
||||||
if (rc <= 0)
|
if (rc <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -153,21 +153,20 @@ static const struct tpm_class_ops i2c_atmel = {
|
||||||
static int i2c_atmel_probe(struct i2c_client *client,
|
static int i2c_atmel_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
chip = tpm_register_hardware(dev, &i2c_atmel);
|
chip = tpmm_chip_alloc(dev, &i2c_atmel);
|
||||||
if (!chip) {
|
if (IS_ERR(chip))
|
||||||
dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
|
return PTR_ERR(chip);
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
|
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
if (!chip->vendor.priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Default timeouts */
|
/* Default timeouts */
|
||||||
chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
|
chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
|
||||||
|
@ -179,33 +178,20 @@ static int i2c_atmel_probe(struct i2c_client *client,
|
||||||
/* There is no known way to probe for this device, and all version
|
/* There is no known way to probe for this device, and all version
|
||||||
* information seems to be read via TPM commands. Thus we rely on the
|
* information seems to be read via TPM commands. Thus we rely on the
|
||||||
* TPM startup process in the common code to detect the device. */
|
* TPM startup process in the common code to detect the device. */
|
||||||
if (tpm_get_timeouts(chip)) {
|
if (tpm_get_timeouts(chip))
|
||||||
rc = -ENODEV;
|
return -ENODEV;
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tpm_do_selftest(chip)) {
|
if (tpm_do_selftest(chip))
|
||||||
rc = -ENODEV;
|
return -ENODEV;
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return tpm_chip_register(chip);
|
||||||
|
|
||||||
out_err:
|
|
||||||
tpm_dev_vendor_release(chip);
|
|
||||||
tpm_remove_hardware(chip->dev);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_atmel_remove(struct i2c_client *client)
|
static int i2c_atmel_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct device *dev = &(client->dev);
|
struct device *dev = &(client->dev);
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
if (chip)
|
|
||||||
tpm_dev_vendor_release(chip);
|
|
||||||
tpm_remove_hardware(dev);
|
|
||||||
kfree(chip);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -446,7 +446,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
/* read first 10 bytes, including tag, paramsize, and result */
|
/* read first 10 bytes, including tag, paramsize, and result */
|
||||||
size = recv_data(chip, buf, TPM_HEADER_SIZE);
|
size = recv_data(chip, buf, TPM_HEADER_SIZE);
|
||||||
if (size < TPM_HEADER_SIZE) {
|
if (size < TPM_HEADER_SIZE) {
|
||||||
dev_err(chip->dev, "Unable to read header\n");
|
dev_err(chip->pdev, "Unable to read header\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,14 +459,14 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
size += recv_data(chip, &buf[TPM_HEADER_SIZE],
|
size += recv_data(chip, &buf[TPM_HEADER_SIZE],
|
||||||
expected - TPM_HEADER_SIZE);
|
expected - TPM_HEADER_SIZE);
|
||||||
if (size < expected) {
|
if (size < expected) {
|
||||||
dev_err(chip->dev, "Unable to read remainder of result\n");
|
dev_err(chip->pdev, "Unable to read remainder of result\n");
|
||||||
size = -ETIME;
|
size = -ETIME;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
|
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
|
||||||
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
|
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
|
||||||
dev_err(chip->dev, "Error left over data\n");
|
dev_err(chip->pdev, "Error left over data\n");
|
||||||
size = -EIO;
|
size = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev)
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
|
|
||||||
chip = tpm_register_hardware(dev, &tpm_tis_i2c);
|
chip = tpmm_chip_alloc(dev, &tpm_tis_i2c);
|
||||||
if (!chip) {
|
if (IS_ERR(chip))
|
||||||
dev_err(dev, "could not register hardware\n");
|
return PTR_ERR(chip);
|
||||||
rc = -ENODEV;
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable interrupts */
|
/* Disable interrupts */
|
||||||
chip->vendor.irq = 0;
|
chip->vendor.irq = 0;
|
||||||
|
@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev)
|
||||||
if (request_locality(chip, 0) != 0) {
|
if (request_locality(chip, 0) != 0) {
|
||||||
dev_err(dev, "could not request locality\n");
|
dev_err(dev, "could not request locality\n");
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
goto out_vendor;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read four bytes from DID_VID register */
|
/* read four bytes from DID_VID register */
|
||||||
|
@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev)
|
||||||
tpm_get_timeouts(chip);
|
tpm_get_timeouts(chip);
|
||||||
tpm_do_selftest(chip);
|
tpm_do_selftest(chip);
|
||||||
|
|
||||||
return 0;
|
return tpm_chip_register(chip);
|
||||||
|
|
||||||
out_release:
|
out_release:
|
||||||
release_locality(chip, chip->vendor.locality, 1);
|
release_locality(chip, chip->vendor.locality, 1);
|
||||||
|
|
||||||
out_vendor:
|
|
||||||
/* close file handles */
|
|
||||||
tpm_dev_vendor_release(chip);
|
|
||||||
|
|
||||||
/* remove hardware */
|
|
||||||
tpm_remove_hardware(chip->dev);
|
|
||||||
|
|
||||||
/* reset these pointers, otherwise we oops */
|
|
||||||
chip->dev->release = NULL;
|
|
||||||
chip->release = NULL;
|
|
||||||
tpm_dev.client = NULL;
|
tpm_dev.client = NULL;
|
||||||
out_err:
|
out_err:
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
|
||||||
static int tpm_tis_i2c_remove(struct i2c_client *client)
|
static int tpm_tis_i2c_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = tpm_dev.chip;
|
struct tpm_chip *chip = tpm_dev.chip;
|
||||||
|
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
release_locality(chip, chip->vendor.locality, 1);
|
release_locality(chip, chip->vendor.locality, 1);
|
||||||
|
|
||||||
/* close file handles */
|
|
||||||
tpm_dev_vendor_release(chip);
|
|
||||||
|
|
||||||
/* remove hardware */
|
|
||||||
tpm_remove_hardware(chip->dev);
|
|
||||||
|
|
||||||
/* reset these pointers, otherwise we oops */
|
|
||||||
chip->dev->release = NULL;
|
|
||||||
chip->release = NULL;
|
|
||||||
tpm_dev.client = NULL;
|
tpm_dev.client = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -96,13 +96,13 @@ static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size,
|
||||||
/* read TPM_STS register */
|
/* read TPM_STS register */
|
||||||
static u8 i2c_nuvoton_read_status(struct tpm_chip *chip)
|
static u8 i2c_nuvoton_read_status(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(chip->dev);
|
struct i2c_client *client = to_i2c_client(chip->pdev);
|
||||||
s32 status;
|
s32 status;
|
||||||
u8 data;
|
u8 data;
|
||||||
|
|
||||||
status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data);
|
status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data);
|
||||||
if (status <= 0) {
|
if (status <= 0) {
|
||||||
dev_err(chip->dev, "%s() error return %d\n", __func__,
|
dev_err(chip->pdev, "%s() error return %d\n", __func__,
|
||||||
status);
|
status);
|
||||||
data = TPM_STS_ERR_VAL;
|
data = TPM_STS_ERR_VAL;
|
||||||
}
|
}
|
||||||
|
@ -127,13 +127,13 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data)
|
||||||
/* write commandReady to TPM_STS register */
|
/* write commandReady to TPM_STS register */
|
||||||
static void i2c_nuvoton_ready(struct tpm_chip *chip)
|
static void i2c_nuvoton_ready(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(chip->dev);
|
struct i2c_client *client = to_i2c_client(chip->pdev);
|
||||||
s32 status;
|
s32 status;
|
||||||
|
|
||||||
/* this causes the current command to be aborted */
|
/* this causes the current command to be aborted */
|
||||||
status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY);
|
status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"%s() fail to write TPM_STS.commandReady\n", __func__);
|
"%s() fail to write TPM_STS.commandReady\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value,
|
||||||
return 0;
|
return 0;
|
||||||
} while (time_before(jiffies, stop));
|
} while (time_before(jiffies, stop));
|
||||||
}
|
}
|
||||||
dev_err(chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
|
dev_err(chip->pdev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
|
||||||
value);
|
value);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
|
||||||
&chip->vendor.read_queue) == 0) {
|
&chip->vendor.read_queue) == 0) {
|
||||||
burst_count = i2c_nuvoton_get_burstcount(client, chip);
|
burst_count = i2c_nuvoton_get_burstcount(client, chip);
|
||||||
if (burst_count < 0) {
|
if (burst_count < 0) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"%s() fail to read burstCount=%d\n", __func__,
|
"%s() fail to read burstCount=%d\n", __func__,
|
||||||
burst_count);
|
burst_count);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -249,12 +249,12 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
|
||||||
rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R,
|
rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R,
|
||||||
bytes2read, &buf[size]);
|
bytes2read, &buf[size]);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"%s() fail on i2c_nuvoton_read_buf()=%d\n",
|
"%s() fail on i2c_nuvoton_read_buf()=%d\n",
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read);
|
dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read);
|
||||||
size += bytes2read;
|
size += bytes2read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
|
||||||
/* Read TPM command results */
|
/* Read TPM command results */
|
||||||
static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct device *dev = chip->dev;
|
struct device *dev = chip->pdev;
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
s32 rc;
|
s32 rc;
|
||||||
int expected, status, burst_count, retries, size = 0;
|
int expected, status, burst_count, retries, size = 0;
|
||||||
|
@ -334,7 +334,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i2c_nuvoton_ready(chip);
|
i2c_nuvoton_ready(chip);
|
||||||
dev_dbg(chip->dev, "%s() -> %d\n", __func__, size);
|
dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
*/
|
*/
|
||||||
static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct device *dev = chip->dev;
|
struct device *dev = chip->pdev;
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
u32 ordinal;
|
u32 ordinal;
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
@ -530,14 +530,15 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
|
||||||
dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
|
dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
|
||||||
(u8) (vid >> 16), (u8) (vid >> 24));
|
(u8) (vid >> 16), (u8) (vid >> 24));
|
||||||
|
|
||||||
chip = tpm_register_hardware(dev, &tpm_i2c);
|
chip = tpmm_chip_alloc(dev, &tpm_i2c);
|
||||||
if (!chip) {
|
if (IS_ERR(chip))
|
||||||
dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
|
return PTR_ERR(chip);
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
|
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
if (!chip->vendor.priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
init_waitqueue_head(&chip->vendor.read_queue);
|
init_waitqueue_head(&chip->vendor.read_queue);
|
||||||
init_waitqueue_head(&chip->vendor.int_queue);
|
init_waitqueue_head(&chip->vendor.int_queue);
|
||||||
|
|
||||||
|
@ -559,7 +560,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
|
||||||
rc = devm_request_irq(dev, chip->vendor.irq,
|
rc = devm_request_irq(dev, chip->vendor.irq,
|
||||||
i2c_nuvoton_int_handler,
|
i2c_nuvoton_int_handler,
|
||||||
IRQF_TRIGGER_LOW,
|
IRQF_TRIGGER_LOW,
|
||||||
chip->vendor.miscdev.name,
|
chip->devname,
|
||||||
chip);
|
chip);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(dev, "%s() Unable to request irq: %d for use\n",
|
dev_err(dev, "%s() Unable to request irq: %d for use\n",
|
||||||
|
@ -584,7 +585,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
|
||||||
TPM_DATA_FIFO_W,
|
TPM_DATA_FIFO_W,
|
||||||
1, (u8 *) (&rc));
|
1, (u8 *) (&rc));
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto out_err;
|
return rc;
|
||||||
/* TPM_STS <- 0x40 (commandReady) */
|
/* TPM_STS <- 0x40 (commandReady) */
|
||||||
i2c_nuvoton_ready(chip);
|
i2c_nuvoton_ready(chip);
|
||||||
} else {
|
} else {
|
||||||
|
@ -594,45 +595,29 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
|
||||||
* only TPM_STS_VALID should be set
|
* only TPM_STS_VALID should be set
|
||||||
*/
|
*/
|
||||||
if (i2c_nuvoton_read_status(chip) !=
|
if (i2c_nuvoton_read_status(chip) !=
|
||||||
TPM_STS_VALID) {
|
TPM_STS_VALID)
|
||||||
rc = -EIO;
|
return -EIO;
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tpm_get_timeouts(chip)) {
|
if (tpm_get_timeouts(chip))
|
||||||
rc = -ENODEV;
|
return -ENODEV;
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tpm_do_selftest(chip)) {
|
if (tpm_do_selftest(chip))
|
||||||
rc = -ENODEV;
|
return -ENODEV;
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return tpm_chip_register(chip);
|
||||||
|
|
||||||
out_err:
|
|
||||||
tpm_dev_vendor_release(chip);
|
|
||||||
tpm_remove_hardware(chip->dev);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_nuvoton_remove(struct i2c_client *client)
|
static int i2c_nuvoton_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct device *dev = &(client->dev);
|
struct device *dev = &(client->dev);
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
if (chip)
|
|
||||||
tpm_dev_vendor_release(chip);
|
|
||||||
tpm_remove_hardware(dev);
|
|
||||||
kfree(chip);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct i2c_device_id i2c_nuvoton_id[] = {
|
static const struct i2c_device_id i2c_nuvoton_id[] = {
|
||||||
{I2C_DRIVER_NAME, 0},
|
{I2C_DRIVER_NAME, 0},
|
||||||
{}
|
{}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 IBM Corporation
|
* Copyright (C) 2012 IBM Corporation
|
||||||
*
|
*
|
||||||
* Author: Ashley Lai <adlai@us.ibm.com>
|
* Author: Ashley Lai <ashleydlai@gmail.com>
|
||||||
*
|
*
|
||||||
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
||||||
*
|
*
|
||||||
|
@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
|
||||||
static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
|
static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
|
||||||
{
|
{
|
||||||
struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
|
struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
|
|
||||||
free_irq(vdev->irq, ibmvtpm);
|
free_irq(vdev->irq, ibmvtpm);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
|
||||||
kfree(ibmvtpm->rtce_buf);
|
kfree(ibmvtpm->rtce_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
tpm_remove_hardware(ibmvtpm->dev);
|
|
||||||
|
|
||||||
kfree(ibmvtpm);
|
kfree(ibmvtpm);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -307,6 +308,14 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
|
||||||
static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
|
static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
|
||||||
{
|
{
|
||||||
struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
|
struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
|
||||||
|
|
||||||
|
/* ibmvtpm initializes at probe time, so the data we are
|
||||||
|
* asking for may not be set yet. Estimate that 4K required
|
||||||
|
* for TCE-mapped buffer in addition to CRQ.
|
||||||
|
*/
|
||||||
|
if (!ibmvtpm)
|
||||||
|
return CRQ_RES_BUF_SIZE + PAGE_SIZE;
|
||||||
|
|
||||||
return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
|
return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,11 +564,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
int rc = -ENOMEM, rc1;
|
int rc = -ENOMEM, rc1;
|
||||||
|
|
||||||
chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
|
chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm);
|
||||||
if (!chip) {
|
if (IS_ERR(chip))
|
||||||
dev_err(dev, "tpm_register_hardware failed\n");
|
return PTR_ERR(chip);
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
|
ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
|
||||||
if (!ibmvtpm) {
|
if (!ibmvtpm) {
|
||||||
|
@ -629,7 +636,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
|
||||||
if (rc)
|
if (rc)
|
||||||
goto init_irq_cleanup;
|
goto init_irq_cleanup;
|
||||||
|
|
||||||
return rc;
|
return tpm_chip_register(chip);
|
||||||
init_irq_cleanup:
|
init_irq_cleanup:
|
||||||
do {
|
do {
|
||||||
rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
|
rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
|
||||||
|
@ -644,8 +651,6 @@ cleanup:
|
||||||
kfree(ibmvtpm);
|
kfree(ibmvtpm);
|
||||||
}
|
}
|
||||||
|
|
||||||
tpm_remove_hardware(dev);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 IBM Corporation
|
* Copyright (C) 2012 IBM Corporation
|
||||||
*
|
*
|
||||||
* Author: Ashley Lai <adlai@us.ibm.com>
|
* Author: Ashley Lai <ashleydlai@gmail.com>
|
||||||
*
|
*
|
||||||
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
||||||
*
|
*
|
||||||
|
|
|
@ -195,9 +195,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
|
||||||
}
|
}
|
||||||
if (i == TPM_MAX_TRIES) { /* timeout occurs */
|
if (i == TPM_MAX_TRIES) { /* timeout occurs */
|
||||||
if (wait_for_bit == STAT_XFE)
|
if (wait_for_bit == STAT_XFE)
|
||||||
dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n");
|
dev_err(chip->pdev, "Timeout in wait(STAT_XFE)\n");
|
||||||
if (wait_for_bit == STAT_RDA)
|
if (wait_for_bit == STAT_RDA)
|
||||||
dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n");
|
dev_err(chip->pdev, "Timeout in wait(STAT_RDA)\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -220,7 +220,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
|
||||||
static void tpm_wtx(struct tpm_chip *chip)
|
static void tpm_wtx(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
number_of_wtx++;
|
number_of_wtx++;
|
||||||
dev_info(chip->dev, "Granting WTX (%02d / %02d)\n",
|
dev_info(chip->pdev, "Granting WTX (%02d / %02d)\n",
|
||||||
number_of_wtx, TPM_MAX_WTX_PACKAGES);
|
number_of_wtx, TPM_MAX_WTX_PACKAGES);
|
||||||
wait_and_send(chip, TPM_VL_VER);
|
wait_and_send(chip, TPM_VL_VER);
|
||||||
wait_and_send(chip, TPM_CTRL_WTX);
|
wait_and_send(chip, TPM_CTRL_WTX);
|
||||||
|
@ -231,7 +231,7 @@ static void tpm_wtx(struct tpm_chip *chip)
|
||||||
|
|
||||||
static void tpm_wtx_abort(struct tpm_chip *chip)
|
static void tpm_wtx_abort(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
dev_info(chip->dev, "Aborting WTX\n");
|
dev_info(chip->pdev, "Aborting WTX\n");
|
||||||
wait_and_send(chip, TPM_VL_VER);
|
wait_and_send(chip, TPM_VL_VER);
|
||||||
wait_and_send(chip, TPM_CTRL_WTX_ABORT);
|
wait_and_send(chip, TPM_CTRL_WTX_ABORT);
|
||||||
wait_and_send(chip, 0x00);
|
wait_and_send(chip, 0x00);
|
||||||
|
@ -257,7 +257,7 @@ recv_begin:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[0] != TPM_VL_VER) {
|
if (buf[0] != TPM_VL_VER) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"Wrong transport protocol implementation!\n");
|
"Wrong transport protocol implementation!\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +272,7 @@ recv_begin:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((size == 0x6D00) && (buf[1] == 0x80)) {
|
if ((size == 0x6D00) && (buf[1] == 0x80)) {
|
||||||
dev_err(chip->dev, "Error handling on vendor layer!\n");
|
dev_err(chip->pdev, "Error handling on vendor layer!\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ recv_begin:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[1] == TPM_CTRL_WTX) {
|
if (buf[1] == TPM_CTRL_WTX) {
|
||||||
dev_info(chip->dev, "WTX-package received\n");
|
dev_info(chip->pdev, "WTX-package received\n");
|
||||||
if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
|
if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
|
||||||
tpm_wtx(chip);
|
tpm_wtx(chip);
|
||||||
goto recv_begin;
|
goto recv_begin;
|
||||||
|
@ -295,14 +295,14 @@ recv_begin:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
|
if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
|
||||||
dev_info(chip->dev, "WTX-abort acknowledged\n");
|
dev_info(chip->pdev, "WTX-abort acknowledged\n");
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[1] == TPM_CTRL_ERROR) {
|
if (buf[1] == TPM_CTRL_ERROR) {
|
||||||
dev_err(chip->dev, "ERROR-package received:\n");
|
dev_err(chip->pdev, "ERROR-package received:\n");
|
||||||
if (buf[4] == TPM_INF_NAK)
|
if (buf[4] == TPM_INF_NAK)
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"-> Negative acknowledgement"
|
"-> Negative acknowledgement"
|
||||||
" - retransmit command!\n");
|
" - retransmit command!\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -321,7 +321,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
|
||||||
|
|
||||||
ret = empty_fifo(chip, 1);
|
ret = empty_fifo(chip, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(chip->dev, "Timeout while clearing FIFO\n");
|
dev_err(chip->pdev, "Timeout while clearing FIFO\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
|
||||||
vendorid[0], vendorid[1],
|
vendorid[0], vendorid[1],
|
||||||
productid[0], productid[1], chipname);
|
productid[0], productid[1], chipname);
|
||||||
|
|
||||||
if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
|
chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
|
||||||
|
if (IS_ERR(chip)) {
|
||||||
|
rc = PTR_ERR(chip);
|
||||||
|
goto err_release_region;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = tpm_chip_register(chip);
|
||||||
|
if (rc)
|
||||||
goto err_release_region;
|
goto err_release_region;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = pnp_get_drvdata(dev);
|
struct tpm_chip *chip = pnp_get_drvdata(dev);
|
||||||
|
|
||||||
if (chip) {
|
tpm_chip_unregister(chip);
|
||||||
if (tpm_dev.iotype == TPM_INF_IO_PORT) {
|
|
||||||
release_region(tpm_dev.data_regs, tpm_dev.data_size);
|
if (tpm_dev.iotype == TPM_INF_IO_PORT) {
|
||||||
release_region(tpm_dev.config_port,
|
release_region(tpm_dev.data_regs, tpm_dev.data_size);
|
||||||
tpm_dev.config_size);
|
release_region(tpm_dev.config_port,
|
||||||
} else {
|
tpm_dev.config_size);
|
||||||
iounmap(tpm_dev.mem_base);
|
} else {
|
||||||
release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
|
iounmap(tpm_dev.mem_base);
|
||||||
}
|
release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
|
||||||
tpm_dev_vendor_release(chip);
|
|
||||||
tpm_remove_hardware(chip->dev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
|
||||||
}
|
}
|
||||||
while (time_before(jiffies, stop));
|
while (time_before(jiffies, stop));
|
||||||
|
|
||||||
dev_info(chip->dev, "wait for ready failed\n");
|
dev_info(chip->pdev, "wait for ready failed\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,12 +129,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
|
if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
|
||||||
dev_err(chip->dev, "F0 timeout\n");
|
dev_err(chip->pdev, "F0 timeout\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
if ((data =
|
if ((data =
|
||||||
inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
|
inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
|
||||||
dev_err(chip->dev, "not in normal mode (0x%x)\n",
|
dev_err(chip->pdev, "not in normal mode (0x%x)\n",
|
||||||
data);
|
data);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
|
||||||
for (p = buffer; p < &buffer[count]; p++) {
|
for (p = buffer; p < &buffer[count]; p++) {
|
||||||
if (wait_for_stat
|
if (wait_for_stat
|
||||||
(chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
|
(chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"OBF timeout (while reading data)\n");
|
"OBF timeout (while reading data)\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -154,11 +154,11 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
|
||||||
|
|
||||||
if ((data & NSC_STATUS_F0) == 0 &&
|
if ((data & NSC_STATUS_F0) == 0 &&
|
||||||
(wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
|
(wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
|
||||||
dev_err(chip->dev, "F0 not set\n");
|
dev_err(chip->pdev, "F0 not set\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
|
if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"expected end of command(0x%x)\n", data);
|
"expected end of command(0x%x)\n", data);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -189,19 +189,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
|
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
|
||||||
dev_err(chip->dev, "IBF timeout\n");
|
dev_err(chip->pdev, "IBF timeout\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
|
outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
|
||||||
if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
|
if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
|
||||||
dev_err(chip->dev, "IBR timeout\n");
|
dev_err(chip->pdev, "IBR timeout\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
|
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
|
||||||
dev_err(chip->dev,
|
dev_err(chip->pdev,
|
||||||
"IBF timeout (while writing data)\n");
|
"IBF timeout (while writing data)\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
|
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
|
||||||
dev_err(chip->dev, "IBF timeout\n");
|
dev_err(chip->pdev, "IBF timeout\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
|
outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
|
||||||
|
@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL;
|
||||||
static void tpm_nsc_remove(struct device *dev)
|
static void tpm_nsc_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
if ( chip ) {
|
|
||||||
release_region(chip->vendor.base, 2);
|
tpm_chip_unregister(chip);
|
||||||
tpm_remove_hardware(chip->dev);
|
release_region(chip->vendor.base, 2);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
|
static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
|
||||||
|
@ -307,11 +306,16 @@ static int __init init_nsc(void)
|
||||||
goto err_del_dev;
|
goto err_del_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
|
chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
|
||||||
|
if (IS_ERR(chip)) {
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
goto err_rel_reg;
|
goto err_rel_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = tpm_chip_register(chip);
|
||||||
|
if (rc)
|
||||||
|
goto err_rel_reg;
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "NSC TPM detected\n");
|
dev_dbg(&pdev->dev, "NSC TPM detected\n");
|
||||||
dev_dbg(&pdev->dev,
|
dev_dbg(&pdev->dev,
|
||||||
"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
|
"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012 IBM Corporation
|
* Copyright 2012 IBM Corporation
|
||||||
*
|
*
|
||||||
* Author: Ashley Lai <adlai@us.ibm.com>
|
* Author: Ashley Lai <ashleydlai@gmail.com>
|
||||||
*
|
*
|
||||||
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 Intel Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Xiaoyan Zhang <xiaoyan.zhang@intel.com>
|
||||||
|
* Jiang Liu <jiang.liu@linux.intel.com>
|
||||||
|
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
||||||
|
*
|
||||||
|
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
|
||||||
|
*
|
||||||
|
* This file contains implementation of the sysfs interface for PPI.
|
||||||
|
*
|
||||||
|
* 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/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
|
|
||||||
|
@ -12,7 +31,6 @@
|
||||||
#define PPI_TPM_REQ_MAX 22
|
#define PPI_TPM_REQ_MAX 22
|
||||||
#define PPI_VS_REQ_START 128
|
#define PPI_VS_REQ_START 128
|
||||||
#define PPI_VS_REQ_END 255
|
#define PPI_VS_REQ_END 255
|
||||||
#define PPI_VERSION_LEN 3
|
|
||||||
|
|
||||||
static const u8 tpm_ppi_uuid[] = {
|
static const u8 tpm_ppi_uuid[] = {
|
||||||
0xA6, 0xFA, 0xDD, 0x3D,
|
0xA6, 0xFA, 0xDD, 0x3D,
|
||||||
|
@ -22,45 +40,22 @@ static const u8 tpm_ppi_uuid[] = {
|
||||||
0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
|
0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
|
||||||
};
|
};
|
||||||
|
|
||||||
static char tpm_ppi_version[PPI_VERSION_LEN + 1];
|
|
||||||
static acpi_handle tpm_ppi_handle;
|
|
||||||
|
|
||||||
static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
|
|
||||||
void **return_value)
|
|
||||||
{
|
|
||||||
union acpi_object *obj;
|
|
||||||
|
|
||||||
if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
|
|
||||||
1 << TPM_PPI_FN_VERSION))
|
|
||||||
return AE_OK;
|
|
||||||
|
|
||||||
/* Cache version string */
|
|
||||||
obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
|
|
||||||
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
|
|
||||||
NULL, ACPI_TYPE_STRING);
|
|
||||||
if (obj) {
|
|
||||||
strlcpy(tpm_ppi_version, obj->string.pointer,
|
|
||||||
PPI_VERSION_LEN + 1);
|
|
||||||
ACPI_FREE(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
*return_value = handle;
|
|
||||||
|
|
||||||
return AE_CTRL_TERMINATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union acpi_object *
|
static inline union acpi_object *
|
||||||
tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)
|
tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
|
||||||
|
union acpi_object *argv4)
|
||||||
{
|
{
|
||||||
BUG_ON(!tpm_ppi_handle);
|
BUG_ON(!ppi_handle);
|
||||||
return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid,
|
return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid,
|
||||||
TPM_PPI_REVISION_ID, func, argv4, type);
|
TPM_PPI_REVISION_ID,
|
||||||
|
func, argv4, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t tpm_show_ppi_version(struct device *dev,
|
static ssize_t tpm_show_ppi_version(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t tpm_show_ppi_request(struct device *dev,
|
static ssize_t tpm_show_ppi_request(struct device *dev,
|
||||||
|
@ -68,8 +63,10 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
|
||||||
{
|
{
|
||||||
ssize_t size = -EINVAL;
|
ssize_t size = -EINVAL;
|
||||||
union acpi_object *obj;
|
union acpi_object *obj;
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL);
|
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
|
||||||
|
ACPI_TYPE_PACKAGE, NULL);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
|
@ -103,14 +100,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
||||||
int func = TPM_PPI_FN_SUBREQ;
|
int func = TPM_PPI_FN_SUBREQ;
|
||||||
union acpi_object *obj, tmp;
|
union acpi_object *obj, tmp;
|
||||||
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
|
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the function to submit TPM operation request to pre-os environment
|
* the function to submit TPM operation request to pre-os environment
|
||||||
* is updated with function index from SUBREQ to SUBREQ2 since PPI
|
* is updated with function index from SUBREQ to SUBREQ2 since PPI
|
||||||
* version 1.1
|
* version 1.1
|
||||||
*/
|
*/
|
||||||
if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
|
if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
|
||||||
1 << TPM_PPI_FN_SUBREQ2))
|
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
|
||||||
func = TPM_PPI_FN_SUBREQ2;
|
func = TPM_PPI_FN_SUBREQ2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -119,7 +117,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
||||||
* string/package type. For PPI version 1.0 and 1.1, use buffer type
|
* string/package type. For PPI version 1.0 and 1.1, use buffer type
|
||||||
* for compatibility, and use package type since 1.2 according to spec.
|
* for compatibility, and use package type since 1.2 according to spec.
|
||||||
*/
|
*/
|
||||||
if (strcmp(tpm_ppi_version, "1.2") < 0) {
|
if (strcmp(chip->ppi_version, "1.2") < 0) {
|
||||||
if (sscanf(buf, "%d", &req) != 1)
|
if (sscanf(buf, "%d", &req) != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
argv4.type = ACPI_TYPE_BUFFER;
|
argv4.type = ACPI_TYPE_BUFFER;
|
||||||
|
@ -131,7 +129,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4);
|
obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
|
||||||
|
&argv4);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
} else {
|
} else {
|
||||||
|
@ -157,6 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
|
||||||
.buffer.length = 0,
|
.buffer.length = 0,
|
||||||
.buffer.pointer = NULL
|
.buffer.pointer = NULL
|
||||||
};
|
};
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
static char *info[] = {
|
static char *info[] = {
|
||||||
"None",
|
"None",
|
||||||
|
@ -171,9 +171,10 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
|
||||||
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
|
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
|
||||||
* compatibility, define params[3].type as buffer, if PPI version < 1.2
|
* compatibility, define params[3].type as buffer, if PPI version < 1.2
|
||||||
*/
|
*/
|
||||||
if (strcmp(tpm_ppi_version, "1.2") < 0)
|
if (strcmp(chip->ppi_version, "1.2") < 0)
|
||||||
obj = &tmp;
|
obj = &tmp;
|
||||||
obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj);
|
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
|
||||||
|
ACPI_TYPE_INTEGER, obj);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
} else {
|
} else {
|
||||||
|
@ -196,8 +197,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
|
||||||
acpi_status status = -EINVAL;
|
acpi_status status = -EINVAL;
|
||||||
union acpi_object *obj, *ret_obj;
|
union acpi_object *obj, *ret_obj;
|
||||||
u64 req, res;
|
u64 req, res;
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL);
|
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
|
||||||
|
ACPI_TYPE_PACKAGE, NULL);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
|
@ -248,7 +251,8 @@ cleanup:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
|
static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
|
||||||
|
u32 end)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u32 ret;
|
u32 ret;
|
||||||
|
@ -264,14 +268,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
|
||||||
"User not required",
|
"User not required",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
|
if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
|
||||||
1 << TPM_PPI_FN_GETOPR))
|
1 << TPM_PPI_FN_GETOPR))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
tmp.integer.type = ACPI_TYPE_INTEGER;
|
tmp.integer.type = ACPI_TYPE_INTEGER;
|
||||||
for (i = start; i <= end; i++) {
|
for (i = start; i <= end; i++) {
|
||||||
tmp.integer.value = i;
|
tmp.integer.value = i;
|
||||||
obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv);
|
obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
|
||||||
|
ACPI_TYPE_INTEGER, &argv);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
} else {
|
} else {
|
||||||
|
@ -291,14 +296,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
|
||||||
|
PPI_TPM_REQ_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
|
static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
|
||||||
|
PPI_VS_REQ_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
|
static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
|
||||||
|
@ -323,16 +334,38 @@ static struct attribute_group ppi_attr_grp = {
|
||||||
.attrs = ppi_attrs
|
.attrs = ppi_attrs
|
||||||
};
|
};
|
||||||
|
|
||||||
int tpm_add_ppi(struct kobject *parent)
|
int tpm_add_ppi(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
/* Cache TPM ACPI handle and version string */
|
union acpi_object *obj;
|
||||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
|
int rc;
|
||||||
ppi_callback, NULL, NULL, &tpm_ppi_handle);
|
|
||||||
return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0;
|
if (!chip->acpi_dev_handle)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
|
||||||
|
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Cache PPI version string. */
|
||||||
|
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
|
||||||
|
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
|
||||||
|
NULL, ACPI_TYPE_STRING);
|
||||||
|
if (obj) {
|
||||||
|
strlcpy(chip->ppi_version, obj->string.pointer,
|
||||||
|
sizeof(chip->ppi_version));
|
||||||
|
ACPI_FREE(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp);
|
||||||
|
|
||||||
|
if (!rc)
|
||||||
|
chip->flags |= TPM_CHIP_FLAG_PPI;
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tpm_remove_ppi(struct kobject *parent)
|
void tpm_remove_ppi(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
if (tpm_ppi_handle)
|
if (chip->flags & TPM_CHIP_FLAG_PPI)
|
||||||
sysfs_remove_group(parent, &ppi_attr_grp);
|
sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2005, 2006 IBM Corporation
|
* Copyright (C) 2005, 2006 IBM Corporation
|
||||||
|
* Copyright (C) 2014 Intel Corporation
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Leendert van Doorn <leendert@watson.ibm.com>
|
* Leendert van Doorn <leendert@watson.ibm.com>
|
||||||
|
@ -64,19 +65,30 @@ enum tis_defaults {
|
||||||
TIS_LONG_TIMEOUT = 2000, /* 2 sec */
|
TIS_LONG_TIMEOUT = 2000, /* 2 sec */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Some timeout values are needed before it is known whether the chip is
|
||||||
|
* TPM 1.0 or TPM 2.0.
|
||||||
|
*/
|
||||||
|
#define TIS_TIMEOUT_A_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A)
|
||||||
|
#define TIS_TIMEOUT_B_MAX max(TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B)
|
||||||
|
#define TIS_TIMEOUT_C_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C)
|
||||||
|
#define TIS_TIMEOUT_D_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D)
|
||||||
|
|
||||||
#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
|
#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
|
||||||
#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
|
#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
|
||||||
#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
|
#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
|
||||||
#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
|
#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
|
||||||
#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
|
#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
|
||||||
#define TPM_STS(l) (0x0018 | ((l) << 12))
|
#define TPM_STS(l) (0x0018 | ((l) << 12))
|
||||||
|
#define TPM_STS3(l) (0x001b | ((l) << 12))
|
||||||
#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
|
#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
|
||||||
|
|
||||||
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
|
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
|
||||||
#define TPM_RID(l) (0x0F04 | ((l) << 12))
|
#define TPM_RID(l) (0x0F04 | ((l) << 12))
|
||||||
|
|
||||||
static LIST_HEAD(tis_chips);
|
struct priv_data {
|
||||||
static DEFINE_MUTEX(tis_lock);
|
bool irq_tested;
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
|
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
|
||||||
static int is_itpm(struct pnp_dev *dev)
|
static int is_itpm(struct pnp_dev *dev)
|
||||||
|
@ -241,7 +253,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
/* read first 10 bytes, including tag, paramsize, and result */
|
/* read first 10 bytes, including tag, paramsize, and result */
|
||||||
if ((size =
|
if ((size =
|
||||||
recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
|
recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
|
||||||
dev_err(chip->dev, "Unable to read header\n");
|
dev_err(chip->pdev, "Unable to read header\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +266,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
if ((size +=
|
if ((size +=
|
||||||
recv_data(chip, &buf[TPM_HEADER_SIZE],
|
recv_data(chip, &buf[TPM_HEADER_SIZE],
|
||||||
expected - TPM_HEADER_SIZE)) < expected) {
|
expected - TPM_HEADER_SIZE)) < expected) {
|
||||||
dev_err(chip->dev, "Unable to read remainder of result\n");
|
dev_err(chip->pdev, "Unable to read remainder of result\n");
|
||||||
size = -ETIME;
|
size = -ETIME;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +275,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
&chip->vendor.int_queue, false);
|
&chip->vendor.int_queue, false);
|
||||||
status = tpm_tis_status(chip);
|
status = tpm_tis_status(chip);
|
||||||
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
|
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
|
||||||
dev_err(chip->dev, "Error left over data\n");
|
dev_err(chip->pdev, "Error left over data\n");
|
||||||
size = -EIO;
|
size = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -338,15 +350,31 @@ out_err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void disable_interrupts(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
u32 intmask;
|
||||||
|
|
||||||
|
intmask =
|
||||||
|
ioread32(chip->vendor.iobase +
|
||||||
|
TPM_INT_ENABLE(chip->vendor.locality));
|
||||||
|
intmask &= ~TPM_GLOBAL_INT_ENABLE;
|
||||||
|
iowrite32(intmask,
|
||||||
|
chip->vendor.iobase +
|
||||||
|
TPM_INT_ENABLE(chip->vendor.locality));
|
||||||
|
free_irq(chip->vendor.irq, chip);
|
||||||
|
chip->vendor.irq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If interrupts are used (signaled by an irq set in the vendor structure)
|
* If interrupts are used (signaled by an irq set in the vendor structure)
|
||||||
* tpm.c can skip polling for the data to be available as the interrupt is
|
* tpm.c can skip polling for the data to be available as the interrupt is
|
||||||
* waited for here
|
* waited for here
|
||||||
*/
|
*/
|
||||||
static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
u32 ordinal;
|
u32 ordinal;
|
||||||
|
unsigned long dur;
|
||||||
|
|
||||||
rc = tpm_tis_send_data(chip, buf, len);
|
rc = tpm_tis_send_data(chip, buf, len);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
|
@ -358,9 +386,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
|
|
||||||
if (chip->vendor.irq) {
|
if (chip->vendor.irq) {
|
||||||
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
|
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
|
||||||
|
|
||||||
|
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||||
|
dur = tpm2_calc_ordinal_duration(chip, ordinal);
|
||||||
|
else
|
||||||
|
dur = tpm_calc_ordinal_duration(chip, ordinal);
|
||||||
|
|
||||||
if (wait_for_tpm_stat
|
if (wait_for_tpm_stat
|
||||||
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
|
||||||
tpm_calc_ordinal_duration(chip, ordinal),
|
|
||||||
&chip->vendor.read_queue, false) < 0) {
|
&chip->vendor.read_queue, false) < 0) {
|
||||||
rc = -ETIME;
|
rc = -ETIME;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
@ -373,6 +406,30 @@ out_err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
int rc, irq;
|
||||||
|
struct priv_data *priv = chip->vendor.priv;
|
||||||
|
|
||||||
|
if (!chip->vendor.irq || priv->irq_tested)
|
||||||
|
return tpm_tis_send_main(chip, buf, len);
|
||||||
|
|
||||||
|
/* Verify receipt of the expected IRQ */
|
||||||
|
irq = chip->vendor.irq;
|
||||||
|
chip->vendor.irq = 0;
|
||||||
|
rc = tpm_tis_send_main(chip, buf, len);
|
||||||
|
chip->vendor.irq = irq;
|
||||||
|
if (!priv->irq_tested)
|
||||||
|
msleep(1);
|
||||||
|
if (!priv->irq_tested) {
|
||||||
|
disable_interrupts(chip);
|
||||||
|
dev_err(chip->pdev,
|
||||||
|
FW_BUG "TPM interrupt not working, polling instead\n");
|
||||||
|
}
|
||||||
|
priv->irq_tested = true;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
struct tis_vendor_timeout_override {
|
struct tis_vendor_timeout_override {
|
||||||
u32 did_vid;
|
u32 did_vid;
|
||||||
unsigned long timeout_us[4];
|
unsigned long timeout_us[4];
|
||||||
|
@ -436,7 +493,7 @@ static int probe_itpm(struct tpm_chip *chip)
|
||||||
|
|
||||||
rc = tpm_tis_send_data(chip, cmd_getticks, len);
|
rc = tpm_tis_send_data(chip, cmd_getticks, len);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
dev_info(chip->dev, "Detected an iTPM.\n");
|
dev_info(chip->pdev, "Detected an iTPM.\n");
|
||||||
rc = 1;
|
rc = 1;
|
||||||
} else
|
} else
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
|
@ -505,6 +562,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
|
||||||
if (interrupt == 0)
|
if (interrupt == 0)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
((struct priv_data *)chip->vendor.priv)->irq_tested = true;
|
||||||
if (interrupt & TPM_INTF_DATA_AVAIL_INT)
|
if (interrupt & TPM_INTF_DATA_AVAIL_INT)
|
||||||
wake_up_interruptible(&chip->vendor.read_queue);
|
wake_up_interruptible(&chip->vendor.read_queue);
|
||||||
if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
|
if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
|
||||||
|
@ -528,27 +586,48 @@ static bool interrupts = true;
|
||||||
module_param(interrupts, bool, 0444);
|
module_param(interrupts, bool, 0444);
|
||||||
MODULE_PARM_DESC(interrupts, "Enable interrupts");
|
MODULE_PARM_DESC(interrupts, "Enable interrupts");
|
||||||
|
|
||||||
static int tpm_tis_init(struct device *dev, resource_size_t start,
|
static void tpm_tis_remove(struct tpm_chip *chip)
|
||||||
resource_size_t len, unsigned int irq)
|
{
|
||||||
|
iowrite32(~TPM_GLOBAL_INT_ENABLE &
|
||||||
|
ioread32(chip->vendor.iobase +
|
||||||
|
TPM_INT_ENABLE(chip->vendor.
|
||||||
|
locality)),
|
||||||
|
chip->vendor.iobase +
|
||||||
|
TPM_INT_ENABLE(chip->vendor.locality));
|
||||||
|
release_locality(chip, chip->vendor.locality, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
|
||||||
|
resource_size_t start, resource_size_t len,
|
||||||
|
unsigned int irq)
|
||||||
{
|
{
|
||||||
u32 vendor, intfcaps, intmask;
|
u32 vendor, intfcaps, intmask;
|
||||||
int rc, i, irq_s, irq_e, probe;
|
int rc, i, irq_s, irq_e, probe;
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
|
struct priv_data *priv;
|
||||||
|
|
||||||
if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
|
priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL);
|
||||||
return -ENODEV;
|
if (priv == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
chip->vendor.iobase = ioremap(start, len);
|
chip = tpmm_chip_alloc(dev, &tpm_tis);
|
||||||
if (!chip->vendor.iobase) {
|
if (IS_ERR(chip))
|
||||||
rc = -EIO;
|
return PTR_ERR(chip);
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default timeouts */
|
chip->vendor.priv = priv;
|
||||||
chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
|
#ifdef CONFIG_ACPI
|
||||||
chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
|
chip->acpi_dev_handle = acpi_dev_handle;
|
||||||
chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
|
#endif
|
||||||
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
|
|
||||||
|
chip->vendor.iobase = devm_ioremap(dev, start, len);
|
||||||
|
if (!chip->vendor.iobase)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
/* Maximum timeouts */
|
||||||
|
chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX;
|
||||||
|
chip->vendor.timeout_b = TIS_TIMEOUT_B_MAX;
|
||||||
|
chip->vendor.timeout_c = TIS_TIMEOUT_C_MAX;
|
||||||
|
chip->vendor.timeout_d = TIS_TIMEOUT_D_MAX;
|
||||||
|
|
||||||
if (wait_startup(chip, 0) != 0) {
|
if (wait_startup(chip, 0) != 0) {
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
|
@ -560,11 +639,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Every TPM 2.x command has a higher ordinal than TPM 1.x commands.
|
||||||
|
* Therefore, we can use an idempotent TPM 2.x command to probe TPM 2.x.
|
||||||
|
*/
|
||||||
|
rc = tpm2_gen_interrupt(chip, true);
|
||||||
|
if (rc == 0 || rc == TPM2_RC_INITIALIZE)
|
||||||
|
chip->flags |= TPM_CHIP_FLAG_TPM2;
|
||||||
|
|
||||||
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
|
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
|
||||||
chip->vendor.manufacturer_id = vendor;
|
chip->vendor.manufacturer_id = vendor;
|
||||||
|
|
||||||
dev_info(dev,
|
dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
|
||||||
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
|
(chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
|
||||||
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
|
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
|
||||||
|
|
||||||
if (!itpm) {
|
if (!itpm) {
|
||||||
|
@ -605,19 +691,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||||
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
|
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
|
||||||
dev_dbg(dev, "\tData Avail Int Support\n");
|
dev_dbg(dev, "\tData Avail Int Support\n");
|
||||||
|
|
||||||
/* get the timeouts before testing for irqs */
|
|
||||||
if (tpm_get_timeouts(chip)) {
|
|
||||||
dev_err(dev, "Could not get TPM timeouts and durations\n");
|
|
||||||
rc = -ENODEV;
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tpm_do_selftest(chip)) {
|
|
||||||
dev_err(dev, "TPM self test failed\n");
|
|
||||||
rc = -ENODEV;
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* INTERRUPT Setup */
|
/* INTERRUPT Setup */
|
||||||
init_waitqueue_head(&chip->vendor.read_queue);
|
init_waitqueue_head(&chip->vendor.read_queue);
|
||||||
init_waitqueue_head(&chip->vendor.int_queue);
|
init_waitqueue_head(&chip->vendor.int_queue);
|
||||||
|
@ -649,10 +722,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||||
for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
|
for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
|
||||||
iowrite8(i, chip->vendor.iobase +
|
iowrite8(i, chip->vendor.iobase +
|
||||||
TPM_INT_VECTOR(chip->vendor.locality));
|
TPM_INT_VECTOR(chip->vendor.locality));
|
||||||
if (request_irq
|
if (devm_request_irq
|
||||||
(i, tis_int_probe, IRQF_SHARED,
|
(dev, i, tis_int_probe, IRQF_SHARED,
|
||||||
chip->vendor.miscdev.name, chip) != 0) {
|
chip->devname, chip) != 0) {
|
||||||
dev_info(chip->dev,
|
dev_info(chip->pdev,
|
||||||
"Unable to request irq: %d for probe\n",
|
"Unable to request irq: %d for probe\n",
|
||||||
i);
|
i);
|
||||||
continue;
|
continue;
|
||||||
|
@ -673,7 +746,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||||
chip->vendor.probed_irq = 0;
|
chip->vendor.probed_irq = 0;
|
||||||
|
|
||||||
/* Generate Interrupts */
|
/* Generate Interrupts */
|
||||||
tpm_gen_interrupt(chip);
|
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||||
|
tpm2_gen_interrupt(chip, false);
|
||||||
|
else
|
||||||
|
tpm_gen_interrupt(chip);
|
||||||
|
|
||||||
chip->vendor.irq = chip->vendor.probed_irq;
|
chip->vendor.irq = chip->vendor.probed_irq;
|
||||||
|
|
||||||
|
@ -690,17 +766,16 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||||
iowrite32(intmask,
|
iowrite32(intmask,
|
||||||
chip->vendor.iobase +
|
chip->vendor.iobase +
|
||||||
TPM_INT_ENABLE(chip->vendor.locality));
|
TPM_INT_ENABLE(chip->vendor.locality));
|
||||||
free_irq(i, chip);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chip->vendor.irq) {
|
if (chip->vendor.irq) {
|
||||||
iowrite8(chip->vendor.irq,
|
iowrite8(chip->vendor.irq,
|
||||||
chip->vendor.iobase +
|
chip->vendor.iobase +
|
||||||
TPM_INT_VECTOR(chip->vendor.locality));
|
TPM_INT_VECTOR(chip->vendor.locality));
|
||||||
if (request_irq
|
if (devm_request_irq
|
||||||
(chip->vendor.irq, tis_int_handler, IRQF_SHARED,
|
(dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
|
||||||
chip->vendor.miscdev.name, chip) != 0) {
|
chip->devname, chip) != 0) {
|
||||||
dev_info(chip->dev,
|
dev_info(chip->pdev,
|
||||||
"Unable to request irq: %d for use\n",
|
"Unable to request irq: %d for use\n",
|
||||||
chip->vendor.irq);
|
chip->vendor.irq);
|
||||||
chip->vendor.irq = 0;
|
chip->vendor.irq = 0;
|
||||||
|
@ -719,17 +794,49 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&chip->vendor.list);
|
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||||
mutex_lock(&tis_lock);
|
chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
|
||||||
list_add(&chip->vendor.list, &tis_chips);
|
chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
|
||||||
mutex_unlock(&tis_lock);
|
chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
|
||||||
|
chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
|
||||||
|
chip->vendor.duration[TPM_SHORT] =
|
||||||
|
msecs_to_jiffies(TPM2_DURATION_SHORT);
|
||||||
|
chip->vendor.duration[TPM_MEDIUM] =
|
||||||
|
msecs_to_jiffies(TPM2_DURATION_MEDIUM);
|
||||||
|
chip->vendor.duration[TPM_LONG] =
|
||||||
|
msecs_to_jiffies(TPM2_DURATION_LONG);
|
||||||
|
|
||||||
|
rc = tpm2_do_selftest(chip);
|
||||||
|
if (rc == TPM2_RC_INITIALIZE) {
|
||||||
|
dev_warn(dev, "Firmware has not started TPM\n");
|
||||||
|
rc = tpm2_startup(chip, TPM2_SU_CLEAR);
|
||||||
|
if (!rc)
|
||||||
|
rc = tpm2_do_selftest(chip);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
if (rc) {
|
||||||
|
dev_err(dev, "TPM self test failed\n");
|
||||||
|
if (rc > 0)
|
||||||
|
rc = -ENODEV;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tpm_get_timeouts(chip)) {
|
||||||
|
dev_err(dev, "Could not get TPM timeouts and durations\n");
|
||||||
|
rc = -ENODEV;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tpm_do_selftest(chip)) {
|
||||||
|
dev_err(dev, "TPM self test failed\n");
|
||||||
|
rc = -ENODEV;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tpm_chip_register(chip);
|
||||||
out_err:
|
out_err:
|
||||||
if (chip->vendor.iobase)
|
tpm_tis_remove(chip);
|
||||||
iounmap(chip->vendor.iobase);
|
|
||||||
tpm_remove_hardware(chip->dev);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,14 +865,23 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
|
||||||
static int tpm_tis_resume(struct device *dev)
|
static int tpm_tis_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (chip->vendor.irq)
|
if (chip->vendor.irq)
|
||||||
tpm_tis_reenable_interrupts(chip);
|
tpm_tis_reenable_interrupts(chip);
|
||||||
|
|
||||||
ret = tpm_pm_resume(dev);
|
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||||
if (!ret)
|
/* NOP if firmware properly does this. */
|
||||||
tpm_do_selftest(chip);
|
tpm2_startup(chip, TPM2_SU_STATE);
|
||||||
|
|
||||||
|
ret = tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||||
|
if (!ret)
|
||||||
|
ret = tpm2_do_selftest(chip);
|
||||||
|
} else {
|
||||||
|
ret = tpm_pm_resume(dev);
|
||||||
|
if (!ret)
|
||||||
|
tpm_do_selftest(chip);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -779,6 +895,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
|
||||||
{
|
{
|
||||||
resource_size_t start, len;
|
resource_size_t start, len;
|
||||||
unsigned int irq = 0;
|
unsigned int irq = 0;
|
||||||
|
acpi_handle acpi_dev_handle = NULL;
|
||||||
|
|
||||||
start = pnp_mem_start(pnp_dev, 0);
|
start = pnp_mem_start(pnp_dev, 0);
|
||||||
len = pnp_mem_len(pnp_dev, 0);
|
len = pnp_mem_len(pnp_dev, 0);
|
||||||
|
@ -791,7 +908,12 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
|
||||||
if (is_itpm(pnp_dev))
|
if (is_itpm(pnp_dev))
|
||||||
itpm = true;
|
itpm = true;
|
||||||
|
|
||||||
return tpm_tis_init(&pnp_dev->dev, start, len, irq);
|
#ifdef CONFIG_ACPI
|
||||||
|
if (pnp_acpi_device(pnp_dev))
|
||||||
|
acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pnp_device_id tpm_pnp_tbl[] = {
|
static struct pnp_device_id tpm_pnp_tbl[] = {
|
||||||
|
@ -811,13 +933,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
|
||||||
static void tpm_tis_pnp_remove(struct pnp_dev *dev)
|
static void tpm_tis_pnp_remove(struct pnp_dev *dev)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = pnp_get_drvdata(dev);
|
struct tpm_chip *chip = pnp_get_drvdata(dev);
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
tpm_dev_vendor_release(chip);
|
tpm_tis_remove(chip);
|
||||||
|
|
||||||
kfree(chip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct pnp_driver tis_pnp_driver = {
|
static struct pnp_driver tis_pnp_driver = {
|
||||||
.name = "tpm_tis",
|
.name = "tpm_tis",
|
||||||
.id_table = tpm_pnp_tbl,
|
.id_table = tpm_pnp_tbl,
|
||||||
|
@ -836,7 +955,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
|
||||||
|
|
||||||
static struct platform_driver tis_drv = {
|
static struct platform_driver tis_drv = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "tpm_tis",
|
.name = "tpm_tis",
|
||||||
.pm = &tpm_tis_pm,
|
.pm = &tpm_tis_pm,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -862,7 +981,7 @@ static int __init init_tis(void)
|
||||||
rc = PTR_ERR(pdev);
|
rc = PTR_ERR(pdev);
|
||||||
goto err_dev;
|
goto err_dev;
|
||||||
}
|
}
|
||||||
rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0);
|
rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_init;
|
goto err_init;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -875,31 +994,16 @@ err_dev:
|
||||||
|
|
||||||
static void __exit cleanup_tis(void)
|
static void __exit cleanup_tis(void)
|
||||||
{
|
{
|
||||||
struct tpm_vendor_specific *i, *j;
|
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
mutex_lock(&tis_lock);
|
|
||||||
list_for_each_entry_safe(i, j, &tis_chips, list) {
|
|
||||||
chip = to_tpm_chip(i);
|
|
||||||
tpm_remove_hardware(chip->dev);
|
|
||||||
iowrite32(~TPM_GLOBAL_INT_ENABLE &
|
|
||||||
ioread32(chip->vendor.iobase +
|
|
||||||
TPM_INT_ENABLE(chip->vendor.
|
|
||||||
locality)),
|
|
||||||
chip->vendor.iobase +
|
|
||||||
TPM_INT_ENABLE(chip->vendor.locality));
|
|
||||||
release_locality(chip, chip->vendor.locality, 1);
|
|
||||||
if (chip->vendor.irq)
|
|
||||||
free_irq(chip->vendor.irq, chip);
|
|
||||||
iounmap(i->iobase);
|
|
||||||
list_del(&i->list);
|
|
||||||
}
|
|
||||||
mutex_unlock(&tis_lock);
|
|
||||||
#ifdef CONFIG_PNP
|
#ifdef CONFIG_PNP
|
||||||
if (!force) {
|
if (!force) {
|
||||||
pnp_unregister_driver(&tis_pnp_driver);
|
pnp_unregister_driver(&tis_pnp_driver);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
chip = dev_get_drvdata(&pdev->dev);
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
|
tpm_tis_remove(chip);
|
||||||
platform_device_unregister(pdev);
|
platform_device_unregister(pdev);
|
||||||
platform_driver_unregister(&tis_drv);
|
platform_driver_unregister(&tis_drv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
|
|
||||||
chip = tpm_register_hardware(dev, &tpm_vtpm);
|
chip = tpmm_chip_alloc(dev, &tpm_vtpm);
|
||||||
if (!chip)
|
if (IS_ERR(chip))
|
||||||
return -ENODEV;
|
return PTR_ERR(chip);
|
||||||
|
|
||||||
init_waitqueue_head(&chip->vendor.read_queue);
|
init_waitqueue_head(&chip->vendor.read_queue);
|
||||||
|
|
||||||
|
@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev,
|
||||||
const struct xenbus_device_id *id)
|
const struct xenbus_device_id *id)
|
||||||
{
|
{
|
||||||
struct tpm_private *priv;
|
struct tpm_private *priv;
|
||||||
|
struct tpm_chip *chip;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||||
|
@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev,
|
||||||
|
|
||||||
rv = setup_ring(dev, priv);
|
rv = setup_ring(dev, priv);
|
||||||
if (rv) {
|
if (rv) {
|
||||||
tpm_remove_hardware(&dev->dev);
|
chip = dev_get_drvdata(&dev->dev);
|
||||||
|
tpm_chip_unregister(chip);
|
||||||
ring_free(priv);
|
ring_free(priv);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
tpm_get_timeouts(priv->chip);
|
tpm_get_timeouts(priv->chip);
|
||||||
|
|
||||||
return rv;
|
return tpm_chip_register(priv->chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tpmfront_remove(struct xenbus_device *dev)
|
static int tpmfront_remove(struct xenbus_device *dev)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
|
struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
|
||||||
struct tpm_private *priv = TPM_VPRIV(chip);
|
struct tpm_private *priv = TPM_VPRIV(chip);
|
||||||
tpm_remove_hardware(&dev->dev);
|
tpm_chip_unregister(chip);
|
||||||
ring_free(priv);
|
ring_free(priv);
|
||||||
TPM_VPRIV(chip) = NULL;
|
TPM_VPRIV(chip) = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -12,9 +12,8 @@
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along
|
* You should have received a copy of the GNU General Public License
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
*
|
||||||
* STMicroelectronics version 1.2.0, Copyright (C) 2010
|
* STMicroelectronics version 1.2.0, Copyright (C) 2010
|
||||||
* STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
|
* STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
|
||||||
|
@ -23,39 +22,18 @@
|
||||||
*
|
*
|
||||||
* @Author: Christophe RICARD tpmsupport@st.com
|
* @Author: Christophe RICARD tpmsupport@st.com
|
||||||
*
|
*
|
||||||
* @File: stm_st33_tpm_i2c.h
|
* @File: stm_st33_tpm.h
|
||||||
*
|
*
|
||||||
* @Date: 09/15/2010
|
* @Date: 09/15/2010
|
||||||
*/
|
*/
|
||||||
#ifndef __STM_ST33_TPM_I2C_MAIN_H__
|
#ifndef __STM_ST33_TPM_H__
|
||||||
#define __STM_ST33_TPM_I2C_MAIN_H__
|
#define __STM_ST33_TPM_H__
|
||||||
|
|
||||||
#define TPM_ACCESS (0x0)
|
#define TPM_ST33_I2C "st33zp24-i2c"
|
||||||
#define TPM_STS (0x18)
|
#define TPM_ST33_SPI "st33zp24-spi"
|
||||||
#define TPM_HASH_END (0x20)
|
|
||||||
#define TPM_DATA_FIFO (0x24)
|
|
||||||
#define TPM_HASH_DATA (0x24)
|
|
||||||
#define TPM_HASH_START (0x28)
|
|
||||||
#define TPM_INTF_CAPABILITY (0x14)
|
|
||||||
#define TPM_INT_STATUS (0x10)
|
|
||||||
#define TPM_INT_ENABLE (0x08)
|
|
||||||
|
|
||||||
#define TPM_DUMMY_BYTE 0xAA
|
|
||||||
#define TPM_WRITE_DIRECTION 0x80
|
|
||||||
#define TPM_HEADER_SIZE 10
|
|
||||||
#define TPM_BUFSIZE 2048
|
|
||||||
|
|
||||||
#define LOCALITY0 0
|
|
||||||
|
|
||||||
#define TPM_ST33_I2C "st33zp24_i2c"
|
|
||||||
|
|
||||||
struct st33zp24_platform_data {
|
struct st33zp24_platform_data {
|
||||||
int io_serirq;
|
|
||||||
int io_lpcpd;
|
int io_lpcpd;
|
||||||
struct i2c_client *client;
|
|
||||||
u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
|
|
||||||
struct completion irq_detection;
|
|
||||||
struct mutex lock;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */
|
#endif /* __STM_ST33_TPM_H__ */
|
|
@ -120,13 +120,6 @@ extern int cipso_v4_rbm_optfmt;
|
||||||
extern int cipso_v4_rbm_strictvalid;
|
extern int cipso_v4_rbm_strictvalid;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper Functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0)
|
|
||||||
#define CIPSO_V4_OPTPTR(x) (skb_network_header(x) + IPCB(x)->opt.cipso)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DOI List Functions
|
* DOI List Functions
|
||||||
*/
|
*/
|
||||||
|
@ -190,7 +183,7 @@ static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
|
||||||
|
|
||||||
#ifdef CONFIG_NETLABEL
|
#ifdef CONFIG_NETLABEL
|
||||||
void cipso_v4_cache_invalidate(void);
|
void cipso_v4_cache_invalidate(void);
|
||||||
int cipso_v4_cache_add(const struct sk_buff *skb,
|
int cipso_v4_cache_add(const unsigned char *cipso_ptr,
|
||||||
const struct netlbl_lsm_secattr *secattr);
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
#else
|
#else
|
||||||
static inline void cipso_v4_cache_invalidate(void)
|
static inline void cipso_v4_cache_invalidate(void)
|
||||||
|
@ -198,7 +191,7 @@ static inline void cipso_v4_cache_invalidate(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int cipso_v4_cache_add(const struct sk_buff *skb,
|
static inline int cipso_v4_cache_add(const unsigned char *cipso_ptr,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -211,6 +204,8 @@ static inline int cipso_v4_cache_add(const struct sk_buff *skb,
|
||||||
|
|
||||||
#ifdef CONFIG_NETLABEL
|
#ifdef CONFIG_NETLABEL
|
||||||
void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
|
void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
|
||||||
|
int cipso_v4_getattr(const unsigned char *cipso,
|
||||||
|
struct netlbl_lsm_secattr *secattr);
|
||||||
int cipso_v4_sock_setattr(struct sock *sk,
|
int cipso_v4_sock_setattr(struct sock *sk,
|
||||||
const struct cipso_v4_doi *doi_def,
|
const struct cipso_v4_doi *doi_def,
|
||||||
const struct netlbl_lsm_secattr *secattr);
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
@ -226,6 +221,7 @@ int cipso_v4_skbuff_setattr(struct sk_buff *skb,
|
||||||
int cipso_v4_skbuff_delattr(struct sk_buff *skb);
|
int cipso_v4_skbuff_delattr(struct sk_buff *skb);
|
||||||
int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
|
int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
|
||||||
struct netlbl_lsm_secattr *secattr);
|
struct netlbl_lsm_secattr *secattr);
|
||||||
|
unsigned char *cipso_v4_optptr(const struct sk_buff *skb);
|
||||||
int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
|
int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
|
||||||
#else
|
#else
|
||||||
static inline void cipso_v4_error(struct sk_buff *skb,
|
static inline void cipso_v4_error(struct sk_buff *skb,
|
||||||
|
@ -235,6 +231,12 @@ static inline void cipso_v4_error(struct sk_buff *skb,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int cipso_v4_getattr(const unsigned char *cipso,
|
||||||
|
struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int cipso_v4_sock_setattr(struct sock *sk,
|
static inline int cipso_v4_sock_setattr(struct sock *sk,
|
||||||
const struct cipso_v4_doi *doi_def,
|
const struct cipso_v4_doi *doi_def,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
@ -282,6 +284,11 @@ static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned char *cipso_v4_optptr(const struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int cipso_v4_validate(const struct sk_buff *skb,
|
static inline int cipso_v4_validate(const struct sk_buff *skb,
|
||||||
unsigned char **option)
|
unsigned char **option)
|
||||||
{
|
{
|
||||||
|
|
|
@ -143,7 +143,7 @@ endif
|
||||||
kernel/system_certificates.o: $(obj)/x509_certificate_list
|
kernel/system_certificates.o: $(obj)/x509_certificate_list
|
||||||
|
|
||||||
quiet_cmd_x509certs = CERTS $@
|
quiet_cmd_x509certs = CERTS $@
|
||||||
cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; echo " - Including cert $(X509)")
|
cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; $(kecho) " - Including cert $(X509)")
|
||||||
|
|
||||||
targets += $(obj)/x509_certificate_list
|
targets += $(obj)/x509_certificate_list
|
||||||
$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
|
$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
|
||||||
|
|
|
@ -57,14 +57,12 @@ int mpi_cmp(MPI u, MPI v)
|
||||||
if (usize != vsize && !u->sign && !v->sign)
|
if (usize != vsize && !u->sign && !v->sign)
|
||||||
return usize - vsize;
|
return usize - vsize;
|
||||||
if (usize != vsize && u->sign && v->sign)
|
if (usize != vsize && u->sign && v->sign)
|
||||||
return vsize + usize;
|
return vsize - usize;
|
||||||
if (!usize)
|
if (!usize)
|
||||||
return 0;
|
return 0;
|
||||||
cmp = mpihelp_cmp(u->d, v->d, usize);
|
cmp = mpihelp_cmp(u->d, v->d, usize);
|
||||||
if (!cmp)
|
if (u->sign)
|
||||||
return 0;
|
return -cmp;
|
||||||
if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0))
|
return cmp;
|
||||||
return 1;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mpi_cmp);
|
EXPORT_SYMBOL_GPL(mpi_cmp);
|
||||||
|
|
|
@ -84,7 +84,7 @@ static inline int RESIZE_IF_NEEDED(MPI a, unsigned b)
|
||||||
do { \
|
do { \
|
||||||
mpi_size_t _i; \
|
mpi_size_t _i; \
|
||||||
for (_i = 0; _i < (n); _i++) \
|
for (_i = 0; _i < (n); _i++) \
|
||||||
(d)[_i] = (d)[_i]; \
|
(d)[_i] = (s)[_i]; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MPN_COPY_DECR(d, s, n) \
|
#define MPN_COPY_DECR(d, s, n) \
|
||||||
|
|
|
@ -378,20 +378,18 @@ static int cipso_v4_cache_check(const unsigned char *key,
|
||||||
* negative values on failure.
|
* negative values on failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int cipso_v4_cache_add(const struct sk_buff *skb,
|
int cipso_v4_cache_add(const unsigned char *cipso_ptr,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
int ret_val = -EPERM;
|
int ret_val = -EPERM;
|
||||||
u32 bkt;
|
u32 bkt;
|
||||||
struct cipso_v4_map_cache_entry *entry = NULL;
|
struct cipso_v4_map_cache_entry *entry = NULL;
|
||||||
struct cipso_v4_map_cache_entry *old_entry = NULL;
|
struct cipso_v4_map_cache_entry *old_entry = NULL;
|
||||||
unsigned char *cipso_ptr;
|
|
||||||
u32 cipso_ptr_len;
|
u32 cipso_ptr_len;
|
||||||
|
|
||||||
if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
|
if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cipso_ptr = CIPSO_V4_OPTPTR(skb);
|
|
||||||
cipso_ptr_len = cipso_ptr[1];
|
cipso_ptr_len = cipso_ptr[1];
|
||||||
|
|
||||||
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||||
|
@ -1578,6 +1576,33 @@ static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cipso_v4_optptr - Find the CIPSO option in the packet
|
||||||
|
* @skb: the packet
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Parse the packet's IP header looking for a CIPSO option. Returns a pointer
|
||||||
|
* to the start of the CIPSO option on success, NULL if one if not found.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
unsigned char *cipso_v4_optptr(const struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
const struct iphdr *iph = ip_hdr(skb);
|
||||||
|
unsigned char *optptr = (unsigned char *)&(ip_hdr(skb)[1]);
|
||||||
|
int optlen;
|
||||||
|
int taglen;
|
||||||
|
|
||||||
|
for (optlen = iph->ihl*4 - sizeof(struct iphdr); optlen > 0; ) {
|
||||||
|
if (optptr[0] == IPOPT_CIPSO)
|
||||||
|
return optptr;
|
||||||
|
taglen = optptr[1];
|
||||||
|
optlen -= taglen;
|
||||||
|
optptr += taglen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cipso_v4_validate - Validate a CIPSO option
|
* cipso_v4_validate - Validate a CIPSO option
|
||||||
* @option: the start of the option, on error it is set to point to the error
|
* @option: the start of the option, on error it is set to point to the error
|
||||||
|
@ -2119,8 +2144,8 @@ void cipso_v4_req_delattr(struct request_sock *req)
|
||||||
* on success and negative values on failure.
|
* on success and negative values on failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int cipso_v4_getattr(const unsigned char *cipso,
|
int cipso_v4_getattr(const unsigned char *cipso,
|
||||||
struct netlbl_lsm_secattr *secattr)
|
struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
int ret_val = -ENOMSG;
|
int ret_val = -ENOMSG;
|
||||||
u32 doi;
|
u32 doi;
|
||||||
|
@ -2305,22 +2330,6 @@ int cipso_v4_skbuff_delattr(struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
|
|
||||||
* @skb: the packet
|
|
||||||
* @secattr: the security attributes
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Parse the given packet's CIPSO option and return the security attributes.
|
|
||||||
* Returns zero on success and negative values on failure.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
|
|
||||||
struct netlbl_lsm_secattr *secattr)
|
|
||||||
{
|
|
||||||
return cipso_v4_getattr(CIPSO_V4_OPTPTR(skb), secattr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup Functions
|
* Setup Functions
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1065,10 +1065,12 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
||||||
u16 family,
|
u16 family,
|
||||||
struct netlbl_lsm_secattr *secattr)
|
struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
|
unsigned char *ptr;
|
||||||
|
|
||||||
switch (family) {
|
switch (family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
if (CIPSO_V4_OPTEXIST(skb) &&
|
ptr = cipso_v4_optptr(skb);
|
||||||
cipso_v4_skbuff_getattr(skb, secattr) == 0)
|
if (ptr && cipso_v4_getattr(ptr, secattr) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
@ -1094,7 +1096,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
||||||
*/
|
*/
|
||||||
void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
|
void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
|
||||||
{
|
{
|
||||||
if (CIPSO_V4_OPTEXIST(skb))
|
if (cipso_v4_optptr(skb))
|
||||||
cipso_v4_error(skb, error, gateway);
|
cipso_v4_error(skb, error, gateway);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1126,11 +1128,14 @@ void netlbl_cache_invalidate(void)
|
||||||
int netlbl_cache_add(const struct sk_buff *skb,
|
int netlbl_cache_add(const struct sk_buff *skb,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
|
unsigned char *ptr;
|
||||||
|
|
||||||
if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
|
if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
|
|
||||||
if (CIPSO_V4_OPTEXIST(skb))
|
ptr = cipso_v4_optptr(skb);
|
||||||
return cipso_v4_cache_add(skb, secattr);
|
if (ptr)
|
||||||
|
return cipso_v4_cache_add(ptr, secattr);
|
||||||
|
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
}
|
}
|
||||||
|
|
|
@ -311,6 +311,9 @@ struct token {
|
||||||
|
|
||||||
static struct token *token_list;
|
static struct token *token_list;
|
||||||
static unsigned nr_tokens;
|
static unsigned nr_tokens;
|
||||||
|
static _Bool verbose;
|
||||||
|
|
||||||
|
#define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0)
|
||||||
|
|
||||||
static int directive_compare(const void *_key, const void *_pdir)
|
static int directive_compare(const void *_key, const void *_pdir)
|
||||||
{
|
{
|
||||||
|
@ -322,21 +325,21 @@ static int directive_compare(const void *_key, const void *_pdir)
|
||||||
dlen = strlen(dir);
|
dlen = strlen(dir);
|
||||||
clen = (dlen < token->size) ? dlen : token->size;
|
clen = (dlen < token->size) ? dlen : token->size;
|
||||||
|
|
||||||
//printf("cmp(%*.*s,%s) = ",
|
//debug("cmp(%*.*s,%s) = ",
|
||||||
// (int)token->size, (int)token->size, token->value,
|
// (int)token->size, (int)token->size, token->value,
|
||||||
// dir);
|
// dir);
|
||||||
|
|
||||||
val = memcmp(token->value, dir, clen);
|
val = memcmp(token->value, dir, clen);
|
||||||
if (val != 0) {
|
if (val != 0) {
|
||||||
//printf("%d [cmp]\n", val);
|
//debug("%d [cmp]\n", val);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dlen == token->size) {
|
if (dlen == token->size) {
|
||||||
//printf("0\n");
|
//debug("0\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//printf("%d\n", (int)dlen - (int)token->size);
|
//debug("%d\n", (int)dlen - (int)token->size);
|
||||||
return dlen - token->size; /* shorter -> negative */
|
return dlen - token->size; /* shorter -> negative */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,13 +518,13 @@ static void tokenise(char *buffer, char *end)
|
||||||
}
|
}
|
||||||
|
|
||||||
nr_tokens = tix;
|
nr_tokens = tix;
|
||||||
printf("Extracted %u tokens\n", nr_tokens);
|
debug("Extracted %u tokens\n", nr_tokens);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n < nr_tokens; n++)
|
for (n = 0; n < nr_tokens; n++)
|
||||||
printf("Token %3u: '%*.*s'\n",
|
debug("Token %3u: '%*.*s'\n",
|
||||||
n,
|
n,
|
||||||
(int)token_list[n].size, (int)token_list[n].size,
|
(int)token_list[n].size, (int)token_list[n].size,
|
||||||
token_list[n].value);
|
token_list[n].value);
|
||||||
|
@ -542,6 +545,7 @@ int main(int argc, char **argv)
|
||||||
ssize_t readlen;
|
ssize_t readlen;
|
||||||
FILE *out, *hdr;
|
FILE *out, *hdr;
|
||||||
char *buffer, *p;
|
char *buffer, *p;
|
||||||
|
char *kbuild_verbose;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if (argc != 4) {
|
if (argc != 4) {
|
||||||
|
@ -550,6 +554,10 @@ int main(int argc, char **argv)
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kbuild_verbose = getenv("KBUILD_VERBOSE");
|
||||||
|
if (kbuild_verbose)
|
||||||
|
verbose = atoi(kbuild_verbose);
|
||||||
|
|
||||||
filename = argv[1];
|
filename = argv[1];
|
||||||
outputname = argv[2];
|
outputname = argv[2];
|
||||||
headername = argv[3];
|
headername = argv[3];
|
||||||
|
@ -748,11 +756,11 @@ static void build_type_list(void)
|
||||||
|
|
||||||
qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
|
qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
|
||||||
|
|
||||||
printf("Extracted %u types\n", nr_types);
|
debug("Extracted %u types\n", nr_types);
|
||||||
#if 0
|
#if 0
|
||||||
for (n = 0; n < nr_types; n++) {
|
for (n = 0; n < nr_types; n++) {
|
||||||
struct type *type = type_index[n];
|
struct type *type = type_index[n];
|
||||||
printf("- %*.*s\n",
|
debug("- %*.*s\n",
|
||||||
(int)type->name->size,
|
(int)type->name->size,
|
||||||
(int)type->name->size,
|
(int)type->name->size,
|
||||||
type->name->value);
|
type->name->value);
|
||||||
|
@ -793,7 +801,7 @@ static void parse(void)
|
||||||
|
|
||||||
} while (type++, !(type->flags & TYPE_STOP_MARKER));
|
} while (type++, !(type->flags & TYPE_STOP_MARKER));
|
||||||
|
|
||||||
printf("Extracted %u actions\n", nr_actions);
|
debug("Extracted %u actions\n", nr_actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct element *element_list;
|
static struct element *element_list;
|
||||||
|
@ -1284,7 +1292,7 @@ static void render(FILE *out, FILE *hdr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We do two passes - the first one calculates all the offsets */
|
/* We do two passes - the first one calculates all the offsets */
|
||||||
printf("Pass 1\n");
|
debug("Pass 1\n");
|
||||||
nr_entries = 0;
|
nr_entries = 0;
|
||||||
root = &type_list[0];
|
root = &type_list[0];
|
||||||
render_element(NULL, root->element, NULL);
|
render_element(NULL, root->element, NULL);
|
||||||
|
@ -1295,7 +1303,7 @@ static void render(FILE *out, FILE *hdr)
|
||||||
e->flags &= ~ELEMENT_RENDERED;
|
e->flags &= ~ELEMENT_RENDERED;
|
||||||
|
|
||||||
/* And then we actually render */
|
/* And then we actually render */
|
||||||
printf("Pass 2\n");
|
debug("Pass 2\n");
|
||||||
fprintf(out, "\n");
|
fprintf(out, "\n");
|
||||||
fprintf(out, "static const unsigned char %s_machine[] = {\n",
|
fprintf(out, "static const unsigned char %s_machine[] = {\n",
|
||||||
grammar_name);
|
grammar_name);
|
||||||
|
|
|
@ -126,7 +126,6 @@ config IMA_TRUSTED_KEYRING
|
||||||
bool "Require all keys on the .ima keyring be signed"
|
bool "Require all keys on the .ima keyring be signed"
|
||||||
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
|
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
|
||||||
depends on INTEGRITY_ASYMMETRIC_KEYS
|
depends on INTEGRITY_ASYMMETRIC_KEYS
|
||||||
select KEYS_DEBUG_PROC_KEYS
|
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This option requires that all keys added to the .ima
|
This option requires that all keys added to the .ima
|
||||||
|
|
|
@ -80,21 +80,3 @@ config ENCRYPTED_KEYS
|
||||||
Userspace only ever sees/stores encrypted blobs.
|
Userspace only ever sees/stores encrypted blobs.
|
||||||
|
|
||||||
If you are unsure as to whether this is required, answer N.
|
If you are unsure as to whether this is required, answer N.
|
||||||
|
|
||||||
config KEYS_DEBUG_PROC_KEYS
|
|
||||||
bool "Enable the /proc/keys file by which keys may be viewed"
|
|
||||||
depends on KEYS
|
|
||||||
help
|
|
||||||
This option turns on support for the /proc/keys file - through which
|
|
||||||
can be listed all the keys on the system that are viewable by the
|
|
||||||
reading process.
|
|
||||||
|
|
||||||
The only keys included in the list are those that grant View
|
|
||||||
permission to the reading process whether or not it possesses them.
|
|
||||||
Note that LSM security checks are still performed, and may further
|
|
||||||
filter out keys that the current process is not authorised to view.
|
|
||||||
|
|
||||||
Only key attributes are listed here; key payloads are not included in
|
|
||||||
the resulting table.
|
|
||||||
|
|
||||||
If you are unsure as to whether this is required, answer N.
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
|
|
||||||
static int proc_keys_open(struct inode *inode, struct file *file);
|
static int proc_keys_open(struct inode *inode, struct file *file);
|
||||||
static void *proc_keys_start(struct seq_file *p, loff_t *_pos);
|
static void *proc_keys_start(struct seq_file *p, loff_t *_pos);
|
||||||
static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos);
|
static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos);
|
||||||
|
@ -38,7 +37,6 @@ static const struct file_operations proc_keys_fops = {
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = seq_release,
|
.release = seq_release,
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
static int proc_key_users_open(struct inode *inode, struct file *file);
|
static int proc_key_users_open(struct inode *inode, struct file *file);
|
||||||
static void *proc_key_users_start(struct seq_file *p, loff_t *_pos);
|
static void *proc_key_users_start(struct seq_file *p, loff_t *_pos);
|
||||||
|
@ -67,11 +65,9 @@ static int __init key_proc_init(void)
|
||||||
{
|
{
|
||||||
struct proc_dir_entry *p;
|
struct proc_dir_entry *p;
|
||||||
|
|
||||||
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
|
|
||||||
p = proc_create("keys", 0, NULL, &proc_keys_fops);
|
p = proc_create("keys", 0, NULL, &proc_keys_fops);
|
||||||
if (!p)
|
if (!p)
|
||||||
panic("Cannot create /proc/keys\n");
|
panic("Cannot create /proc/keys\n");
|
||||||
#endif
|
|
||||||
|
|
||||||
p = proc_create("key-users", 0, NULL, &proc_key_users_fops);
|
p = proc_create("key-users", 0, NULL, &proc_key_users_fops);
|
||||||
if (!p)
|
if (!p)
|
||||||
|
@ -86,8 +82,6 @@ __initcall(key_proc_init);
|
||||||
* Implement "/proc/keys" to provide a list of the keys on the system that
|
* Implement "/proc/keys" to provide a list of the keys on the system that
|
||||||
* grant View permission to the caller.
|
* grant View permission to the caller.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
|
|
||||||
|
|
||||||
static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n)
|
static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n)
|
||||||
{
|
{
|
||||||
struct user_namespace *user_ns = seq_user_ns(p);
|
struct user_namespace *user_ns = seq_user_ns(p);
|
||||||
|
@ -275,8 +269,6 @@ static int proc_keys_show(struct seq_file *m, void *v)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
|
|
||||||
|
|
||||||
static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
|
static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
|
||||||
{
|
{
|
||||||
while (n) {
|
while (n) {
|
||||||
|
|
|
@ -517,11 +517,6 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int avc_sidcmp(u32 x, u32 y)
|
|
||||||
{
|
|
||||||
return (x == y || x == SECSID_WILD || y == SECSID_WILD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* avc_update_node Update an AVC entry
|
* avc_update_node Update an AVC entry
|
||||||
* @event : Updating event
|
* @event : Updating event
|
||||||
|
|
|
@ -401,23 +401,14 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct superblock_security_struct *sbsec = sb->s_security;
|
struct superblock_security_struct *sbsec = sb->s_security;
|
||||||
|
|
||||||
if (sbsec->behavior == SECURITY_FS_USE_XATTR ||
|
return sbsec->behavior == SECURITY_FS_USE_XATTR ||
|
||||||
sbsec->behavior == SECURITY_FS_USE_TRANS ||
|
sbsec->behavior == SECURITY_FS_USE_TRANS ||
|
||||||
sbsec->behavior == SECURITY_FS_USE_TASK)
|
sbsec->behavior == SECURITY_FS_USE_TASK ||
|
||||||
return 1;
|
/* Special handling. Genfs but also in-core setxattr handler */
|
||||||
|
!strcmp(sb->s_type->name, "sysfs") ||
|
||||||
/* Special handling for sysfs. Is genfs but also has setxattr handler*/
|
!strcmp(sb->s_type->name, "pstore") ||
|
||||||
if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
|
!strcmp(sb->s_type->name, "debugfs") ||
|
||||||
return 1;
|
!strcmp(sb->s_type->name, "rootfs");
|
||||||
|
|
||||||
/*
|
|
||||||
* Special handling for rootfs. Is genfs but supports
|
|
||||||
* setting SELinux context on in-core inodes.
|
|
||||||
*/
|
|
||||||
if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sb_finish_set_opts(struct super_block *sb)
|
static int sb_finish_set_opts(struct super_block *sb)
|
||||||
|
@ -456,10 +447,6 @@ static int sb_finish_set_opts(struct super_block *sb)
|
||||||
if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
|
if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
|
||||||
printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
|
printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
|
||||||
sb->s_id, sb->s_type->name);
|
sb->s_id, sb->s_type->name);
|
||||||
else
|
|
||||||
printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
|
|
||||||
sb->s_id, sb->s_type->name,
|
|
||||||
labeling_behaviors[sbsec->behavior-1]);
|
|
||||||
|
|
||||||
sbsec->flags |= SE_SBINITIALIZED;
|
sbsec->flags |= SE_SBINITIALIZED;
|
||||||
if (selinux_is_sblabel_mnt(sb))
|
if (selinux_is_sblabel_mnt(sb))
|
||||||
|
|
|
@ -289,12 +289,16 @@ static int policydb_init(struct policydb *p)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
|
p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
|
||||||
if (!p->filename_trans)
|
if (!p->filename_trans) {
|
||||||
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
|
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
|
||||||
if (!p->range_tr)
|
if (!p->range_tr) {
|
||||||
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ebitmap_init(&p->filename_trans_ttypes);
|
ebitmap_init(&p->filename_trans_ttypes);
|
||||||
ebitmap_init(&p->policycaps);
|
ebitmap_init(&p->policycaps);
|
||||||
|
|
|
@ -28,3 +28,15 @@ config SECURITY_SMACK_BRINGUP
|
||||||
access rule set once the behavior is well understood.
|
access rule set once the behavior is well understood.
|
||||||
This is a superior mechanism to the oft abused
|
This is a superior mechanism to the oft abused
|
||||||
"permissive" mode of other systems.
|
"permissive" mode of other systems.
|
||||||
|
If you are unsure how to answer this question, answer N.
|
||||||
|
|
||||||
|
config SECURITY_SMACK_NETFILTER
|
||||||
|
bool "Packet marking using secmarks for netfilter"
|
||||||
|
depends on SECURITY_SMACK
|
||||||
|
depends on NETWORK_SECMARK
|
||||||
|
depends on NETFILTER
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This enables security marking of network packets using
|
||||||
|
Smack labels.
|
||||||
|
If you are unsure how to answer this question, answer N.
|
||||||
|
|
|
@ -5,3 +5,4 @@
|
||||||
obj-$(CONFIG_SECURITY_SMACK) := smack.o
|
obj-$(CONFIG_SECURITY_SMACK) := smack.o
|
||||||
|
|
||||||
smack-y := smack_lsm.o smack_access.o smackfs.o
|
smack-y := smack_lsm.o smack_access.o smackfs.o
|
||||||
|
smack-$(CONFIG_SECURITY_SMACK_NETFILTER) += smack_netfilter.o
|
||||||
|
|
|
@ -248,6 +248,7 @@ struct smack_known *smk_find_entry(const char *);
|
||||||
/*
|
/*
|
||||||
* Shared data.
|
* Shared data.
|
||||||
*/
|
*/
|
||||||
|
extern int smack_enabled;
|
||||||
extern int smack_cipso_direct;
|
extern int smack_cipso_direct;
|
||||||
extern int smack_cipso_mapped;
|
extern int smack_cipso_mapped;
|
||||||
extern struct smack_known *smack_net_ambient;
|
extern struct smack_known *smack_net_ambient;
|
||||||
|
@ -298,6 +299,16 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
|
||||||
return tsp->smk_task;
|
return tsp->smk_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct smack_known *smk_of_task_struct(const struct task_struct *t)
|
||||||
|
{
|
||||||
|
struct smack_known *skp;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
skp = smk_of_task(__task_cred(t)->security);
|
||||||
|
rcu_read_unlock();
|
||||||
|
return skp;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Present a pointer to the forked smack label entry in an task blob.
|
* Present a pointer to the forked smack label entry in an task blob.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -43,8 +43,6 @@
|
||||||
#include <linux/binfmts.h>
|
#include <linux/binfmts.h>
|
||||||
#include "smack.h"
|
#include "smack.h"
|
||||||
|
|
||||||
#define task_security(task) (task_cred_xxx((task), security))
|
|
||||||
|
|
||||||
#define TRANS_TRUE "TRUE"
|
#define TRANS_TRUE "TRUE"
|
||||||
#define TRANS_TRUE_SIZE 4
|
#define TRANS_TRUE_SIZE 4
|
||||||
|
|
||||||
|
@ -52,8 +50,11 @@
|
||||||
#define SMK_RECEIVING 1
|
#define SMK_RECEIVING 1
|
||||||
#define SMK_SENDING 2
|
#define SMK_SENDING 2
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
|
||||||
LIST_HEAD(smk_ipv6_port_list);
|
LIST_HEAD(smk_ipv6_port_list);
|
||||||
|
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
static struct kmem_cache *smack_inode_cache;
|
static struct kmem_cache *smack_inode_cache;
|
||||||
|
int smack_enabled;
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
|
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
|
||||||
static void smk_bu_mode(int mode, char *s)
|
static void smk_bu_mode(int mode, char *s)
|
||||||
|
@ -120,7 +121,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp,
|
||||||
static int smk_bu_task(struct task_struct *otp, int mode, int rc)
|
static int smk_bu_task(struct task_struct *otp, int mode, int rc)
|
||||||
{
|
{
|
||||||
struct task_smack *tsp = current_security();
|
struct task_smack *tsp = current_security();
|
||||||
struct task_smack *otsp = task_security(otp);
|
struct smack_known *smk_task = smk_of_task_struct(otp);
|
||||||
char acc[SMK_NUM_ACCESS_TYPE + 1];
|
char acc[SMK_NUM_ACCESS_TYPE + 1];
|
||||||
|
|
||||||
if (rc <= 0)
|
if (rc <= 0)
|
||||||
|
@ -128,7 +129,7 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc)
|
||||||
|
|
||||||
smk_bu_mode(mode, acc);
|
smk_bu_mode(mode, acc);
|
||||||
pr_info("Smack Bringup: (%s %s %s) %s to %s\n",
|
pr_info("Smack Bringup: (%s %s %s) %s to %s\n",
|
||||||
tsp->smk_task->smk_known, otsp->smk_task->smk_known, acc,
|
tsp->smk_task->smk_known, smk_task->smk_known, acc,
|
||||||
current->comm, otp->comm);
|
current->comm, otp->comm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +161,7 @@ static int smk_bu_file(struct file *file, int mode, int rc)
|
||||||
{
|
{
|
||||||
struct task_smack *tsp = current_security();
|
struct task_smack *tsp = current_security();
|
||||||
struct smack_known *sskp = tsp->smk_task;
|
struct smack_known *sskp = tsp->smk_task;
|
||||||
struct inode *inode = file->f_inode;
|
struct inode *inode = file_inode(file);
|
||||||
char acc[SMK_NUM_ACCESS_TYPE + 1];
|
char acc[SMK_NUM_ACCESS_TYPE + 1];
|
||||||
|
|
||||||
if (rc <= 0)
|
if (rc <= 0)
|
||||||
|
@ -168,7 +169,7 @@ static int smk_bu_file(struct file *file, int mode, int rc)
|
||||||
|
|
||||||
smk_bu_mode(mode, acc);
|
smk_bu_mode(mode, acc);
|
||||||
pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n",
|
pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n",
|
||||||
sskp->smk_known, (char *)file->f_security, acc,
|
sskp->smk_known, smk_of_inode(inode)->smk_known, acc,
|
||||||
inode->i_sb->s_id, inode->i_ino, file,
|
inode->i_sb->s_id, inode->i_ino, file,
|
||||||
current->comm);
|
current->comm);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -202,6 +203,7 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_fetch - Fetch the smack label from a file.
|
* smk_fetch - Fetch the smack label from a file.
|
||||||
|
* @name: type of the label (attribute)
|
||||||
* @ip: a pointer to the inode
|
* @ip: a pointer to the inode
|
||||||
* @dp: a pointer to the dentry
|
* @dp: a pointer to the dentry
|
||||||
*
|
*
|
||||||
|
@ -254,7 +256,9 @@ struct inode_smack *new_inode_smack(struct smack_known *skp)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* new_task_smack - allocate a task security blob
|
* new_task_smack - allocate a task security blob
|
||||||
* @smack: a pointer to the Smack label to use in the blob
|
* @task: a pointer to the Smack label for the running task
|
||||||
|
* @forked: a pointer to the Smack label for the forked task
|
||||||
|
* @gfp: type of the memory for the allocation
|
||||||
*
|
*
|
||||||
* Returns the new blob or NULL if there's no memory available
|
* Returns the new blob or NULL if there's no memory available
|
||||||
*/
|
*/
|
||||||
|
@ -277,8 +281,9 @@ static struct task_smack *new_task_smack(struct smack_known *task,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_copy_rules - copy a rule set
|
* smk_copy_rules - copy a rule set
|
||||||
* @nhead - new rules header pointer
|
* @nhead: new rules header pointer
|
||||||
* @ohead - old rules header pointer
|
* @ohead: old rules header pointer
|
||||||
|
* @gfp: type of the memory for the allocation
|
||||||
*
|
*
|
||||||
* Returns 0 on success, -ENOMEM on error
|
* Returns 0 on success, -ENOMEM on error
|
||||||
*/
|
*/
|
||||||
|
@ -345,7 +350,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
|
||||||
saip = &ad;
|
saip = &ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
tsp = task_security(tracer);
|
rcu_read_lock();
|
||||||
|
tsp = __task_cred(tracer)->security;
|
||||||
tracer_known = smk_of_task(tsp);
|
tracer_known = smk_of_task(tsp);
|
||||||
|
|
||||||
if ((mode & PTRACE_MODE_ATTACH) &&
|
if ((mode & PTRACE_MODE_ATTACH) &&
|
||||||
|
@ -365,11 +371,14 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
|
||||||
tracee_known->smk_known,
|
tracee_known->smk_known,
|
||||||
0, rc, saip);
|
0, rc, saip);
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
|
/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
|
||||||
rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
|
rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +405,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
skp = smk_of_task(task_security(ctp));
|
skp = smk_of_task_struct(ctp);
|
||||||
|
|
||||||
rc = smk_ptrace_rule_check(current, skp, mode, __func__);
|
rc = smk_ptrace_rule_check(current, skp, mode, __func__);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -796,7 +805,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
|
||||||
if (name)
|
if (name)
|
||||||
*name = XATTR_SMACK_SUFFIX;
|
*name = XATTR_SMACK_SUFFIX;
|
||||||
|
|
||||||
if (value) {
|
if (value && len) {
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
may = smk_access_entry(skp->smk_known, dsp->smk_known,
|
may = smk_access_entry(skp->smk_known, dsp->smk_known,
|
||||||
&skp->smk_rules);
|
&skp->smk_rules);
|
||||||
|
@ -817,10 +826,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
|
||||||
*value = kstrdup(isp->smk_known, GFP_NOFS);
|
*value = kstrdup(isp->smk_known, GFP_NOFS);
|
||||||
if (*value == NULL)
|
if (*value == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
*len = strlen(isp->smk_known);
|
*len = strlen(isp->smk_known);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1344,6 +1352,9 @@ static int smack_file_permission(struct file *file, int mask)
|
||||||
* The security blob for a file is a pointer to the master
|
* The security blob for a file is a pointer to the master
|
||||||
* label list, so no allocation is done.
|
* label list, so no allocation is done.
|
||||||
*
|
*
|
||||||
|
* f_security is the owner security information. It
|
||||||
|
* isn't used on file access checks, it's for send_sigio.
|
||||||
|
*
|
||||||
* Returns 0
|
* Returns 0
|
||||||
*/
|
*/
|
||||||
static int smack_file_alloc_security(struct file *file)
|
static int smack_file_alloc_security(struct file *file)
|
||||||
|
@ -1381,17 +1392,18 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
|
struct inode *inode = file_inode(file);
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||||
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
||||||
|
|
||||||
if (_IOC_DIR(cmd) & _IOC_WRITE) {
|
if (_IOC_DIR(cmd) & _IOC_WRITE) {
|
||||||
rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
|
rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad);
|
||||||
rc = smk_bu_file(file, MAY_WRITE, rc);
|
rc = smk_bu_file(file, MAY_WRITE, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) {
|
if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) {
|
||||||
rc = smk_curacc(file->f_security, MAY_READ, &ad);
|
rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad);
|
||||||
rc = smk_bu_file(file, MAY_READ, rc);
|
rc = smk_bu_file(file, MAY_READ, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1409,10 +1421,11 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
|
||||||
{
|
{
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
int rc;
|
int rc;
|
||||||
|
struct inode *inode = file_inode(file);
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||||
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
||||||
rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
|
rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad);
|
||||||
rc = smk_bu_file(file, MAY_LOCK, rc);
|
rc = smk_bu_file(file, MAY_LOCK, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1434,7 +1447,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
|
||||||
{
|
{
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
struct inode *inode = file_inode(file);
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case F_GETLK:
|
case F_GETLK:
|
||||||
|
@ -1443,14 +1456,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
|
||||||
case F_SETLKW:
|
case F_SETLKW:
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||||
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
||||||
rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
|
rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad);
|
||||||
rc = smk_bu_file(file, MAY_LOCK, rc);
|
rc = smk_bu_file(file, MAY_LOCK, rc);
|
||||||
break;
|
break;
|
||||||
case F_SETOWN:
|
case F_SETOWN:
|
||||||
case F_SETSIG:
|
case F_SETSIG:
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||||
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
||||||
rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
|
rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad);
|
||||||
rc = smk_bu_file(file, MAY_WRITE, rc);
|
rc = smk_bu_file(file, MAY_WRITE, rc);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1568,14 +1581,10 @@ static int smack_mmap_file(struct file *file,
|
||||||
* smack_file_set_fowner - set the file security blob value
|
* smack_file_set_fowner - set the file security blob value
|
||||||
* @file: object in question
|
* @file: object in question
|
||||||
*
|
*
|
||||||
* Returns 0
|
|
||||||
* Further research may be required on this one.
|
|
||||||
*/
|
*/
|
||||||
static void smack_file_set_fowner(struct file *file)
|
static void smack_file_set_fowner(struct file *file)
|
||||||
{
|
{
|
||||||
struct smack_known *skp = smk_of_current();
|
file->f_security = smk_of_current();
|
||||||
|
|
||||||
file->f_security = skp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1627,6 +1636,7 @@ static int smack_file_receive(struct file *file)
|
||||||
int rc;
|
int rc;
|
||||||
int may = 0;
|
int may = 0;
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
|
struct inode *inode = file_inode(file);
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||||
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
||||||
|
@ -1638,7 +1648,7 @@ static int smack_file_receive(struct file *file)
|
||||||
if (file->f_mode & FMODE_WRITE)
|
if (file->f_mode & FMODE_WRITE)
|
||||||
may |= MAY_WRITE;
|
may |= MAY_WRITE;
|
||||||
|
|
||||||
rc = smk_curacc(file->f_security, may, &ad);
|
rc = smk_curacc(smk_of_inode(inode), may, &ad);
|
||||||
rc = smk_bu_file(file, may, rc);
|
rc = smk_bu_file(file, may, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1658,21 +1668,17 @@ static int smack_file_receive(struct file *file)
|
||||||
static int smack_file_open(struct file *file, const struct cred *cred)
|
static int smack_file_open(struct file *file, const struct cred *cred)
|
||||||
{
|
{
|
||||||
struct task_smack *tsp = cred->security;
|
struct task_smack *tsp = cred->security;
|
||||||
struct inode_smack *isp = file_inode(file)->i_security;
|
struct inode *inode = file_inode(file);
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (smack_privileged(CAP_MAC_OVERRIDE)) {
|
if (smack_privileged(CAP_MAC_OVERRIDE))
|
||||||
file->f_security = isp->smk_inode;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||||
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
||||||
rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad);
|
rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad);
|
||||||
rc = smk_bu_credfile(cred, file, MAY_READ, rc);
|
rc = smk_bu_credfile(cred, file, MAY_READ, rc);
|
||||||
if (rc == 0)
|
|
||||||
file->f_security = isp->smk_inode;
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1826,7 +1832,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
|
||||||
const char *caller)
|
const char *caller)
|
||||||
{
|
{
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
struct smack_known *skp = smk_of_task(task_security(p));
|
struct smack_known *skp = smk_of_task_struct(p);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
|
smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
|
||||||
|
@ -1879,7 +1885,7 @@ static int smack_task_getsid(struct task_struct *p)
|
||||||
*/
|
*/
|
||||||
static void smack_task_getsecid(struct task_struct *p, u32 *secid)
|
static void smack_task_getsecid(struct task_struct *p, u32 *secid)
|
||||||
{
|
{
|
||||||
struct smack_known *skp = smk_of_task(task_security(p));
|
struct smack_known *skp = smk_of_task_struct(p);
|
||||||
|
|
||||||
*secid = skp->smk_secid;
|
*secid = skp->smk_secid;
|
||||||
}
|
}
|
||||||
|
@ -1986,7 +1992,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
|
||||||
{
|
{
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
struct smack_known *tkp = smk_of_task(task_security(p));
|
struct smack_known *tkp = smk_of_task_struct(p);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
||||||
|
@ -2040,7 +2046,7 @@ static int smack_task_wait(struct task_struct *p)
|
||||||
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
|
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
|
||||||
{
|
{
|
||||||
struct inode_smack *isp = inode->i_security;
|
struct inode_smack *isp = inode->i_security;
|
||||||
struct smack_known *skp = smk_of_task(task_security(p));
|
struct smack_known *skp = smk_of_task_struct(p);
|
||||||
|
|
||||||
isp->smk_inode = skp;
|
isp->smk_inode = skp;
|
||||||
}
|
}
|
||||||
|
@ -2212,6 +2218,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
|
||||||
return smack_netlabel(sk, sk_lbl);
|
return smack_netlabel(sk, sk_lbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
|
||||||
/**
|
/**
|
||||||
* smk_ipv6_port_label - Smack port access table management
|
* smk_ipv6_port_label - Smack port access table management
|
||||||
* @sock: socket
|
* @sock: socket
|
||||||
|
@ -2361,6 +2368,7 @@ auditout:
|
||||||
rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
|
rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_inode_setsecurity - set smack xattrs
|
* smack_inode_setsecurity - set smack xattrs
|
||||||
|
@ -2421,8 +2429,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
|
||||||
} else
|
} else
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
|
||||||
if (sock->sk->sk_family == PF_INET6)
|
if (sock->sk->sk_family == PF_INET6)
|
||||||
smk_ipv6_port_label(sock, NULL);
|
smk_ipv6_port_label(sock, NULL);
|
||||||
|
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2450,6 +2460,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
|
||||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SECURITY_SMACK_NETFILTER
|
||||||
/**
|
/**
|
||||||
* smack_socket_bind - record port binding information.
|
* smack_socket_bind - record port binding information.
|
||||||
* @sock: the socket
|
* @sock: the socket
|
||||||
|
@ -2463,11 +2474,14 @@ static int smack_socket_post_create(struct socket *sock, int family,
|
||||||
static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
|
static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
|
||||||
int addrlen)
|
int addrlen)
|
||||||
{
|
{
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
|
if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
|
||||||
smk_ipv6_port_label(sock, address);
|
smk_ipv6_port_label(sock, address);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* !CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_socket_connect - connect access check
|
* smack_socket_connect - connect access check
|
||||||
|
@ -2496,8 +2510,10 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
|
||||||
case PF_INET6:
|
case PF_INET6:
|
||||||
if (addrlen < sizeof(struct sockaddr_in6))
|
if (addrlen < sizeof(struct sockaddr_in6))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
|
||||||
rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap,
|
rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap,
|
||||||
SMK_CONNECTING);
|
SMK_CONNECTING);
|
||||||
|
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -3033,7 +3049,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
* of the superblock.
|
* of the superblock.
|
||||||
*/
|
*/
|
||||||
if (opt_dentry->d_parent == opt_dentry) {
|
if (opt_dentry->d_parent == opt_dentry) {
|
||||||
if (sbp->s_magic == CGROUP_SUPER_MAGIC) {
|
switch (sbp->s_magic) {
|
||||||
|
case CGROUP_SUPER_MAGIC:
|
||||||
/*
|
/*
|
||||||
* The cgroup filesystem is never mounted,
|
* The cgroup filesystem is never mounted,
|
||||||
* so there's no opportunity to set the mount
|
* so there's no opportunity to set the mount
|
||||||
|
@ -3041,8 +3058,19 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
*/
|
*/
|
||||||
sbsp->smk_root = &smack_known_star;
|
sbsp->smk_root = &smack_known_star;
|
||||||
sbsp->smk_default = &smack_known_star;
|
sbsp->smk_default = &smack_known_star;
|
||||||
|
isp->smk_inode = sbsp->smk_root;
|
||||||
|
break;
|
||||||
|
case TMPFS_MAGIC:
|
||||||
|
/*
|
||||||
|
* What about shmem/tmpfs anonymous files with dentry
|
||||||
|
* obtained from d_alloc_pseudo()?
|
||||||
|
*/
|
||||||
|
isp->smk_inode = smk_of_current();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
isp->smk_inode = sbsp->smk_root;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
isp->smk_inode = sbsp->smk_root;
|
|
||||||
isp->smk_flags |= SMK_INODE_INSTANT;
|
isp->smk_flags |= SMK_INODE_INSTANT;
|
||||||
goto unlockandout;
|
goto unlockandout;
|
||||||
}
|
}
|
||||||
|
@ -3200,7 +3228,7 @@ unlockandout:
|
||||||
*/
|
*/
|
||||||
static int smack_getprocattr(struct task_struct *p, char *name, char **value)
|
static int smack_getprocattr(struct task_struct *p, char *name, char **value)
|
||||||
{
|
{
|
||||||
struct smack_known *skp = smk_of_task(task_security(p));
|
struct smack_known *skp = smk_of_task_struct(p);
|
||||||
char *cp;
|
char *cp;
|
||||||
int slen;
|
int slen;
|
||||||
|
|
||||||
|
@ -3297,7 +3325,7 @@ static int smack_unix_stream_connect(struct sock *sock,
|
||||||
|
|
||||||
if (!smack_privileged(CAP_MAC_OVERRIDE)) {
|
if (!smack_privileged(CAP_MAC_OVERRIDE)) {
|
||||||
skp = ssp->smk_out;
|
skp = ssp->smk_out;
|
||||||
okp = osp->smk_out;
|
okp = osp->smk_in;
|
||||||
#ifdef CONFIG_AUDIT
|
#ifdef CONFIG_AUDIT
|
||||||
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
|
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
|
||||||
smk_ad_setfield_u_net_sk(&ad, other);
|
smk_ad_setfield_u_net_sk(&ad, other);
|
||||||
|
@ -3305,7 +3333,9 @@ static int smack_unix_stream_connect(struct sock *sock,
|
||||||
rc = smk_access(skp, okp, MAY_WRITE, &ad);
|
rc = smk_access(skp, okp, MAY_WRITE, &ad);
|
||||||
rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
|
rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
rc = smk_access(okp, skp, MAY_WRITE, NULL);
|
okp = osp->smk_out;
|
||||||
|
skp = ssp->smk_in;
|
||||||
|
rc = smk_access(okp, skp, MAY_WRITE, &ad);
|
||||||
rc = smk_bu_note("UDS connect", okp, skp,
|
rc = smk_bu_note("UDS connect", okp, skp,
|
||||||
MAY_WRITE, rc);
|
MAY_WRITE, rc);
|
||||||
}
|
}
|
||||||
|
@ -3366,7 +3396,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
|
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
|
||||||
struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
|
struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
|
||||||
|
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3380,7 +3412,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||||
rc = smack_netlabel_send(sock->sk, sip);
|
rc = smack_netlabel_send(sock->sk, sip);
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
|
||||||
rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
|
rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
|
||||||
|
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -3471,6 +3505,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
|
||||||
return smack_net_ambient;
|
return smack_net_ambient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
|
static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
|
||||||
{
|
{
|
||||||
u8 nexthdr;
|
u8 nexthdr;
|
||||||
|
@ -3517,6 +3552,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
|
||||||
}
|
}
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_socket_sock_rcv_skb - Smack packet delivery access check
|
* smack_socket_sock_rcv_skb - Smack packet delivery access check
|
||||||
|
@ -3529,15 +3565,30 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct netlbl_lsm_secattr secattr;
|
struct netlbl_lsm_secattr secattr;
|
||||||
struct socket_smack *ssp = sk->sk_security;
|
struct socket_smack *ssp = sk->sk_security;
|
||||||
struct smack_known *skp;
|
struct smack_known *skp = NULL;
|
||||||
struct sockaddr_in6 sadd;
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
#ifdef CONFIG_AUDIT
|
#ifdef CONFIG_AUDIT
|
||||||
struct lsm_network_audit net;
|
struct lsm_network_audit net;
|
||||||
#endif
|
#endif
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
struct sockaddr_in6 sadd;
|
||||||
|
int proto;
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
|
|
||||||
switch (sk->sk_family) {
|
switch (sk->sk_family) {
|
||||||
case PF_INET:
|
case PF_INET:
|
||||||
|
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
|
||||||
|
/*
|
||||||
|
* If there is a secmark use it rather than the CIPSO label.
|
||||||
|
* If there is no secmark fall back to CIPSO.
|
||||||
|
* The secmark is assumed to reflect policy better.
|
||||||
|
*/
|
||||||
|
if (skb && skb->secmark != 0) {
|
||||||
|
skp = smack_from_secid(skb->secmark);
|
||||||
|
goto access_check;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
/*
|
/*
|
||||||
* Translate what netlabel gave us.
|
* Translate what netlabel gave us.
|
||||||
*/
|
*/
|
||||||
|
@ -3551,6 +3602,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||||
|
|
||||||
netlbl_secattr_destroy(&secattr);
|
netlbl_secattr_destroy(&secattr);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
|
||||||
|
access_check:
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_AUDIT
|
#ifdef CONFIG_AUDIT
|
||||||
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
|
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
|
||||||
ad.a.u.net->family = sk->sk_family;
|
ad.a.u.net->family = sk->sk_family;
|
||||||
|
@ -3569,14 +3623,32 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
netlbl_skbuff_err(skb, rc, 0);
|
netlbl_skbuff_err(skb, rc, 0);
|
||||||
break;
|
break;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
case PF_INET6:
|
case PF_INET6:
|
||||||
rc = smk_skb_to_addr_ipv6(skb, &sadd);
|
proto = smk_skb_to_addr_ipv6(skb, &sadd);
|
||||||
if (rc == IPPROTO_UDP || rc == IPPROTO_TCP)
|
if (proto != IPPROTO_UDP && proto != IPPROTO_TCP)
|
||||||
rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
|
break;
|
||||||
|
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
|
||||||
|
if (skb && skb->secmark != 0)
|
||||||
|
skp = smack_from_secid(skb->secmark);
|
||||||
else
|
else
|
||||||
rc = 0;
|
skp = smack_net_ambient;
|
||||||
|
#ifdef CONFIG_AUDIT
|
||||||
|
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
|
||||||
|
ad.a.u.net->family = sk->sk_family;
|
||||||
|
ad.a.u.net->netif = skb->skb_iif;
|
||||||
|
ipv6_skb_to_auditdata(skb, &ad.a, NULL);
|
||||||
|
#endif /* CONFIG_AUDIT */
|
||||||
|
rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
|
||||||
|
rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in,
|
||||||
|
MAY_WRITE, rc);
|
||||||
|
#else /* CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
|
rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
|
||||||
|
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
break;
|
break;
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3638,16 +3710,25 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
|
||||||
if (skb != NULL) {
|
if (skb != NULL) {
|
||||||
if (skb->protocol == htons(ETH_P_IP))
|
if (skb->protocol == htons(ETH_P_IP))
|
||||||
family = PF_INET;
|
family = PF_INET;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
else if (skb->protocol == htons(ETH_P_IPV6))
|
else if (skb->protocol == htons(ETH_P_IPV6))
|
||||||
family = PF_INET6;
|
family = PF_INET6;
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
}
|
}
|
||||||
if (family == PF_UNSPEC && sock != NULL)
|
if (family == PF_UNSPEC && sock != NULL)
|
||||||
family = sock->sk->sk_family;
|
family = sock->sk->sk_family;
|
||||||
|
|
||||||
if (family == PF_UNIX) {
|
switch (family) {
|
||||||
|
case PF_UNIX:
|
||||||
ssp = sock->sk->sk_security;
|
ssp = sock->sk->sk_security;
|
||||||
s = ssp->smk_out->smk_secid;
|
s = ssp->smk_out->smk_secid;
|
||||||
} else if (family == PF_INET || family == PF_INET6) {
|
break;
|
||||||
|
case PF_INET:
|
||||||
|
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
|
||||||
|
s = skb->secmark;
|
||||||
|
if (s != 0)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* Translate what netlabel gave us.
|
* Translate what netlabel gave us.
|
||||||
*/
|
*/
|
||||||
|
@ -3660,6 +3741,14 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
|
||||||
s = skp->smk_secid;
|
s = skp->smk_secid;
|
||||||
}
|
}
|
||||||
netlbl_secattr_destroy(&secattr);
|
netlbl_secattr_destroy(&secattr);
|
||||||
|
break;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
case PF_INET6:
|
||||||
|
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
|
||||||
|
s = skb->secmark;
|
||||||
|
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
}
|
}
|
||||||
*secid = s;
|
*secid = s;
|
||||||
if (s == 0)
|
if (s == 0)
|
||||||
|
@ -3715,6 +3804,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||||
struct lsm_network_audit net;
|
struct lsm_network_audit net;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
if (family == PF_INET6) {
|
if (family == PF_INET6) {
|
||||||
/*
|
/*
|
||||||
* Handle mapped IPv4 packets arriving
|
* Handle mapped IPv4 packets arriving
|
||||||
|
@ -3726,6 +3816,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
|
|
||||||
netlbl_secattr_init(&secattr);
|
netlbl_secattr_init(&secattr);
|
||||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||||
|
@ -3834,11 +3925,11 @@ static void smack_key_free(struct key *key)
|
||||||
key->security = NULL;
|
key->security = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* smack_key_permission - Smack access on a key
|
* smack_key_permission - Smack access on a key
|
||||||
* @key_ref: gets to the object
|
* @key_ref: gets to the object
|
||||||
* @cred: the credentials to use
|
* @cred: the credentials to use
|
||||||
* @perm: unused
|
* @perm: requested key permissions
|
||||||
*
|
*
|
||||||
* Return 0 if the task has read and write to the object,
|
* Return 0 if the task has read and write to the object,
|
||||||
* an error code otherwise
|
* an error code otherwise
|
||||||
|
@ -4184,7 +4275,9 @@ struct security_operations smack_ops = {
|
||||||
.unix_may_send = smack_unix_may_send,
|
.unix_may_send = smack_unix_may_send,
|
||||||
|
|
||||||
.socket_post_create = smack_socket_post_create,
|
.socket_post_create = smack_socket_post_create,
|
||||||
|
#ifndef CONFIG_SECURITY_SMACK_NETFILTER
|
||||||
.socket_bind = smack_socket_bind,
|
.socket_bind = smack_socket_bind,
|
||||||
|
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
|
||||||
.socket_connect = smack_socket_connect,
|
.socket_connect = smack_socket_connect,
|
||||||
.socket_sendmsg = smack_socket_sendmsg,
|
.socket_sendmsg = smack_socket_sendmsg,
|
||||||
.socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
|
.socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
|
||||||
|
@ -4265,6 +4358,8 @@ static __init int smack_init(void)
|
||||||
if (!security_module_enable(&smack_ops))
|
if (!security_module_enable(&smack_ops))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
smack_enabled = 1;
|
||||||
|
|
||||||
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
|
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
|
||||||
if (!smack_inode_cache)
|
if (!smack_inode_cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Simplified MAC Kernel (smack) security module
|
||||||
|
*
|
||||||
|
* This file contains the Smack netfilter implementation
|
||||||
|
*
|
||||||
|
* Author:
|
||||||
|
* Casey Schaufler <casey@schaufler-ca.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Casey Schaufler <casey@schaufler-ca.com>
|
||||||
|
* Copyright (C) 2014 Intel Corporation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/netfilter_ipv4.h>
|
||||||
|
#include <linux/netfilter_ipv6.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include "smack.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||||
|
|
||||||
|
static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops,
|
||||||
|
struct sk_buff *skb,
|
||||||
|
const struct net_device *in,
|
||||||
|
const struct net_device *out,
|
||||||
|
int (*okfn)(struct sk_buff *))
|
||||||
|
{
|
||||||
|
struct socket_smack *ssp;
|
||||||
|
struct smack_known *skp;
|
||||||
|
|
||||||
|
if (skb && skb->sk && skb->sk->sk_security) {
|
||||||
|
ssp = skb->sk->sk_security;
|
||||||
|
skp = ssp->smk_out;
|
||||||
|
skb->secmark = skp->smk_secid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NF_ACCEPT;
|
||||||
|
}
|
||||||
|
#endif /* IPV6 */
|
||||||
|
|
||||||
|
static unsigned int smack_ipv4_output(const struct nf_hook_ops *ops,
|
||||||
|
struct sk_buff *skb,
|
||||||
|
const struct net_device *in,
|
||||||
|
const struct net_device *out,
|
||||||
|
int (*okfn)(struct sk_buff *))
|
||||||
|
{
|
||||||
|
struct socket_smack *ssp;
|
||||||
|
struct smack_known *skp;
|
||||||
|
|
||||||
|
if (skb && skb->sk && skb->sk->sk_security) {
|
||||||
|
ssp = skb->sk->sk_security;
|
||||||
|
skp = ssp->smk_out;
|
||||||
|
skb->secmark = skp->smk_secid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NF_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nf_hook_ops smack_nf_ops[] = {
|
||||||
|
{
|
||||||
|
.hook = smack_ipv4_output,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.pf = NFPROTO_IPV4,
|
||||||
|
.hooknum = NF_INET_LOCAL_OUT,
|
||||||
|
.priority = NF_IP_PRI_SELINUX_FIRST,
|
||||||
|
},
|
||||||
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||||
|
{
|
||||||
|
.hook = smack_ipv6_output,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.pf = NFPROTO_IPV6,
|
||||||
|
.hooknum = NF_INET_LOCAL_OUT,
|
||||||
|
.priority = NF_IP6_PRI_SELINUX_FIRST,
|
||||||
|
},
|
||||||
|
#endif /* IPV6 */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init smack_nf_ip_init(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (smack_enabled == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
|
||||||
|
|
||||||
|
err = nf_register_hooks(smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
|
||||||
|
if (err)
|
||||||
|
pr_info("Smack: nf_register_hooks: error %d\n", err);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__initcall(smack_nf_ip_init);
|
Loading…
Reference in New Issue