mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	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:
		
						commit
						fb2e2c8537
					
				
					 30 changed files with 1007 additions and 1041 deletions
				
			
		|  | @ -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 | ||||||
|  |  | ||||||
							
								
								
									
										213
									
								
								drivers/char/tpm/tpm-dev.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								drivers/char/tpm/tpm-dev.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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,7 +331,7 @@ 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; | ||||||
|  | @ -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: | ||||||
|  |  | ||||||
							
								
								
									
										318
									
								
								drivers/char/tpm/tpm-sysfs.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								drivers/char/tpm/tpm-sysfs.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||||
|  | 		check_import = 1; | ||||||
|  | 	} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || | ||||||
| 		   strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { | 		   strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { | ||||||
| 		if (!smack_privileged(CAP_MAC_ADMIN)) | 		check_priv = 1; | ||||||
| 			rc = -EPERM; | 		check_import = 1; | ||||||
| 		/*
 | 		check_star = 1; | ||||||
| 		 * check label validity here so import wont fail on |  | ||||||
| 		 * post_setxattr |  | ||||||
| 		 */ |  | ||||||
| 		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) | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 		res = smk_access(rule.smk_subject, rule.smk_object, | 		res = smk_access(rule.smk_subject, rule.smk_object, | ||||||
| 				 rule.smk_access1, NULL); | 				 rule.smk_access1, NULL); | ||||||
|  | 	else if (res != -ENOENT) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
| 	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 */ | ||||||
| 			{""} | 			{""} | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds