Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris: "Changes for this kernel include maintenance updates for Smack, SELinux (and several networking fixes), IMA and TPM" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (39 commits) SELinux: Fix memory leak upon loading policy tpm/tpm-sysfs: active_show() can be static tpm: tpm_tis: Fix compile problems with CONFIG_PM_SLEEP/CONFIG_PNP tpm: Make tpm-dev allocate a per-file structure tpm: Use the ops structure instead of a copy in tpm_vendor_specific tpm: Create a tpm_class_ops structure and use it in the drivers tpm: Pull all driver sysfs code into tpm-sysfs.c tpm: Move sysfs functions from tpm-interface to tpm-sysfs tpm: Pull everything related to /dev/tpmX into tpm-dev.c char: tpm: nuvoton: remove unused variable tpm: MAINTAINERS: Cleanup TPM Maintainers file tpm/tpm_i2c_atmel: fix coccinelle warnings tpm/tpm_ibmvtpm: fix unreachable code warning (smatch warning) tpm/tpm_i2c_stm_st33: Check return code of get_burstcount tpm/tpm_ppi: Check return value of acpi_get_name tpm/tpm_ppi: Do not compare strcmp(a,b) == -1 ima: remove unneeded size_limit argument from ima_eventdigest_init_common() ima: update IMA-templates.txt documentation ima: pass HASH_ALGO__LAST as hash algo in ima_eventdigest_init() ima: change the default hash algorithm to SHA1 in ima_eventdigest_ng_init() ...
This commit is contained in:
Коммит
fb2e2c8537
|
@ -67,12 +67,14 @@ descriptors by adding their identifier to the format string
|
||||||
- 'd-ng': the digest of the event, calculated with an arbitrary hash
|
- 'd-ng': the digest of the event, calculated with an arbitrary hash
|
||||||
algorithm (field format: [<hash algo>:]digest, where the digest
|
algorithm (field format: [<hash algo>:]digest, where the digest
|
||||||
prefix is shown only if the hash algorithm is not SHA1 or MD5);
|
prefix is shown only if the hash algorithm is not SHA1 or MD5);
|
||||||
- 'n-ng': the name of the event, without size limitations.
|
- 'n-ng': the name of the event, without size limitations;
|
||||||
|
- 'sig': the file signature.
|
||||||
|
|
||||||
|
|
||||||
Below, there is the list of defined template descriptors:
|
Below, there is the list of defined template descriptors:
|
||||||
- "ima": its format is 'd|n';
|
- "ima": its format is 'd|n';
|
||||||
- "ima-ng" (default): its format is 'd-ng|n-ng'.
|
- "ima-ng" (default): its format is 'd-ng|n-ng';
|
||||||
|
- "ima-sig": its format is 'd-ng|n-ng|sig'.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8746,14 +8746,10 @@ S: Odd fixes
|
||||||
F: drivers/media/usb/tm6000/
|
F: drivers/media/usb/tm6000/
|
||||||
|
|
||||||
TPM DEVICE DRIVER
|
TPM DEVICE DRIVER
|
||||||
M: Leonidas Da Silva Barbosa <leosilva@linux.vnet.ibm.com>
|
|
||||||
M: Ashley Lai <ashley@ashleylai.com>
|
|
||||||
M: Peter Huewe <peterhuewe@gmx.de>
|
M: Peter Huewe <peterhuewe@gmx.de>
|
||||||
M: Rajiv Andrade <mail@srajiv.net>
|
M: Ashley Lai <ashley@ashleylai.com>
|
||||||
W: http://tpmdd.sourceforge.net
|
|
||||||
M: Marcel Selhorst <tpmdd@selhorst.net>
|
M: Marcel Selhorst <tpmdd@selhorst.net>
|
||||||
M: Sirrix AG <tpmdd@sirrix.com>
|
W: http://tpmdd.sourceforge.net
|
||||||
W: http://www.sirrix.com
|
|
||||||
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
|
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/char/tpm/
|
F: drivers/char/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-y := tpm-interface.o tpm-dev.o tpm-sysfs.o
|
||||||
tpm-$(CONFIG_ACPI) += tpm_ppi.o
|
tpm-$(CONFIG_ACPI) += tpm_ppi.o
|
||||||
|
|
||||||
ifdef CONFIG_ACPI
|
ifdef CONFIG_ACPI
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2004 IBM Corporation
|
||||||
|
* Authors:
|
||||||
|
* Leendert van Doorn <leendert@watson.ibm.com>
|
||||||
|
* Dave Safford <safford@watson.ibm.com>
|
||||||
|
* Reiner Sailer <sailer@watson.ibm.com>
|
||||||
|
* Kylene Hall <kjhall@us.ibm.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Obsidian Research Corp
|
||||||
|
* Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
|
||||||
|
*
|
||||||
|
* Device file system interface to the TPM
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation, version 2 of the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include "tpm.h"
|
||||||
|
|
||||||
|
struct file_priv {
|
||||||
|
struct tpm_chip *chip;
|
||||||
|
|
||||||
|
/* Data passed to and from the tpm via the read/write calls */
|
||||||
|
atomic_t data_pending;
|
||||||
|
struct mutex buffer_mutex;
|
||||||
|
|
||||||
|
struct timer_list user_read_timer; /* user needs to claim result */
|
||||||
|
struct work_struct work;
|
||||||
|
|
||||||
|
u8 data_buffer[TPM_BUFSIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void user_reader_timeout(unsigned long ptr)
|
||||||
|
{
|
||||||
|
struct file_priv *priv = (struct file_priv *)ptr;
|
||||||
|
|
||||||
|
schedule_work(&priv->work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timeout_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct file_priv *priv = container_of(work, struct file_priv, work);
|
||||||
|
|
||||||
|
mutex_lock(&priv->buffer_mutex);
|
||||||
|
atomic_set(&priv->data_pending, 0);
|
||||||
|
memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
|
||||||
|
mutex_unlock(&priv->buffer_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tpm_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct miscdevice *misc = file->private_data;
|
||||||
|
struct tpm_chip *chip = container_of(misc, struct tpm_chip,
|
||||||
|
vendor.miscdev);
|
||||||
|
struct file_priv *priv;
|
||||||
|
|
||||||
|
/* It's assured that the chip will be opened just once,
|
||||||
|
* by the check of is_open variable, which is protected
|
||||||
|
* by driver_lock. */
|
||||||
|
if (test_and_set_bit(0, &chip->is_open)) {
|
||||||
|
dev_dbg(chip->dev, "Another process owns this TPM\n");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (priv == NULL) {
|
||||||
|
clear_bit(0, &chip->is_open);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->chip = chip;
|
||||||
|
atomic_set(&priv->data_pending, 0);
|
||||||
|
mutex_init(&priv->buffer_mutex);
|
||||||
|
setup_timer(&priv->user_read_timer, user_reader_timeout,
|
||||||
|
(unsigned long)priv);
|
||||||
|
INIT_WORK(&priv->work, timeout_work);
|
||||||
|
|
||||||
|
file->private_data = priv;
|
||||||
|
get_device(chip->dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t tpm_read(struct file *file, char __user *buf,
|
||||||
|
size_t size, loff_t *off)
|
||||||
|
{
|
||||||
|
struct file_priv *priv = file->private_data;
|
||||||
|
ssize_t ret_size;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
del_singleshot_timer_sync(&priv->user_read_timer);
|
||||||
|
flush_work(&priv->work);
|
||||||
|
ret_size = atomic_read(&priv->data_pending);
|
||||||
|
if (ret_size > 0) { /* relay data */
|
||||||
|
ssize_t orig_ret_size = ret_size;
|
||||||
|
if (size < ret_size)
|
||||||
|
ret_size = size;
|
||||||
|
|
||||||
|
mutex_lock(&priv->buffer_mutex);
|
||||||
|
rc = copy_to_user(buf, priv->data_buffer, ret_size);
|
||||||
|
memset(priv->data_buffer, 0, orig_ret_size);
|
||||||
|
if (rc)
|
||||||
|
ret_size = -EFAULT;
|
||||||
|
|
||||||
|
mutex_unlock(&priv->buffer_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_set(&priv->data_pending, 0);
|
||||||
|
|
||||||
|
return ret_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t tpm_write(struct file *file, const char __user *buf,
|
||||||
|
size_t size, loff_t *off)
|
||||||
|
{
|
||||||
|
struct file_priv *priv = file->private_data;
|
||||||
|
size_t in_size = size;
|
||||||
|
ssize_t out_size;
|
||||||
|
|
||||||
|
/* cannot perform a write until the read has cleared
|
||||||
|
either via tpm_read or a user_read_timer timeout.
|
||||||
|
This also prevents splitted buffered writes from blocking here.
|
||||||
|
*/
|
||||||
|
if (atomic_read(&priv->data_pending) != 0)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (in_size > TPM_BUFSIZE)
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
mutex_lock(&priv->buffer_mutex);
|
||||||
|
|
||||||
|
if (copy_from_user
|
||||||
|
(priv->data_buffer, (void __user *) buf, in_size)) {
|
||||||
|
mutex_unlock(&priv->buffer_mutex);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* atomic tpm command send and result receive */
|
||||||
|
out_size = tpm_transmit(priv->chip, priv->data_buffer,
|
||||||
|
sizeof(priv->data_buffer));
|
||||||
|
if (out_size < 0) {
|
||||||
|
mutex_unlock(&priv->buffer_mutex);
|
||||||
|
return out_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_set(&priv->data_pending, out_size);
|
||||||
|
mutex_unlock(&priv->buffer_mutex);
|
||||||
|
|
||||||
|
/* Set a timeout by which the reader must come claim the result */
|
||||||
|
mod_timer(&priv->user_read_timer, jiffies + (60 * HZ));
|
||||||
|
|
||||||
|
return in_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called on file close
|
||||||
|
*/
|
||||||
|
static int tpm_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct file_priv *priv = file->private_data;
|
||||||
|
|
||||||
|
del_singleshot_timer_sync(&priv->user_read_timer);
|
||||||
|
flush_work(&priv->work);
|
||||||
|
file->private_data = NULL;
|
||||||
|
atomic_set(&priv->data_pending, 0);
|
||||||
|
clear_bit(0, &priv->chip->is_open);
|
||||||
|
put_device(priv->chip->dev);
|
||||||
|
kfree(priv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations tpm_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.llseek = no_llseek,
|
||||||
|
.open = tpm_open,
|
||||||
|
.read = tpm_read,
|
||||||
|
.write = tpm_write,
|
||||||
|
.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);
|
||||||
|
}
|
|
@ -32,13 +32,6 @@
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_eventlog.h"
|
#include "tpm_eventlog.h"
|
||||||
|
|
||||||
enum tpm_duration {
|
|
||||||
TPM_SHORT = 0,
|
|
||||||
TPM_MEDIUM = 1,
|
|
||||||
TPM_LONG = 2,
|
|
||||||
TPM_UNDEFINED,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define TPM_MAX_ORDINAL 243
|
#define TPM_MAX_ORDINAL 243
|
||||||
#define TSC_MAX_ORDINAL 12
|
#define TSC_MAX_ORDINAL 12
|
||||||
#define TPM_PROTECTED_COMMAND 0x00
|
#define TPM_PROTECTED_COMMAND 0x00
|
||||||
|
@ -312,23 +305,6 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
|
||||||
TPM_MEDIUM,
|
TPM_MEDIUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void user_reader_timeout(unsigned long ptr)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = (struct tpm_chip *) ptr;
|
|
||||||
|
|
||||||
schedule_work(&chip->work);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timeout_work(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = container_of(work, struct tpm_chip, work);
|
|
||||||
|
|
||||||
mutex_lock(&chip->buffer_mutex);
|
|
||||||
atomic_set(&chip->data_pending, 0);
|
|
||||||
memset(chip->data_buffer, 0, TPM_BUFSIZE);
|
|
||||||
mutex_unlock(&chip->buffer_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns max number of jiffies to wait
|
* Returns max number of jiffies to wait
|
||||||
*/
|
*/
|
||||||
|
@ -355,8 +331,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
|
||||||
/*
|
/*
|
||||||
* Internal kernel interface to transmit TPM commands
|
* Internal kernel interface to transmit TPM commands
|
||||||
*/
|
*/
|
||||||
static 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 rc;
|
ssize_t rc;
|
||||||
u32 count, ordinal;
|
u32 count, ordinal;
|
||||||
|
@ -377,7 +353,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
|
|
||||||
mutex_lock(&chip->tpm_mutex);
|
mutex_lock(&chip->tpm_mutex);
|
||||||
|
|
||||||
rc = chip->vendor.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->dev,
|
||||||
"tpm_transmit: tpm_send: error %zd\n", rc);
|
"tpm_transmit: tpm_send: error %zd\n", rc);
|
||||||
|
@ -389,12 +365,12 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
|
|
||||||
stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
|
stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
|
||||||
do {
|
do {
|
||||||
u8 status = chip->vendor.status(chip);
|
u8 status = chip->ops->status(chip);
|
||||||
if ((status & chip->vendor.req_complete_mask) ==
|
if ((status & chip->ops->req_complete_mask) ==
|
||||||
chip->vendor.req_complete_val)
|
chip->ops->req_complete_val)
|
||||||
goto out_recv;
|
goto out_recv;
|
||||||
|
|
||||||
if (chip->vendor.req_canceled(chip, status)) {
|
if (chip->ops->req_canceled(chip, status)) {
|
||||||
dev_err(chip->dev, "Operation Canceled\n");
|
dev_err(chip->dev, "Operation Canceled\n");
|
||||||
rc = -ECANCELED;
|
rc = -ECANCELED;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -404,13 +380,13 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
rmb();
|
rmb();
|
||||||
} while (time_before(jiffies, stop));
|
} while (time_before(jiffies, stop));
|
||||||
|
|
||||||
chip->vendor.cancel(chip);
|
chip->ops->cancel(chip);
|
||||||
dev_err(chip->dev, "Operation Timed out\n");
|
dev_err(chip->dev, "Operation Timed out\n");
|
||||||
rc = -ETIME;
|
rc = -ETIME;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
out_recv:
|
out_recv:
|
||||||
rc = chip->vendor.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->dev,
|
||||||
"tpm_transmit: tpm_recv: error %zd\n", rc);
|
"tpm_transmit: tpm_recv: error %zd\n", rc);
|
||||||
|
@ -422,24 +398,6 @@ out:
|
||||||
#define TPM_DIGEST_SIZE 20
|
#define TPM_DIGEST_SIZE 20
|
||||||
#define TPM_RET_CODE_IDX 6
|
#define TPM_RET_CODE_IDX 6
|
||||||
|
|
||||||
enum tpm_capabilities {
|
|
||||||
TPM_CAP_FLAG = cpu_to_be32(4),
|
|
||||||
TPM_CAP_PROP = cpu_to_be32(5),
|
|
||||||
CAP_VERSION_1_1 = cpu_to_be32(0x06),
|
|
||||||
CAP_VERSION_1_2 = cpu_to_be32(0x1A)
|
|
||||||
};
|
|
||||||
|
|
||||||
enum tpm_sub_capabilities {
|
|
||||||
TPM_CAP_PROP_PCR = cpu_to_be32(0x101),
|
|
||||||
TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103),
|
|
||||||
TPM_CAP_FLAG_PERM = cpu_to_be32(0x108),
|
|
||||||
TPM_CAP_FLAG_VOL = cpu_to_be32(0x109),
|
|
||||||
TPM_CAP_PROP_OWNER = cpu_to_be32(0x111),
|
|
||||||
TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115),
|
|
||||||
TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120),
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
||||||
int len, const char *desc)
|
int len, const char *desc)
|
||||||
{
|
{
|
||||||
|
@ -459,7 +417,6 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TPM_INTERNAL_RESULT_SIZE 200
|
#define TPM_INTERNAL_RESULT_SIZE 200
|
||||||
#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
|
|
||||||
#define TPM_ORD_GET_CAP cpu_to_be32(101)
|
#define TPM_ORD_GET_CAP cpu_to_be32(101)
|
||||||
#define TPM_ORD_GET_RANDOM cpu_to_be32(70)
|
#define TPM_ORD_GET_RANDOM cpu_to_be32(70)
|
||||||
|
|
||||||
|
@ -659,70 +616,6 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
cap_t cap;
|
|
||||||
ssize_t rc;
|
|
||||||
|
|
||||||
rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
|
|
||||||
"attempting to determine the permanent enabled state");
|
|
||||||
if (rc)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_enabled);
|
|
||||||
|
|
||||||
ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
cap_t cap;
|
|
||||||
ssize_t rc;
|
|
||||||
|
|
||||||
rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
|
|
||||||
"attempting to determine the permanent active state");
|
|
||||||
if (rc)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_active);
|
|
||||||
|
|
||||||
ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
cap_t cap;
|
|
||||||
ssize_t rc;
|
|
||||||
|
|
||||||
rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
|
|
||||||
"attempting to determine the owner state");
|
|
||||||
if (rc)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rc = sprintf(buf, "%d\n", cap.owned);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_owned);
|
|
||||||
|
|
||||||
ssize_t tpm_show_temp_deactivated(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
cap_t cap;
|
|
||||||
ssize_t rc;
|
|
||||||
|
|
||||||
rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
|
|
||||||
"attempting to determine the temporary state");
|
|
||||||
if (rc)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tpm_chip_find_get - return tpm_chip for given chip number
|
* tpm_chip_find_get - return tpm_chip for given chip number
|
||||||
*/
|
*/
|
||||||
|
@ -752,7 +645,7 @@ static struct tpm_input_header pcrread_header = {
|
||||||
.ordinal = TPM_ORDINAL_PCRREAD
|
.ordinal = TPM_ORDINAL_PCRREAD
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __tpm_pcr_read(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)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct tpm_cmd_t cmd;
|
struct tpm_cmd_t cmd;
|
||||||
|
@ -787,7 +680,7 @@ 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(chip, pcr_idx, res_buf);
|
rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
|
||||||
tpm_chip_put(chip);
|
tpm_chip_put(chip);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -911,196 +804,15 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_send);
|
EXPORT_SYMBOL_GPL(tpm_send);
|
||||||
|
|
||||||
ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
cap_t cap;
|
|
||||||
u8 digest[TPM_DIGEST_SIZE];
|
|
||||||
ssize_t rc;
|
|
||||||
int i, j, num_pcrs;
|
|
||||||
char *str = buf;
|
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
|
|
||||||
"attempting to determine the number of PCRS");
|
|
||||||
if (rc)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
num_pcrs = be32_to_cpu(cap.num_pcrs);
|
|
||||||
for (i = 0; i < num_pcrs; i++) {
|
|
||||||
rc = __tpm_pcr_read(chip, i, digest);
|
|
||||||
if (rc)
|
|
||||||
break;
|
|
||||||
str += sprintf(str, "PCR-%02d: ", i);
|
|
||||||
for (j = 0; j < TPM_DIGEST_SIZE; j++)
|
|
||||||
str += sprintf(str, "%02X ", digest[j]);
|
|
||||||
str += sprintf(str, "\n");
|
|
||||||
}
|
|
||||||
return str - buf;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_pcrs);
|
|
||||||
|
|
||||||
#define READ_PUBEK_RESULT_SIZE 314
|
|
||||||
#define TPM_ORD_READPUBEK cpu_to_be32(124)
|
|
||||||
static struct tpm_input_header tpm_readpubek_header = {
|
|
||||||
.tag = TPM_TAG_RQU_COMMAND,
|
|
||||||
.length = cpu_to_be32(30),
|
|
||||||
.ordinal = TPM_ORD_READPUBEK
|
|
||||||
};
|
|
||||||
|
|
||||||
ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
u8 *data;
|
|
||||||
struct tpm_cmd_t tpm_cmd;
|
|
||||||
ssize_t err;
|
|
||||||
int i, rc;
|
|
||||||
char *str = buf;
|
|
||||||
|
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
tpm_cmd.header.in = tpm_readpubek_header;
|
|
||||||
err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
|
|
||||||
"attempting to read the PUBEK");
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/*
|
|
||||||
ignore header 10 bytes
|
|
||||||
algorithm 32 bits (1 == RSA )
|
|
||||||
encscheme 16 bits
|
|
||||||
sigscheme 16 bits
|
|
||||||
parameters (RSA 12->bytes: keybit, #primes, expbit)
|
|
||||||
keylenbytes 32 bits
|
|
||||||
256 byte modulus
|
|
||||||
ignore checksum 20 bytes
|
|
||||||
*/
|
|
||||||
data = tpm_cmd.params.readpubek_out_buffer;
|
|
||||||
str +=
|
|
||||||
sprintf(str,
|
|
||||||
"Algorithm: %02X %02X %02X %02X\n"
|
|
||||||
"Encscheme: %02X %02X\n"
|
|
||||||
"Sigscheme: %02X %02X\n"
|
|
||||||
"Parameters: %02X %02X %02X %02X "
|
|
||||||
"%02X %02X %02X %02X "
|
|
||||||
"%02X %02X %02X %02X\n"
|
|
||||||
"Modulus length: %d\n"
|
|
||||||
"Modulus:\n",
|
|
||||||
data[0], data[1], data[2], data[3],
|
|
||||||
data[4], data[5],
|
|
||||||
data[6], data[7],
|
|
||||||
data[12], data[13], data[14], data[15],
|
|
||||||
data[16], data[17], data[18], data[19],
|
|
||||||
data[20], data[21], data[22], data[23],
|
|
||||||
be32_to_cpu(*((__be32 *) (data + 24))));
|
|
||||||
|
|
||||||
for (i = 0; i < 256; i++) {
|
|
||||||
str += sprintf(str, "%02X ", data[i + 28]);
|
|
||||||
if ((i + 1) % 16 == 0)
|
|
||||||
str += sprintf(str, "\n");
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
rc = str - buf;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_pubek);
|
|
||||||
|
|
||||||
|
|
||||||
ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
cap_t cap;
|
|
||||||
ssize_t rc;
|
|
||||||
char *str = buf;
|
|
||||||
|
|
||||||
rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
|
|
||||||
"attempting to determine the manufacturer");
|
|
||||||
if (rc)
|
|
||||||
return 0;
|
|
||||||
str += sprintf(str, "Manufacturer: 0x%x\n",
|
|
||||||
be32_to_cpu(cap.manufacturer_id));
|
|
||||||
|
|
||||||
/* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
|
|
||||||
rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
|
|
||||||
"attempting to determine the 1.2 version");
|
|
||||||
if (!rc) {
|
|
||||||
str += sprintf(str,
|
|
||||||
"TCG version: %d.%d\nFirmware version: %d.%d\n",
|
|
||||||
cap.tpm_version_1_2.Major,
|
|
||||||
cap.tpm_version_1_2.Minor,
|
|
||||||
cap.tpm_version_1_2.revMajor,
|
|
||||||
cap.tpm_version_1_2.revMinor);
|
|
||||||
} else {
|
|
||||||
/* Otherwise just use TPM_STRUCT_VER */
|
|
||||||
rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
|
|
||||||
"attempting to determine the 1.1 version");
|
|
||||||
if (rc)
|
|
||||||
return 0;
|
|
||||||
str += sprintf(str,
|
|
||||||
"TCG version: %d.%d\nFirmware version: %d.%d\n",
|
|
||||||
cap.tpm_version.Major,
|
|
||||||
cap.tpm_version.Minor,
|
|
||||||
cap.tpm_version.revMajor,
|
|
||||||
cap.tpm_version.revMinor);
|
|
||||||
}
|
|
||||||
|
|
||||||
return str - buf;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_caps);
|
|
||||||
|
|
||||||
ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
if (chip->vendor.duration[TPM_LONG] == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return sprintf(buf, "%d %d %d [%s]\n",
|
|
||||||
jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
|
|
||||||
jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
|
|
||||||
jiffies_to_usecs(chip->vendor.duration[TPM_LONG]),
|
|
||||||
chip->vendor.duration_adjusted
|
|
||||||
? "adjusted" : "original");
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_durations);
|
|
||||||
|
|
||||||
ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
return sprintf(buf, "%d %d %d %d [%s]\n",
|
|
||||||
jiffies_to_usecs(chip->vendor.timeout_a),
|
|
||||||
jiffies_to_usecs(chip->vendor.timeout_b),
|
|
||||||
jiffies_to_usecs(chip->vendor.timeout_c),
|
|
||||||
jiffies_to_usecs(chip->vendor.timeout_d),
|
|
||||||
chip->vendor.timeout_adjusted
|
|
||||||
? "adjusted" : "original");
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_show_timeouts);
|
|
||||||
|
|
||||||
ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
|
|
||||||
const char *buf, size_t count)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
|
||||||
if (chip == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
chip->vendor.cancel(chip);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_store_cancel);
|
|
||||||
|
|
||||||
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
|
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
|
||||||
bool check_cancel, bool *canceled)
|
bool check_cancel, bool *canceled)
|
||||||
{
|
{
|
||||||
u8 status = chip->vendor.status(chip);
|
u8 status = chip->ops->status(chip);
|
||||||
|
|
||||||
*canceled = false;
|
*canceled = false;
|
||||||
if ((status & mask) == mask)
|
if ((status & mask) == mask)
|
||||||
return true;
|
return true;
|
||||||
if (check_cancel && chip->vendor.req_canceled(chip, status)) {
|
if (check_cancel && chip->ops->req_canceled(chip, status)) {
|
||||||
*canceled = true;
|
*canceled = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1116,7 +828,7 @@ int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||||
bool canceled = false;
|
bool canceled = false;
|
||||||
|
|
||||||
/* check current status */
|
/* check current status */
|
||||||
status = chip->vendor.status(chip);
|
status = chip->ops->status(chip);
|
||||||
if ((status & mask) == mask)
|
if ((status & mask) == mask)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1143,7 +855,7 @@ again:
|
||||||
} else {
|
} else {
|
||||||
do {
|
do {
|
||||||
msleep(TPM_TIMEOUT);
|
msleep(TPM_TIMEOUT);
|
||||||
status = chip->vendor.status(chip);
|
status = chip->ops->status(chip);
|
||||||
if ((status & mask) == mask)
|
if ((status & mask) == mask)
|
||||||
return 0;
|
return 0;
|
||||||
} while (time_before(jiffies, stop));
|
} while (time_before(jiffies, stop));
|
||||||
|
@ -1151,127 +863,6 @@ again:
|
||||||
return -ETIME;
|
return -ETIME;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
|
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
|
||||||
/*
|
|
||||||
* Device file system interface to the TPM
|
|
||||||
*
|
|
||||||
* It's assured that the chip will be opened just once,
|
|
||||||
* by the check of is_open variable, which is protected
|
|
||||||
* by driver_lock.
|
|
||||||
*/
|
|
||||||
int tpm_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
struct miscdevice *misc = file->private_data;
|
|
||||||
struct tpm_chip *chip = container_of(misc, struct tpm_chip,
|
|
||||||
vendor.miscdev);
|
|
||||||
|
|
||||||
if (test_and_set_bit(0, &chip->is_open)) {
|
|
||||||
dev_dbg(chip->dev, "Another process owns this TPM\n");
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
|
|
||||||
if (chip->data_buffer == NULL) {
|
|
||||||
clear_bit(0, &chip->is_open);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_set(&chip->data_pending, 0);
|
|
||||||
|
|
||||||
file->private_data = chip;
|
|
||||||
get_device(chip->dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_open);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called on file close
|
|
||||||
*/
|
|
||||||
int tpm_release(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = file->private_data;
|
|
||||||
|
|
||||||
del_singleshot_timer_sync(&chip->user_read_timer);
|
|
||||||
flush_work(&chip->work);
|
|
||||||
file->private_data = NULL;
|
|
||||||
atomic_set(&chip->data_pending, 0);
|
|
||||||
kzfree(chip->data_buffer);
|
|
||||||
clear_bit(0, &chip->is_open);
|
|
||||||
put_device(chip->dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_release);
|
|
||||||
|
|
||||||
ssize_t tpm_write(struct file *file, const char __user *buf,
|
|
||||||
size_t size, loff_t *off)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = file->private_data;
|
|
||||||
size_t in_size = size;
|
|
||||||
ssize_t out_size;
|
|
||||||
|
|
||||||
/* cannot perform a write until the read has cleared
|
|
||||||
either via tpm_read or a user_read_timer timeout.
|
|
||||||
This also prevents splitted buffered writes from blocking here.
|
|
||||||
*/
|
|
||||||
if (atomic_read(&chip->data_pending) != 0)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
if (in_size > TPM_BUFSIZE)
|
|
||||||
return -E2BIG;
|
|
||||||
|
|
||||||
mutex_lock(&chip->buffer_mutex);
|
|
||||||
|
|
||||||
if (copy_from_user
|
|
||||||
(chip->data_buffer, (void __user *) buf, in_size)) {
|
|
||||||
mutex_unlock(&chip->buffer_mutex);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* atomic tpm command send and result receive */
|
|
||||||
out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
|
|
||||||
if (out_size < 0) {
|
|
||||||
mutex_unlock(&chip->buffer_mutex);
|
|
||||||
return out_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_set(&chip->data_pending, out_size);
|
|
||||||
mutex_unlock(&chip->buffer_mutex);
|
|
||||||
|
|
||||||
/* Set a timeout by which the reader must come claim the result */
|
|
||||||
mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
|
|
||||||
|
|
||||||
return in_size;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_write);
|
|
||||||
|
|
||||||
ssize_t tpm_read(struct file *file, char __user *buf,
|
|
||||||
size_t size, loff_t *off)
|
|
||||||
{
|
|
||||||
struct tpm_chip *chip = file->private_data;
|
|
||||||
ssize_t ret_size;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
del_singleshot_timer_sync(&chip->user_read_timer);
|
|
||||||
flush_work(&chip->work);
|
|
||||||
ret_size = atomic_read(&chip->data_pending);
|
|
||||||
if (ret_size > 0) { /* relay data */
|
|
||||||
ssize_t orig_ret_size = ret_size;
|
|
||||||
if (size < ret_size)
|
|
||||||
ret_size = size;
|
|
||||||
|
|
||||||
mutex_lock(&chip->buffer_mutex);
|
|
||||||
rc = copy_to_user(buf, chip->data_buffer, ret_size);
|
|
||||||
memset(chip->data_buffer, 0, orig_ret_size);
|
|
||||||
if (rc)
|
|
||||||
ret_size = -EFAULT;
|
|
||||||
|
|
||||||
mutex_unlock(&chip->buffer_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_set(&chip->data_pending, 0);
|
|
||||||
|
|
||||||
return ret_size;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(tpm_read);
|
|
||||||
|
|
||||||
void tpm_remove_hardware(struct device *dev)
|
void tpm_remove_hardware(struct device *dev)
|
||||||
{
|
{
|
||||||
|
@ -1287,8 +878,8 @@ void tpm_remove_hardware(struct device *dev)
|
||||||
spin_unlock(&driver_lock);
|
spin_unlock(&driver_lock);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
misc_deregister(&chip->vendor.miscdev);
|
tpm_dev_del_device(chip);
|
||||||
sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
|
tpm_sysfs_del_device(chip);
|
||||||
tpm_remove_ppi(&dev->kobj);
|
tpm_remove_ppi(&dev->kobj);
|
||||||
tpm_bios_log_teardown(chip->bios_dir);
|
tpm_bios_log_teardown(chip->bios_dir);
|
||||||
|
|
||||||
|
@ -1436,9 +1027,6 @@ void tpm_dev_vendor_release(struct tpm_chip *chip)
|
||||||
if (!chip)
|
if (!chip)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (chip->vendor.release)
|
|
||||||
chip->vendor.release(chip->dev);
|
|
||||||
|
|
||||||
clear_bit(chip->dev_num, dev_mask);
|
clear_bit(chip->dev_num, dev_mask);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
|
EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
|
||||||
|
@ -1448,7 +1036,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
|
||||||
* Once all references to platform device are down to 0,
|
* Once all references to platform device are down to 0,
|
||||||
* release all allocated structures.
|
* release all allocated structures.
|
||||||
*/
|
*/
|
||||||
void tpm_dev_release(struct device *dev)
|
static void tpm_dev_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
@ -1460,7 +1048,6 @@ void tpm_dev_release(struct device *dev)
|
||||||
chip->release(dev);
|
chip->release(dev);
|
||||||
kfree(chip);
|
kfree(chip);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_dev_release);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called from tpm_<specific>.c probe function only for devices
|
* Called from tpm_<specific>.c probe function only for devices
|
||||||
|
@ -1470,7 +1057,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_release);
|
||||||
* pci_disable_device
|
* pci_disable_device
|
||||||
*/
|
*/
|
||||||
struct tpm_chip *tpm_register_hardware(struct device *dev,
|
struct tpm_chip *tpm_register_hardware(struct device *dev,
|
||||||
const struct tpm_vendor_specific *entry)
|
const struct tpm_class_ops *ops)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
|
|
||||||
|
@ -1480,56 +1067,35 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
|
||||||
if (chip == NULL)
|
if (chip == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
mutex_init(&chip->buffer_mutex);
|
|
||||||
mutex_init(&chip->tpm_mutex);
|
mutex_init(&chip->tpm_mutex);
|
||||||
INIT_LIST_HEAD(&chip->list);
|
INIT_LIST_HEAD(&chip->list);
|
||||||
|
|
||||||
INIT_WORK(&chip->work, timeout_work);
|
chip->ops = ops;
|
||||||
|
|
||||||
setup_timer(&chip->user_read_timer, user_reader_timeout,
|
|
||||||
(unsigned long)chip);
|
|
||||||
|
|
||||||
memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
|
|
||||||
|
|
||||||
chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
|
chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
|
||||||
|
|
||||||
if (chip->dev_num >= TPM_NUM_DEVICES) {
|
if (chip->dev_num >= TPM_NUM_DEVICES) {
|
||||||
dev_err(dev, "No available tpm device numbers\n");
|
dev_err(dev, "No available tpm device numbers\n");
|
||||||
goto out_free;
|
goto out_free;
|
||||||
} else if (chip->dev_num == 0)
|
}
|
||||||
chip->vendor.miscdev.minor = TPM_MINOR;
|
|
||||||
else
|
|
||||||
chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
|
|
||||||
|
|
||||||
set_bit(chip->dev_num, dev_mask);
|
set_bit(chip->dev_num, dev_mask);
|
||||||
|
|
||||||
scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
|
scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
|
||||||
chip->dev_num);
|
chip->dev_num);
|
||||||
chip->vendor.miscdev.name = chip->devname;
|
|
||||||
|
|
||||||
chip->vendor.miscdev.parent = dev;
|
|
||||||
chip->dev = get_device(dev);
|
chip->dev = get_device(dev);
|
||||||
chip->release = dev->release;
|
chip->release = dev->release;
|
||||||
dev->release = tpm_dev_release;
|
dev->release = tpm_dev_release;
|
||||||
dev_set_drvdata(dev, chip);
|
dev_set_drvdata(dev, chip);
|
||||||
|
|
||||||
if (misc_register(&chip->vendor.miscdev)) {
|
if (tpm_dev_add_device(chip))
|
||||||
dev_err(chip->dev,
|
|
||||||
"unable to misc_register %s, minor %d\n",
|
|
||||||
chip->vendor.miscdev.name,
|
|
||||||
chip->vendor.miscdev.minor);
|
|
||||||
goto put_device;
|
goto put_device;
|
||||||
}
|
|
||||||
|
|
||||||
if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
|
if (tpm_sysfs_add_device(chip))
|
||||||
misc_deregister(&chip->vendor.miscdev);
|
goto del_misc;
|
||||||
goto put_device;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tpm_add_ppi(&dev->kobj)) {
|
if (tpm_add_ppi(&dev->kobj))
|
||||||
misc_deregister(&chip->vendor.miscdev);
|
goto del_misc;
|
||||||
goto put_device;
|
|
||||||
}
|
|
||||||
|
|
||||||
chip->bios_dir = tpm_bios_log_setup(chip->devname);
|
chip->bios_dir = tpm_bios_log_setup(chip->devname);
|
||||||
|
|
||||||
|
@ -1540,6 +1106,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
|
||||||
|
|
||||||
return chip;
|
return chip;
|
||||||
|
|
||||||
|
del_misc:
|
||||||
|
tpm_dev_del_device(chip);
|
||||||
put_device:
|
put_device:
|
||||||
put_device(chip->dev);
|
put_device(chip->dev);
|
||||||
out_free:
|
out_free:
|
||||||
|
|
|
@ -0,0 +1,318 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2004 IBM Corporation
|
||||||
|
* Authors:
|
||||||
|
* Leendert van Doorn <leendert@watson.ibm.com>
|
||||||
|
* Dave Safford <safford@watson.ibm.com>
|
||||||
|
* Reiner Sailer <sailer@watson.ibm.com>
|
||||||
|
* Kylene Hall <kjhall@us.ibm.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Obsidian Research Corp
|
||||||
|
* Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
|
||||||
|
*
|
||||||
|
* sysfs filesystem inspection interface to the TPM
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation, version 2 of the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include "tpm.h"
|
||||||
|
|
||||||
|
/* 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 TPM_ORD_READPUBEK cpu_to_be32(124)
|
||||||
|
static struct tpm_input_header tpm_readpubek_header = {
|
||||||
|
.tag = TPM_TAG_RQU_COMMAND,
|
||||||
|
.length = cpu_to_be32(30),
|
||||||
|
.ordinal = TPM_ORD_READPUBEK
|
||||||
|
};
|
||||||
|
static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
u8 *data;
|
||||||
|
struct tpm_cmd_t tpm_cmd;
|
||||||
|
ssize_t err;
|
||||||
|
int i, rc;
|
||||||
|
char *str = buf;
|
||||||
|
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
tpm_cmd.header.in = tpm_readpubek_header;
|
||||||
|
err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
|
||||||
|
"attempting to read the PUBEK");
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ignore header 10 bytes
|
||||||
|
algorithm 32 bits (1 == RSA )
|
||||||
|
encscheme 16 bits
|
||||||
|
sigscheme 16 bits
|
||||||
|
parameters (RSA 12->bytes: keybit, #primes, expbit)
|
||||||
|
keylenbytes 32 bits
|
||||||
|
256 byte modulus
|
||||||
|
ignore checksum 20 bytes
|
||||||
|
*/
|
||||||
|
data = tpm_cmd.params.readpubek_out_buffer;
|
||||||
|
str +=
|
||||||
|
sprintf(str,
|
||||||
|
"Algorithm: %02X %02X %02X %02X\n"
|
||||||
|
"Encscheme: %02X %02X\n"
|
||||||
|
"Sigscheme: %02X %02X\n"
|
||||||
|
"Parameters: %02X %02X %02X %02X "
|
||||||
|
"%02X %02X %02X %02X "
|
||||||
|
"%02X %02X %02X %02X\n"
|
||||||
|
"Modulus length: %d\n"
|
||||||
|
"Modulus:\n",
|
||||||
|
data[0], data[1], data[2], data[3],
|
||||||
|
data[4], data[5],
|
||||||
|
data[6], data[7],
|
||||||
|
data[12], data[13], data[14], data[15],
|
||||||
|
data[16], data[17], data[18], data[19],
|
||||||
|
data[20], data[21], data[22], data[23],
|
||||||
|
be32_to_cpu(*((__be32 *) (data + 24))));
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
str += sprintf(str, "%02X ", data[i + 28]);
|
||||||
|
if ((i + 1) % 16 == 0)
|
||||||
|
str += sprintf(str, "\n");
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
rc = str - buf;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(pubek);
|
||||||
|
|
||||||
|
static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
cap_t cap;
|
||||||
|
u8 digest[TPM_DIGEST_SIZE];
|
||||||
|
ssize_t rc;
|
||||||
|
int i, j, num_pcrs;
|
||||||
|
char *str = buf;
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
|
||||||
|
"attempting to determine the number of PCRS");
|
||||||
|
if (rc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
num_pcrs = be32_to_cpu(cap.num_pcrs);
|
||||||
|
for (i = 0; i < num_pcrs; i++) {
|
||||||
|
rc = tpm_pcr_read_dev(chip, i, digest);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
str += sprintf(str, "PCR-%02d: ", i);
|
||||||
|
for (j = 0; j < TPM_DIGEST_SIZE; j++)
|
||||||
|
str += sprintf(str, "%02X ", digest[j]);
|
||||||
|
str += sprintf(str, "\n");
|
||||||
|
}
|
||||||
|
return str - buf;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(pcrs);
|
||||||
|
|
||||||
|
static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
cap_t cap;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
|
||||||
|
"attempting to determine the permanent enabled state");
|
||||||
|
if (rc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(enabled);
|
||||||
|
|
||||||
|
static ssize_t active_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
cap_t cap;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
|
||||||
|
"attempting to determine the permanent active state");
|
||||||
|
if (rc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(active);
|
||||||
|
|
||||||
|
static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
cap_t cap;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
|
||||||
|
"attempting to determine the owner state");
|
||||||
|
if (rc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rc = sprintf(buf, "%d\n", cap.owned);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(owned);
|
||||||
|
|
||||||
|
static ssize_t temp_deactivated_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
cap_t cap;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
|
||||||
|
"attempting to determine the temporary state");
|
||||||
|
if (rc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(temp_deactivated);
|
||||||
|
|
||||||
|
static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
cap_t cap;
|
||||||
|
ssize_t rc;
|
||||||
|
char *str = buf;
|
||||||
|
|
||||||
|
rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
|
||||||
|
"attempting to determine the manufacturer");
|
||||||
|
if (rc)
|
||||||
|
return 0;
|
||||||
|
str += sprintf(str, "Manufacturer: 0x%x\n",
|
||||||
|
be32_to_cpu(cap.manufacturer_id));
|
||||||
|
|
||||||
|
/* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
|
||||||
|
rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
|
||||||
|
"attempting to determine the 1.2 version");
|
||||||
|
if (!rc) {
|
||||||
|
str += sprintf(str,
|
||||||
|
"TCG version: %d.%d\nFirmware version: %d.%d\n",
|
||||||
|
cap.tpm_version_1_2.Major,
|
||||||
|
cap.tpm_version_1_2.Minor,
|
||||||
|
cap.tpm_version_1_2.revMajor,
|
||||||
|
cap.tpm_version_1_2.revMinor);
|
||||||
|
} else {
|
||||||
|
/* Otherwise just use TPM_STRUCT_VER */
|
||||||
|
rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
|
||||||
|
"attempting to determine the 1.1 version");
|
||||||
|
if (rc)
|
||||||
|
return 0;
|
||||||
|
str += sprintf(str,
|
||||||
|
"TCG version: %d.%d\nFirmware version: %d.%d\n",
|
||||||
|
cap.tpm_version.Major,
|
||||||
|
cap.tpm_version.Minor,
|
||||||
|
cap.tpm_version.revMajor,
|
||||||
|
cap.tpm_version.revMinor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str - buf;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(caps);
|
||||||
|
|
||||||
|
static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
if (chip == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
chip->ops->cancel(chip);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_WO(cancel);
|
||||||
|
|
||||||
|
static ssize_t durations_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (chip->vendor.duration[TPM_LONG] == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return sprintf(buf, "%d %d %d [%s]\n",
|
||||||
|
jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
|
||||||
|
jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
|
||||||
|
jiffies_to_usecs(chip->vendor.duration[TPM_LONG]),
|
||||||
|
chip->vendor.duration_adjusted
|
||||||
|
? "adjusted" : "original");
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(durations);
|
||||||
|
|
||||||
|
static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d %d %d %d [%s]\n",
|
||||||
|
jiffies_to_usecs(chip->vendor.timeout_a),
|
||||||
|
jiffies_to_usecs(chip->vendor.timeout_b),
|
||||||
|
jiffies_to_usecs(chip->vendor.timeout_c),
|
||||||
|
jiffies_to_usecs(chip->vendor.timeout_d),
|
||||||
|
chip->vendor.timeout_adjusted
|
||||||
|
? "adjusted" : "original");
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(timeouts);
|
||||||
|
|
||||||
|
static struct attribute *tpm_dev_attrs[] = {
|
||||||
|
&dev_attr_pubek.attr,
|
||||||
|
&dev_attr_pcrs.attr,
|
||||||
|
&dev_attr_enabled.attr,
|
||||||
|
&dev_attr_active.attr,
|
||||||
|
&dev_attr_owned.attr,
|
||||||
|
&dev_attr_temp_deactivated.attr,
|
||||||
|
&dev_attr_caps.attr,
|
||||||
|
&dev_attr_cancel.attr,
|
||||||
|
&dev_attr_durations.attr,
|
||||||
|
&dev_attr_timeouts.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group tpm_dev_group = {
|
||||||
|
.attrs = tpm_dev_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
int tpm_sysfs_add_device(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
err = sysfs_create_group(&chip->dev->kobj,
|
||||||
|
&tpm_dev_group);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
dev_err(chip->dev,
|
||||||
|
"failed to create sysfs attributes, %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tpm_sysfs_del_device(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group);
|
||||||
|
}
|
|
@ -46,6 +46,14 @@ enum tpm_addr {
|
||||||
TPM_ADDR = 0x4E,
|
TPM_ADDR = 0x4E,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Indexes the duration array */
|
||||||
|
enum tpm_duration {
|
||||||
|
TPM_SHORT = 0,
|
||||||
|
TPM_MEDIUM = 1,
|
||||||
|
TPM_LONG = 2,
|
||||||
|
TPM_UNDEFINED,
|
||||||
|
};
|
||||||
|
|
||||||
#define TPM_WARN_RETRY 0x800
|
#define TPM_WARN_RETRY 0x800
|
||||||
#define TPM_WARN_DOING_SELFTEST 0x802
|
#define TPM_WARN_DOING_SELFTEST 0x802
|
||||||
#define TPM_ERR_DEACTIVATED 0x6
|
#define TPM_ERR_DEACTIVATED 0x6
|
||||||
|
@ -53,33 +61,9 @@ enum tpm_addr {
|
||||||
#define TPM_ERR_INVALID_POSTINIT 38
|
#define TPM_ERR_INVALID_POSTINIT 38
|
||||||
|
|
||||||
#define TPM_HEADER_SIZE 10
|
#define TPM_HEADER_SIZE 10
|
||||||
extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
|
|
||||||
char *);
|
|
||||||
extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
|
|
||||||
char *);
|
|
||||||
extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
|
|
||||||
char *);
|
|
||||||
extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
|
|
||||||
const char *, size_t);
|
|
||||||
extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr,
|
|
||||||
char *);
|
|
||||||
extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr,
|
|
||||||
char *);
|
|
||||||
extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr,
|
|
||||||
char *);
|
|
||||||
extern ssize_t tpm_show_temp_deactivated(struct device *,
|
|
||||||
struct device_attribute *attr, char *);
|
|
||||||
extern ssize_t tpm_show_durations(struct device *,
|
|
||||||
struct device_attribute *attr, char *);
|
|
||||||
extern ssize_t tpm_show_timeouts(struct device *,
|
|
||||||
struct device_attribute *attr, char *);
|
|
||||||
|
|
||||||
struct tpm_chip;
|
struct tpm_chip;
|
||||||
|
|
||||||
struct tpm_vendor_specific {
|
struct tpm_vendor_specific {
|
||||||
const u8 req_complete_mask;
|
|
||||||
const u8 req_complete_val;
|
|
||||||
bool (*req_canceled)(struct tpm_chip *chip, u8 status);
|
|
||||||
void __iomem *iobase; /* ioremapped address */
|
void __iomem *iobase; /* ioremapped address */
|
||||||
unsigned long base; /* TPM base address */
|
unsigned long base; /* TPM base address */
|
||||||
|
|
||||||
|
@ -89,13 +73,7 @@ struct tpm_vendor_specific {
|
||||||
int region_size;
|
int region_size;
|
||||||
int have_region;
|
int have_region;
|
||||||
|
|
||||||
int (*recv) (struct tpm_chip *, u8 *, size_t);
|
|
||||||
int (*send) (struct tpm_chip *, u8 *, size_t);
|
|
||||||
void (*cancel) (struct tpm_chip *);
|
|
||||||
u8 (*status) (struct tpm_chip *);
|
|
||||||
void (*release) (struct device *);
|
|
||||||
struct miscdevice miscdev;
|
struct miscdevice miscdev;
|
||||||
struct attribute_group *attr_group;
|
|
||||||
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 */
|
||||||
|
@ -118,19 +96,13 @@ struct tpm_vendor_specific {
|
||||||
|
|
||||||
struct tpm_chip {
|
struct tpm_chip {
|
||||||
struct device *dev; /* Device stuff */
|
struct device *dev; /* Device stuff */
|
||||||
|
const struct tpm_class_ops *ops;
|
||||||
|
|
||||||
int dev_num; /* /dev/tpm# */
|
int dev_num; /* /dev/tpm# */
|
||||||
char devname[7];
|
char devname[7];
|
||||||
unsigned long is_open; /* only one allowed */
|
unsigned long is_open; /* only one allowed */
|
||||||
int time_expired;
|
int time_expired;
|
||||||
|
|
||||||
/* Data passed to and from the tpm via the read/write calls */
|
|
||||||
u8 *data_buffer;
|
|
||||||
atomic_t data_pending;
|
|
||||||
struct mutex buffer_mutex;
|
|
||||||
|
|
||||||
struct timer_list user_read_timer; /* user needs to claim result */
|
|
||||||
struct work_struct work;
|
|
||||||
struct mutex tpm_mutex; /* tpm is processing */
|
struct mutex tpm_mutex; /* tpm is processing */
|
||||||
|
|
||||||
struct tpm_vendor_specific vendor;
|
struct tpm_vendor_specific vendor;
|
||||||
|
@ -171,6 +143,8 @@ struct tpm_output_header {
|
||||||
__be32 return_code;
|
__be32 return_code;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
|
||||||
|
|
||||||
struct stclear_flags_t {
|
struct stclear_flags_t {
|
||||||
__be16 tag;
|
__be16 tag;
|
||||||
u8 deactivated;
|
u8 deactivated;
|
||||||
|
@ -244,6 +218,24 @@ typedef union {
|
||||||
struct duration_t duration;
|
struct duration_t duration;
|
||||||
} cap_t;
|
} cap_t;
|
||||||
|
|
||||||
|
enum tpm_capabilities {
|
||||||
|
TPM_CAP_FLAG = cpu_to_be32(4),
|
||||||
|
TPM_CAP_PROP = cpu_to_be32(5),
|
||||||
|
CAP_VERSION_1_1 = cpu_to_be32(0x06),
|
||||||
|
CAP_VERSION_1_2 = cpu_to_be32(0x1A)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tpm_sub_capabilities {
|
||||||
|
TPM_CAP_PROP_PCR = cpu_to_be32(0x101),
|
||||||
|
TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103),
|
||||||
|
TPM_CAP_FLAG_PERM = cpu_to_be32(0x108),
|
||||||
|
TPM_CAP_FLAG_VOL = cpu_to_be32(0x109),
|
||||||
|
TPM_CAP_PROP_OWNER = cpu_to_be32(0x111),
|
||||||
|
TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115),
|
||||||
|
TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120),
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct tpm_getcap_params_in {
|
struct tpm_getcap_params_in {
|
||||||
__be32 cap;
|
__be32 cap;
|
||||||
__be32 subcap_size;
|
__be32 subcap_size;
|
||||||
|
@ -323,25 +315,28 @@ struct tpm_cmd_t {
|
||||||
|
|
||||||
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
|
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
|
||||||
|
|
||||||
|
ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||||
|
size_t bufsiz);
|
||||||
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 *,
|
extern struct tpm_chip* tpm_register_hardware(struct device *,
|
||||||
const struct tpm_vendor_specific *);
|
const struct tpm_class_ops *ops);
|
||||||
extern int tpm_open(struct inode *, struct file *);
|
|
||||||
extern int tpm_release(struct inode *, struct file *);
|
|
||||||
extern void tpm_dev_release(struct device *dev);
|
|
||||||
extern void tpm_dev_vendor_release(struct tpm_chip *);
|
extern void tpm_dev_vendor_release(struct tpm_chip *);
|
||||||
extern ssize_t tpm_write(struct file *, const char __user *, size_t,
|
|
||||||
loff_t *);
|
|
||||||
extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
|
|
||||||
extern void tpm_remove_hardware(struct device *);
|
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);
|
||||||
|
void tpm_dev_del_device(struct tpm_chip *chip);
|
||||||
|
int tpm_sysfs_add_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);
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
extern int tpm_add_ppi(struct kobject *);
|
extern int tpm_add_ppi(struct kobject *);
|
||||||
extern void tpm_remove_ppi(struct kobject *);
|
extern void tpm_remove_ppi(struct kobject *);
|
||||||
|
|
|
@ -121,31 +121,7 @@ static bool tpm_atml_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
return (status == ATML_STATUS_READY);
|
return (status == ATML_STATUS_READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations atmel_ops = {
|
static const struct tpm_class_ops tpm_atmel = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
|
|
||||||
static struct attribute* atmel_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
|
|
||||||
|
|
||||||
static const struct tpm_vendor_specific tpm_atmel = {
|
|
||||||
.recv = tpm_atml_recv,
|
.recv = tpm_atml_recv,
|
||||||
.send = tpm_atml_send,
|
.send = tpm_atml_send,
|
||||||
.cancel = tpm_atml_cancel,
|
.cancel = tpm_atml_cancel,
|
||||||
|
@ -153,8 +129,6 @@ static const struct tpm_vendor_specific tpm_atmel = {
|
||||||
.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
|
.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
|
||||||
.req_complete_val = ATML_STATUS_DATA_AVAIL,
|
.req_complete_val = ATML_STATUS_DATA_AVAIL,
|
||||||
.req_canceled = tpm_atml_req_canceled,
|
.req_canceled = tpm_atml_req_canceled,
|
||||||
.attr_group = &atmel_attr_grp,
|
|
||||||
.miscdev = { .fops = &atmel_ops, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_device *pdev;
|
static struct platform_device *pdev;
|
||||||
|
|
|
@ -135,50 +135,12 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip)
|
||||||
return ATMEL_STS_OK;
|
return ATMEL_STS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations i2c_atmel_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
|
|
||||||
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
|
|
||||||
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
|
|
||||||
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
|
|
||||||
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
|
|
||||||
|
|
||||||
static struct attribute *i2c_atmel_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_enabled.attr,
|
|
||||||
&dev_attr_active.attr,
|
|
||||||
&dev_attr_owned.attr,
|
|
||||||
&dev_attr_temp_deactivated.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
&dev_attr_durations.attr,
|
|
||||||
&dev_attr_timeouts.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group i2c_atmel_attr_grp = {
|
|
||||||
.attrs = i2c_atmel_attrs
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status)
|
static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct tpm_vendor_specific i2c_atmel = {
|
static const struct tpm_class_ops i2c_atmel = {
|
||||||
.status = i2c_atmel_read_status,
|
.status = i2c_atmel_read_status,
|
||||||
.recv = i2c_atmel_recv,
|
.recv = i2c_atmel_recv,
|
||||||
.send = i2c_atmel_send,
|
.send = i2c_atmel_send,
|
||||||
|
@ -186,8 +148,6 @@ static const struct tpm_vendor_specific i2c_atmel = {
|
||||||
.req_complete_mask = ATMEL_STS_OK,
|
.req_complete_mask = ATMEL_STS_OK,
|
||||||
.req_complete_val = ATMEL_STS_OK,
|
.req_complete_val = ATMEL_STS_OK,
|
||||||
.req_canceled = i2c_atmel_req_canceled,
|
.req_canceled = i2c_atmel_req_canceled,
|
||||||
.attr_group = &i2c_atmel_attr_grp,
|
|
||||||
.miscdev.fops = &i2c_atmel_ops,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int i2c_atmel_probe(struct i2c_client *client,
|
static int i2c_atmel_probe(struct i2c_client *client,
|
||||||
|
|
|
@ -566,45 +566,7 @@ static bool tpm_tis_i2c_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
return (status == TPM_STS_COMMAND_READY);
|
return (status == TPM_STS_COMMAND_READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations tis_ops = {
|
static const struct tpm_class_ops tpm_tis_i2c = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
|
|
||||||
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
|
|
||||||
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
|
|
||||||
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
|
|
||||||
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
|
|
||||||
|
|
||||||
static struct attribute *tis_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_enabled.attr,
|
|
||||||
&dev_attr_active.attr,
|
|
||||||
&dev_attr_owned.attr,
|
|
||||||
&dev_attr_temp_deactivated.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
&dev_attr_durations.attr,
|
|
||||||
&dev_attr_timeouts.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group tis_attr_grp = {
|
|
||||||
.attrs = tis_attrs
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct tpm_vendor_specific tpm_tis_i2c = {
|
|
||||||
.status = tpm_tis_i2c_status,
|
.status = tpm_tis_i2c_status,
|
||||||
.recv = tpm_tis_i2c_recv,
|
.recv = tpm_tis_i2c_recv,
|
||||||
.send = tpm_tis_i2c_send,
|
.send = tpm_tis_i2c_send,
|
||||||
|
@ -612,8 +574,6 @@ static struct tpm_vendor_specific tpm_tis_i2c = {
|
||||||
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||||
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||||
.req_canceled = tpm_tis_i2c_req_canceled,
|
.req_canceled = tpm_tis_i2c_req_canceled,
|
||||||
.attr_group = &tis_attr_grp,
|
|
||||||
.miscdev.fops = &tis_ops,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int tpm_tis_i2c_init(struct device *dev)
|
static int tpm_tis_i2c_init(struct device *dev)
|
||||||
|
|
|
@ -178,7 +178,6 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value,
|
||||||
{
|
{
|
||||||
if (chip->vendor.irq && queue) {
|
if (chip->vendor.irq && queue) {
|
||||||
s32 rc;
|
s32 rc;
|
||||||
DEFINE_WAIT(wait);
|
|
||||||
struct priv_data *priv = chip->vendor.priv;
|
struct priv_data *priv = chip->vendor.priv;
|
||||||
unsigned int cur_intrs = priv->intrs;
|
unsigned int cur_intrs = priv->intrs;
|
||||||
|
|
||||||
|
@ -456,45 +455,7 @@ static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
return (status == TPM_STS_COMMAND_READY);
|
return (status == TPM_STS_COMMAND_READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations i2c_nuvoton_ops = {
|
static const struct tpm_class_ops tpm_i2c = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
|
|
||||||
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
|
|
||||||
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
|
|
||||||
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
|
|
||||||
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
|
|
||||||
|
|
||||||
static struct attribute *i2c_nuvoton_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_enabled.attr,
|
|
||||||
&dev_attr_active.attr,
|
|
||||||
&dev_attr_owned.attr,
|
|
||||||
&dev_attr_temp_deactivated.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
&dev_attr_durations.attr,
|
|
||||||
&dev_attr_timeouts.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group i2c_nuvoton_attr_grp = {
|
|
||||||
.attrs = i2c_nuvoton_attrs
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct tpm_vendor_specific tpm_i2c = {
|
|
||||||
.status = i2c_nuvoton_read_status,
|
.status = i2c_nuvoton_read_status,
|
||||||
.recv = i2c_nuvoton_recv,
|
.recv = i2c_nuvoton_recv,
|
||||||
.send = i2c_nuvoton_send,
|
.send = i2c_nuvoton_send,
|
||||||
|
@ -502,8 +463,6 @@ static const struct tpm_vendor_specific tpm_i2c = {
|
||||||
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||||
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||||
.req_canceled = i2c_nuvoton_req_canceled,
|
.req_canceled = i2c_nuvoton_req_canceled,
|
||||||
.attr_group = &i2c_nuvoton_attr_grp,
|
|
||||||
.miscdev.fops = &i2c_nuvoton_ops,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The only purpose for the handler is to signal to any waiting threads that
|
/* The only purpose for the handler is to signal to any waiting threads that
|
||||||
|
|
|
@ -410,6 +410,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
&chip->vendor.read_queue)
|
&chip->vendor.read_queue)
|
||||||
== 0) {
|
== 0) {
|
||||||
burstcnt = get_burstcount(chip);
|
burstcnt = get_burstcount(chip);
|
||||||
|
if (burstcnt < 0)
|
||||||
|
return burstcnt;
|
||||||
len = min_t(int, burstcnt, count - size);
|
len = min_t(int, burstcnt, count - size);
|
||||||
I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len);
|
I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len);
|
||||||
size += len;
|
size += len;
|
||||||
|
@ -451,7 +453,8 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
|
||||||
static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
|
static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
u32 status, burstcnt = 0, i, size;
|
u32 status, i, size;
|
||||||
|
int burstcnt = 0;
|
||||||
int ret;
|
int ret;
|
||||||
u8 data;
|
u8 data;
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
|
@ -482,6 +485,8 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
|
||||||
|
|
||||||
for (i = 0; i < len - 1;) {
|
for (i = 0; i < len - 1;) {
|
||||||
burstcnt = get_burstcount(chip);
|
burstcnt = get_burstcount(chip);
|
||||||
|
if (burstcnt < 0)
|
||||||
|
return burstcnt;
|
||||||
size = min_t(int, len - i - 1, burstcnt);
|
size = min_t(int, len - i - 1, burstcnt);
|
||||||
ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
|
ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -559,7 +564,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
chip->vendor.cancel(chip);
|
chip->ops->cancel(chip);
|
||||||
release_locality(chip);
|
release_locality(chip);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -569,40 +574,7 @@ static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
return (status == TPM_STS_COMMAND_READY);
|
return (status == TPM_STS_COMMAND_READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations tpm_st33_i2c_fops = {
|
static const struct tpm_class_ops st_i2c_tpm = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.open = tpm_open,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
|
|
||||||
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
|
|
||||||
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
|
|
||||||
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
|
|
||||||
static struct attribute *stm_tpm_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_enabled.attr,
|
|
||||||
&dev_attr_active.attr,
|
|
||||||
&dev_attr_owned.attr,
|
|
||||||
&dev_attr_temp_deactivated.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr, NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group stm_tpm_attr_grp = {
|
|
||||||
.attrs = stm_tpm_attrs
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct tpm_vendor_specific st_i2c_tpm = {
|
|
||||||
.send = tpm_stm_i2c_send,
|
.send = tpm_stm_i2c_send,
|
||||||
.recv = tpm_stm_i2c_recv,
|
.recv = tpm_stm_i2c_recv,
|
||||||
.cancel = tpm_stm_i2c_cancel,
|
.cancel = tpm_stm_i2c_cancel,
|
||||||
|
@ -610,8 +582,6 @@ static struct tpm_vendor_specific st_i2c_tpm = {
|
||||||
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||||
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||||
.req_canceled = tpm_st33_i2c_req_canceled,
|
.req_canceled = tpm_st33_i2c_req_canceled,
|
||||||
.attr_group = &stm_tpm_attr_grp,
|
|
||||||
.miscdev = {.fops = &tpm_st33_i2c_fops,},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int interrupts;
|
static int interrupts;
|
||||||
|
@ -837,7 +807,7 @@ static int tpm_st33_i2c_pm_resume(struct device *dev)
|
||||||
if (power_mgt) {
|
if (power_mgt) {
|
||||||
gpio_set_value(pin_infos->io_lpcpd, 1);
|
gpio_set_value(pin_infos->io_lpcpd, 1);
|
||||||
ret = wait_for_serirq_timeout(chip,
|
ret = wait_for_serirq_timeout(chip,
|
||||||
(chip->vendor.status(chip) &
|
(chip->ops->status(chip) &
|
||||||
TPM_STS_VALID) == TPM_STS_VALID,
|
TPM_STS_VALID) == TPM_STS_VALID,
|
||||||
chip->vendor.timeout_b);
|
chip->vendor.timeout_b);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -403,43 +403,7 @@ static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
return (status == 0);
|
return (status == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations ibmvtpm_ops = {
|
static const struct tpm_class_ops tpm_ibmvtpm = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
|
|
||||||
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
|
|
||||||
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
|
|
||||||
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
|
|
||||||
NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
|
|
||||||
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
|
|
||||||
|
|
||||||
static struct attribute *ibmvtpm_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_enabled.attr,
|
|
||||||
&dev_attr_active.attr,
|
|
||||||
&dev_attr_owned.attr,
|
|
||||||
&dev_attr_temp_deactivated.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
&dev_attr_durations.attr,
|
|
||||||
&dev_attr_timeouts.attr, NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs };
|
|
||||||
|
|
||||||
static const struct tpm_vendor_specific tpm_ibmvtpm = {
|
|
||||||
.recv = tpm_ibmvtpm_recv,
|
.recv = tpm_ibmvtpm_recv,
|
||||||
.send = tpm_ibmvtpm_send,
|
.send = tpm_ibmvtpm_send,
|
||||||
.cancel = tpm_ibmvtpm_cancel,
|
.cancel = tpm_ibmvtpm_cancel,
|
||||||
|
@ -447,8 +411,6 @@ static const struct tpm_vendor_specific tpm_ibmvtpm = {
|
||||||
.req_complete_mask = 0,
|
.req_complete_mask = 0,
|
||||||
.req_complete_val = 0,
|
.req_complete_val = 0,
|
||||||
.req_canceled = tpm_ibmvtpm_req_canceled,
|
.req_canceled = tpm_ibmvtpm_req_canceled,
|
||||||
.attr_group = &ibmvtpm_attr_grp,
|
|
||||||
.miscdev = { .fops = &ibmvtpm_ops, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = {
|
static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = {
|
||||||
|
@ -507,7 +469,6 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
|
||||||
dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg);
|
dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
case IBMVTPM_VALID_CMD:
|
case IBMVTPM_VALID_CMD:
|
||||||
switch (crq->msg) {
|
switch (crq->msg) {
|
||||||
case VTPM_GET_RTCE_BUFFER_SIZE_RES:
|
case VTPM_GET_RTCE_BUFFER_SIZE_RES:
|
||||||
|
|
|
@ -371,39 +371,13 @@ static u8 tpm_inf_status(struct tpm_chip *chip)
|
||||||
return tpm_data_in(STAT);
|
return tpm_data_in(STAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
static const struct tpm_class_ops tpm_inf = {
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
|
|
||||||
static struct attribute *inf_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group inf_attr_grp = {.attrs = inf_attrs };
|
|
||||||
|
|
||||||
static const struct file_operations inf_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct tpm_vendor_specific tpm_inf = {
|
|
||||||
.recv = tpm_inf_recv,
|
.recv = tpm_inf_recv,
|
||||||
.send = tpm_inf_send,
|
.send = tpm_inf_send,
|
||||||
.cancel = tpm_inf_cancel,
|
.cancel = tpm_inf_cancel,
|
||||||
.status = tpm_inf_status,
|
.status = tpm_inf_status,
|
||||||
.req_complete_mask = 0,
|
.req_complete_mask = 0,
|
||||||
.req_complete_val = 0,
|
.req_complete_val = 0,
|
||||||
.attr_group = &inf_attr_grp,
|
|
||||||
.miscdev = {.fops = &inf_ops,},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pnp_device_id tpm_inf_pnp_tbl[] = {
|
static const struct pnp_device_id tpm_inf_pnp_tbl[] = {
|
||||||
|
|
|
@ -232,31 +232,7 @@ static bool tpm_nsc_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
return (status == NSC_STATUS_RDY);
|
return (status == NSC_STATUS_RDY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations nsc_ops = {
|
static const struct tpm_class_ops tpm_nsc = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
|
|
||||||
static struct attribute * nsc_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
|
|
||||||
|
|
||||||
static const struct tpm_vendor_specific tpm_nsc = {
|
|
||||||
.recv = tpm_nsc_recv,
|
.recv = tpm_nsc_recv,
|
||||||
.send = tpm_nsc_send,
|
.send = tpm_nsc_send,
|
||||||
.cancel = tpm_nsc_cancel,
|
.cancel = tpm_nsc_cancel,
|
||||||
|
@ -264,8 +240,6 @@ static const struct tpm_vendor_specific tpm_nsc = {
|
||||||
.req_complete_mask = NSC_STATUS_OBF,
|
.req_complete_mask = NSC_STATUS_OBF,
|
||||||
.req_complete_val = NSC_STATUS_OBF,
|
.req_complete_val = NSC_STATUS_OBF,
|
||||||
.req_canceled = tpm_nsc_req_canceled,
|
.req_canceled = tpm_nsc_req_canceled,
|
||||||
.attr_group = &nsc_attr_grp,
|
|
||||||
.miscdev = { .fops = &nsc_ops, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_device *pdev = NULL;
|
static struct platform_device *pdev = NULL;
|
||||||
|
|
|
@ -172,7 +172,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
||||||
* 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 (strcmp(version, "1.1") == -1)
|
if (strcmp(version, "1.1") < 0)
|
||||||
params[2].integer.value = TPM_PPI_FN_SUBREQ;
|
params[2].integer.value = TPM_PPI_FN_SUBREQ;
|
||||||
else
|
else
|
||||||
params[2].integer.value = TPM_PPI_FN_SUBREQ2;
|
params[2].integer.value = TPM_PPI_FN_SUBREQ2;
|
||||||
|
@ -182,7 +182,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(version, "1.2") == -1) {
|
if (strcmp(version, "1.2") < 0) {
|
||||||
params[3].type = ACPI_TYPE_BUFFER;
|
params[3].type = ACPI_TYPE_BUFFER;
|
||||||
params[3].buffer.length = sizeof(req);
|
params[3].buffer.length = sizeof(req);
|
||||||
sscanf(buf, "%d", &req);
|
sscanf(buf, "%d", &req);
|
||||||
|
@ -248,7 +248,7 @@ 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(version, "1.2") == -1) {
|
if (strcmp(version, "1.2") < 0) {
|
||||||
params[3].type = ACPI_TYPE_BUFFER;
|
params[3].type = ACPI_TYPE_BUFFER;
|
||||||
params[3].buffer.length = 0;
|
params[3].buffer.length = 0;
|
||||||
params[3].buffer.pointer = NULL;
|
params[3].buffer.pointer = NULL;
|
||||||
|
@ -390,7 +390,7 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
|
||||||
kfree(output.pointer);
|
kfree(output.pointer);
|
||||||
output.length = ACPI_ALLOCATE_BUFFER;
|
output.length = ACPI_ALLOCATE_BUFFER;
|
||||||
output.pointer = NULL;
|
output.pointer = NULL;
|
||||||
if (strcmp(version, "1.2") == -1)
|
if (strcmp(version, "1.2") < 0)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
params[2].integer.value = TPM_PPI_FN_GETOPR;
|
params[2].integer.value = TPM_PPI_FN_GETOPR;
|
||||||
|
|
|
@ -432,45 +432,7 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations tis_ops = {
|
static const struct tpm_class_ops tpm_tis = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
|
|
||||||
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
|
|
||||||
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
|
|
||||||
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
|
|
||||||
NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
|
|
||||||
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
|
|
||||||
|
|
||||||
static struct attribute *tis_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_enabled.attr,
|
|
||||||
&dev_attr_active.attr,
|
|
||||||
&dev_attr_owned.attr,
|
|
||||||
&dev_attr_temp_deactivated.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
&dev_attr_durations.attr,
|
|
||||||
&dev_attr_timeouts.attr, NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group tis_attr_grp = {
|
|
||||||
.attrs = tis_attrs
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct tpm_vendor_specific tpm_tis = {
|
|
||||||
.status = tpm_tis_status,
|
.status = tpm_tis_status,
|
||||||
.recv = tpm_tis_recv,
|
.recv = tpm_tis_recv,
|
||||||
.send = tpm_tis_send,
|
.send = tpm_tis_send,
|
||||||
|
@ -478,9 +440,6 @@ static struct tpm_vendor_specific tpm_tis = {
|
||||||
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||||
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||||
.req_canceled = tpm_tis_req_canceled,
|
.req_canceled = tpm_tis_req_canceled,
|
||||||
.attr_group = &tis_attr_grp,
|
|
||||||
.miscdev = {
|
|
||||||
.fops = &tis_ops,},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t tis_int_probe(int irq, void *dev_id)
|
static irqreturn_t tis_int_probe(int irq, void *dev_id)
|
||||||
|
@ -743,7 +702,7 @@ out_err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_PNP) || defined(CONFIG_PM_SLEEP)
|
#ifdef CONFIG_PM_SLEEP
|
||||||
static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
|
static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
u32 intmask;
|
u32 intmask;
|
||||||
|
@ -764,9 +723,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
|
||||||
iowrite32(intmask,
|
iowrite32(intmask,
|
||||||
chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
|
chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
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);
|
||||||
|
@ -835,11 +792,9 @@ static struct pnp_driver tis_pnp_driver = {
|
||||||
.id_table = tpm_pnp_tbl,
|
.id_table = tpm_pnp_tbl,
|
||||||
.probe = tpm_tis_pnp_init,
|
.probe = tpm_tis_pnp_init,
|
||||||
.remove = tpm_tis_pnp_remove,
|
.remove = tpm_tis_pnp_remove,
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
.driver = {
|
.driver = {
|
||||||
.pm = &tpm_tis_pm,
|
.pm = &tpm_tis_pm,
|
||||||
},
|
},
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
|
#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
|
||||||
|
|
|
@ -143,46 +143,7 @@ static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations vtpm_ops = {
|
static const struct tpm_class_ops tpm_vtpm = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.open = tpm_open,
|
|
||||||
.read = tpm_read,
|
|
||||||
.write = tpm_write,
|
|
||||||
.release = tpm_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
|
||||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
|
||||||
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
|
|
||||||
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
|
|
||||||
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
|
|
||||||
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
|
|
||||||
NULL);
|
|
||||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
|
||||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
|
||||||
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
|
|
||||||
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
|
|
||||||
|
|
||||||
static struct attribute *vtpm_attrs[] = {
|
|
||||||
&dev_attr_pubek.attr,
|
|
||||||
&dev_attr_pcrs.attr,
|
|
||||||
&dev_attr_enabled.attr,
|
|
||||||
&dev_attr_active.attr,
|
|
||||||
&dev_attr_owned.attr,
|
|
||||||
&dev_attr_temp_deactivated.attr,
|
|
||||||
&dev_attr_caps.attr,
|
|
||||||
&dev_attr_cancel.attr,
|
|
||||||
&dev_attr_durations.attr,
|
|
||||||
&dev_attr_timeouts.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group vtpm_attr_grp = {
|
|
||||||
.attrs = vtpm_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct tpm_vendor_specific tpm_vtpm = {
|
|
||||||
.status = vtpm_status,
|
.status = vtpm_status,
|
||||||
.recv = vtpm_recv,
|
.recv = vtpm_recv,
|
||||||
.send = vtpm_send,
|
.send = vtpm_send,
|
||||||
|
@ -190,10 +151,6 @@ static const struct tpm_vendor_specific tpm_vtpm = {
|
||||||
.req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,
|
.req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,
|
||||||
.req_complete_val = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,
|
.req_complete_val = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,
|
||||||
.req_canceled = vtpm_req_canceled,
|
.req_canceled = vtpm_req_canceled,
|
||||||
.attr_group = &vtpm_attr_grp,
|
|
||||||
.miscdev = {
|
|
||||||
.fops = &vtpm_ops,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t tpmif_interrupt(int dummy, void *dev_id)
|
static irqreturn_t tpmif_interrupt(int dummy, void *dev_id)
|
||||||
|
|
|
@ -29,6 +29,18 @@
|
||||||
*/
|
*/
|
||||||
#define TPM_ANY_NUM 0xFFFF
|
#define TPM_ANY_NUM 0xFFFF
|
||||||
|
|
||||||
|
struct tpm_chip;
|
||||||
|
|
||||||
|
struct tpm_class_ops {
|
||||||
|
const u8 req_complete_mask;
|
||||||
|
const u8 req_complete_val;
|
||||||
|
bool (*req_canceled)(struct tpm_chip *chip, u8 status);
|
||||||
|
int (*recv) (struct tpm_chip *chip, u8 *buf, size_t len);
|
||||||
|
int (*send) (struct tpm_chip *chip, u8 *buf, size_t len);
|
||||||
|
void (*cancel) (struct tpm_chip *chip);
|
||||||
|
u8 (*status) (struct tpm_chip *chip);
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
|
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
|
||||||
|
|
||||||
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
|
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
|
||||||
|
|
|
@ -162,8 +162,7 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
|
static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
|
||||||
struct ima_field_data *field_data,
|
struct ima_field_data *field_data)
|
||||||
bool size_limit)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* digest formats:
|
* digest formats:
|
||||||
|
@ -176,11 +175,10 @@ static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
|
||||||
enum data_formats fmt = DATA_FMT_DIGEST;
|
enum data_formats fmt = DATA_FMT_DIGEST;
|
||||||
u32 offset = 0;
|
u32 offset = 0;
|
||||||
|
|
||||||
if (!size_limit) {
|
if (hash_algo < HASH_ALGO__LAST) {
|
||||||
fmt = DATA_FMT_DIGEST_WITH_ALGO;
|
fmt = DATA_FMT_DIGEST_WITH_ALGO;
|
||||||
if (hash_algo < HASH_ALGO__LAST)
|
offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s",
|
||||||
offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1,
|
hash_algo_name[hash_algo]);
|
||||||
"%s", hash_algo_name[hash_algo]);
|
|
||||||
buffer[offset] = ':';
|
buffer[offset] = ':';
|
||||||
offset += 2;
|
offset += 2;
|
||||||
}
|
}
|
||||||
|
@ -243,8 +241,8 @@ int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file,
|
||||||
cur_digest = hash.hdr.digest;
|
cur_digest = hash.hdr.digest;
|
||||||
cur_digestsize = hash.hdr.length;
|
cur_digestsize = hash.hdr.length;
|
||||||
out:
|
out:
|
||||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize, -1,
|
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
||||||
field_data, true);
|
HASH_ALGO__LAST, field_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -255,7 +253,7 @@ int ima_eventdigest_ng_init(struct integrity_iint_cache *iint,
|
||||||
struct evm_ima_xattr_data *xattr_value,
|
struct evm_ima_xattr_data *xattr_value,
|
||||||
int xattr_len, struct ima_field_data *field_data)
|
int xattr_len, struct ima_field_data *field_data)
|
||||||
{
|
{
|
||||||
u8 *cur_digest = NULL, hash_algo = HASH_ALGO__LAST;
|
u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1;
|
||||||
u32 cur_digestsize = 0;
|
u32 cur_digestsize = 0;
|
||||||
|
|
||||||
/* If iint is NULL, we are recording a violation. */
|
/* If iint is NULL, we are recording a violation. */
|
||||||
|
@ -268,7 +266,7 @@ int ima_eventdigest_ng_init(struct integrity_iint_cache *iint,
|
||||||
hash_algo = iint->ima_hash->algo;
|
hash_algo = iint->ima_hash->algo;
|
||||||
out:
|
out:
|
||||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
||||||
hash_algo, field_data, false);
|
hash_algo, field_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ima_eventname_init_common(struct integrity_iint_cache *iint,
|
static int ima_eventname_init_common(struct integrity_iint_cache *iint,
|
||||||
|
|
|
@ -82,7 +82,6 @@
|
||||||
#include <linux/syslog.h>
|
#include <linux/syslog.h>
|
||||||
#include <linux/user_namespace.h>
|
#include <linux/user_namespace.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/security.h>
|
|
||||||
#include <linux/msg.h>
|
#include <linux/msg.h>
|
||||||
#include <linux/shm.h>
|
#include <linux/shm.h>
|
||||||
|
|
||||||
|
@ -4490,14 +4489,10 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||||
{
|
{
|
||||||
struct sk_security_struct *sksec = sk->sk_security;
|
struct sk_security_struct *sksec = sk->sk_security;
|
||||||
int err;
|
int err;
|
||||||
u16 family = sk->sk_family;
|
u16 family = req->rsk_ops->family;
|
||||||
u32 connsid;
|
u32 connsid;
|
||||||
u32 peersid;
|
u32 peersid;
|
||||||
|
|
||||||
/* handle mapped IPv4 packets arriving via IPv6 sockets */
|
|
||||||
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
|
|
||||||
family = PF_INET;
|
|
||||||
|
|
||||||
err = selinux_skb_peerlbl_sid(skb, family, &peersid);
|
err = selinux_skb_peerlbl_sid(skb, family, &peersid);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -33,13 +33,14 @@
|
||||||
#define POLICYDB_VERSION_ROLETRANS 26
|
#define POLICYDB_VERSION_ROLETRANS 26
|
||||||
#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
|
#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
|
||||||
#define POLICYDB_VERSION_DEFAULT_TYPE 28
|
#define POLICYDB_VERSION_DEFAULT_TYPE 28
|
||||||
|
#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
|
||||||
|
|
||||||
/* Range of policy versions we understand*/
|
/* Range of policy versions we understand*/
|
||||||
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
||||||
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||||
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
|
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
|
||||||
#else
|
#else
|
||||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE
|
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Mask for just the mount related flags */
|
/* Mask for just the mount related flags */
|
||||||
|
|
|
@ -100,6 +100,32 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
|
||||||
return secattr;
|
return secattr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
|
||||||
|
* @sk: the socket
|
||||||
|
* @sid: the SID
|
||||||
|
*
|
||||||
|
* Query the socket's cached secattr and if the SID matches the cached value
|
||||||
|
* return the cache, otherwise return NULL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
|
||||||
|
const struct sock *sk,
|
||||||
|
u32 sid)
|
||||||
|
{
|
||||||
|
struct sk_security_struct *sksec = sk->sk_security;
|
||||||
|
struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
|
||||||
|
|
||||||
|
if (secattr == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((secattr->flags & NETLBL_SECATTR_SECID) &&
|
||||||
|
(secattr->attr.secid == sid))
|
||||||
|
return secattr;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
|
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
|
||||||
*
|
*
|
||||||
|
@ -224,7 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
|
||||||
struct sk_security_struct *sksec = sk->sk_security;
|
struct sk_security_struct *sksec = sk->sk_security;
|
||||||
if (sksec->nlbl_state != NLBL_REQSKB)
|
if (sksec->nlbl_state != NLBL_REQSKB)
|
||||||
return 0;
|
return 0;
|
||||||
secattr = sksec->nlbl_secattr;
|
secattr = selinux_netlbl_sock_getattr(sk, sid);
|
||||||
}
|
}
|
||||||
if (secattr == NULL) {
|
if (secattr == NULL) {
|
||||||
secattr = &secattr_storage;
|
secattr = &secattr_storage;
|
||||||
|
@ -410,6 +436,9 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
|
||||||
sksec->nlbl_state == NLBL_CONNLABELED)) {
|
sksec->nlbl_state == NLBL_CONNLABELED)) {
|
||||||
netlbl_secattr_init(&secattr);
|
netlbl_secattr_init(&secattr);
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
|
/* call the netlabel function directly as we want to see the
|
||||||
|
* on-the-wire label that is assigned via the socket's options
|
||||||
|
* and not the cached netlabel/lsm attributes */
|
||||||
rc = netlbl_sock_getattr(sk, &secattr);
|
rc = netlbl_sock_getattr(sk, &secattr);
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct constraint_expr {
|
||||||
u32 op; /* operator */
|
u32 op; /* operator */
|
||||||
|
|
||||||
struct ebitmap names; /* names */
|
struct ebitmap names; /* names */
|
||||||
|
struct type_set *type_names;
|
||||||
|
|
||||||
struct constraint_expr *next; /* next expression */
|
struct constraint_expr *next; /* next expression */
|
||||||
};
|
};
|
||||||
|
|
|
@ -143,6 +143,11 @@ static struct policydb_compat_info policydb_compat[] = {
|
||||||
.sym_num = SYM_NUM,
|
.sym_num = SYM_NUM,
|
||||||
.ocon_num = OCON_NUM,
|
.ocon_num = OCON_NUM,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.version = POLICYDB_VERSION_CONSTRAINT_NAMES,
|
||||||
|
.sym_num = SYM_NUM,
|
||||||
|
.ocon_num = OCON_NUM,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct policydb_compat_info *policydb_lookup_compat(int version)
|
static struct policydb_compat_info *policydb_lookup_compat(int version)
|
||||||
|
@ -613,6 +618,19 @@ static int common_destroy(void *key, void *datum, void *p)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void constraint_expr_destroy(struct constraint_expr *expr)
|
||||||
|
{
|
||||||
|
if (expr) {
|
||||||
|
ebitmap_destroy(&expr->names);
|
||||||
|
if (expr->type_names) {
|
||||||
|
ebitmap_destroy(&expr->type_names->types);
|
||||||
|
ebitmap_destroy(&expr->type_names->negset);
|
||||||
|
kfree(expr->type_names);
|
||||||
|
}
|
||||||
|
kfree(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int cls_destroy(void *key, void *datum, void *p)
|
static int cls_destroy(void *key, void *datum, void *p)
|
||||||
{
|
{
|
||||||
struct class_datum *cladatum;
|
struct class_datum *cladatum;
|
||||||
|
@ -628,10 +646,9 @@ static int cls_destroy(void *key, void *datum, void *p)
|
||||||
while (constraint) {
|
while (constraint) {
|
||||||
e = constraint->expr;
|
e = constraint->expr;
|
||||||
while (e) {
|
while (e) {
|
||||||
ebitmap_destroy(&e->names);
|
|
||||||
etmp = e;
|
etmp = e;
|
||||||
e = e->next;
|
e = e->next;
|
||||||
kfree(etmp);
|
constraint_expr_destroy(etmp);
|
||||||
}
|
}
|
||||||
ctemp = constraint;
|
ctemp = constraint;
|
||||||
constraint = constraint->next;
|
constraint = constraint->next;
|
||||||
|
@ -642,16 +659,14 @@ static int cls_destroy(void *key, void *datum, void *p)
|
||||||
while (constraint) {
|
while (constraint) {
|
||||||
e = constraint->expr;
|
e = constraint->expr;
|
||||||
while (e) {
|
while (e) {
|
||||||
ebitmap_destroy(&e->names);
|
|
||||||
etmp = e;
|
etmp = e;
|
||||||
e = e->next;
|
e = e->next;
|
||||||
kfree(etmp);
|
constraint_expr_destroy(etmp);
|
||||||
}
|
}
|
||||||
ctemp = constraint;
|
ctemp = constraint;
|
||||||
constraint = constraint->next;
|
constraint = constraint->next;
|
||||||
kfree(ctemp);
|
kfree(ctemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(cladatum->comkey);
|
kfree(cladatum->comkey);
|
||||||
}
|
}
|
||||||
kfree(datum);
|
kfree(datum);
|
||||||
|
@ -1156,8 +1171,34 @@ bad:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_cons_helper(struct constraint_node **nodep, int ncons,
|
static void type_set_init(struct type_set *t)
|
||||||
int allowxtarget, void *fp)
|
{
|
||||||
|
ebitmap_init(&t->types);
|
||||||
|
ebitmap_init(&t->negset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int type_set_read(struct type_set *t, void *fp)
|
||||||
|
{
|
||||||
|
__le32 buf[1];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (ebitmap_read(&t->types, fp))
|
||||||
|
return -EINVAL;
|
||||||
|
if (ebitmap_read(&t->negset, fp))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
rc = next_entry(buf, fp, sizeof(u32));
|
||||||
|
if (rc < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
t->flags = le32_to_cpu(buf[0]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int read_cons_helper(struct policydb *p,
|
||||||
|
struct constraint_node **nodep,
|
||||||
|
int ncons, int allowxtarget, void *fp)
|
||||||
{
|
{
|
||||||
struct constraint_node *c, *lc;
|
struct constraint_node *c, *lc;
|
||||||
struct constraint_expr *e, *le;
|
struct constraint_expr *e, *le;
|
||||||
|
@ -1225,6 +1266,18 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
|
||||||
rc = ebitmap_read(&e->names, fp);
|
rc = ebitmap_read(&e->names, fp);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
if (p->policyvers >=
|
||||||
|
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
||||||
|
e->type_names = kzalloc(sizeof
|
||||||
|
(*e->type_names),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!e->type_names)
|
||||||
|
return -ENOMEM;
|
||||||
|
type_set_init(e->type_names);
|
||||||
|
rc = type_set_read(e->type_names, fp);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1301,7 +1354,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
|
rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
|
@ -1311,7 +1364,8 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto bad;
|
goto bad;
|
||||||
ncons = le32_to_cpu(buf[0]);
|
ncons = le32_to_cpu(buf[0]);
|
||||||
rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
|
rc = read_cons_helper(p, &cladatum->validatetrans,
|
||||||
|
ncons, 1, fp);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
@ -1941,7 +1995,19 @@ static int filename_trans_read(struct policydb *p, void *fp)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hashtab_insert(p->filename_trans, ft, otype);
|
rc = hashtab_insert(p->filename_trans, ft, otype);
|
||||||
|
if (rc) {
|
||||||
|
/*
|
||||||
|
* Do not return -EEXIST to the caller, or the system
|
||||||
|
* will not boot.
|
||||||
|
*/
|
||||||
|
if (rc != -EEXIST)
|
||||||
|
goto out;
|
||||||
|
/* But free memory to avoid memory leak. */
|
||||||
|
kfree(ft);
|
||||||
|
kfree(name);
|
||||||
|
kfree(otype);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hash_eval(p->filename_trans, "filenametr");
|
hash_eval(p->filename_trans, "filenametr");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2753,6 +2819,24 @@ static int common_write(void *vkey, void *datum, void *ptr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int type_set_write(struct type_set *t, void *fp)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
__le32 buf[1];
|
||||||
|
|
||||||
|
if (ebitmap_write(&t->types, fp))
|
||||||
|
return -EINVAL;
|
||||||
|
if (ebitmap_write(&t->negset, fp))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
buf[0] = cpu_to_le32(t->flags);
|
||||||
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||||
|
if (rc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int write_cons_helper(struct policydb *p, struct constraint_node *node,
|
static int write_cons_helper(struct policydb *p, struct constraint_node *node,
|
||||||
void *fp)
|
void *fp)
|
||||||
{
|
{
|
||||||
|
@ -2784,6 +2868,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node,
|
||||||
rc = ebitmap_write(&e->names, fp);
|
rc = ebitmap_write(&e->names, fp);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
if (p->policyvers >=
|
||||||
|
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
||||||
|
rc = type_set_write(e->type_names, fp);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -153,6 +153,17 @@ struct cond_bool_datum {
|
||||||
|
|
||||||
struct cond_node;
|
struct cond_node;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* type set preserves data needed to determine constraint info from
|
||||||
|
* policy source. This is not used by the kernel policy but allows
|
||||||
|
* utilities such as audit2allow to determine constraint denials.
|
||||||
|
*/
|
||||||
|
struct type_set {
|
||||||
|
struct ebitmap types;
|
||||||
|
struct ebitmap negset;
|
||||||
|
u32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The configuration data includes security contexts for
|
* The configuration data includes security contexts for
|
||||||
* initial SIDs, unlabeled file systems, TCP and UDP port numbers,
|
* initial SIDs, unlabeled file systems, TCP and UDP port numbers,
|
||||||
|
|
|
@ -1831,7 +1831,7 @@ static int security_preserve_bools(struct policydb *p);
|
||||||
*/
|
*/
|
||||||
int security_load_policy(void *data, size_t len)
|
int security_load_policy(void *data, size_t len)
|
||||||
{
|
{
|
||||||
struct policydb oldpolicydb, newpolicydb;
|
struct policydb *oldpolicydb, *newpolicydb;
|
||||||
struct sidtab oldsidtab, newsidtab;
|
struct sidtab oldsidtab, newsidtab;
|
||||||
struct selinux_mapping *oldmap, *map = NULL;
|
struct selinux_mapping *oldmap, *map = NULL;
|
||||||
struct convert_context_args args;
|
struct convert_context_args args;
|
||||||
|
@ -1840,12 +1840,19 @@ int security_load_policy(void *data, size_t len)
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct policy_file file = { data, len }, *fp = &file;
|
struct policy_file file = { data, len }, *fp = &file;
|
||||||
|
|
||||||
|
oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL);
|
||||||
|
if (!oldpolicydb) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
newpolicydb = oldpolicydb + 1;
|
||||||
|
|
||||||
if (!ss_initialized) {
|
if (!ss_initialized) {
|
||||||
avtab_cache_init();
|
avtab_cache_init();
|
||||||
rc = policydb_read(&policydb, fp);
|
rc = policydb_read(&policydb, fp);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
avtab_cache_destroy();
|
avtab_cache_destroy();
|
||||||
return rc;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
policydb.len = len;
|
policydb.len = len;
|
||||||
|
@ -1855,14 +1862,14 @@ int security_load_policy(void *data, size_t len)
|
||||||
if (rc) {
|
if (rc) {
|
||||||
policydb_destroy(&policydb);
|
policydb_destroy(&policydb);
|
||||||
avtab_cache_destroy();
|
avtab_cache_destroy();
|
||||||
return rc;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = policydb_load_isids(&policydb, &sidtab);
|
rc = policydb_load_isids(&policydb, &sidtab);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
policydb_destroy(&policydb);
|
policydb_destroy(&policydb);
|
||||||
avtab_cache_destroy();
|
avtab_cache_destroy();
|
||||||
return rc;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
security_load_policycaps();
|
security_load_policycaps();
|
||||||
|
@ -1874,36 +1881,36 @@ int security_load_policy(void *data, size_t len)
|
||||||
selinux_status_update_policyload(seqno);
|
selinux_status_update_policyload(seqno);
|
||||||
selinux_netlbl_cache_invalidate();
|
selinux_netlbl_cache_invalidate();
|
||||||
selinux_xfrm_notify_policyload();
|
selinux_xfrm_notify_policyload();
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
sidtab_hash_eval(&sidtab, "sids");
|
sidtab_hash_eval(&sidtab, "sids");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rc = policydb_read(&newpolicydb, fp);
|
rc = policydb_read(newpolicydb, fp);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
goto out;
|
||||||
|
|
||||||
newpolicydb.len = len;
|
newpolicydb->len = len;
|
||||||
/* If switching between different policy types, log MLS status */
|
/* If switching between different policy types, log MLS status */
|
||||||
if (policydb.mls_enabled && !newpolicydb.mls_enabled)
|
if (policydb.mls_enabled && !newpolicydb->mls_enabled)
|
||||||
printk(KERN_INFO "SELinux: Disabling MLS support...\n");
|
printk(KERN_INFO "SELinux: Disabling MLS support...\n");
|
||||||
else if (!policydb.mls_enabled && newpolicydb.mls_enabled)
|
else if (!policydb.mls_enabled && newpolicydb->mls_enabled)
|
||||||
printk(KERN_INFO "SELinux: Enabling MLS support...\n");
|
printk(KERN_INFO "SELinux: Enabling MLS support...\n");
|
||||||
|
|
||||||
rc = policydb_load_isids(&newpolicydb, &newsidtab);
|
rc = policydb_load_isids(newpolicydb, &newsidtab);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "SELinux: unable to load the initial SIDs\n");
|
printk(KERN_ERR "SELinux: unable to load the initial SIDs\n");
|
||||||
policydb_destroy(&newpolicydb);
|
policydb_destroy(newpolicydb);
|
||||||
return rc;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size);
|
rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
rc = security_preserve_bools(&newpolicydb);
|
rc = security_preserve_bools(newpolicydb);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "SELinux: unable to preserve booleans\n");
|
printk(KERN_ERR "SELinux: unable to preserve booleans\n");
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -1921,7 +1928,7 @@ int security_load_policy(void *data, size_t len)
|
||||||
* in the new SID table.
|
* in the new SID table.
|
||||||
*/
|
*/
|
||||||
args.oldp = &policydb;
|
args.oldp = &policydb;
|
||||||
args.newp = &newpolicydb;
|
args.newp = newpolicydb;
|
||||||
rc = sidtab_map(&newsidtab, convert_context, &args);
|
rc = sidtab_map(&newsidtab, convert_context, &args);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "SELinux: unable to convert the internal"
|
printk(KERN_ERR "SELinux: unable to convert the internal"
|
||||||
|
@ -1931,12 +1938,12 @@ int security_load_policy(void *data, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save the old policydb and SID table to free later. */
|
/* Save the old policydb and SID table to free later. */
|
||||||
memcpy(&oldpolicydb, &policydb, sizeof policydb);
|
memcpy(oldpolicydb, &policydb, sizeof(policydb));
|
||||||
sidtab_set(&oldsidtab, &sidtab);
|
sidtab_set(&oldsidtab, &sidtab);
|
||||||
|
|
||||||
/* Install the new policydb and SID table. */
|
/* Install the new policydb and SID table. */
|
||||||
write_lock_irq(&policy_rwlock);
|
write_lock_irq(&policy_rwlock);
|
||||||
memcpy(&policydb, &newpolicydb, sizeof policydb);
|
memcpy(&policydb, newpolicydb, sizeof(policydb));
|
||||||
sidtab_set(&sidtab, &newsidtab);
|
sidtab_set(&sidtab, &newsidtab);
|
||||||
security_load_policycaps();
|
security_load_policycaps();
|
||||||
oldmap = current_mapping;
|
oldmap = current_mapping;
|
||||||
|
@ -1946,7 +1953,7 @@ int security_load_policy(void *data, size_t len)
|
||||||
write_unlock_irq(&policy_rwlock);
|
write_unlock_irq(&policy_rwlock);
|
||||||
|
|
||||||
/* Free the old policydb and SID table. */
|
/* Free the old policydb and SID table. */
|
||||||
policydb_destroy(&oldpolicydb);
|
policydb_destroy(oldpolicydb);
|
||||||
sidtab_destroy(&oldsidtab);
|
sidtab_destroy(&oldsidtab);
|
||||||
kfree(oldmap);
|
kfree(oldmap);
|
||||||
|
|
||||||
|
@ -1956,14 +1963,17 @@ int security_load_policy(void *data, size_t len)
|
||||||
selinux_netlbl_cache_invalidate();
|
selinux_netlbl_cache_invalidate();
|
||||||
selinux_xfrm_notify_policyload();
|
selinux_xfrm_notify_policyload();
|
||||||
|
|
||||||
return 0;
|
rc = 0;
|
||||||
|
goto out;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
kfree(map);
|
kfree(map);
|
||||||
sidtab_destroy(&newsidtab);
|
sidtab_destroy(&newsidtab);
|
||||||
policydb_destroy(&newpolicydb);
|
policydb_destroy(newpolicydb);
|
||||||
return rc;
|
|
||||||
|
|
||||||
|
out:
|
||||||
|
kfree(oldpolicydb);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t security_policydb_len(void)
|
size_t security_policydb_len(void)
|
||||||
|
|
|
@ -241,7 +241,8 @@ u32 smack_to_secid(const char *);
|
||||||
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;
|
||||||
extern char *smack_onlycap;
|
extern struct smack_known *smack_onlycap;
|
||||||
|
extern struct smack_known *smack_syslog_label;
|
||||||
extern const char *smack_cipso_option;
|
extern const char *smack_cipso_option;
|
||||||
|
|
||||||
extern struct smack_known smack_known_floor;
|
extern struct smack_known smack_known_floor;
|
||||||
|
@ -312,7 +313,7 @@ static inline int smack_privileged(int cap)
|
||||||
|
|
||||||
if (!capable(cap))
|
if (!capable(cap))
|
||||||
return 0;
|
return 0;
|
||||||
if (smack_onlycap == NULL || smack_onlycap == skp->smk_known)
|
if (smack_onlycap == NULL || smack_onlycap == skp)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,8 +219,6 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
|
||||||
* smack_syslog - Smack approval on syslog
|
* smack_syslog - Smack approval on syslog
|
||||||
* @type: message type
|
* @type: message type
|
||||||
*
|
*
|
||||||
* Require that the task has the floor label
|
|
||||||
*
|
|
||||||
* Returns 0 on success, error code otherwise.
|
* Returns 0 on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
static int smack_syslog(int typefrom_file)
|
static int smack_syslog(int typefrom_file)
|
||||||
|
@ -231,7 +229,7 @@ static int smack_syslog(int typefrom_file)
|
||||||
if (smack_privileged(CAP_MAC_OVERRIDE))
|
if (smack_privileged(CAP_MAC_OVERRIDE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (skp != &smack_known_floor)
|
if (smack_syslog_label != NULL && smack_syslog_label != skp)
|
||||||
rc = -EACCES;
|
rc = -EACCES;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -341,10 +339,12 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||||
struct inode *inode = root->d_inode;
|
struct inode *inode = root->d_inode;
|
||||||
struct superblock_smack *sp = sb->s_security;
|
struct superblock_smack *sp = sb->s_security;
|
||||||
struct inode_smack *isp;
|
struct inode_smack *isp;
|
||||||
|
struct smack_known *skp;
|
||||||
char *op;
|
char *op;
|
||||||
char *commap;
|
char *commap;
|
||||||
char *nsp;
|
char *nsp;
|
||||||
int transmute = 0;
|
int transmute = 0;
|
||||||
|
int specified = 0;
|
||||||
|
|
||||||
if (sp->smk_initialized)
|
if (sp->smk_initialized)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -359,34 +359,56 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||||
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
|
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
|
||||||
op += strlen(SMK_FSHAT);
|
op += strlen(SMK_FSHAT);
|
||||||
nsp = smk_import(op, 0);
|
nsp = smk_import(op, 0);
|
||||||
if (nsp != NULL)
|
if (nsp != NULL) {
|
||||||
sp->smk_hat = nsp;
|
sp->smk_hat = nsp;
|
||||||
|
specified = 1;
|
||||||
|
}
|
||||||
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
|
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
|
||||||
op += strlen(SMK_FSFLOOR);
|
op += strlen(SMK_FSFLOOR);
|
||||||
nsp = smk_import(op, 0);
|
nsp = smk_import(op, 0);
|
||||||
if (nsp != NULL)
|
if (nsp != NULL) {
|
||||||
sp->smk_floor = nsp;
|
sp->smk_floor = nsp;
|
||||||
|
specified = 1;
|
||||||
|
}
|
||||||
} else if (strncmp(op, SMK_FSDEFAULT,
|
} else if (strncmp(op, SMK_FSDEFAULT,
|
||||||
strlen(SMK_FSDEFAULT)) == 0) {
|
strlen(SMK_FSDEFAULT)) == 0) {
|
||||||
op += strlen(SMK_FSDEFAULT);
|
op += strlen(SMK_FSDEFAULT);
|
||||||
nsp = smk_import(op, 0);
|
nsp = smk_import(op, 0);
|
||||||
if (nsp != NULL)
|
if (nsp != NULL) {
|
||||||
sp->smk_default = nsp;
|
sp->smk_default = nsp;
|
||||||
|
specified = 1;
|
||||||
|
}
|
||||||
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
|
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
|
||||||
op += strlen(SMK_FSROOT);
|
op += strlen(SMK_FSROOT);
|
||||||
nsp = smk_import(op, 0);
|
nsp = smk_import(op, 0);
|
||||||
if (nsp != NULL)
|
if (nsp != NULL) {
|
||||||
sp->smk_root = nsp;
|
sp->smk_root = nsp;
|
||||||
|
specified = 1;
|
||||||
|
}
|
||||||
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
|
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
|
||||||
op += strlen(SMK_FSTRANS);
|
op += strlen(SMK_FSTRANS);
|
||||||
nsp = smk_import(op, 0);
|
nsp = smk_import(op, 0);
|
||||||
if (nsp != NULL) {
|
if (nsp != NULL) {
|
||||||
sp->smk_root = nsp;
|
sp->smk_root = nsp;
|
||||||
transmute = 1;
|
transmute = 1;
|
||||||
|
specified = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!smack_privileged(CAP_MAC_ADMIN)) {
|
||||||
|
/*
|
||||||
|
* Unprivileged mounts don't get to specify Smack values.
|
||||||
|
*/
|
||||||
|
if (specified)
|
||||||
|
return -EPERM;
|
||||||
|
/*
|
||||||
|
* Unprivileged mounts get root and default from the caller.
|
||||||
|
*/
|
||||||
|
skp = smk_of_current();
|
||||||
|
sp->smk_root = skp->smk_known;
|
||||||
|
sp->smk_default = skp->smk_known;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Initialize the root inode.
|
* Initialize the root inode.
|
||||||
*/
|
*/
|
||||||
|
@ -423,53 +445,6 @@ static int smack_sb_statfs(struct dentry *dentry)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* smack_sb_mount - Smack check for mounting
|
|
||||||
* @dev_name: unused
|
|
||||||
* @path: mount point
|
|
||||||
* @type: unused
|
|
||||||
* @flags: unused
|
|
||||||
* @data: unused
|
|
||||||
*
|
|
||||||
* Returns 0 if current can write the floor of the filesystem
|
|
||||||
* being mounted on, an error code otherwise.
|
|
||||||
*/
|
|
||||||
static int smack_sb_mount(const char *dev_name, struct path *path,
|
|
||||||
const char *type, unsigned long flags, void *data)
|
|
||||||
{
|
|
||||||
struct superblock_smack *sbp = path->dentry->d_sb->s_security;
|
|
||||||
struct smk_audit_info ad;
|
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
|
||||||
smk_ad_setfield_u_fs_path(&ad, *path);
|
|
||||||
|
|
||||||
return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* smack_sb_umount - Smack check for unmounting
|
|
||||||
* @mnt: file system to unmount
|
|
||||||
* @flags: unused
|
|
||||||
*
|
|
||||||
* Returns 0 if current can write the floor of the filesystem
|
|
||||||
* being unmounted, an error code otherwise.
|
|
||||||
*/
|
|
||||||
static int smack_sb_umount(struct vfsmount *mnt, int flags)
|
|
||||||
{
|
|
||||||
struct superblock_smack *sbp;
|
|
||||||
struct smk_audit_info ad;
|
|
||||||
struct path path;
|
|
||||||
|
|
||||||
path.dentry = mnt->mnt_root;
|
|
||||||
path.mnt = mnt;
|
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
|
||||||
smk_ad_setfield_u_fs_path(&ad, path);
|
|
||||||
|
|
||||||
sbp = path.dentry->d_sb->s_security;
|
|
||||||
return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BPRM hooks
|
* BPRM hooks
|
||||||
*/
|
*/
|
||||||
|
@ -837,31 +812,43 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
|
||||||
const void *value, size_t size, int flags)
|
const void *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
|
struct smack_known *skp;
|
||||||
|
int check_priv = 0;
|
||||||
|
int check_import = 0;
|
||||||
|
int check_star = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check label validity here so import won't fail in post_setxattr
|
||||||
|
*/
|
||||||
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
|
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
|
||||||
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
|
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
|
||||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
|
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
|
||||||
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
|
check_priv = 1;
|
||||||
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
|
check_import = 1;
|
||||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
|
||||||
rc = -EPERM;
|
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
|
||||||
/*
|
check_priv = 1;
|
||||||
* check label validity here so import wont fail on
|
check_import = 1;
|
||||||
* post_setxattr
|
check_star = 1;
|
||||||
*/
|
|
||||||
if (size == 0 || size >= SMK_LONGLABEL ||
|
|
||||||
smk_import(value, size) == NULL)
|
|
||||||
rc = -EINVAL;
|
|
||||||
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
|
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
|
||||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
check_priv = 1;
|
||||||
rc = -EPERM;
|
|
||||||
if (size != TRANS_TRUE_SIZE ||
|
if (size != TRANS_TRUE_SIZE ||
|
||||||
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
|
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
} else
|
} else
|
||||||
rc = cap_inode_setxattr(dentry, name, value, size, flags);
|
rc = cap_inode_setxattr(dentry, name, value, size, flags);
|
||||||
|
|
||||||
|
if (check_priv && !smack_privileged(CAP_MAC_ADMIN))
|
||||||
|
rc = -EPERM;
|
||||||
|
|
||||||
|
if (rc == 0 && check_import) {
|
||||||
|
skp = smk_import_entry(value, size);
|
||||||
|
if (skp == NULL || (check_star &&
|
||||||
|
(skp == &smack_known_star || skp == &smack_known_web)))
|
||||||
|
rc = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
|
||||||
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
|
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
|
||||||
|
|
||||||
|
@ -1364,7 +1351,7 @@ static int smack_file_receive(struct file *file)
|
||||||
int may = 0;
|
int may = 0;
|
||||||
struct smk_audit_info ad;
|
struct smk_audit_info ad;
|
||||||
|
|
||||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
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);
|
||||||
/*
|
/*
|
||||||
* This code relies on bitmasks.
|
* This code relies on bitmasks.
|
||||||
|
@ -2847,8 +2834,17 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
if (rc >= 0)
|
if (rc >= 0)
|
||||||
transflag = SMK_INODE_TRANSMUTE;
|
transflag = SMK_INODE_TRANSMUTE;
|
||||||
}
|
}
|
||||||
isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
|
/*
|
||||||
isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp);
|
* Don't let the exec or mmap label be "*" or "@".
|
||||||
|
*/
|
||||||
|
skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
|
||||||
|
if (skp == &smack_known_star || skp == &smack_known_web)
|
||||||
|
skp = NULL;
|
||||||
|
isp->smk_task = skp;
|
||||||
|
skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp);
|
||||||
|
if (skp == &smack_known_star || skp == &smack_known_web)
|
||||||
|
skp = NULL;
|
||||||
|
isp->smk_mmap = skp;
|
||||||
|
|
||||||
dput(dp);
|
dput(dp);
|
||||||
break;
|
break;
|
||||||
|
@ -3743,8 +3739,6 @@ struct security_operations smack_ops = {
|
||||||
.sb_copy_data = smack_sb_copy_data,
|
.sb_copy_data = smack_sb_copy_data,
|
||||||
.sb_kern_mount = smack_sb_kern_mount,
|
.sb_kern_mount = smack_sb_kern_mount,
|
||||||
.sb_statfs = smack_sb_statfs,
|
.sb_statfs = smack_sb_statfs,
|
||||||
.sb_mount = smack_sb_mount,
|
|
||||||
.sb_umount = smack_sb_umount,
|
|
||||||
|
|
||||||
.bprm_set_creds = smack_bprm_set_creds,
|
.bprm_set_creds = smack_bprm_set_creds,
|
||||||
.bprm_committing_creds = smack_bprm_committing_creds,
|
.bprm_committing_creds = smack_bprm_committing_creds,
|
||||||
|
|
|
@ -52,6 +52,7 @@ enum smk_inos {
|
||||||
SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
|
SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
|
||||||
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
|
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
|
||||||
SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
|
SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
|
||||||
|
SMK_SYSLOG = 20, /* change syslog label) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -59,6 +60,7 @@ enum smk_inos {
|
||||||
*/
|
*/
|
||||||
static DEFINE_MUTEX(smack_cipso_lock);
|
static DEFINE_MUTEX(smack_cipso_lock);
|
||||||
static DEFINE_MUTEX(smack_ambient_lock);
|
static DEFINE_MUTEX(smack_ambient_lock);
|
||||||
|
static DEFINE_MUTEX(smack_syslog_lock);
|
||||||
static DEFINE_MUTEX(smk_netlbladdr_lock);
|
static DEFINE_MUTEX(smk_netlbladdr_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -90,7 +92,13 @@ int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT;
|
||||||
* everyone. It is expected that the hat (^) label
|
* everyone. It is expected that the hat (^) label
|
||||||
* will be used if any label is used.
|
* will be used if any label is used.
|
||||||
*/
|
*/
|
||||||
char *smack_onlycap;
|
struct smack_known *smack_onlycap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this value is set restrict syslog use to the label specified.
|
||||||
|
* It can be reset via smackfs/syslog
|
||||||
|
*/
|
||||||
|
struct smack_known *smack_syslog_label;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Certain IP addresses may be designated as single label hosts.
|
* Certain IP addresses may be designated as single label hosts.
|
||||||
|
@ -301,7 +309,8 @@ static int smk_perm_from_str(const char *string)
|
||||||
* @import: if non-zero, import labels
|
* @import: if non-zero, import labels
|
||||||
* @len: label length limit
|
* @len: label length limit
|
||||||
*
|
*
|
||||||
* Returns 0 on success, -1 on failure
|
* Returns 0 on success, -EINVAL on failure and -ENOENT when either subject
|
||||||
|
* or object is missing.
|
||||||
*/
|
*/
|
||||||
static int smk_fill_rule(const char *subject, const char *object,
|
static int smk_fill_rule(const char *subject, const char *object,
|
||||||
const char *access1, const char *access2,
|
const char *access1, const char *access2,
|
||||||
|
@ -314,28 +323,28 @@ static int smk_fill_rule(const char *subject, const char *object,
|
||||||
if (import) {
|
if (import) {
|
||||||
rule->smk_subject = smk_import_entry(subject, len);
|
rule->smk_subject = smk_import_entry(subject, len);
|
||||||
if (rule->smk_subject == NULL)
|
if (rule->smk_subject == NULL)
|
||||||
return -1;
|
return -EINVAL;
|
||||||
|
|
||||||
rule->smk_object = smk_import(object, len);
|
rule->smk_object = smk_import(object, len);
|
||||||
if (rule->smk_object == NULL)
|
if (rule->smk_object == NULL)
|
||||||
return -1;
|
return -EINVAL;
|
||||||
} else {
|
} else {
|
||||||
cp = smk_parse_smack(subject, len);
|
cp = smk_parse_smack(subject, len);
|
||||||
if (cp == NULL)
|
if (cp == NULL)
|
||||||
return -1;
|
return -EINVAL;
|
||||||
skp = smk_find_entry(cp);
|
skp = smk_find_entry(cp);
|
||||||
kfree(cp);
|
kfree(cp);
|
||||||
if (skp == NULL)
|
if (skp == NULL)
|
||||||
return -1;
|
return -ENOENT;
|
||||||
rule->smk_subject = skp;
|
rule->smk_subject = skp;
|
||||||
|
|
||||||
cp = smk_parse_smack(object, len);
|
cp = smk_parse_smack(object, len);
|
||||||
if (cp == NULL)
|
if (cp == NULL)
|
||||||
return -1;
|
return -EINVAL;
|
||||||
skp = smk_find_entry(cp);
|
skp = smk_find_entry(cp);
|
||||||
kfree(cp);
|
kfree(cp);
|
||||||
if (skp == NULL)
|
if (skp == NULL)
|
||||||
return -1;
|
return -ENOENT;
|
||||||
rule->smk_object = skp->smk_known;
|
rule->smk_object = skp->smk_known;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,6 +390,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
|
||||||
{
|
{
|
||||||
ssize_t cnt = 0;
|
ssize_t cnt = 0;
|
||||||
char *tok[4];
|
char *tok[4];
|
||||||
|
int rc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -405,10 +415,8 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
|
||||||
while (i < 4)
|
while (i < 4)
|
||||||
tok[i++] = NULL;
|
tok[i++] = NULL;
|
||||||
|
|
||||||
if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0))
|
rc = smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0);
|
||||||
return -1;
|
return rc == 0 ? cnt : rc;
|
||||||
|
|
||||||
return cnt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
|
#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
|
||||||
|
@ -1603,7 +1611,7 @@ static const struct file_operations smk_ambient_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_read_onlycap - read() for /smack/onlycap
|
* smk_read_onlycap - read() for smackfs/onlycap
|
||||||
* @filp: file pointer, not actually used
|
* @filp: file pointer, not actually used
|
||||||
* @buf: where to put the result
|
* @buf: where to put the result
|
||||||
* @cn: maximum to send along
|
* @cn: maximum to send along
|
||||||
|
@ -1622,7 +1630,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (smack_onlycap != NULL)
|
if (smack_onlycap != NULL)
|
||||||
smack = smack_onlycap;
|
smack = smack_onlycap->smk_known;
|
||||||
|
|
||||||
asize = strlen(smack) + 1;
|
asize = strlen(smack) + 1;
|
||||||
|
|
||||||
|
@ -1633,7 +1641,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_write_onlycap - write() for /smack/onlycap
|
* smk_write_onlycap - write() for smackfs/onlycap
|
||||||
* @file: file pointer, not actually used
|
* @file: file pointer, not actually used
|
||||||
* @buf: where to get the data from
|
* @buf: where to get the data from
|
||||||
* @count: bytes sent
|
* @count: bytes sent
|
||||||
|
@ -1656,7 +1664,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
|
||||||
* explicitly for clarity. The smk_access() implementation
|
* explicitly for clarity. The smk_access() implementation
|
||||||
* would use smk_access(smack_onlycap, MAY_WRITE)
|
* would use smk_access(smack_onlycap, MAY_WRITE)
|
||||||
*/
|
*/
|
||||||
if (smack_onlycap != NULL && smack_onlycap != skp->smk_known)
|
if (smack_onlycap != NULL && smack_onlycap != skp)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
data = kzalloc(count, GFP_KERNEL);
|
data = kzalloc(count, GFP_KERNEL);
|
||||||
|
@ -1676,7 +1684,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
|
||||||
if (copy_from_user(data, buf, count) != 0)
|
if (copy_from_user(data, buf, count) != 0)
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
else
|
else
|
||||||
smack_onlycap = smk_import(data, count);
|
smack_onlycap = smk_import_entry(data, count);
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -1856,11 +1864,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
|
||||||
res = smk_parse_long_rule(data, &rule, 0, 3);
|
res = smk_parse_long_rule(data, &rule, 0, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res < 0)
|
if (res >= 0)
|
||||||
|
res = smk_access(rule.smk_subject, rule.smk_object,
|
||||||
|
rule.smk_access1, NULL);
|
||||||
|
else if (res != -ENOENT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
res = smk_access(rule.smk_subject, rule.smk_object,
|
|
||||||
rule.smk_access1, NULL);
|
|
||||||
data[0] = res == 0 ? '1' : '0';
|
data[0] = res == 0 ? '1' : '0';
|
||||||
data[1] = '\0';
|
data[1] = '\0';
|
||||||
|
|
||||||
|
@ -2143,7 +2152,7 @@ static ssize_t smk_write_change_rule(struct file *file, const char __user *buf,
|
||||||
/*
|
/*
|
||||||
* Must have privilege.
|
* Must have privilege.
|
||||||
*/
|
*/
|
||||||
if (!capable(CAP_MAC_ADMIN))
|
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,
|
return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,
|
||||||
|
@ -2158,12 +2167,89 @@ static const struct file_operations smk_change_rule_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_fill_super - fill the /smackfs superblock
|
* smk_read_syslog - read() for smackfs/syslog
|
||||||
|
* @filp: file pointer, not actually used
|
||||||
|
* @buf: where to put the result
|
||||||
|
* @cn: maximum to send along
|
||||||
|
* @ppos: where to start
|
||||||
|
*
|
||||||
|
* Returns number of bytes read or error code, as appropriate
|
||||||
|
*/
|
||||||
|
static ssize_t smk_read_syslog(struct file *filp, char __user *buf,
|
||||||
|
size_t cn, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct smack_known *skp;
|
||||||
|
ssize_t rc = -EINVAL;
|
||||||
|
int asize;
|
||||||
|
|
||||||
|
if (*ppos != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (smack_syslog_label == NULL)
|
||||||
|
skp = &smack_known_star;
|
||||||
|
else
|
||||||
|
skp = smack_syslog_label;
|
||||||
|
|
||||||
|
asize = strlen(skp->smk_known) + 1;
|
||||||
|
|
||||||
|
if (cn >= asize)
|
||||||
|
rc = simple_read_from_buffer(buf, cn, ppos, skp->smk_known,
|
||||||
|
asize);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_write_syslog - write() for smackfs/syslog
|
||||||
|
* @file: file pointer, not actually used
|
||||||
|
* @buf: where to get the data from
|
||||||
|
* @count: bytes sent
|
||||||
|
* @ppos: where to start
|
||||||
|
*
|
||||||
|
* Returns number of bytes written or error code, as appropriate
|
||||||
|
*/
|
||||||
|
static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
char *data;
|
||||||
|
struct smack_known *skp;
|
||||||
|
int rc = count;
|
||||||
|
|
||||||
|
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
data = kzalloc(count, GFP_KERNEL);
|
||||||
|
if (data == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (copy_from_user(data, buf, count) != 0)
|
||||||
|
rc = -EFAULT;
|
||||||
|
else {
|
||||||
|
skp = smk_import_entry(data, count);
|
||||||
|
if (skp == NULL)
|
||||||
|
rc = -EINVAL;
|
||||||
|
else
|
||||||
|
smack_syslog_label = smk_import_entry(data, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(data);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations smk_syslog_ops = {
|
||||||
|
.read = smk_read_syslog,
|
||||||
|
.write = smk_write_syslog,
|
||||||
|
.llseek = default_llseek,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_fill_super - fill the smackfs superblock
|
||||||
* @sb: the empty superblock
|
* @sb: the empty superblock
|
||||||
* @data: unused
|
* @data: unused
|
||||||
* @silent: unused
|
* @silent: unused
|
||||||
*
|
*
|
||||||
* Fill in the well known entries for /smack
|
* Fill in the well known entries for the smack filesystem
|
||||||
*
|
*
|
||||||
* Returns 0 on success, an error code on failure
|
* Returns 0 on success, an error code on failure
|
||||||
*/
|
*/
|
||||||
|
@ -2208,6 +2294,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
S_IRUGO|S_IWUSR},
|
S_IRUGO|S_IWUSR},
|
||||||
[SMK_CHANGE_RULE] = {
|
[SMK_CHANGE_RULE] = {
|
||||||
"change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
|
"change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
|
||||||
|
[SMK_SYSLOG] = {
|
||||||
|
"syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR},
|
||||||
/* last one */
|
/* last one */
|
||||||
{""}
|
{""}
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче