Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d80ce80 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of...

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (71 commits)
  SELinux: inode_doinit_with_dentry drop no dentry printk
  SELinux: new permission between tty audit and audit socket
  SELinux: open perm for sock files
  smack: fixes for unlabeled host support
  keys: make procfiles per-user-namespace
  keys: skip keys from another user namespace
  keys: consider user namespace in key_permission
  keys: distinguish per-uid keys in different namespaces
  integrity: ima iint radix_tree_lookup locking fix
  TOMOYO: Do not call tomoyo_realpath_init unless registered.
  integrity: ima scatterlist bug fix
  smack: fix lots of kernel-doc notation
  TOMOYO: Don't create securityfs entries unless registered.
  TOMOYO: Fix exception policy read failure.
  SELinux: convert the avc cache hash list to an hlist
  SELinux: code readability with avc_cache
  SELinux: remove unused av.decided field
  SELinux: more careful use of avd in avc_has_perm_noaudit
  SELinux: remove the unused ae.used
  SELinux: check seqno when updating an avc_node
  ...
parents 1646df40 703a3cd7
Loading
Loading
Loading
Loading
+61 −0
Original line number Diff line number Diff line
What:		security/ima/policy
Date:		May 2008
Contact:	Mimi Zohar <zohar@us.ibm.com>
Description:
		The Trusted Computing Group(TCG) runtime Integrity
		Measurement Architecture(IMA) maintains a list of hash
		values of executables and other sensitive system files
		loaded into the run-time of this system.  At runtime,
		the policy can be constrained based on LSM specific data.
		Policies are loaded into the securityfs file ima/policy
		by opening the file, writing the rules one at a time and
		then closing the file.  The new policy takes effect after
		the file ima/policy is closed.

		rule format: action [condition ...]

		action: measure | dont_measure
		condition:= base | lsm
			base:	[[func=] [mask=] [fsmagic=] [uid=]]
			lsm:	[[subj_user=] [subj_role=] [subj_type=]
				 [obj_user=] [obj_role=] [obj_type=]]

		base: 	func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION]
			mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
			fsmagic:= hex value
			uid:= decimal value
		lsm:  	are LSM specific

		default policy:
			# PROC_SUPER_MAGIC
			dont_measure fsmagic=0x9fa0
			# SYSFS_MAGIC
			dont_measure fsmagic=0x62656572
			# DEBUGFS_MAGIC
			dont_measure fsmagic=0x64626720
			# TMPFS_MAGIC
			dont_measure fsmagic=0x01021994
			# SECURITYFS_MAGIC
			dont_measure fsmagic=0x73636673

			measure func=BPRM_CHECK
			measure func=FILE_MMAP mask=MAY_EXEC
			measure func=INODE_PERM mask=MAY_READ uid=0

		The default policy measures all executables in bprm_check,
		all files mmapped executable in file_mmap, and all files
		open for read by root in inode_permission.

		Examples of LSM specific definitions:

		SELinux:
			# SELINUX_MAGIC
			dont_measure fsmagic=0xF97CFF8C

			dont_measure obj_type=var_log_t
			dont_measure obj_type=auditd_log_t
			measure subj_user=system_u func=INODE_PERM mask=MAY_READ
			measure subj_role=system_r func=INODE_PERM mask=MAY_READ

		Smack:
			measure subj_user=_ func=INODE_PERM mask=MAY_READ
+10 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ parameter is applicable:
	FB	The frame buffer device is enabled.
	HW	Appropriate hardware is enabled.
	IA-64	IA-64 architecture is enabled.
	IMA     Integrity measurement architecture is enabled.
	IOSCHED	More than one I/O scheduler is enabled.
	IP_PNP	IP DHCP, BOOTP, or RARP is enabled.
	ISAPNP	ISA PnP code is enabled.
@@ -902,6 +903,15 @@ and is between 256 and 4096 characters. It is defined in the file
	ihash_entries=	[KNL]
			Set number of hash buckets for inode cache.

	ima_audit=	[IMA]
			Format: { "0" | "1" }
			0 -- integrity auditing messages. (Default)
			1 -- enable informational integrity auditing messages.

	ima_hash=	[IMA]
			Formt: { "sha1" | "md5" }
			default: "sha1"

	in2000=		[HW,SCSI]
			See header of drivers/scsi/in2000.c.

+19 −0
Original line number Diff line number Diff line
@@ -2216,6 +2216,11 @@ M: stefanr@s5r6.in-berlin.de
L:	linux1394-devel@lists.sourceforge.net
S:	Maintained

INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
P:	Mimi Zohar
M:	zohar@us.ibm.com
S:	Supported

IMS TWINTURBO FRAMEBUFFER DRIVER
L:	linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S:	Orphan
@@ -3844,6 +3849,7 @@ M: jmorris@namei.org
L:	linux-kernel@vger.kernel.org
L:	linux-security-module@vger.kernel.org (suggested Cc:)
T:	git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
W:	http://security.wiki.kernel.org/
S:	Supported

SECURITY CONTACT
@@ -4285,6 +4291,19 @@ L: tlan-devel@lists.sourceforge.net (subscribers-only)
W:	http://sourceforge.net/projects/tlan/
S:	Maintained

TOMOYO SECURITY MODULE
P:	Kentaro Takeda
M:	takedakn@nttdata.co.jp
P:	Tetsuo Handa
M:	penguin-kernel@I-love.SAKURA.ne.jp
L:	linux-kernel@vger.kernel.org (kernel issues)
L:	tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English)
L:	tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
L:	tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
W:	http://tomoyo.sourceforge.jp/
T:	quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches/
S:	Maintained

TOSHIBA ACPI EXTRAS DRIVER
P:	John Belmonte
M:	toshiba_acpi@memebeam.org
+248 −282
Original line number Diff line number Diff line
@@ -429,134 +429,148 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
#define TPM_DIGEST_SIZE 20
#define TPM_ERROR_SIZE 10
#define TPM_RET_CODE_IDX 6
#define TPM_GET_CAP_RET_SIZE_IDX 10
#define TPM_GET_CAP_RET_UINT32_1_IDX 14
#define TPM_GET_CAP_RET_UINT32_2_IDX 18
#define TPM_GET_CAP_RET_UINT32_3_IDX 22
#define TPM_GET_CAP_RET_UINT32_4_IDX 26
#define TPM_GET_CAP_PERM_DISABLE_IDX 16
#define TPM_GET_CAP_PERM_INACTIVE_IDX 18
#define TPM_GET_CAP_RET_BOOL_1_IDX 14
#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16

#define TPM_CAP_IDX 13
#define TPM_CAP_SUBCAP_IDX 21

enum tpm_capabilities {
	TPM_CAP_FLAG = 4,
	TPM_CAP_PROP = 5,
	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 = 0x1,
	TPM_CAP_PROP_MANUFACTURER = 0x3,
	TPM_CAP_FLAG_PERM = 0x8,
	TPM_CAP_FLAG_VOL = 0x9,
	TPM_CAP_PROP_OWNER = 0x11,
	TPM_CAP_PROP_TIS_TIMEOUT = 0x15,
	TPM_CAP_PROP_TIS_DURATION = 0x20,
};

/*
 * This is a semi generic GetCapability command for use
 * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG
 * and their associated 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 const u8 tpm_cap[] = {
	0, 193,			/* TPM_TAG_RQU_COMMAND */
	0, 0, 0, 22,		/* length */
	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
	0, 0, 0, 0,		/* TPM_CAP_<TYPE> */
	0, 0, 0, 4,		/* TPM_CAP_SUB_<TYPE> size */
	0, 0, 1, 0		/* TPM_CAP_SUB_<TYPE> */
};

static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len,
			    char *desc)
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, data, len);
	len = tpm_transmit(chip,(u8 *) cmd, len);
	if (len <  0)
		return len;
	if (len == TPM_ERROR_SIZE) {
		err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)));
		err = be32_to_cpu(cmd->header.out.return_code);
		dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
		return err;
	}
	return 0;
}

#define TPM_INTERNAL_RESULT_SIZE 200
#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
#define TPM_ORD_GET_CAP cpu_to_be32(101)

static const struct tpm_input_header tpm_getcap_header = {
	.tag = TPM_TAG_RQU_COMMAND,
	.length = cpu_to_be32(22),
	.ordinal = TPM_ORD_GET_CAP
};

ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
		   const char *desc)
{
	struct tpm_cmd_t tpm_cmd;
	int rc;
	struct tpm_chip *chip = dev_get_drvdata(dev);

	tpm_cmd.header.in = tpm_getcap_header;
	if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
		tpm_cmd.params.getcap_in.cap = subcap_id;
		/*subcap field not necessary */
		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
		tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32));
	} else {
		if (subcap_id == TPM_CAP_FLAG_PERM ||
		    subcap_id == TPM_CAP_FLAG_VOL)
			tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
		else
			tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
		tpm_cmd.params.getcap_in.subcap = subcap_id;
	}
	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
	if (!rc)
		*cap = tpm_cmd.params.getcap_out.cap;
	return rc;
}

void tpm_gen_interrupt(struct tpm_chip *chip)
{
	u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)];
	struct	tpm_cmd_t tpm_cmd;
	ssize_t rc;

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_PROP;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
	tpm_cmd.header.in = tpm_getcap_header;
	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;

	rc = transmit_cmd(chip, data, sizeof(data),
	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
			"attempting to determine the timeouts");
}
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);

void tpm_get_timeouts(struct tpm_chip *chip)
{
	u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)];
	struct tpm_cmd_t tpm_cmd;
	struct timeout_t *timeout_cap;
	struct duration_t *duration_cap;
	ssize_t rc;
	u32 timeout;

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_PROP;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
	tpm_cmd.header.in = tpm_getcap_header;
	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;

	rc = transmit_cmd(chip, data, sizeof(data),
	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
			"attempting to determine the timeouts");
	if (rc)
		goto duration;

	if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX)))
	if (be32_to_cpu(tpm_cmd.header.out.length)
	    != 4 * sizeof(u32))
		goto duration;

	timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
	/* Don't overwrite default if value is 0 */
	timeout =
	    be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
	timeout = be32_to_cpu(timeout_cap->a);
	if (timeout)
		chip->vendor.timeout_a = usecs_to_jiffies(timeout);
	timeout =
	    be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
	timeout = be32_to_cpu(timeout_cap->b);
	if (timeout)
		chip->vendor.timeout_b = usecs_to_jiffies(timeout);
	timeout =
	    be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
	timeout = be32_to_cpu(timeout_cap->c);
	if (timeout)
		chip->vendor.timeout_c = usecs_to_jiffies(timeout);
	timeout =
	    be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
	timeout = be32_to_cpu(timeout_cap->d);
	if (timeout)
		chip->vendor.timeout_d = usecs_to_jiffies(timeout);

duration:
	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_PROP;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION;
	tpm_cmd.header.in = tpm_getcap_header;
	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;

	rc = transmit_cmd(chip, data, sizeof(data),
	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
			"attempting to determine the durations");
	if (rc)
		return;

	if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX)))
	if (be32_to_cpu(tpm_cmd.header.out.return_code)
	    != 3 * sizeof(u32))
		return;

	duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
	chip->vendor.duration[TPM_SHORT] =
	    usecs_to_jiffies(be32_to_cpu
			     (*((__be32 *) (data +
					    TPM_GET_CAP_RET_UINT32_1_IDX))));
	    usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
	/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
	 * value wrong and apparently reports msecs rather than usecs. So we
	 * fix up the resulting too-small TPM_SHORT value to make things work.
@@ -565,13 +579,9 @@ void tpm_get_timeouts(struct tpm_chip *chip)
		chip->vendor.duration[TPM_SHORT] = HZ;

	chip->vendor.duration[TPM_MEDIUM] =
	    usecs_to_jiffies(be32_to_cpu
			     (*((__be32 *) (data +
					    TPM_GET_CAP_RET_UINT32_2_IDX))));
	    usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
	chip->vendor.duration[TPM_LONG] =
	    usecs_to_jiffies(be32_to_cpu
			     (*((__be32 *) (data +
					    TPM_GET_CAP_RET_UINT32_3_IDX))));
	    usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
}
EXPORT_SYMBOL_GPL(tpm_get_timeouts);

@@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip)
}
EXPORT_SYMBOL_GPL(tpm_continue_selftest);

#define  TPM_INTERNAL_RESULT_SIZE 200

ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
			char *buf)
{
	u8 *data;
	cap_t cap;
	ssize_t rc;

	struct tpm_chip *chip = dev_get_drvdata(dev);
	if (chip == NULL)
		return -ENODEV;

	data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_FLAG;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;

	rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
			"attemtping to determine the permanent enabled state");
	if (rc) {
		kfree(data);
	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", !data[TPM_GET_CAP_PERM_DISABLE_IDX]);

	kfree(data);
	rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm_show_enabled);
@@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled);
ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
			char *buf)
{
	u8 *data;
	cap_t cap;
	ssize_t rc;

	struct tpm_chip *chip = dev_get_drvdata(dev);
	if (chip == NULL)
		return -ENODEV;

	data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_FLAG;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;

	rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
			"attemtping to determine the permanent active state");
	if (rc) {
		kfree(data);
	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", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]);

	kfree(data);
	rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm_show_active);
@@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active);
ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
			char *buf)
{
	u8 *data;
	cap_t cap;
	ssize_t rc;

	struct tpm_chip *chip = dev_get_drvdata(dev);
	if (chip == NULL)
		return -ENODEV;

	data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_PROP;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;

	rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
	rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
			 "attempting to determine the owner state");
	if (rc) {
		kfree(data);
	if (rc)
		return 0;
	}

	rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]);

	kfree(data);
	rc = sprintf(buf, "%d\n", cap.owned);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm_show_owned);
@@ -688,116 +648,180 @@ EXPORT_SYMBOL_GPL(tpm_show_owned);
ssize_t tpm_show_temp_deactivated(struct device * dev,
				struct device_attribute * attr, char *buf)
{
	u8 *data;
	cap_t cap;
	ssize_t rc;

	struct tpm_chip *chip = dev_get_drvdata(dev);
	if (chip == NULL)
		return -ENODEV;
	rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
			 "attempting to determine the temporary state");
	if (rc)
		return 0;

	data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;
	rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_FLAG;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
/*
 * tpm_chip_find_get - return tpm_chip for given chip number
 */
static struct tpm_chip *tpm_chip_find_get(int chip_num)
{
	struct tpm_chip *pos, *chip = NULL;

	rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
			"attempting to determine the temporary state");
	if (rc) {
		kfree(data);
		return 0;
	rcu_read_lock();
	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
			continue;

		if (try_module_get(pos->dev->driver->owner)) {
			chip = pos;
			break;
		}
	}
	rcu_read_unlock();
	return chip;
}

	rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]);
#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
#define READ_PCR_RESULT_SIZE 30
static struct tpm_input_header pcrread_header = {
	.tag = TPM_TAG_RQU_COMMAND,
	.length = cpu_to_be32(14),
	.ordinal = TPM_ORDINAL_PCRREAD
};

	kfree(data);
int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
{
	int rc;
	struct tpm_cmd_t cmd;

	cmd.header.in = pcrread_header;
	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
	BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE);
	rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
			  "attempting to read a pcr value");

	if (rc == 0)
		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
		       TPM_DIGEST_SIZE);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);

static const u8 pcrread[] = {
	0, 193,			/* TPM_TAG_RQU_COMMAND */
	0, 0, 0, 14,		/* length */
	0, 0, 0, 21,		/* TPM_ORD_PcrRead */
	0, 0, 0, 0		/* PCR index */
/**
 * tpm_pcr_read - read a pcr value
 * @chip_num: 	tpm idx # or ANY
 * @pcr_idx:	pcr idx to retrieve
 * @res_buf: 	TPM_PCR value
 * 		size of res_buf is 20 bytes (or NULL if you don't care)
 *
 * The TPM driver should be built-in, but for whatever reason it
 * isn't, protect against the chip disappearing, by incrementing
 * the module usage count.
 */
int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
{
	struct tpm_chip *chip;
	int rc;

	chip = tpm_chip_find_get(chip_num);
	if (chip == NULL)
		return -ENODEV;
	rc = __tpm_pcr_read(chip, pcr_idx, res_buf);
	module_put(chip->dev->driver->owner);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm_pcr_read);

/**
 * tpm_pcr_extend - extend pcr value with hash
 * @chip_num: 	tpm idx # or AN&
 * @pcr_idx:	pcr idx to extend
 * @hash: 	hash value used to extend pcr value
 *
 * The TPM driver should be built-in, but for whatever reason it
 * isn't, protect against the chip disappearing, by incrementing
 * the module usage count.
 */
#define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
#define EXTEND_PCR_SIZE 34
static struct tpm_input_header pcrextend_header = {
	.tag = TPM_TAG_RQU_COMMAND,
	.length = cpu_to_be32(34),
	.ordinal = TPM_ORD_PCR_EXTEND
};

int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
{
	struct tpm_cmd_t cmd;
	int rc;
	struct tpm_chip *chip;

	chip = tpm_chip_find_get(chip_num);
	if (chip == NULL)
		return -ENODEV;

	cmd.header.in = pcrextend_header;
	BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE);
	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
	rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
			  "attempting extend a PCR value");

	module_put(chip->dev->driver->owner);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm_pcr_extend);

ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
		      char *buf)
{
	u8 *data;
	cap_t cap;
	u8 digest[TPM_DIGEST_SIZE];
	ssize_t rc;
	int i, j, num_pcrs;
	__be32 index;
	char *str = buf;

	struct tpm_chip *chip = dev_get_drvdata(dev);
	if (chip == NULL)
		return -ENODEV;

	data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_PROP;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR;

	rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
	rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
			"attempting to determine the number of PCRS");
	if (rc) {
		kfree(data);
	if (rc)
		return 0;
	}

	num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
	num_pcrs = be32_to_cpu(cap.num_pcrs);
	for (i = 0; i < num_pcrs; i++) {
		memcpy(data, pcrread, sizeof(pcrread));
		index = cpu_to_be32(i);
		memcpy(data + 10, &index, 4);
		rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
				"attempting to read a PCR");
		rc = __tpm_pcr_read(chip, i, digest);
		if (rc)
			goto out;
			break;
		str += sprintf(str, "PCR-%02d: ", i);
		for (j = 0; j < TPM_DIGEST_SIZE; j++)
			str += sprintf(str, "%02X ", *(data + 10 + j));
			str += sprintf(str, "%02X ", digest[j]);
		str += sprintf(str, "\n");
	}
out:
	kfree(data);
	return str - buf;
}
EXPORT_SYMBOL_GPL(tpm_show_pcrs);

#define  READ_PUBEK_RESULT_SIZE 314
static const u8 readpubek[] = {
	0, 193,			/* TPM_TAG_RQU_COMMAND */
	0, 0, 0, 30,		/* length */
	0, 0, 0, 124,		/* TPM_ORD_ReadPubek */
#define TPM_ORD_READPUBEK cpu_to_be32(124)
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);
	if (chip == NULL)
		return -ENODEV;

	data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	memcpy(data, readpubek, sizeof(readpubek));

	err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE,
	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;
@@ -812,7 +836,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
	   256 byte modulus
	   ignore checksum 20 bytes
	 */

	data = tpm_cmd.params.readpubek_out_buffer;
	str +=
	    sprintf(str,
		    "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
@@ -832,65 +856,33 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
	}
out:
	rc = str - buf;
	kfree(data);
	return rc;
}
EXPORT_SYMBOL_GPL(tpm_show_pubek);

#define CAP_VERSION_1_1 6
#define CAP_VERSION_1_2 0x1A
#define CAP_VERSION_IDX 13
static const u8 cap_version[] = {
	0, 193,			/* TPM_TAG_RQU_COMMAND */
	0, 0, 0, 18,		/* length */
	0, 0, 0, 101,		/* TPM_ORD_GetCapability */
	0, 0, 0, 0,
	0, 0, 0, 0
};

ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
		      char *buf)
{
	u8 *data;
	cap_t cap;
	ssize_t rc;
	char *str = buf;

	struct tpm_chip *chip = dev_get_drvdata(dev);
	if (chip == NULL)
		return -ENODEV;

	data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_PROP;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;

	rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
	rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
			"attempting to determine the manufacturer");
	if (rc) {
		kfree(data);
	if (rc)
		return 0;
	}

	str += sprintf(str, "Manufacturer: 0x%x\n",
		       be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
		       be32_to_cpu(cap.manufacturer_id));

	memcpy(data, cap_version, sizeof(cap_version));
	data[CAP_VERSION_IDX] = CAP_VERSION_1_1;
	rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
	rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
		        "attempting to determine the 1.1 version");
	if (rc)
		goto out;

		return 0;
	str += sprintf(str,
		       "TCG version: %d.%d\nFirmware version: %d.%d\n",
		       (int) data[14], (int) data[15], (int) data[16],
		       (int) data[17]);

out:
	kfree(data);
		       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);
@@ -898,51 +890,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps);
ssize_t tpm_show_caps_1_2(struct device * dev,
			  struct device_attribute * attr, char *buf)
{
	u8 *data;
	ssize_t len;
	cap_t cap;
	ssize_t rc;
	char *str = buf;

	struct tpm_chip *chip = dev_get_drvdata(dev);
	if (chip == NULL)
		return -ENODEV;

	data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	memcpy(data, tpm_cap, sizeof(tpm_cap));
	data[TPM_CAP_IDX] = TPM_CAP_PROP;
	data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;

	len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
	if (len <= TPM_ERROR_SIZE) {
		dev_dbg(chip->dev, "A TPM error (%d) occurred "
			"attempting to determine the manufacturer\n",
			be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
		kfree(data);
	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(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));

	memcpy(data, cap_version, sizeof(cap_version));
	data[CAP_VERSION_IDX] = CAP_VERSION_1_2;

	len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
	if (len <= TPM_ERROR_SIZE) {
		dev_err(chip->dev, "A TPM error (%d) occurred "
			"attempting to determine the 1.2 version\n",
			be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
		goto out;
	}
		       be32_to_cpu(cap.manufacturer_id));
	rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
			 "attempting to determine the 1.2 version");
	if (rc)
		return 0;
	str += sprintf(str,
		       "TCG version: %d.%d\nFirmware version: %d.%d\n",
		       (int) data[16], (int) data[17], (int) data[18],
		       (int) data[19]);

out:
	kfree(data);
		       cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor,
		       cap.tpm_version_1_2.revMajor,
		       cap.tpm_version_1_2.revMinor);
	return str - buf;
}
EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
Loading