diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-03 00:38:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-03 00:38:48 -0400 |
| commit | 88265322c14cce39f7afbc416726ef4fac413298 (patch) | |
| tree | e4956f905ef617971f87788d8f8a09dbb66b70a3 | |
| parent | 65b99c74fdd325d1ffa2e5663295888704712604 (diff) | |
| parent | bf5308344527d015ac9a6d2bda4ad4d40fd7d943 (diff) | |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"Highlights:
- Integrity: add local fs integrity verification to detect offline
attacks
- Integrity: add digital signature verification
- Simple stacking of Yama with other LSMs (per LSS discussions)
- IBM vTPM support on ppc64
- Add new driver for Infineon I2C TIS TPM
- Smack: add rule revocation for subject labels"
Fixed conflicts with the user namespace support in kernel/auditsc.c and
security/integrity/ima/ima_policy.c.
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (39 commits)
Documentation: Update git repository URL for Smack userland tools
ima: change flags container data type
Smack: setprocattr memory leak fix
Smack: implement revoking all rules for a subject label
Smack: remove task_wait() hook.
ima: audit log hashes
ima: generic IMA action flag handling
ima: rename ima_must_appraise_or_measure
audit: export audit_log_task_info
tpm: fix tpm_acpi sparse warning on different address spaces
samples/seccomp: fix 31 bit build on s390
ima: digital signature verification support
ima: add support for different security.ima data types
ima: add ima_inode_setxattr/removexattr function and calls
ima: add inode_post_setattr call
ima: replace iint spinblock with rwlock/read_lock
ima: allocating iint improvements
ima: add appraise action keywords and default rules
ima: integrity appraisal extension
vfs: move ima_file_free before releasing the file
...
52 files changed, 3546 insertions, 463 deletions
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 6cd6daefaaed..986946613542 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy | |||
| @@ -12,11 +12,14 @@ Description: | |||
| 12 | then closing the file. The new policy takes effect after | 12 | then closing the file. The new policy takes effect after |
| 13 | the file ima/policy is closed. | 13 | the file ima/policy is closed. |
| 14 | 14 | ||
| 15 | IMA appraisal, if configured, uses these file measurements | ||
| 16 | for local measurement appraisal. | ||
| 17 | |||
| 15 | rule format: action [condition ...] | 18 | rule format: action [condition ...] |
| 16 | 19 | ||
| 17 | action: measure | dont_measure | 20 | action: measure | dont_measure | appraise | dont_appraise | audit |
| 18 | condition:= base | lsm | 21 | condition:= base | lsm |
| 19 | base: [[func=] [mask=] [fsmagic=] [uid=]] | 22 | base: [[func=] [mask=] [fsmagic=] [uid=] [fowner]] |
| 20 | lsm: [[subj_user=] [subj_role=] [subj_type=] | 23 | lsm: [[subj_user=] [subj_role=] [subj_type=] |
| 21 | [obj_user=] [obj_role=] [obj_type=]] | 24 | [obj_user=] [obj_role=] [obj_type=]] |
| 22 | 25 | ||
| @@ -24,36 +27,50 @@ Description: | |||
| 24 | mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] | 27 | mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] |
| 25 | fsmagic:= hex value | 28 | fsmagic:= hex value |
| 26 | uid:= decimal value | 29 | uid:= decimal value |
| 30 | fowner:=decimal value | ||
| 27 | lsm: are LSM specific | 31 | lsm: are LSM specific |
| 28 | 32 | ||
| 29 | default policy: | 33 | default policy: |
| 30 | # PROC_SUPER_MAGIC | 34 | # PROC_SUPER_MAGIC |
| 31 | dont_measure fsmagic=0x9fa0 | 35 | dont_measure fsmagic=0x9fa0 |
| 36 | dont_appraise fsmagic=0x9fa0 | ||
| 32 | # SYSFS_MAGIC | 37 | # SYSFS_MAGIC |
| 33 | dont_measure fsmagic=0x62656572 | 38 | dont_measure fsmagic=0x62656572 |
| 39 | dont_appraise fsmagic=0x62656572 | ||
| 34 | # DEBUGFS_MAGIC | 40 | # DEBUGFS_MAGIC |
| 35 | dont_measure fsmagic=0x64626720 | 41 | dont_measure fsmagic=0x64626720 |
| 42 | dont_appraise fsmagic=0x64626720 | ||
| 36 | # TMPFS_MAGIC | 43 | # TMPFS_MAGIC |
| 37 | dont_measure fsmagic=0x01021994 | 44 | dont_measure fsmagic=0x01021994 |
| 45 | dont_appraise fsmagic=0x01021994 | ||
| 46 | # RAMFS_MAGIC | ||
| 47 | dont_measure fsmagic=0x858458f6 | ||
| 48 | dont_appraise fsmagic=0x858458f6 | ||
| 38 | # SECURITYFS_MAGIC | 49 | # SECURITYFS_MAGIC |
| 39 | dont_measure fsmagic=0x73636673 | 50 | dont_measure fsmagic=0x73636673 |
| 51 | dont_appraise fsmagic=0x73636673 | ||
| 40 | 52 | ||
| 41 | measure func=BPRM_CHECK | 53 | measure func=BPRM_CHECK |
| 42 | measure func=FILE_MMAP mask=MAY_EXEC | 54 | measure func=FILE_MMAP mask=MAY_EXEC |
| 43 | measure func=FILE_CHECK mask=MAY_READ uid=0 | 55 | measure func=FILE_CHECK mask=MAY_READ uid=0 |
| 56 | appraise fowner=0 | ||
| 44 | 57 | ||
| 45 | The default policy measures all executables in bprm_check, | 58 | The default policy measures all executables in bprm_check, |
| 46 | all files mmapped executable in file_mmap, and all files | 59 | all files mmapped executable in file_mmap, and all files |
| 47 | open for read by root in do_filp_open. | 60 | open for read by root in do_filp_open. The default appraisal |
| 61 | policy appraises all files owned by root. | ||
| 48 | 62 | ||
| 49 | Examples of LSM specific definitions: | 63 | Examples of LSM specific definitions: |
| 50 | 64 | ||
| 51 | SELinux: | 65 | SELinux: |
| 52 | # SELINUX_MAGIC | 66 | # SELINUX_MAGIC |
| 53 | dont_measure fsmagic=0xF97CFF8C | 67 | dont_measure fsmagic=0xf97cff8c |
| 68 | dont_appraise fsmagic=0xf97cff8c | ||
| 54 | 69 | ||
| 55 | dont_measure obj_type=var_log_t | 70 | dont_measure obj_type=var_log_t |
| 71 | dont_appraise obj_type=var_log_t | ||
| 56 | dont_measure obj_type=auditd_log_t | 72 | dont_measure obj_type=auditd_log_t |
| 73 | dont_appraise obj_type=auditd_log_t | ||
| 57 | measure subj_user=system_u func=FILE_CHECK mask=MAY_READ | 74 | measure subj_user=system_u func=FILE_CHECK mask=MAY_READ |
| 58 | measure subj_role=system_r func=FILE_CHECK mask=MAY_READ | 75 | measure subj_role=system_r func=FILE_CHECK mask=MAY_READ |
| 59 | 76 | ||
diff --git a/Documentation/ABI/testing/sysfs-driver-ppi b/Documentation/ABI/testing/sysfs-driver-ppi new file mode 100644 index 000000000000..97a003ee058b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-ppi | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | What: /sys/devices/pnp0/<bus-num>/ppi/ | ||
| 2 | Date: August 2012 | ||
| 3 | Kernel Version: 3.6 | ||
| 4 | Contact: xiaoyan.zhang@intel.com | ||
| 5 | Description: | ||
| 6 | This folder includes the attributes related with PPI (Physical | ||
| 7 | Presence Interface). Only if TPM is supported by BIOS, this | ||
| 8 | folder makes sence. The folder path can be got by command | ||
| 9 | 'find /sys/ -name 'pcrs''. For the detail information of PPI, | ||
| 10 | please refer to the PPI specification from | ||
| 11 | http://www.trustedcomputinggroup.org/ | ||
| 12 | |||
| 13 | What: /sys/devices/pnp0/<bus-num>/ppi/version | ||
| 14 | Date: August 2012 | ||
| 15 | Contact: xiaoyan.zhang@intel.com | ||
| 16 | Description: | ||
| 17 | This attribute shows the version of the PPI supported by the | ||
| 18 | platform. | ||
| 19 | This file is readonly. | ||
| 20 | |||
| 21 | What: /sys/devices/pnp0/<bus-num>/ppi/request | ||
| 22 | Date: August 2012 | ||
| 23 | Contact: xiaoyan.zhang@intel.com | ||
| 24 | Description: | ||
| 25 | This attribute shows the request for an operation to be | ||
| 26 | executed in the pre-OS environment. It is the only input from | ||
| 27 | the OS to the pre-OS environment. The request should be an | ||
| 28 | integer value range from 1 to 160, and 0 means no request. | ||
| 29 | This file can be read and written. | ||
| 30 | |||
| 31 | What: /sys/devices/pnp0/00:<bus-num>/ppi/response | ||
| 32 | Date: August 2012 | ||
| 33 | Contact: xiaoyan.zhang@intel.com | ||
| 34 | Description: | ||
| 35 | This attribute shows the response to the most recent operation | ||
| 36 | request it acted upon. The format is "<request> <response num> | ||
| 37 | : <response description>". | ||
| 38 | This file is readonly. | ||
| 39 | |||
| 40 | What: /sys/devices/pnp0/<bus-num>/ppi/transition_action | ||
| 41 | Date: August 2012 | ||
| 42 | Contact: xiaoyan.zhang@intel.com | ||
| 43 | Description: | ||
| 44 | This attribute shows the platform-specific action that should | ||
| 45 | take place in order to transition to the BIOS for execution of | ||
| 46 | a requested operation. The format is "<action num>: <action | ||
| 47 | description>". | ||
| 48 | This file is readonly. | ||
| 49 | |||
| 50 | What: /sys/devices/pnp0/<bus-num>/ppi/tcg_operations | ||
| 51 | Date: August 2012 | ||
| 52 | Contact: xiaoyan.zhang@intel.com | ||
| 53 | Description: | ||
| 54 | This attribute shows whether it is allowed to request an | ||
| 55 | operation to be executed in the pre-OS environment by the BIOS | ||
| 56 | for the requests defined by TCG, i.e. requests from 1 to 22. | ||
| 57 | The format is "<request> <status num>: <status description>". | ||
| 58 | This attribute is only supported by PPI version 1.2+. | ||
| 59 | This file is readonly. | ||
| 60 | |||
| 61 | What: /sys/devices/pnp0/<bus-num>/ppi/vs_operations | ||
| 62 | Date: August 2012 | ||
| 63 | Contact: xiaoyan.zhang@intel.com | ||
| 64 | Description: | ||
| 65 | This attribute shows whether it is allowed to request an | ||
| 66 | operation to be executed in the pre-OS environment by the BIOS | ||
| 67 | for the verdor specific requests, i.e. requests from 128 to | ||
| 68 | 255. The format is same with tcg_operations. This attribute | ||
| 69 | is also only supported by PPI version 1.2+. | ||
| 70 | This file is readonly. | ||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index aab409f335bf..f777fa96243d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -1051,6 +1051,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 1051 | ihash_entries= [KNL] | 1051 | ihash_entries= [KNL] |
| 1052 | Set number of hash buckets for inode cache. | 1052 | Set number of hash buckets for inode cache. |
| 1053 | 1053 | ||
| 1054 | ima_appraise= [IMA] appraise integrity measurements | ||
| 1055 | Format: { "off" | "enforce" | "fix" } | ||
| 1056 | default: "enforce" | ||
| 1057 | |||
| 1058 | ima_appraise_tcb [IMA] | ||
| 1059 | The builtin appraise policy appraises all files | ||
| 1060 | owned by uid=0. | ||
| 1061 | |||
| 1054 | ima_audit= [IMA] | 1062 | ima_audit= [IMA] |
| 1055 | Format: { "0" | "1" } | 1063 | Format: { "0" | "1" } |
| 1056 | 0 -- integrity auditing messages. (Default) | 1064 | 0 -- integrity auditing messages. (Default) |
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt index a416479b8a1c..8a177e4b6e21 100644 --- a/Documentation/security/Smack.txt +++ b/Documentation/security/Smack.txt | |||
| @@ -28,12 +28,11 @@ Smack kernels use the CIPSO IP option. Some network | |||
| 28 | configurations are intolerant of IP options and can impede | 28 | configurations are intolerant of IP options and can impede |
| 29 | access to systems that use them as Smack does. | 29 | access to systems that use them as Smack does. |
| 30 | 30 | ||
| 31 | The current git repositories for Smack user space are: | 31 | The current git repository for Smack user space is: |
| 32 | 32 | ||
| 33 | git@gitorious.org:meego-platform-security/smackutil.git | 33 | git://github.com/smack-team/smack.git |
| 34 | git@gitorious.org:meego-platform-security/libsmack.git | ||
| 35 | 34 | ||
| 36 | These should make and install on most modern distributions. | 35 | This should make and install on most modern distributions. |
| 37 | There are three commands included in smackutil: | 36 | There are three commands included in smackutil: |
| 38 | 37 | ||
| 39 | smackload - properly formats data for writing to /smack/load | 38 | smackload - properly formats data for writing to /smack/load |
| @@ -194,6 +193,9 @@ onlycap | |||
| 194 | these capabilities are effective at for processes with any | 193 | these capabilities are effective at for processes with any |
| 195 | label. The value is set by writing the desired label to the | 194 | label. The value is set by writing the desired label to the |
| 196 | file or cleared by writing "-" to the file. | 195 | file or cleared by writing "-" to the file. |
| 196 | revoke-subject | ||
| 197 | Writing a Smack label here sets the access to '-' for all access | ||
| 198 | rules with that subject label. | ||
| 197 | 199 | ||
| 198 | You can add access rules in /etc/smack/accesses. They take the form: | 200 | You can add access rules in /etc/smack/accesses. They take the form: |
| 199 | 201 | ||
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 0794a3017b1b..e144498bcddd 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
| @@ -1624,6 +1624,63 @@ static void __init prom_instantiate_rtas(void) | |||
| 1624 | 1624 | ||
| 1625 | #ifdef CONFIG_PPC64 | 1625 | #ifdef CONFIG_PPC64 |
| 1626 | /* | 1626 | /* |
| 1627 | * Allocate room for and instantiate Stored Measurement Log (SML) | ||
| 1628 | */ | ||
| 1629 | static void __init prom_instantiate_sml(void) | ||
| 1630 | { | ||
| 1631 | phandle ibmvtpm_node; | ||
| 1632 | ihandle ibmvtpm_inst; | ||
| 1633 | u32 entry = 0, size = 0; | ||
| 1634 | u64 base; | ||
| 1635 | |||
| 1636 | prom_debug("prom_instantiate_sml: start...\n"); | ||
| 1637 | |||
| 1638 | ibmvtpm_node = call_prom("finddevice", 1, 1, ADDR("/ibm,vtpm")); | ||
| 1639 | prom_debug("ibmvtpm_node: %x\n", ibmvtpm_node); | ||
| 1640 | if (!PHANDLE_VALID(ibmvtpm_node)) | ||
| 1641 | return; | ||
| 1642 | |||
| 1643 | ibmvtpm_inst = call_prom("open", 1, 1, ADDR("/ibm,vtpm")); | ||
| 1644 | if (!IHANDLE_VALID(ibmvtpm_inst)) { | ||
| 1645 | prom_printf("opening vtpm package failed (%x)\n", ibmvtpm_inst); | ||
| 1646 | return; | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | if (call_prom_ret("call-method", 2, 2, &size, | ||
| 1650 | ADDR("sml-get-handover-size"), | ||
| 1651 | ibmvtpm_inst) != 0 || size == 0) { | ||
| 1652 | prom_printf("SML get handover size failed\n"); | ||
| 1653 | return; | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | base = alloc_down(size, PAGE_SIZE, 0); | ||
| 1657 | if (base == 0) | ||
| 1658 | prom_panic("Could not allocate memory for sml\n"); | ||
| 1659 | |||
| 1660 | prom_printf("instantiating sml at 0x%x...", base); | ||
| 1661 | |||
| 1662 | if (call_prom_ret("call-method", 4, 2, &entry, | ||
| 1663 | ADDR("sml-handover"), | ||
| 1664 | ibmvtpm_inst, size, base) != 0 || entry == 0) { | ||
| 1665 | prom_printf("SML handover failed\n"); | ||
| 1666 | return; | ||
| 1667 | } | ||
| 1668 | prom_printf(" done\n"); | ||
| 1669 | |||
| 1670 | reserve_mem(base, size); | ||
| 1671 | |||
| 1672 | prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-base", | ||
| 1673 | &base, sizeof(base)); | ||
| 1674 | prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-size", | ||
| 1675 | &size, sizeof(size)); | ||
| 1676 | |||
| 1677 | prom_debug("sml base = 0x%x\n", base); | ||
| 1678 | prom_debug("sml size = 0x%x\n", (long)size); | ||
| 1679 | |||
| 1680 | prom_debug("prom_instantiate_sml: end...\n"); | ||
| 1681 | } | ||
| 1682 | |||
| 1683 | /* | ||
| 1627 | * Allocate room for and initialize TCE tables | 1684 | * Allocate room for and initialize TCE tables |
| 1628 | */ | 1685 | */ |
| 1629 | static void __init prom_initialize_tce_table(void) | 1686 | static void __init prom_initialize_tce_table(void) |
| @@ -2916,6 +2973,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
| 2916 | prom_instantiate_opal(); | 2973 | prom_instantiate_opal(); |
| 2917 | #endif | 2974 | #endif |
| 2918 | 2975 | ||
| 2976 | #ifdef CONFIG_PPC64 | ||
| 2977 | /* instantiate sml */ | ||
| 2978 | prom_instantiate_sml(); | ||
| 2979 | #endif | ||
| 2980 | |||
| 2919 | /* | 2981 | /* |
| 2920 | * On non-powermacs, put all CPUs in spin-loops. | 2982 | * On non-powermacs, put all CPUs in spin-loops. |
| 2921 | * | 2983 | * |
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 7c0d391996b5..fbd9b2b850ef 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
| @@ -289,3 +289,16 @@ config HW_RANDOM_EXYNOS | |||
| 289 | module will be called exynos-rng. | 289 | module will be called exynos-rng. |
| 290 | 290 | ||
| 291 | If unsure, say Y. | 291 | If unsure, say Y. |
| 292 | |||
| 293 | config HW_RANDOM_TPM | ||
| 294 | tristate "TPM HW Random Number Generator support" | ||
| 295 | depends on HW_RANDOM && TCG_TPM | ||
| 296 | default HW_RANDOM | ||
| 297 | ---help--- | ||
| 298 | This driver provides kernel-side support for the Random Number | ||
| 299 | Generator in the Trusted Platform Module | ||
| 300 | |||
| 301 | To compile this driver as a module, choose M here: the | ||
| 302 | module will be called tpm-rng. | ||
| 303 | |||
| 304 | If unsure, say Y. | ||
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 39a757ca15b6..1fd7eec9fbf6 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile | |||
| @@ -25,3 +25,4 @@ obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o | |||
| 25 | obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o | 25 | obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o |
| 26 | obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o | 26 | obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o |
| 27 | obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o | 27 | obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o |
| 28 | obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o | ||
diff --git a/drivers/char/hw_random/tpm-rng.c b/drivers/char/hw_random/tpm-rng.c new file mode 100644 index 000000000000..d6d448266f07 --- /dev/null +++ b/drivers/char/hw_random/tpm-rng.c | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Kent Yoder IBM Corporation | ||
| 3 | * | ||
| 4 | * HWRNG interfaces to pull RNG data from a TPM | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/hw_random.h> | ||
| 22 | #include <linux/tpm.h> | ||
| 23 | |||
| 24 | #define MODULE_NAME "tpm-rng" | ||
| 25 | |||
| 26 | static int tpm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) | ||
| 27 | { | ||
| 28 | return tpm_get_random(TPM_ANY_NUM, data, max); | ||
| 29 | } | ||
| 30 | |||
| 31 | static struct hwrng tpm_rng = { | ||
| 32 | .name = MODULE_NAME, | ||
| 33 | .read = tpm_rng_read, | ||
| 34 | }; | ||
| 35 | |||
| 36 | static int __init rng_init(void) | ||
| 37 | { | ||
| 38 | return hwrng_register(&tpm_rng); | ||
| 39 | } | ||
| 40 | module_init(rng_init); | ||
| 41 | |||
| 42 | static void __exit rng_exit(void) | ||
| 43 | { | ||
| 44 | hwrng_unregister(&tpm_rng); | ||
| 45 | } | ||
| 46 | module_exit(rng_exit); | ||
| 47 | |||
| 48 | MODULE_LICENSE("GPL v2"); | ||
| 49 | MODULE_AUTHOR("Kent Yoder <key@linux.vnet.ibm.com>"); | ||
| 50 | MODULE_DESCRIPTION("RNG driver for TPM devices"); | ||
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index a048199ce866..915875e431d2 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig | |||
| @@ -33,6 +33,17 @@ config TCG_TIS | |||
| 33 | from within Linux. To compile this driver as a module, choose | 33 | from within Linux. To compile this driver as a module, choose |
| 34 | M here; the module will be called tpm_tis. | 34 | M here; the module will be called tpm_tis. |
| 35 | 35 | ||
| 36 | config TCG_TIS_I2C_INFINEON | ||
| 37 | tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)" | ||
| 38 | depends on I2C | ||
| 39 | ---help--- | ||
| 40 | If you have a TPM security chip that is compliant with the | ||
| 41 | TCG TIS 1.2 TPM specification and Infineon's I2C Protocol Stack | ||
| 42 | Specification 0.20 say Yes and it will be accessible from within | ||
| 43 | Linux. | ||
| 44 | To compile this driver as a module, choose M here; the module | ||
| 45 | will be called tpm_tis_i2c_infineon. | ||
| 46 | |||
| 36 | config TCG_NSC | 47 | config TCG_NSC |
| 37 | tristate "National Semiconductor TPM Interface" | 48 | tristate "National Semiconductor TPM Interface" |
| 38 | depends on X86 | 49 | depends on X86 |
| @@ -62,4 +73,12 @@ config TCG_INFINEON | |||
| 62 | Further information on this driver and the supported hardware | 73 | Further information on this driver and the supported hardware |
| 63 | can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ | 74 | can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ |
| 64 | 75 | ||
| 76 | config TCG_IBMVTPM | ||
| 77 | tristate "IBM VTPM Interface" | ||
| 78 | depends on PPC64 | ||
| 79 | ---help--- | ||
| 80 | If you have IBM virtual TPM (VTPM) support say Yes and it | ||
| 81 | will be accessible from within Linux. To compile this driver | ||
| 82 | as a module, choose M here; the module will be called tpm_ibmvtpm. | ||
| 83 | |||
| 65 | endif # TCG_TPM | 84 | endif # TCG_TPM |
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index ea3a1e02a824..5b3fc8bc6c13 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile | |||
| @@ -4,8 +4,16 @@ | |||
| 4 | obj-$(CONFIG_TCG_TPM) += tpm.o | 4 | obj-$(CONFIG_TCG_TPM) += tpm.o |
| 5 | ifdef CONFIG_ACPI | 5 | ifdef CONFIG_ACPI |
| 6 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o | 6 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o |
| 7 | tpm_bios-objs += tpm_eventlog.o tpm_acpi.o tpm_ppi.o | ||
| 8 | else | ||
| 9 | ifdef CONFIG_TCG_IBMVTPM | ||
| 10 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o | ||
| 11 | tpm_bios-objs += tpm_eventlog.o tpm_of.o | ||
| 12 | endif | ||
| 7 | endif | 13 | endif |
| 8 | obj-$(CONFIG_TCG_TIS) += tpm_tis.o | 14 | obj-$(CONFIG_TCG_TIS) += tpm_tis.o |
| 15 | obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o | ||
| 9 | obj-$(CONFIG_TCG_NSC) += tpm_nsc.o | 16 | obj-$(CONFIG_TCG_NSC) += tpm_nsc.o |
| 10 | obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o | 17 | obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o |
| 11 | obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o | 18 | obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o |
| 19 | obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o | ||
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 3af9f4d1a23f..f26afdb1a702 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
| @@ -30,12 +30,7 @@ | |||
| 30 | #include <linux/freezer.h> | 30 | #include <linux/freezer.h> |
| 31 | 31 | ||
| 32 | #include "tpm.h" | 32 | #include "tpm.h" |
| 33 | 33 | #include "tpm_eventlog.h" | |
| 34 | enum tpm_const { | ||
| 35 | TPM_MINOR = 224, /* officially assigned */ | ||
| 36 | TPM_BUFSIZE = 4096, | ||
| 37 | TPM_NUM_DEVICES = 256, | ||
| 38 | }; | ||
| 39 | 34 | ||
| 40 | enum tpm_duration { | 35 | enum tpm_duration { |
| 41 | TPM_SHORT = 0, | 36 | TPM_SHORT = 0, |
| @@ -482,6 +477,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, | |||
| 482 | #define TPM_INTERNAL_RESULT_SIZE 200 | 477 | #define TPM_INTERNAL_RESULT_SIZE 200 |
| 483 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) | 478 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) |
| 484 | #define TPM_ORD_GET_CAP cpu_to_be32(101) | 479 | #define TPM_ORD_GET_CAP cpu_to_be32(101) |
| 480 | #define TPM_ORD_GET_RANDOM cpu_to_be32(70) | ||
| 485 | 481 | ||
| 486 | static const struct tpm_input_header tpm_getcap_header = { | 482 | static const struct tpm_input_header tpm_getcap_header = { |
| 487 | .tag = TPM_TAG_RQU_COMMAND, | 483 | .tag = TPM_TAG_RQU_COMMAND, |
| @@ -919,7 +915,7 @@ EXPORT_SYMBOL_GPL(tpm_show_pcrs); | |||
| 919 | 915 | ||
| 920 | #define READ_PUBEK_RESULT_SIZE 314 | 916 | #define READ_PUBEK_RESULT_SIZE 314 |
| 921 | #define TPM_ORD_READPUBEK cpu_to_be32(124) | 917 | #define TPM_ORD_READPUBEK cpu_to_be32(124) |
| 922 | struct tpm_input_header tpm_readpubek_header = { | 918 | static struct tpm_input_header tpm_readpubek_header = { |
| 923 | .tag = TPM_TAG_RQU_COMMAND, | 919 | .tag = TPM_TAG_RQU_COMMAND, |
| 924 | .length = cpu_to_be32(30), | 920 | .length = cpu_to_be32(30), |
| 925 | .ordinal = TPM_ORD_READPUBEK | 921 | .ordinal = TPM_ORD_READPUBEK |
| @@ -1175,7 +1171,7 @@ int tpm_release(struct inode *inode, struct file *file) | |||
| 1175 | flush_work(&chip->work); | 1171 | flush_work(&chip->work); |
| 1176 | file->private_data = NULL; | 1172 | file->private_data = NULL; |
| 1177 | atomic_set(&chip->data_pending, 0); | 1173 | atomic_set(&chip->data_pending, 0); |
| 1178 | kfree(chip->data_buffer); | 1174 | kzfree(chip->data_buffer); |
| 1179 | clear_bit(0, &chip->is_open); | 1175 | clear_bit(0, &chip->is_open); |
| 1180 | put_device(chip->dev); | 1176 | put_device(chip->dev); |
| 1181 | return 0; | 1177 | return 0; |
| @@ -1227,7 +1223,6 @@ ssize_t tpm_read(struct file *file, char __user *buf, | |||
| 1227 | del_singleshot_timer_sync(&chip->user_read_timer); | 1223 | del_singleshot_timer_sync(&chip->user_read_timer); |
| 1228 | flush_work(&chip->work); | 1224 | flush_work(&chip->work); |
| 1229 | ret_size = atomic_read(&chip->data_pending); | 1225 | ret_size = atomic_read(&chip->data_pending); |
| 1230 | atomic_set(&chip->data_pending, 0); | ||
| 1231 | if (ret_size > 0) { /* relay data */ | 1226 | if (ret_size > 0) { /* relay data */ |
| 1232 | ssize_t orig_ret_size = ret_size; | 1227 | ssize_t orig_ret_size = ret_size; |
| 1233 | if (size < ret_size) | 1228 | if (size < ret_size) |
| @@ -1242,6 +1237,8 @@ ssize_t tpm_read(struct file *file, char __user *buf, | |||
| 1242 | mutex_unlock(&chip->buffer_mutex); | 1237 | mutex_unlock(&chip->buffer_mutex); |
| 1243 | } | 1238 | } |
| 1244 | 1239 | ||
| 1240 | atomic_set(&chip->data_pending, 0); | ||
| 1241 | |||
| 1245 | return ret_size; | 1242 | return ret_size; |
| 1246 | } | 1243 | } |
| 1247 | EXPORT_SYMBOL_GPL(tpm_read); | 1244 | EXPORT_SYMBOL_GPL(tpm_read); |
| @@ -1326,6 +1323,58 @@ int tpm_pm_resume(struct device *dev) | |||
| 1326 | } | 1323 | } |
| 1327 | EXPORT_SYMBOL_GPL(tpm_pm_resume); | 1324 | EXPORT_SYMBOL_GPL(tpm_pm_resume); |
| 1328 | 1325 | ||
| 1326 | #define TPM_GETRANDOM_RESULT_SIZE 18 | ||
| 1327 | static struct tpm_input_header tpm_getrandom_header = { | ||
| 1328 | .tag = TPM_TAG_RQU_COMMAND, | ||
| 1329 | .length = cpu_to_be32(14), | ||
| 1330 | .ordinal = TPM_ORD_GET_RANDOM | ||
| 1331 | }; | ||
| 1332 | |||
| 1333 | /** | ||
| 1334 | * tpm_get_random() - Get random bytes from the tpm's RNG | ||
| 1335 | * @chip_num: A specific chip number for the request or TPM_ANY_NUM | ||
| 1336 | * @out: destination buffer for the random bytes | ||
| 1337 | * @max: the max number of bytes to write to @out | ||
| 1338 | * | ||
| 1339 | * Returns < 0 on error and the number of bytes read on success | ||
| 1340 | */ | ||
| 1341 | int tpm_get_random(u32 chip_num, u8 *out, size_t max) | ||
| 1342 | { | ||
| 1343 | struct tpm_chip *chip; | ||
| 1344 | struct tpm_cmd_t tpm_cmd; | ||
| 1345 | u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); | ||
| 1346 | int err, total = 0, retries = 5; | ||
| 1347 | u8 *dest = out; | ||
| 1348 | |||
| 1349 | chip = tpm_chip_find_get(chip_num); | ||
| 1350 | if (chip == NULL) | ||
| 1351 | return -ENODEV; | ||
| 1352 | |||
| 1353 | if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) | ||
| 1354 | return -EINVAL; | ||
| 1355 | |||
| 1356 | do { | ||
| 1357 | tpm_cmd.header.in = tpm_getrandom_header; | ||
| 1358 | tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); | ||
| 1359 | |||
| 1360 | err = transmit_cmd(chip, &tpm_cmd, | ||
| 1361 | TPM_GETRANDOM_RESULT_SIZE + num_bytes, | ||
| 1362 | "attempting get random"); | ||
| 1363 | if (err) | ||
| 1364 | break; | ||
| 1365 | |||
| 1366 | recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); | ||
| 1367 | memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); | ||
| 1368 | |||
| 1369 | dest += recd; | ||
| 1370 | total += recd; | ||
| 1371 | num_bytes -= recd; | ||
| 1372 | } while (retries-- && total < max); | ||
| 1373 | |||
| 1374 | return total ? total : -EIO; | ||
| 1375 | } | ||
| 1376 | EXPORT_SYMBOL_GPL(tpm_get_random); | ||
| 1377 | |||
| 1329 | /* In case vendor provided release function, call it too.*/ | 1378 | /* In case vendor provided release function, call it too.*/ |
| 1330 | 1379 | ||
| 1331 | void tpm_dev_vendor_release(struct tpm_chip *chip) | 1380 | void tpm_dev_vendor_release(struct tpm_chip *chip) |
| @@ -1346,7 +1395,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); | |||
| 1346 | * Once all references to platform device are down to 0, | 1395 | * Once all references to platform device are down to 0, |
| 1347 | * release all allocated structures. | 1396 | * release all allocated structures. |
| 1348 | */ | 1397 | */ |
| 1349 | void tpm_dev_release(struct device *dev) | 1398 | static void tpm_dev_release(struct device *dev) |
| 1350 | { | 1399 | { |
| 1351 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1400 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| 1352 | 1401 | ||
| @@ -1427,6 +1476,11 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
| 1427 | goto put_device; | 1476 | goto put_device; |
| 1428 | } | 1477 | } |
| 1429 | 1478 | ||
| 1479 | if (sys_add_ppi(&dev->kobj)) { | ||
| 1480 | misc_deregister(&chip->vendor.miscdev); | ||
| 1481 | goto put_device; | ||
| 1482 | } | ||
| 1483 | |||
| 1430 | chip->bios_dir = tpm_bios_log_setup(devname); | 1484 | chip->bios_dir = tpm_bios_log_setup(devname); |
| 1431 | 1485 | ||
| 1432 | /* Make chip available */ | 1486 | /* Make chip available */ |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 917f727e6740..02c266aa2bf7 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
| @@ -28,6 +28,12 @@ | |||
| 28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
| 29 | #include <linux/tpm.h> | 29 | #include <linux/tpm.h> |
| 30 | 30 | ||
| 31 | enum tpm_const { | ||
| 32 | TPM_MINOR = 224, /* officially assigned */ | ||
| 33 | TPM_BUFSIZE = 4096, | ||
| 34 | TPM_NUM_DEVICES = 256, | ||
| 35 | }; | ||
| 36 | |||
| 31 | enum tpm_timeout { | 37 | enum tpm_timeout { |
| 32 | TPM_TIMEOUT = 5, /* msecs */ | 38 | TPM_TIMEOUT = 5, /* msecs */ |
| 33 | }; | 39 | }; |
| @@ -94,6 +100,7 @@ struct tpm_vendor_specific { | |||
| 94 | bool timeout_adjusted; | 100 | bool timeout_adjusted; |
| 95 | unsigned long duration[3]; /* jiffies */ | 101 | unsigned long duration[3]; /* jiffies */ |
| 96 | bool duration_adjusted; | 102 | bool duration_adjusted; |
| 103 | void *data; | ||
| 97 | 104 | ||
| 98 | wait_queue_head_t read_queue; | 105 | wait_queue_head_t read_queue; |
| 99 | wait_queue_head_t int_queue; | 106 | wait_queue_head_t int_queue; |
| @@ -269,6 +276,21 @@ struct tpm_pcrextend_in { | |||
| 269 | u8 hash[TPM_DIGEST_SIZE]; | 276 | u8 hash[TPM_DIGEST_SIZE]; |
| 270 | }__attribute__((packed)); | 277 | }__attribute__((packed)); |
| 271 | 278 | ||
| 279 | /* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18 | ||
| 280 | * bytes, but 128 is still a relatively large number of random bytes and | ||
| 281 | * anything much bigger causes users of struct tpm_cmd_t to start getting | ||
| 282 | * compiler warnings about stack frame size. */ | ||
| 283 | #define TPM_MAX_RNG_DATA 128 | ||
| 284 | |||
| 285 | struct tpm_getrandom_out { | ||
| 286 | __be32 rng_data_len; | ||
| 287 | u8 rng_data[TPM_MAX_RNG_DATA]; | ||
| 288 | }__attribute__((packed)); | ||
| 289 | |||
| 290 | struct tpm_getrandom_in { | ||
| 291 | __be32 num_bytes; | ||
| 292 | }__attribute__((packed)); | ||
| 293 | |||
| 272 | typedef union { | 294 | typedef union { |
| 273 | struct tpm_getcap_params_out getcap_out; | 295 | struct tpm_getcap_params_out getcap_out; |
| 274 | struct tpm_readpubek_params_out readpubek_out; | 296 | struct tpm_readpubek_params_out readpubek_out; |
| @@ -277,6 +299,8 @@ typedef union { | |||
| 277 | struct tpm_pcrread_in pcrread_in; | 299 | struct tpm_pcrread_in pcrread_in; |
| 278 | struct tpm_pcrread_out pcrread_out; | 300 | struct tpm_pcrread_out pcrread_out; |
| 279 | struct tpm_pcrextend_in pcrextend_in; | 301 | struct tpm_pcrextend_in pcrextend_in; |
| 302 | struct tpm_getrandom_in getrandom_in; | ||
| 303 | struct tpm_getrandom_out getrandom_out; | ||
| 280 | } tpm_cmd_params; | 304 | } tpm_cmd_params; |
| 281 | 305 | ||
| 282 | struct tpm_cmd_t { | 306 | struct tpm_cmd_t { |
| @@ -303,15 +327,12 @@ extern int tpm_pm_suspend(struct device *); | |||
| 303 | extern int tpm_pm_resume(struct device *); | 327 | extern int tpm_pm_resume(struct device *); |
| 304 | extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, | 328 | extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, |
| 305 | wait_queue_head_t *); | 329 | wait_queue_head_t *); |
| 330 | |||
| 306 | #ifdef CONFIG_ACPI | 331 | #ifdef CONFIG_ACPI |
| 307 | extern struct dentry ** tpm_bios_log_setup(char *); | 332 | extern ssize_t sys_add_ppi(struct kobject *parent); |
| 308 | extern void tpm_bios_log_teardown(struct dentry **); | ||
| 309 | #else | 333 | #else |
| 310 | static inline struct dentry ** tpm_bios_log_setup(char *name) | 334 | static inline ssize_t sys_add_ppi(struct kobject *parent) |
| 311 | { | ||
| 312 | return NULL; | ||
| 313 | } | ||
| 314 | static inline void tpm_bios_log_teardown(struct dentry **dir) | ||
| 315 | { | 335 | { |
| 336 | return 0; | ||
| 316 | } | 337 | } |
| 317 | #endif | 338 | #endif |
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c new file mode 100644 index 000000000000..56051d0c97a2 --- /dev/null +++ b/drivers/char/tpm/tpm_acpi.c | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005 IBM Corporation | ||
| 3 | * | ||
| 4 | * Authors: | ||
| 5 | * Seiji Munetoh <munetoh@jp.ibm.com> | ||
| 6 | * Stefan Berger <stefanb@us.ibm.com> | ||
| 7 | * Reiner Sailer <sailer@watson.ibm.com> | ||
| 8 | * Kylene Hall <kjhall@us.ibm.com> | ||
| 9 | * | ||
| 10 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
| 11 | * | ||
| 12 | * Access to the eventlog extended by the TCG BIOS of PC platform | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or | ||
| 15 | * modify it under the terms of the GNU General Public License | ||
| 16 | * as published by the Free Software Foundation; either version | ||
| 17 | * 2 of the License, or (at your option) any later version. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/seq_file.h> | ||
| 22 | #include <linux/fs.h> | ||
| 23 | #include <linux/security.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <acpi/acpi.h> | ||
| 27 | |||
| 28 | #include "tpm.h" | ||
| 29 | #include "tpm_eventlog.h" | ||
| 30 | |||
| 31 | struct acpi_tcpa { | ||
| 32 | struct acpi_table_header hdr; | ||
| 33 | u16 platform_class; | ||
| 34 | union { | ||
| 35 | struct client_hdr { | ||
| 36 | u32 log_max_len __attribute__ ((packed)); | ||
| 37 | u64 log_start_addr __attribute__ ((packed)); | ||
| 38 | } client; | ||
| 39 | struct server_hdr { | ||
| 40 | u16 reserved; | ||
| 41 | u64 log_max_len __attribute__ ((packed)); | ||
| 42 | u64 log_start_addr __attribute__ ((packed)); | ||
| 43 | } server; | ||
| 44 | }; | ||
| 45 | }; | ||
| 46 | |||
| 47 | /* read binary bios log */ | ||
| 48 | int read_log(struct tpm_bios_log *log) | ||
| 49 | { | ||
| 50 | struct acpi_tcpa *buff; | ||
| 51 | acpi_status status; | ||
| 52 | void __iomem *virt; | ||
| 53 | u64 len, start; | ||
| 54 | |||
| 55 | if (log->bios_event_log != NULL) { | ||
| 56 | printk(KERN_ERR | ||
| 57 | "%s: ERROR - Eventlog already initialized\n", | ||
| 58 | __func__); | ||
| 59 | return -EFAULT; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ | ||
| 63 | status = acpi_get_table(ACPI_SIG_TCPA, 1, | ||
| 64 | (struct acpi_table_header **)&buff); | ||
| 65 | |||
| 66 | if (ACPI_FAILURE(status)) { | ||
| 67 | printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", | ||
| 68 | __func__); | ||
| 69 | return -EIO; | ||
| 70 | } | ||
| 71 | |||
| 72 | switch(buff->platform_class) { | ||
| 73 | case BIOS_SERVER: | ||
| 74 | len = buff->server.log_max_len; | ||
| 75 | start = buff->server.log_start_addr; | ||
| 76 | break; | ||
| 77 | case BIOS_CLIENT: | ||
| 78 | default: | ||
| 79 | len = buff->client.log_max_len; | ||
| 80 | start = buff->client.log_start_addr; | ||
| 81 | break; | ||
| 82 | } | ||
| 83 | if (!len) { | ||
| 84 | printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); | ||
| 85 | return -EIO; | ||
| 86 | } | ||
| 87 | |||
| 88 | /* malloc EventLog space */ | ||
| 89 | log->bios_event_log = kmalloc(len, GFP_KERNEL); | ||
| 90 | if (!log->bios_event_log) { | ||
| 91 | printk("%s: ERROR - Not enough Memory for BIOS measurements\n", | ||
| 92 | __func__); | ||
| 93 | return -ENOMEM; | ||
| 94 | } | ||
| 95 | |||
| 96 | log->bios_event_log_end = log->bios_event_log + len; | ||
| 97 | |||
| 98 | virt = acpi_os_map_memory(start, len); | ||
| 99 | if (!virt) { | ||
| 100 | kfree(log->bios_event_log); | ||
| 101 | printk("%s: ERROR - Unable to map memory\n", __func__); | ||
| 102 | return -EIO; | ||
| 103 | } | ||
| 104 | |||
| 105 | memcpy_fromio(log->bios_event_log, virt, len); | ||
| 106 | |||
| 107 | acpi_os_unmap_memory(virt, len); | ||
| 108 | return 0; | ||
| 109 | } | ||
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_eventlog.c index 0636520fa9bf..84ddc557b8f8 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_eventlog.c | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005 IBM Corporation | 2 | * Copyright (C) 2005, 2012 IBM Corporation |
| 3 | * | 3 | * |
| 4 | * Authors: | 4 | * Authors: |
| 5 | * Kent Yoder <key@linux.vnet.ibm.com> | ||
| 5 | * Seiji Munetoh <munetoh@jp.ibm.com> | 6 | * Seiji Munetoh <munetoh@jp.ibm.com> |
| 6 | * Stefan Berger <stefanb@us.ibm.com> | 7 | * Stefan Berger <stefanb@us.ibm.com> |
| 7 | * Reiner Sailer <sailer@watson.ibm.com> | 8 | * Reiner Sailer <sailer@watson.ibm.com> |
| @@ -9,7 +10,7 @@ | |||
| 9 | * | 10 | * |
| 10 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | 11 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> |
| 11 | * | 12 | * |
| 12 | * Access to the eventlog extended by the TCG BIOS of PC platform | 13 | * Access to the eventlog created by a system's firmware / BIOS |
| 13 | * | 14 | * |
| 14 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
| 15 | * modify it under the terms of the GNU General Public License | 16 | * modify it under the terms of the GNU General Public License |
| @@ -23,67 +24,10 @@ | |||
| 23 | #include <linux/security.h> | 24 | #include <linux/security.h> |
| 24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 25 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 26 | #include <acpi/acpi.h> | ||
| 27 | #include "tpm.h" | ||
| 28 | |||
| 29 | #define TCG_EVENT_NAME_LEN_MAX 255 | ||
| 30 | #define MAX_TEXT_EVENT 1000 /* Max event string length */ | ||
| 31 | #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ | ||
| 32 | |||
| 33 | enum bios_platform_class { | ||
| 34 | BIOS_CLIENT = 0x00, | ||
| 35 | BIOS_SERVER = 0x01, | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct tpm_bios_log { | ||
| 39 | void *bios_event_log; | ||
| 40 | void *bios_event_log_end; | ||
| 41 | }; | ||
| 42 | |||
| 43 | struct acpi_tcpa { | ||
| 44 | struct acpi_table_header hdr; | ||
| 45 | u16 platform_class; | ||
| 46 | union { | ||
| 47 | struct client_hdr { | ||
| 48 | u32 log_max_len __attribute__ ((packed)); | ||
| 49 | u64 log_start_addr __attribute__ ((packed)); | ||
| 50 | } client; | ||
| 51 | struct server_hdr { | ||
| 52 | u16 reserved; | ||
| 53 | u64 log_max_len __attribute__ ((packed)); | ||
| 54 | u64 log_start_addr __attribute__ ((packed)); | ||
| 55 | } server; | ||
| 56 | }; | ||
| 57 | }; | ||
| 58 | 27 | ||
| 59 | struct tcpa_event { | 28 | #include "tpm.h" |
| 60 | u32 pcr_index; | 29 | #include "tpm_eventlog.h" |
| 61 | u32 event_type; | ||
| 62 | u8 pcr_value[20]; /* SHA1 */ | ||
| 63 | u32 event_size; | ||
| 64 | u8 event_data[0]; | ||
| 65 | }; | ||
| 66 | 30 | ||
| 67 | enum tcpa_event_types { | ||
| 68 | PREBOOT = 0, | ||
| 69 | POST_CODE, | ||
| 70 | UNUSED, | ||
| 71 | NO_ACTION, | ||
| 72 | SEPARATOR, | ||
| 73 | ACTION, | ||
| 74 | EVENT_TAG, | ||
| 75 | SCRTM_CONTENTS, | ||
| 76 | SCRTM_VERSION, | ||
| 77 | CPU_MICROCODE, | ||
| 78 | PLATFORM_CONFIG_FLAGS, | ||
| 79 | TABLE_OF_DEVICES, | ||
| 80 | COMPACT_HASH, | ||
| 81 | IPL, | ||
| 82 | IPL_PARTITION_DATA, | ||
| 83 | NONHOST_CODE, | ||
| 84 | NONHOST_CONFIG, | ||
| 85 | NONHOST_INFO, | ||
| 86 | }; | ||
| 87 | 31 | ||
| 88 | static const char* tcpa_event_type_strings[] = { | 32 | static const char* tcpa_event_type_strings[] = { |
| 89 | "PREBOOT", | 33 | "PREBOOT", |
| @@ -106,28 +50,6 @@ static const char* tcpa_event_type_strings[] = { | |||
| 106 | "Non-Host Info" | 50 | "Non-Host Info" |
| 107 | }; | 51 | }; |
| 108 | 52 | ||
| 109 | struct tcpa_pc_event { | ||
| 110 | u32 event_id; | ||
| 111 | u32 event_size; | ||
| 112 | u8 event_data[0]; | ||
| 113 | }; | ||
| 114 | |||
| 115 | enum tcpa_pc_event_ids { | ||
| 116 | SMBIOS = 1, | ||
| 117 | BIS_CERT, | ||
| 118 | POST_BIOS_ROM, | ||
| 119 | ESCD, | ||
| 120 | CMOS, | ||
| 121 | NVRAM, | ||
| 122 | OPTION_ROM_EXEC, | ||
| 123 | OPTION_ROM_CONFIG, | ||
| 124 | OPTION_ROM_MICROCODE = 10, | ||
| 125 | S_CRTM_VERSION, | ||
| 126 | S_CRTM_CONTENTS, | ||
| 127 | POST_CONTENTS, | ||
| 128 | HOST_TABLE_OF_DEVICES, | ||
| 129 | }; | ||
| 130 | |||
| 131 | static const char* tcpa_pc_event_id_strings[] = { | 53 | static const char* tcpa_pc_event_id_strings[] = { |
| 132 | "", | 54 | "", |
| 133 | "SMBIOS", | 55 | "SMBIOS", |
| @@ -358,65 +280,6 @@ static const struct seq_operations tpm_binary_b_measurments_seqops = { | |||
| 358 | .show = tpm_binary_bios_measurements_show, | 280 | .show = tpm_binary_bios_measurements_show, |
| 359 | }; | 281 | }; |
| 360 | 282 | ||
| 361 | /* read binary bios log */ | ||
| 362 | static int read_log(struct tpm_bios_log *log) | ||
| 363 | { | ||
| 364 | struct acpi_tcpa *buff; | ||
| 365 | acpi_status status; | ||
| 366 | struct acpi_table_header *virt; | ||
| 367 | u64 len, start; | ||
| 368 | |||
| 369 | if (log->bios_event_log != NULL) { | ||
| 370 | printk(KERN_ERR | ||
| 371 | "%s: ERROR - Eventlog already initialized\n", | ||
| 372 | __func__); | ||
| 373 | return -EFAULT; | ||
| 374 | } | ||
| 375 | |||
| 376 | /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ | ||
| 377 | status = acpi_get_table(ACPI_SIG_TCPA, 1, | ||
| 378 | (struct acpi_table_header **)&buff); | ||
| 379 | |||
| 380 | if (ACPI_FAILURE(status)) { | ||
| 381 | printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", | ||
| 382 | __func__); | ||
| 383 | return -EIO; | ||
| 384 | } | ||
| 385 | |||
| 386 | switch(buff->platform_class) { | ||
| 387 | case BIOS_SERVER: | ||
| 388 | len = buff->server.log_max_len; | ||
| 389 | start = buff->server.log_start_addr; | ||
| 390 | break; | ||
| 391 | case BIOS_CLIENT: | ||
| 392 | default: | ||
| 393 | len = buff->client.log_max_len; | ||
| 394 | start = buff->client.log_start_addr; | ||
| 395 | break; | ||
| 396 | } | ||
| 397 | if (!len) { | ||
| 398 | printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); | ||
| 399 | return -EIO; | ||
| 400 | } | ||
| 401 | |||
| 402 | /* malloc EventLog space */ | ||
| 403 | log->bios_event_log = kmalloc(len, GFP_KERNEL); | ||
| 404 | if (!log->bios_event_log) { | ||
| 405 | printk("%s: ERROR - Not enough Memory for BIOS measurements\n", | ||
| 406 | __func__); | ||
| 407 | return -ENOMEM; | ||
| 408 | } | ||
| 409 | |||
| 410 | log->bios_event_log_end = log->bios_event_log + len; | ||
| 411 | |||
| 412 | virt = acpi_os_map_memory(start, len); | ||
| 413 | |||
| 414 | memcpy(log->bios_event_log, virt, len); | ||
| 415 | |||
| 416 | acpi_os_unmap_memory(virt, len); | ||
| 417 | return 0; | ||
| 418 | } | ||
| 419 | |||
| 420 | static int tpm_ascii_bios_measurements_open(struct inode *inode, | 283 | static int tpm_ascii_bios_measurements_open(struct inode *inode, |
| 421 | struct file *file) | 284 | struct file *file) |
| 422 | { | 285 | { |
diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h new file mode 100644 index 000000000000..e7da086d6928 --- /dev/null +++ b/drivers/char/tpm/tpm_eventlog.h | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | |||
| 2 | #ifndef __TPM_EVENTLOG_H__ | ||
| 3 | #define __TPM_EVENTLOG_H__ | ||
| 4 | |||
| 5 | #define TCG_EVENT_NAME_LEN_MAX 255 | ||
| 6 | #define MAX_TEXT_EVENT 1000 /* Max event string length */ | ||
| 7 | #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ | ||
| 8 | |||
| 9 | enum bios_platform_class { | ||
| 10 | BIOS_CLIENT = 0x00, | ||
| 11 | BIOS_SERVER = 0x01, | ||
| 12 | }; | ||
| 13 | |||
| 14 | struct tpm_bios_log { | ||
| 15 | void *bios_event_log; | ||
| 16 | void *bios_event_log_end; | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct tcpa_event { | ||
| 20 | u32 pcr_index; | ||
| 21 | u32 event_type; | ||
| 22 | u8 pcr_value[20]; /* SHA1 */ | ||
| 23 | u32 event_size; | ||
| 24 | u8 event_data[0]; | ||
| 25 | }; | ||
| 26 | |||
| 27 | enum tcpa_event_types { | ||
| 28 | PREBOOT = 0, | ||
| 29 | POST_CODE, | ||
| 30 | UNUSED, | ||
| 31 | NO_ACTION, | ||
| 32 | SEPARATOR, | ||
| 33 | ACTION, | ||
| 34 | EVENT_TAG, | ||
| 35 | SCRTM_CONTENTS, | ||
| 36 | SCRTM_VERSION, | ||
| 37 | CPU_MICROCODE, | ||
| 38 | PLATFORM_CONFIG_FLAGS, | ||
| 39 | TABLE_OF_DEVICES, | ||
| 40 | COMPACT_HASH, | ||
| 41 | IPL, | ||
| 42 | IPL_PARTITION_DATA, | ||
| 43 | NONHOST_CODE, | ||
| 44 | NONHOST_CONFIG, | ||
| 45 | NONHOST_INFO, | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct tcpa_pc_event { | ||
| 49 | u32 event_id; | ||
| 50 | u32 event_size; | ||
| 51 | u8 event_data[0]; | ||
| 52 | }; | ||
| 53 | |||
| 54 | enum tcpa_pc_event_ids { | ||
| 55 | SMBIOS = 1, | ||
| 56 | BIS_CERT, | ||
| 57 | POST_BIOS_ROM, | ||
| 58 | ESCD, | ||
| 59 | CMOS, | ||
| 60 | NVRAM, | ||
| 61 | OPTION_ROM_EXEC, | ||
| 62 | OPTION_ROM_CONFIG, | ||
| 63 | OPTION_ROM_MICROCODE = 10, | ||
| 64 | S_CRTM_VERSION, | ||
| 65 | S_CRTM_CONTENTS, | ||
| 66 | POST_CONTENTS, | ||
| 67 | HOST_TABLE_OF_DEVICES, | ||
| 68 | }; | ||
| 69 | |||
| 70 | int read_log(struct tpm_bios_log *log); | ||
| 71 | |||
| 72 | #if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \ | ||
| 73 | defined(CONFIG_ACPI) | ||
| 74 | extern struct dentry **tpm_bios_log_setup(char *); | ||
| 75 | extern void tpm_bios_log_teardown(struct dentry **); | ||
| 76 | #else | ||
| 77 | static inline struct dentry **tpm_bios_log_setup(char *name) | ||
| 78 | { | ||
| 79 | return NULL; | ||
| 80 | } | ||
| 81 | static inline void tpm_bios_log_teardown(struct dentry **dir) | ||
| 82 | { | ||
| 83 | } | ||
| 84 | #endif | ||
| 85 | |||
| 86 | #endif | ||
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c new file mode 100644 index 000000000000..5a831aec9d4b --- /dev/null +++ b/drivers/char/tpm/tpm_i2c_infineon.c | |||
| @@ -0,0 +1,695 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Infineon Technologies | ||
| 3 | * | ||
| 4 | * Authors: | ||
| 5 | * Peter Huewe <peter.huewe@infineon.com> | ||
| 6 | * | ||
| 7 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
| 8 | * Specifications at www.trustedcomputinggroup.org | ||
| 9 | * | ||
| 10 | * This device driver implements the TPM interface as defined in | ||
| 11 | * the TCG TPM Interface Spec version 1.2, revision 1.0 and the | ||
| 12 | * Infineon I2C Protocol Stack Specification v0.20. | ||
| 13 | * | ||
| 14 | * It is based on the original tpm_tis device driver from Leendert van | ||
| 15 | * Dorn and Kyleen Hall. | ||
| 16 | * | ||
| 17 | * This program is free software; you can redistribute it and/or | ||
| 18 | * modify it under the terms of the GNU General Public License as | ||
| 19 | * published by the Free Software Foundation, version 2 of the | ||
| 20 | * License. | ||
| 21 | * | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/i2c.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/moduleparam.h> | ||
| 28 | #include <linux/wait.h> | ||
| 29 | #include "tpm.h" | ||
| 30 | |||
| 31 | /* max. buffer size supported by our TPM */ | ||
| 32 | #define TPM_BUFSIZE 1260 | ||
| 33 | |||
| 34 | /* max. number of iterations after I2C NAK */ | ||
| 35 | #define MAX_COUNT 3 | ||
| 36 | |||
| 37 | #define SLEEP_DURATION_LOW 55 | ||
| 38 | #define SLEEP_DURATION_HI 65 | ||
| 39 | |||
| 40 | /* max. number of iterations after I2C NAK for 'long' commands | ||
| 41 | * we need this especially for sending TPM_READY, since the cleanup after the | ||
| 42 | * transtion to the ready state may take some time, but it is unpredictable | ||
| 43 | * how long it will take. | ||
| 44 | */ | ||
| 45 | #define MAX_COUNT_LONG 50 | ||
| 46 | |||
| 47 | #define SLEEP_DURATION_LONG_LOW 200 | ||
| 48 | #define SLEEP_DURATION_LONG_HI 220 | ||
| 49 | |||
| 50 | /* After sending TPM_READY to 'reset' the TPM we have to sleep even longer */ | ||
| 51 | #define SLEEP_DURATION_RESET_LOW 2400 | ||
| 52 | #define SLEEP_DURATION_RESET_HI 2600 | ||
| 53 | |||
| 54 | /* we want to use usleep_range instead of msleep for the 5ms TPM_TIMEOUT */ | ||
| 55 | #define TPM_TIMEOUT_US_LOW (TPM_TIMEOUT * 1000) | ||
| 56 | #define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000) | ||
| 57 | |||
| 58 | /* expected value for DIDVID register */ | ||
| 59 | #define TPM_TIS_I2C_DID_VID 0x000b15d1L | ||
| 60 | |||
| 61 | /* Structure to store I2C TPM specific stuff */ | ||
| 62 | struct tpm_inf_dev { | ||
| 63 | struct i2c_client *client; | ||
| 64 | u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ | ||
| 65 | struct tpm_chip *chip; | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct tpm_inf_dev tpm_dev; | ||
| 69 | static struct i2c_driver tpm_tis_i2c_driver; | ||
| 70 | |||
| 71 | /* | ||
| 72 | * iic_tpm_read() - read from TPM register | ||
| 73 | * @addr: register address to read from | ||
| 74 | * @buffer: provided by caller | ||
| 75 | * @len: number of bytes to read | ||
| 76 | * | ||
| 77 | * Read len bytes from TPM register and put them into | ||
| 78 | * buffer (little-endian format, i.e. first byte is put into buffer[0]). | ||
| 79 | * | ||
| 80 | * NOTE: TPM is big-endian for multi-byte values. Multi-byte | ||
| 81 | * values have to be swapped. | ||
| 82 | * | ||
| 83 | * NOTE: We can't unfortunately use the combined read/write functions | ||
| 84 | * provided by the i2c core as the TPM currently does not support the | ||
| 85 | * repeated start condition and due to it's special requirements. | ||
| 86 | * The i2c_smbus* functions do not work for this chip. | ||
| 87 | * | ||
| 88 | * Return -EIO on error, 0 on success. | ||
| 89 | */ | ||
| 90 | static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) | ||
| 91 | { | ||
| 92 | |||
| 93 | struct i2c_msg msg1 = { tpm_dev.client->addr, 0, 1, &addr }; | ||
| 94 | struct i2c_msg msg2 = { tpm_dev.client->addr, I2C_M_RD, len, buffer }; | ||
| 95 | |||
| 96 | int rc; | ||
| 97 | int count; | ||
| 98 | |||
| 99 | /* Lock the adapter for the duration of the whole sequence. */ | ||
| 100 | if (!tpm_dev.client->adapter->algo->master_xfer) | ||
| 101 | return -EOPNOTSUPP; | ||
| 102 | i2c_lock_adapter(tpm_dev.client->adapter); | ||
| 103 | |||
| 104 | for (count = 0; count < MAX_COUNT; count++) { | ||
| 105 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); | ||
| 106 | if (rc > 0) | ||
| 107 | break; /* break here to skip sleep */ | ||
| 108 | |||
| 109 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
| 110 | } | ||
| 111 | |||
| 112 | if (rc <= 0) | ||
| 113 | goto out; | ||
| 114 | |||
| 115 | /* After the TPM has successfully received the register address it needs | ||
| 116 | * some time, thus we're sleeping here again, before retrieving the data | ||
| 117 | */ | ||
| 118 | for (count = 0; count < MAX_COUNT; count++) { | ||
| 119 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
| 120 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1); | ||
| 121 | if (rc > 0) | ||
| 122 | break; | ||
| 123 | |||
| 124 | } | ||
| 125 | |||
| 126 | out: | ||
| 127 | i2c_unlock_adapter(tpm_dev.client->adapter); | ||
| 128 | if (rc <= 0) | ||
| 129 | return -EIO; | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, | ||
| 135 | unsigned int sleep_low, | ||
| 136 | unsigned int sleep_hi, u8 max_count) | ||
| 137 | { | ||
| 138 | int rc = -EIO; | ||
| 139 | int count; | ||
| 140 | |||
| 141 | struct i2c_msg msg1 = { tpm_dev.client->addr, 0, len + 1, tpm_dev.buf }; | ||
| 142 | |||
| 143 | if (len > TPM_BUFSIZE) | ||
| 144 | return -EINVAL; | ||
| 145 | |||
| 146 | if (!tpm_dev.client->adapter->algo->master_xfer) | ||
| 147 | return -EOPNOTSUPP; | ||
| 148 | i2c_lock_adapter(tpm_dev.client->adapter); | ||
| 149 | |||
| 150 | /* prepend the 'register address' to the buffer */ | ||
| 151 | tpm_dev.buf[0] = addr; | ||
| 152 | memcpy(&(tpm_dev.buf[1]), buffer, len); | ||
| 153 | |||
| 154 | /* | ||
| 155 | * NOTE: We have to use these special mechanisms here and unfortunately | ||
| 156 | * cannot rely on the standard behavior of i2c_transfer. | ||
| 157 | */ | ||
| 158 | for (count = 0; count < max_count; count++) { | ||
| 159 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); | ||
| 160 | if (rc > 0) | ||
| 161 | break; | ||
| 162 | |||
| 163 | usleep_range(sleep_low, sleep_hi); | ||
| 164 | } | ||
| 165 | |||
| 166 | i2c_unlock_adapter(tpm_dev.client->adapter); | ||
| 167 | if (rc <= 0) | ||
| 168 | return -EIO; | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 174 | * iic_tpm_write() - write to TPM register | ||
| 175 | * @addr: register address to write to | ||
| 176 | * @buffer: containing data to be written | ||
| 177 | * @len: number of bytes to write | ||
| 178 | * | ||
| 179 | * Write len bytes from provided buffer to TPM register (little | ||
| 180 | * endian format, i.e. buffer[0] is written as first byte). | ||
| 181 | * | ||
| 182 | * NOTE: TPM is big-endian for multi-byte values. Multi-byte | ||
| 183 | * values have to be swapped. | ||
| 184 | * | ||
| 185 | * NOTE: use this function instead of the iic_tpm_write_generic function. | ||
| 186 | * | ||
| 187 | * Return -EIO on error, 0 on success | ||
| 188 | */ | ||
| 189 | static int iic_tpm_write(u8 addr, u8 *buffer, size_t len) | ||
| 190 | { | ||
| 191 | return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LOW, | ||
| 192 | SLEEP_DURATION_HI, MAX_COUNT); | ||
| 193 | } | ||
| 194 | |||
| 195 | /* | ||
| 196 | * This function is needed especially for the cleanup situation after | ||
| 197 | * sending TPM_READY | ||
| 198 | * */ | ||
| 199 | static int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len) | ||
| 200 | { | ||
| 201 | return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG_LOW, | ||
| 202 | SLEEP_DURATION_LONG_HI, MAX_COUNT_LONG); | ||
| 203 | } | ||
| 204 | |||
| 205 | enum tis_access { | ||
| 206 | TPM_ACCESS_VALID = 0x80, | ||
| 207 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | ||
| 208 | TPM_ACCESS_REQUEST_PENDING = 0x04, | ||
| 209 | TPM_ACCESS_REQUEST_USE = 0x02, | ||
| 210 | }; | ||
| 211 | |||
| 212 | enum tis_status { | ||
| 213 | TPM_STS_VALID = 0x80, | ||
| 214 | TPM_STS_COMMAND_READY = 0x40, | ||
| 215 | TPM_STS_GO = 0x20, | ||
| 216 | TPM_STS_DATA_AVAIL = 0x10, | ||
| 217 | TPM_STS_DATA_EXPECT = 0x08, | ||
| 218 | }; | ||
| 219 | |||
| 220 | enum tis_defaults { | ||
| 221 | TIS_SHORT_TIMEOUT = 750, /* ms */ | ||
| 222 | TIS_LONG_TIMEOUT = 2000, /* 2 sec */ | ||
| 223 | }; | ||
| 224 | |||
| 225 | #define TPM_ACCESS(l) (0x0000 | ((l) << 4)) | ||
| 226 | #define TPM_STS(l) (0x0001 | ((l) << 4)) | ||
| 227 | #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) | ||
| 228 | #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) | ||
| 229 | |||
| 230 | static int check_locality(struct tpm_chip *chip, int loc) | ||
| 231 | { | ||
| 232 | u8 buf; | ||
| 233 | int rc; | ||
| 234 | |||
| 235 | rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1); | ||
| 236 | if (rc < 0) | ||
| 237 | return rc; | ||
| 238 | |||
| 239 | if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == | ||
| 240 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { | ||
| 241 | chip->vendor.locality = loc; | ||
| 242 | return loc; | ||
| 243 | } | ||
| 244 | |||
| 245 | return -EIO; | ||
| 246 | } | ||
| 247 | |||
| 248 | /* implementation similar to tpm_tis */ | ||
| 249 | static void release_locality(struct tpm_chip *chip, int loc, int force) | ||
| 250 | { | ||
| 251 | u8 buf; | ||
| 252 | if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) | ||
| 253 | return; | ||
| 254 | |||
| 255 | if (force || (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == | ||
| 256 | (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) { | ||
| 257 | buf = TPM_ACCESS_ACTIVE_LOCALITY; | ||
| 258 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | static int request_locality(struct tpm_chip *chip, int loc) | ||
| 263 | { | ||
| 264 | unsigned long stop; | ||
| 265 | u8 buf = TPM_ACCESS_REQUEST_USE; | ||
| 266 | |||
| 267 | if (check_locality(chip, loc) >= 0) | ||
| 268 | return loc; | ||
| 269 | |||
| 270 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); | ||
| 271 | |||
| 272 | /* wait for burstcount */ | ||
| 273 | stop = jiffies + chip->vendor.timeout_a; | ||
| 274 | do { | ||
| 275 | if (check_locality(chip, loc) >= 0) | ||
| 276 | return loc; | ||
| 277 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
| 278 | } while (time_before(jiffies, stop)); | ||
| 279 | |||
| 280 | return -ETIME; | ||
| 281 | } | ||
| 282 | |||
| 283 | static u8 tpm_tis_i2c_status(struct tpm_chip *chip) | ||
| 284 | { | ||
| 285 | /* NOTE: since I2C read may fail, return 0 in this case --> time-out */ | ||
| 286 | u8 buf; | ||
| 287 | if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) | ||
| 288 | return 0; | ||
| 289 | else | ||
| 290 | return buf; | ||
| 291 | } | ||
| 292 | |||
| 293 | static void tpm_tis_i2c_ready(struct tpm_chip *chip) | ||
| 294 | { | ||
| 295 | /* this causes the current command to be aborted */ | ||
| 296 | u8 buf = TPM_STS_COMMAND_READY; | ||
| 297 | iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); | ||
| 298 | } | ||
| 299 | |||
| 300 | static ssize_t get_burstcount(struct tpm_chip *chip) | ||
| 301 | { | ||
| 302 | unsigned long stop; | ||
| 303 | ssize_t burstcnt; | ||
| 304 | u8 buf[3]; | ||
| 305 | |||
| 306 | /* wait for burstcount */ | ||
| 307 | /* which timeout value, spec has 2 answers (c & d) */ | ||
| 308 | stop = jiffies + chip->vendor.timeout_d; | ||
| 309 | do { | ||
| 310 | /* Note: STS is little endian */ | ||
| 311 | if (iic_tpm_read(TPM_STS(chip->vendor.locality)+1, buf, 3) < 0) | ||
| 312 | burstcnt = 0; | ||
| 313 | else | ||
| 314 | burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | ||
| 315 | |||
| 316 | if (burstcnt) | ||
| 317 | return burstcnt; | ||
| 318 | |||
| 319 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
| 320 | } while (time_before(jiffies, stop)); | ||
| 321 | return -EBUSY; | ||
| 322 | } | ||
| 323 | |||
| 324 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | ||
| 325 | int *status) | ||
| 326 | { | ||
| 327 | unsigned long stop; | ||
| 328 | |||
| 329 | /* check current status */ | ||
| 330 | *status = tpm_tis_i2c_status(chip); | ||
| 331 | if ((*status & mask) == mask) | ||
| 332 | return 0; | ||
| 333 | |||
| 334 | stop = jiffies + timeout; | ||
| 335 | do { | ||
| 336 | /* since we just checked the status, give the TPM some time */ | ||
| 337 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
| 338 | *status = tpm_tis_i2c_status(chip); | ||
| 339 | if ((*status & mask) == mask) | ||
| 340 | return 0; | ||
| 341 | |||
| 342 | } while (time_before(jiffies, stop)); | ||
| 343 | |||
| 344 | return -ETIME; | ||
| 345 | } | ||
| 346 | |||
| 347 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | ||
| 348 | { | ||
| 349 | size_t size = 0; | ||
| 350 | ssize_t burstcnt; | ||
| 351 | u8 retries = 0; | ||
| 352 | int rc; | ||
| 353 | |||
| 354 | while (size < count) { | ||
| 355 | burstcnt = get_burstcount(chip); | ||
| 356 | |||
| 357 | /* burstcnt < 0 = TPM is busy */ | ||
| 358 | if (burstcnt < 0) | ||
| 359 | return burstcnt; | ||
| 360 | |||
| 361 | /* limit received data to max. left */ | ||
| 362 | if (burstcnt > (count - size)) | ||
| 363 | burstcnt = count - size; | ||
| 364 | |||
| 365 | rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality), | ||
| 366 | &(buf[size]), burstcnt); | ||
| 367 | if (rc == 0) | ||
| 368 | size += burstcnt; | ||
| 369 | else if (rc < 0) | ||
| 370 | retries++; | ||
| 371 | |||
| 372 | /* avoid endless loop in case of broken HW */ | ||
| 373 | if (retries > MAX_COUNT_LONG) | ||
| 374 | return -EIO; | ||
| 375 | |||
| 376 | } | ||
| 377 | return size; | ||
| 378 | } | ||
| 379 | |||
| 380 | static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) | ||
| 381 | { | ||
| 382 | int size = 0; | ||
| 383 | int expected, status; | ||
| 384 | |||
| 385 | if (count < TPM_HEADER_SIZE) { | ||
| 386 | size = -EIO; | ||
| 387 | goto out; | ||
| 388 | } | ||
| 389 | |||
| 390 | /* read first 10 bytes, including tag, paramsize, and result */ | ||
| 391 | size = recv_data(chip, buf, TPM_HEADER_SIZE); | ||
| 392 | if (size < TPM_HEADER_SIZE) { | ||
| 393 | dev_err(chip->dev, "Unable to read header\n"); | ||
| 394 | goto out; | ||
| 395 | } | ||
| 396 | |||
| 397 | expected = be32_to_cpu(*(__be32 *)(buf + 2)); | ||
| 398 | if ((size_t) expected > count) { | ||
| 399 | size = -EIO; | ||
| 400 | goto out; | ||
| 401 | } | ||
| 402 | |||
| 403 | size += recv_data(chip, &buf[TPM_HEADER_SIZE], | ||
| 404 | expected - TPM_HEADER_SIZE); | ||
| 405 | if (size < expected) { | ||
| 406 | dev_err(chip->dev, "Unable to read remainder of result\n"); | ||
| 407 | size = -ETIME; | ||
| 408 | goto out; | ||
| 409 | } | ||
| 410 | |||
| 411 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); | ||
| 412 | if (status & TPM_STS_DATA_AVAIL) { /* retry? */ | ||
| 413 | dev_err(chip->dev, "Error left over data\n"); | ||
| 414 | size = -EIO; | ||
| 415 | goto out; | ||
| 416 | } | ||
| 417 | |||
| 418 | out: | ||
| 419 | tpm_tis_i2c_ready(chip); | ||
| 420 | /* The TPM needs some time to clean up here, | ||
| 421 | * so we sleep rather than keeping the bus busy | ||
| 422 | */ | ||
| 423 | usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); | ||
| 424 | release_locality(chip, chip->vendor.locality, 0); | ||
| 425 | return size; | ||
| 426 | } | ||
| 427 | |||
| 428 | static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) | ||
| 429 | { | ||
| 430 | int rc, status; | ||
| 431 | ssize_t burstcnt; | ||
| 432 | size_t count = 0; | ||
| 433 | u8 retries = 0; | ||
| 434 | u8 sts = TPM_STS_GO; | ||
| 435 | |||
| 436 | if (len > TPM_BUFSIZE) | ||
| 437 | return -E2BIG; /* command is too long for our tpm, sorry */ | ||
| 438 | |||
| 439 | if (request_locality(chip, 0) < 0) | ||
| 440 | return -EBUSY; | ||
| 441 | |||
| 442 | status = tpm_tis_i2c_status(chip); | ||
| 443 | if ((status & TPM_STS_COMMAND_READY) == 0) { | ||
| 444 | tpm_tis_i2c_ready(chip); | ||
| 445 | if (wait_for_stat | ||
| 446 | (chip, TPM_STS_COMMAND_READY, | ||
| 447 | chip->vendor.timeout_b, &status) < 0) { | ||
| 448 | rc = -ETIME; | ||
| 449 | goto out_err; | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | while (count < len - 1) { | ||
| 454 | burstcnt = get_burstcount(chip); | ||
| 455 | |||
| 456 | /* burstcnt < 0 = TPM is busy */ | ||
| 457 | if (burstcnt < 0) | ||
| 458 | return burstcnt; | ||
| 459 | |||
| 460 | if (burstcnt > (len - 1 - count)) | ||
| 461 | burstcnt = len - 1 - count; | ||
| 462 | |||
| 463 | rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), | ||
| 464 | &(buf[count]), burstcnt); | ||
| 465 | if (rc == 0) | ||
| 466 | count += burstcnt; | ||
| 467 | else if (rc < 0) | ||
| 468 | retries++; | ||
| 469 | |||
| 470 | /* avoid endless loop in case of broken HW */ | ||
| 471 | if (retries > MAX_COUNT_LONG) { | ||
| 472 | rc = -EIO; | ||
| 473 | goto out_err; | ||
| 474 | } | ||
| 475 | |||
| 476 | wait_for_stat(chip, TPM_STS_VALID, | ||
| 477 | chip->vendor.timeout_c, &status); | ||
| 478 | |||
| 479 | if ((status & TPM_STS_DATA_EXPECT) == 0) { | ||
| 480 | rc = -EIO; | ||
| 481 | goto out_err; | ||
| 482 | } | ||
| 483 | |||
| 484 | } | ||
| 485 | |||
| 486 | /* write last byte */ | ||
| 487 | iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); | ||
| 488 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); | ||
| 489 | if ((status & TPM_STS_DATA_EXPECT) != 0) { | ||
| 490 | rc = -EIO; | ||
| 491 | goto out_err; | ||
| 492 | } | ||
| 493 | |||
| 494 | /* go and do it */ | ||
| 495 | iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); | ||
| 496 | |||
| 497 | return len; | ||
| 498 | out_err: | ||
| 499 | tpm_tis_i2c_ready(chip); | ||
| 500 | /* The TPM needs some time to clean up here, | ||
| 501 | * so we sleep rather than keeping the bus busy | ||
| 502 | */ | ||
| 503 | usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); | ||
| 504 | release_locality(chip, chip->vendor.locality, 0); | ||
| 505 | return rc; | ||
| 506 | } | ||
| 507 | |||
| 508 | static const struct file_operations tis_ops = { | ||
| 509 | .owner = THIS_MODULE, | ||
| 510 | .llseek = no_llseek, | ||
| 511 | .open = tpm_open, | ||
| 512 | .read = tpm_read, | ||
| 513 | .write = tpm_write, | ||
| 514 | .release = tpm_release, | ||
| 515 | }; | ||
| 516 | |||
| 517 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 518 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 519 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 520 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 521 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 522 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); | ||
| 523 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); | ||
| 524 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 525 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
| 526 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
| 527 | |||
| 528 | static struct attribute *tis_attrs[] = { | ||
| 529 | &dev_attr_pubek.attr, | ||
| 530 | &dev_attr_pcrs.attr, | ||
| 531 | &dev_attr_enabled.attr, | ||
| 532 | &dev_attr_active.attr, | ||
| 533 | &dev_attr_owned.attr, | ||
| 534 | &dev_attr_temp_deactivated.attr, | ||
| 535 | &dev_attr_caps.attr, | ||
| 536 | &dev_attr_cancel.attr, | ||
| 537 | &dev_attr_durations.attr, | ||
| 538 | &dev_attr_timeouts.attr, | ||
| 539 | NULL, | ||
| 540 | }; | ||
| 541 | |||
| 542 | static struct attribute_group tis_attr_grp = { | ||
| 543 | .attrs = tis_attrs | ||
| 544 | }; | ||
| 545 | |||
| 546 | static struct tpm_vendor_specific tpm_tis_i2c = { | ||
| 547 | .status = tpm_tis_i2c_status, | ||
| 548 | .recv = tpm_tis_i2c_recv, | ||
| 549 | .send = tpm_tis_i2c_send, | ||
| 550 | .cancel = tpm_tis_i2c_ready, | ||
| 551 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
| 552 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
| 553 | .req_canceled = TPM_STS_COMMAND_READY, | ||
| 554 | .attr_group = &tis_attr_grp, | ||
| 555 | .miscdev.fops = &tis_ops, | ||
| 556 | }; | ||
| 557 | |||
| 558 | static int __devinit tpm_tis_i2c_init(struct device *dev) | ||
| 559 | { | ||
| 560 | u32 vendor; | ||
| 561 | int rc = 0; | ||
| 562 | struct tpm_chip *chip; | ||
| 563 | |||
| 564 | chip = tpm_register_hardware(dev, &tpm_tis_i2c); | ||
| 565 | if (!chip) { | ||
| 566 | rc = -ENODEV; | ||
| 567 | goto out_err; | ||
| 568 | } | ||
| 569 | |||
| 570 | /* Disable interrupts */ | ||
| 571 | chip->vendor.irq = 0; | ||
| 572 | |||
| 573 | /* Default timeouts */ | ||
| 574 | chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 575 | chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); | ||
| 576 | chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 577 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 578 | |||
| 579 | if (request_locality(chip, 0) != 0) { | ||
| 580 | rc = -ENODEV; | ||
| 581 | goto out_vendor; | ||
| 582 | } | ||
| 583 | |||
| 584 | /* read four bytes from DID_VID register */ | ||
| 585 | if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) { | ||
| 586 | rc = -EIO; | ||
| 587 | goto out_release; | ||
| 588 | } | ||
| 589 | |||
| 590 | /* create DID_VID register value, after swapping to little-endian */ | ||
| 591 | vendor = be32_to_cpu((__be32) vendor); | ||
| 592 | |||
| 593 | if (vendor != TPM_TIS_I2C_DID_VID) { | ||
| 594 | rc = -ENODEV; | ||
| 595 | goto out_release; | ||
| 596 | } | ||
| 597 | |||
| 598 | dev_info(dev, "1.2 TPM (device-id 0x%X)\n", vendor >> 16); | ||
| 599 | |||
| 600 | INIT_LIST_HEAD(&chip->vendor.list); | ||
| 601 | tpm_dev.chip = chip; | ||
| 602 | |||
| 603 | tpm_get_timeouts(chip); | ||
| 604 | tpm_do_selftest(chip); | ||
| 605 | |||
| 606 | return 0; | ||
| 607 | |||
| 608 | out_release: | ||
| 609 | release_locality(chip, chip->vendor.locality, 1); | ||
| 610 | |||
| 611 | out_vendor: | ||
| 612 | /* close file handles */ | ||
| 613 | tpm_dev_vendor_release(chip); | ||
| 614 | |||
| 615 | /* remove hardware */ | ||
| 616 | tpm_remove_hardware(chip->dev); | ||
| 617 | |||
| 618 | /* reset these pointers, otherwise we oops */ | ||
| 619 | chip->dev->release = NULL; | ||
| 620 | chip->release = NULL; | ||
| 621 | tpm_dev.client = NULL; | ||
| 622 | dev_set_drvdata(chip->dev, chip); | ||
| 623 | out_err: | ||
| 624 | return rc; | ||
| 625 | } | ||
| 626 | |||
| 627 | static const struct i2c_device_id tpm_tis_i2c_table[] = { | ||
| 628 | {"tpm_i2c_infineon", 0}, | ||
| 629 | {}, | ||
| 630 | }; | ||
| 631 | |||
| 632 | MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table); | ||
| 633 | static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume); | ||
| 634 | |||
| 635 | static int __devinit tpm_tis_i2c_probe(struct i2c_client *client, | ||
| 636 | const struct i2c_device_id *id) | ||
| 637 | { | ||
| 638 | int rc; | ||
| 639 | if (tpm_dev.client != NULL) | ||
| 640 | return -EBUSY; /* We only support one client */ | ||
| 641 | |||
| 642 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
| 643 | dev_err(&client->dev, | ||
| 644 | "no algorithms associated to the i2c bus\n"); | ||
| 645 | return -ENODEV; | ||
| 646 | } | ||
| 647 | |||
| 648 | client->driver = &tpm_tis_i2c_driver; | ||
| 649 | tpm_dev.client = client; | ||
| 650 | rc = tpm_tis_i2c_init(&client->dev); | ||
| 651 | if (rc != 0) { | ||
| 652 | client->driver = NULL; | ||
| 653 | tpm_dev.client = NULL; | ||
| 654 | rc = -ENODEV; | ||
| 655 | } | ||
| 656 | return rc; | ||
| 657 | } | ||
| 658 | |||
| 659 | static int __devexit tpm_tis_i2c_remove(struct i2c_client *client) | ||
| 660 | { | ||
| 661 | struct tpm_chip *chip = tpm_dev.chip; | ||
| 662 | release_locality(chip, chip->vendor.locality, 1); | ||
| 663 | |||
| 664 | /* close file handles */ | ||
| 665 | tpm_dev_vendor_release(chip); | ||
| 666 | |||
| 667 | /* remove hardware */ | ||
| 668 | tpm_remove_hardware(chip->dev); | ||
| 669 | |||
| 670 | /* reset these pointers, otherwise we oops */ | ||
| 671 | chip->dev->release = NULL; | ||
| 672 | chip->release = NULL; | ||
| 673 | tpm_dev.client = NULL; | ||
| 674 | dev_set_drvdata(chip->dev, chip); | ||
| 675 | |||
| 676 | return 0; | ||
| 677 | } | ||
| 678 | |||
| 679 | static struct i2c_driver tpm_tis_i2c_driver = { | ||
| 680 | |||
| 681 | .id_table = tpm_tis_i2c_table, | ||
| 682 | .probe = tpm_tis_i2c_probe, | ||
| 683 | .remove = tpm_tis_i2c_remove, | ||
| 684 | .driver = { | ||
| 685 | .name = "tpm_i2c_infineon", | ||
| 686 | .owner = THIS_MODULE, | ||
| 687 | .pm = &tpm_tis_i2c_ops, | ||
| 688 | }, | ||
| 689 | }; | ||
| 690 | |||
| 691 | module_i2c_driver(tpm_tis_i2c_driver); | ||
| 692 | MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>"); | ||
| 693 | MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver"); | ||
| 694 | MODULE_VERSION("2.1.5"); | ||
| 695 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c new file mode 100644 index 000000000000..efc4ab36a9d6 --- /dev/null +++ b/drivers/char/tpm/tpm_ibmvtpm.c | |||
| @@ -0,0 +1,749 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
| 5 | * | ||
| 6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
| 7 | * | ||
| 8 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
| 9 | * Specifications at www.trustedcomputinggroup.org | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or | ||
| 12 | * modify it under the terms of the GNU General Public License as | ||
| 13 | * published by the Free Software Foundation, version 2 of the | ||
| 14 | * License. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/dma-mapping.h> | ||
| 19 | #include <linux/dmapool.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <asm/vio.h> | ||
| 22 | #include <asm/irq.h> | ||
| 23 | #include <linux/types.h> | ||
| 24 | #include <linux/list.h> | ||
| 25 | #include <linux/spinlock.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | #include <linux/wait.h> | ||
| 28 | #include <asm/prom.h> | ||
| 29 | |||
| 30 | #include "tpm.h" | ||
| 31 | #include "tpm_ibmvtpm.h" | ||
| 32 | |||
| 33 | static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm"; | ||
| 34 | |||
| 35 | static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = { | ||
| 36 | { "IBM,vtpm", "IBM,vtpm"}, | ||
| 37 | { "", "" } | ||
| 38 | }; | ||
| 39 | MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); | ||
| 40 | |||
| 41 | DECLARE_WAIT_QUEUE_HEAD(wq); | ||
| 42 | |||
| 43 | /** | ||
| 44 | * ibmvtpm_send_crq - Send a CRQ request | ||
| 45 | * @vdev: vio device struct | ||
| 46 | * @w1: first word | ||
| 47 | * @w2: second word | ||
| 48 | * | ||
| 49 | * Return value: | ||
| 50 | * 0 -Sucess | ||
| 51 | * Non-zero - Failure | ||
| 52 | */ | ||
| 53 | static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2) | ||
| 54 | { | ||
| 55 | return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, w2); | ||
| 56 | } | ||
| 57 | |||
| 58 | /** | ||
| 59 | * ibmvtpm_get_data - Retrieve ibm vtpm data | ||
| 60 | * @dev: device struct | ||
| 61 | * | ||
| 62 | * Return value: | ||
| 63 | * vtpm device struct | ||
| 64 | */ | ||
| 65 | static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev) | ||
| 66 | { | ||
| 67 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 68 | if (chip) | ||
| 69 | return (struct ibmvtpm_dev *)chip->vendor.data; | ||
| 70 | return NULL; | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * tpm_ibmvtpm_recv - Receive data after send | ||
| 75 | * @chip: tpm chip struct | ||
| 76 | * @buf: buffer to read | ||
| 77 | * count: size of buffer | ||
| 78 | * | ||
| 79 | * Return value: | ||
| 80 | * Number of bytes read | ||
| 81 | */ | ||
| 82 | static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) | ||
| 83 | { | ||
| 84 | struct ibmvtpm_dev *ibmvtpm; | ||
| 85 | u16 len; | ||
| 86 | |||
| 87 | ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data; | ||
| 88 | |||
| 89 | if (!ibmvtpm->rtce_buf) { | ||
| 90 | dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); | ||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0); | ||
| 95 | |||
| 96 | if (count < ibmvtpm->crq_res.len) { | ||
| 97 | dev_err(ibmvtpm->dev, | ||
| 98 | "Invalid size in recv: count=%ld, crq_size=%d\n", | ||
| 99 | count, ibmvtpm->crq_res.len); | ||
| 100 | return -EIO; | ||
| 101 | } | ||
| 102 | |||
| 103 | spin_lock(&ibmvtpm->rtce_lock); | ||
| 104 | memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len); | ||
| 105 | memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len); | ||
| 106 | ibmvtpm->crq_res.valid = 0; | ||
| 107 | ibmvtpm->crq_res.msg = 0; | ||
| 108 | len = ibmvtpm->crq_res.len; | ||
| 109 | ibmvtpm->crq_res.len = 0; | ||
| 110 | spin_unlock(&ibmvtpm->rtce_lock); | ||
| 111 | return len; | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * tpm_ibmvtpm_send - Send tpm request | ||
| 116 | * @chip: tpm chip struct | ||
| 117 | * @buf: buffer contains data to send | ||
| 118 | * count: size of buffer | ||
| 119 | * | ||
| 120 | * Return value: | ||
| 121 | * Number of bytes sent | ||
| 122 | */ | ||
| 123 | static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) | ||
| 124 | { | ||
| 125 | struct ibmvtpm_dev *ibmvtpm; | ||
| 126 | struct ibmvtpm_crq crq; | ||
| 127 | u64 *word = (u64 *) &crq; | ||
| 128 | int rc; | ||
| 129 | |||
| 130 | ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data; | ||
| 131 | |||
| 132 | if (!ibmvtpm->rtce_buf) { | ||
| 133 | dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | if (count > ibmvtpm->rtce_size) { | ||
| 138 | dev_err(ibmvtpm->dev, | ||
| 139 | "Invalid size in send: count=%ld, rtce_size=%d\n", | ||
| 140 | count, ibmvtpm->rtce_size); | ||
| 141 | return -EIO; | ||
| 142 | } | ||
| 143 | |||
| 144 | spin_lock(&ibmvtpm->rtce_lock); | ||
| 145 | memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); | ||
| 146 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
| 147 | crq.msg = (u8)VTPM_TPM_COMMAND; | ||
| 148 | crq.len = (u16)count; | ||
| 149 | crq.data = ibmvtpm->rtce_dma_handle; | ||
| 150 | |||
| 151 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]); | ||
| 152 | if (rc != H_SUCCESS) { | ||
| 153 | dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); | ||
| 154 | rc = 0; | ||
| 155 | } else | ||
| 156 | rc = count; | ||
| 157 | |||
| 158 | spin_unlock(&ibmvtpm->rtce_lock); | ||
| 159 | return rc; | ||
| 160 | } | ||
| 161 | |||
| 162 | static void tpm_ibmvtpm_cancel(struct tpm_chip *chip) | ||
| 163 | { | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | |||
| 167 | static u8 tpm_ibmvtpm_status(struct tpm_chip *chip) | ||
| 168 | { | ||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | /** | ||
| 173 | * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size | ||
| 174 | * @ibmvtpm: vtpm device struct | ||
| 175 | * | ||
| 176 | * Return value: | ||
| 177 | * 0 - Success | ||
| 178 | * Non-zero - Failure | ||
| 179 | */ | ||
| 180 | static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) | ||
| 181 | { | ||
| 182 | struct ibmvtpm_crq crq; | ||
| 183 | u64 *buf = (u64 *) &crq; | ||
| 184 | int rc; | ||
| 185 | |||
| 186 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
| 187 | crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE; | ||
| 188 | |||
| 189 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
| 190 | if (rc != H_SUCCESS) | ||
| 191 | dev_err(ibmvtpm->dev, | ||
| 192 | "ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc); | ||
| 193 | |||
| 194 | return rc; | ||
| 195 | } | ||
| 196 | |||
| 197 | /** | ||
| 198 | * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version | ||
| 199 | * - Note that this is vtpm version and not tpm version | ||
| 200 | * @ibmvtpm: vtpm device struct | ||
| 201 | * | ||
| 202 | * Return value: | ||
| 203 | * 0 - Success | ||
| 204 | * Non-zero - Failure | ||
| 205 | */ | ||
| 206 | static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) | ||
| 207 | { | ||
| 208 | struct ibmvtpm_crq crq; | ||
| 209 | u64 *buf = (u64 *) &crq; | ||
| 210 | int rc; | ||
| 211 | |||
| 212 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
| 213 | crq.msg = (u8)VTPM_GET_VERSION; | ||
| 214 | |||
| 215 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
| 216 | if (rc != H_SUCCESS) | ||
| 217 | dev_err(ibmvtpm->dev, | ||
| 218 | "ibmvtpm_crq_get_version failed rc=%d\n", rc); | ||
| 219 | |||
| 220 | return rc; | ||
| 221 | } | ||
| 222 | |||
| 223 | /** | ||
| 224 | * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message | ||
| 225 | * @ibmvtpm: vtpm device struct | ||
| 226 | * | ||
| 227 | * Return value: | ||
| 228 | * 0 - Success | ||
| 229 | * Non-zero - Failure | ||
| 230 | */ | ||
| 231 | static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) | ||
| 232 | { | ||
| 233 | int rc; | ||
| 234 | |||
| 235 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_COMP_CMD, 0); | ||
| 236 | if (rc != H_SUCCESS) | ||
| 237 | dev_err(ibmvtpm->dev, | ||
| 238 | "ibmvtpm_crq_send_init_complete failed rc=%d\n", rc); | ||
| 239 | |||
| 240 | return rc; | ||
| 241 | } | ||
| 242 | |||
| 243 | /** | ||
| 244 | * ibmvtpm_crq_send_init - Send a CRQ initialize message | ||
| 245 | * @ibmvtpm: vtpm device struct | ||
| 246 | * | ||
| 247 | * Return value: | ||
| 248 | * 0 - Success | ||
| 249 | * Non-zero - Failure | ||
| 250 | */ | ||
| 251 | static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) | ||
| 252 | { | ||
| 253 | int rc; | ||
| 254 | |||
| 255 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_CMD, 0); | ||
| 256 | if (rc != H_SUCCESS) | ||
| 257 | dev_err(ibmvtpm->dev, | ||
| 258 | "ibmvtpm_crq_send_init failed rc=%d\n", rc); | ||
| 259 | |||
| 260 | return rc; | ||
| 261 | } | ||
| 262 | |||
| 263 | /** | ||
| 264 | * tpm_ibmvtpm_remove - ibm vtpm remove entry point | ||
| 265 | * @vdev: vio device struct | ||
| 266 | * | ||
| 267 | * Return value: | ||
| 268 | * 0 | ||
| 269 | */ | ||
| 270 | static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev) | ||
| 271 | { | ||
| 272 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); | ||
| 273 | int rc = 0; | ||
| 274 | |||
| 275 | free_irq(vdev->irq, ibmvtpm); | ||
| 276 | tasklet_kill(&ibmvtpm->tasklet); | ||
| 277 | |||
| 278 | do { | ||
| 279 | if (rc) | ||
| 280 | msleep(100); | ||
| 281 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
| 282 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
| 283 | |||
| 284 | dma_unmap_single(ibmvtpm->dev, ibmvtpm->crq_dma_handle, | ||
| 285 | CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL); | ||
| 286 | free_page((unsigned long)ibmvtpm->crq_queue.crq_addr); | ||
| 287 | |||
| 288 | if (ibmvtpm->rtce_buf) { | ||
| 289 | dma_unmap_single(ibmvtpm->dev, ibmvtpm->rtce_dma_handle, | ||
| 290 | ibmvtpm->rtce_size, DMA_BIDIRECTIONAL); | ||
| 291 | kfree(ibmvtpm->rtce_buf); | ||
| 292 | } | ||
| 293 | |||
| 294 | tpm_remove_hardware(ibmvtpm->dev); | ||
| 295 | |||
| 296 | kfree(ibmvtpm); | ||
| 297 | |||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | /** | ||
| 302 | * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver | ||
| 303 | * @vdev: vio device struct | ||
| 304 | * | ||
| 305 | * Return value: | ||
| 306 | * Number of bytes the driver needs to DMA map | ||
| 307 | */ | ||
| 308 | static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) | ||
| 309 | { | ||
| 310 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); | ||
| 311 | return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size; | ||
| 312 | } | ||
| 313 | |||
| 314 | /** | ||
| 315 | * tpm_ibmvtpm_suspend - Suspend | ||
| 316 | * @dev: device struct | ||
| 317 | * | ||
| 318 | * Return value: | ||
| 319 | * 0 | ||
| 320 | */ | ||
| 321 | static int tpm_ibmvtpm_suspend(struct device *dev) | ||
| 322 | { | ||
| 323 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); | ||
| 324 | struct ibmvtpm_crq crq; | ||
| 325 | u64 *buf = (u64 *) &crq; | ||
| 326 | int rc = 0; | ||
| 327 | |||
| 328 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
| 329 | crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND; | ||
| 330 | |||
| 331 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
| 332 | if (rc != H_SUCCESS) | ||
| 333 | dev_err(ibmvtpm->dev, | ||
| 334 | "tpm_ibmvtpm_suspend failed rc=%d\n", rc); | ||
| 335 | |||
| 336 | return rc; | ||
| 337 | } | ||
| 338 | |||
| 339 | /** | ||
| 340 | * ibmvtpm_reset_crq - Reset CRQ | ||
| 341 | * @ibmvtpm: ibm vtpm struct | ||
| 342 | * | ||
| 343 | * Return value: | ||
| 344 | * 0 - Success | ||
| 345 | * Non-zero - Failure | ||
| 346 | */ | ||
| 347 | static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) | ||
| 348 | { | ||
| 349 | int rc = 0; | ||
| 350 | |||
| 351 | do { | ||
| 352 | if (rc) | ||
| 353 | msleep(100); | ||
| 354 | rc = plpar_hcall_norets(H_FREE_CRQ, | ||
| 355 | ibmvtpm->vdev->unit_address); | ||
| 356 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
| 357 | |||
| 358 | memset(ibmvtpm->crq_queue.crq_addr, 0, CRQ_RES_BUF_SIZE); | ||
| 359 | ibmvtpm->crq_queue.index = 0; | ||
| 360 | |||
| 361 | return plpar_hcall_norets(H_REG_CRQ, ibmvtpm->vdev->unit_address, | ||
| 362 | ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE); | ||
| 363 | } | ||
| 364 | |||
| 365 | /** | ||
| 366 | * tpm_ibmvtpm_resume - Resume from suspend | ||
| 367 | * @dev: device struct | ||
| 368 | * | ||
| 369 | * Return value: | ||
| 370 | * 0 | ||
| 371 | */ | ||
| 372 | static int tpm_ibmvtpm_resume(struct device *dev) | ||
| 373 | { | ||
| 374 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); | ||
| 375 | unsigned long flags; | ||
| 376 | int rc = 0; | ||
| 377 | |||
| 378 | do { | ||
| 379 | if (rc) | ||
| 380 | msleep(100); | ||
| 381 | rc = plpar_hcall_norets(H_ENABLE_CRQ, | ||
| 382 | ibmvtpm->vdev->unit_address); | ||
| 383 | } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
| 384 | |||
| 385 | if (rc) { | ||
| 386 | dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc); | ||
| 387 | return rc; | ||
| 388 | } | ||
| 389 | |||
| 390 | spin_lock_irqsave(&ibmvtpm->lock, flags); | ||
| 391 | vio_disable_interrupts(ibmvtpm->vdev); | ||
| 392 | tasklet_schedule(&ibmvtpm->tasklet); | ||
| 393 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | ||
| 394 | |||
| 395 | rc = ibmvtpm_crq_send_init(ibmvtpm); | ||
| 396 | if (rc) | ||
| 397 | dev_err(dev, "Error send_init rc=%d\n", rc); | ||
| 398 | |||
| 399 | return rc; | ||
| 400 | } | ||
| 401 | |||
| 402 | static const struct file_operations ibmvtpm_ops = { | ||
| 403 | .owner = THIS_MODULE, | ||
| 404 | .llseek = no_llseek, | ||
| 405 | .open = tpm_open, | ||
| 406 | .read = tpm_read, | ||
| 407 | .write = tpm_write, | ||
| 408 | .release = tpm_release, | ||
| 409 | }; | ||
| 410 | |||
| 411 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 412 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 413 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 414 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 415 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 416 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, | ||
| 417 | NULL); | ||
| 418 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); | ||
| 419 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 420 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
| 421 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
| 422 | |||
| 423 | static struct attribute *ibmvtpm_attrs[] = { | ||
| 424 | &dev_attr_pubek.attr, | ||
| 425 | &dev_attr_pcrs.attr, | ||
| 426 | &dev_attr_enabled.attr, | ||
| 427 | &dev_attr_active.attr, | ||
| 428 | &dev_attr_owned.attr, | ||
| 429 | &dev_attr_temp_deactivated.attr, | ||
| 430 | &dev_attr_caps.attr, | ||
| 431 | &dev_attr_cancel.attr, | ||
| 432 | &dev_attr_durations.attr, | ||
| 433 | &dev_attr_timeouts.attr, NULL, | ||
| 434 | }; | ||
| 435 | |||
| 436 | static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs }; | ||
| 437 | |||
| 438 | static const struct tpm_vendor_specific tpm_ibmvtpm = { | ||
| 439 | .recv = tpm_ibmvtpm_recv, | ||
| 440 | .send = tpm_ibmvtpm_send, | ||
| 441 | .cancel = tpm_ibmvtpm_cancel, | ||
| 442 | .status = tpm_ibmvtpm_status, | ||
| 443 | .req_complete_mask = 0, | ||
| 444 | .req_complete_val = 0, | ||
| 445 | .req_canceled = 0, | ||
| 446 | .attr_group = &ibmvtpm_attr_grp, | ||
| 447 | .miscdev = { .fops = &ibmvtpm_ops, }, | ||
| 448 | }; | ||
| 449 | |||
| 450 | static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = { | ||
| 451 | .suspend = tpm_ibmvtpm_suspend, | ||
| 452 | .resume = tpm_ibmvtpm_resume, | ||
| 453 | }; | ||
| 454 | |||
| 455 | /** | ||
| 456 | * ibmvtpm_crq_get_next - Get next responded crq | ||
| 457 | * @ibmvtpm vtpm device struct | ||
| 458 | * | ||
| 459 | * Return value: | ||
| 460 | * vtpm crq pointer | ||
| 461 | */ | ||
| 462 | static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm) | ||
| 463 | { | ||
| 464 | struct ibmvtpm_crq_queue *crq_q = &ibmvtpm->crq_queue; | ||
| 465 | struct ibmvtpm_crq *crq = &crq_q->crq_addr[crq_q->index]; | ||
| 466 | |||
| 467 | if (crq->valid & VTPM_MSG_RES) { | ||
| 468 | if (++crq_q->index == crq_q->num_entry) | ||
| 469 | crq_q->index = 0; | ||
| 470 | rmb(); | ||
| 471 | } else | ||
| 472 | crq = NULL; | ||
| 473 | return crq; | ||
| 474 | } | ||
| 475 | |||
| 476 | /** | ||
| 477 | * ibmvtpm_crq_process - Process responded crq | ||
| 478 | * @crq crq to be processed | ||
| 479 | * @ibmvtpm vtpm device struct | ||
| 480 | * | ||
| 481 | * Return value: | ||
| 482 | * Nothing | ||
| 483 | */ | ||
| 484 | static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, | ||
| 485 | struct ibmvtpm_dev *ibmvtpm) | ||
| 486 | { | ||
| 487 | int rc = 0; | ||
| 488 | |||
| 489 | switch (crq->valid) { | ||
| 490 | case VALID_INIT_CRQ: | ||
| 491 | switch (crq->msg) { | ||
| 492 | case INIT_CRQ_RES: | ||
| 493 | dev_info(ibmvtpm->dev, "CRQ initialized\n"); | ||
| 494 | rc = ibmvtpm_crq_send_init_complete(ibmvtpm); | ||
| 495 | if (rc) | ||
| 496 | dev_err(ibmvtpm->dev, "Unable to send CRQ init complete rc=%d\n", rc); | ||
| 497 | return; | ||
| 498 | case INIT_CRQ_COMP_RES: | ||
| 499 | dev_info(ibmvtpm->dev, | ||
| 500 | "CRQ initialization completed\n"); | ||
| 501 | return; | ||
| 502 | default: | ||
| 503 | dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg); | ||
| 504 | return; | ||
| 505 | } | ||
| 506 | return; | ||
| 507 | case IBMVTPM_VALID_CMD: | ||
| 508 | switch (crq->msg) { | ||
| 509 | case VTPM_GET_RTCE_BUFFER_SIZE_RES: | ||
| 510 | if (crq->len <= 0) { | ||
| 511 | dev_err(ibmvtpm->dev, "Invalid rtce size\n"); | ||
| 512 | return; | ||
| 513 | } | ||
| 514 | ibmvtpm->rtce_size = crq->len; | ||
| 515 | ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size, | ||
| 516 | GFP_KERNEL); | ||
| 517 | if (!ibmvtpm->rtce_buf) { | ||
| 518 | dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n"); | ||
| 519 | return; | ||
| 520 | } | ||
| 521 | |||
| 522 | ibmvtpm->rtce_dma_handle = dma_map_single(ibmvtpm->dev, | ||
| 523 | ibmvtpm->rtce_buf, ibmvtpm->rtce_size, | ||
| 524 | DMA_BIDIRECTIONAL); | ||
| 525 | |||
| 526 | if (dma_mapping_error(ibmvtpm->dev, | ||
| 527 | ibmvtpm->rtce_dma_handle)) { | ||
| 528 | kfree(ibmvtpm->rtce_buf); | ||
| 529 | ibmvtpm->rtce_buf = NULL; | ||
| 530 | dev_err(ibmvtpm->dev, "Failed to dma map rtce buffer\n"); | ||
| 531 | } | ||
| 532 | |||
| 533 | return; | ||
| 534 | case VTPM_GET_VERSION_RES: | ||
| 535 | ibmvtpm->vtpm_version = crq->data; | ||
| 536 | return; | ||
| 537 | case VTPM_TPM_COMMAND_RES: | ||
| 538 | ibmvtpm->crq_res.valid = crq->valid; | ||
| 539 | ibmvtpm->crq_res.msg = crq->msg; | ||
| 540 | ibmvtpm->crq_res.len = crq->len; | ||
| 541 | ibmvtpm->crq_res.data = crq->data; | ||
| 542 | wake_up_interruptible(&wq); | ||
| 543 | return; | ||
| 544 | default: | ||
| 545 | return; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | return; | ||
| 549 | } | ||
| 550 | |||
| 551 | /** | ||
| 552 | * ibmvtpm_interrupt - Interrupt handler | ||
| 553 | * @irq: irq number to handle | ||
| 554 | * @vtpm_instance: vtpm that received interrupt | ||
| 555 | * | ||
| 556 | * Returns: | ||
| 557 | * IRQ_HANDLED | ||
| 558 | **/ | ||
| 559 | static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance) | ||
| 560 | { | ||
| 561 | struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance; | ||
| 562 | unsigned long flags; | ||
| 563 | |||
| 564 | spin_lock_irqsave(&ibmvtpm->lock, flags); | ||
| 565 | vio_disable_interrupts(ibmvtpm->vdev); | ||
| 566 | tasklet_schedule(&ibmvtpm->tasklet); | ||
| 567 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | ||
| 568 | |||
| 569 | return IRQ_HANDLED; | ||
| 570 | } | ||
| 571 | |||
| 572 | /** | ||
| 573 | * ibmvtpm_tasklet - Interrupt handler tasklet | ||
| 574 | * @data: ibm vtpm device struct | ||
| 575 | * | ||
| 576 | * Returns: | ||
| 577 | * Nothing | ||
| 578 | **/ | ||
| 579 | static void ibmvtpm_tasklet(void *data) | ||
| 580 | { | ||
| 581 | struct ibmvtpm_dev *ibmvtpm = data; | ||
| 582 | struct ibmvtpm_crq *crq; | ||
| 583 | unsigned long flags; | ||
| 584 | |||
| 585 | spin_lock_irqsave(&ibmvtpm->lock, flags); | ||
| 586 | while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) { | ||
| 587 | ibmvtpm_crq_process(crq, ibmvtpm); | ||
| 588 | crq->valid = 0; | ||
| 589 | wmb(); | ||
| 590 | } | ||
| 591 | |||
| 592 | vio_enable_interrupts(ibmvtpm->vdev); | ||
| 593 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | ||
| 594 | } | ||
| 595 | |||
| 596 | /** | ||
| 597 | * tpm_ibmvtpm_probe - ibm vtpm initialize entry point | ||
| 598 | * @vio_dev: vio device struct | ||
| 599 | * @id: vio device id struct | ||
| 600 | * | ||
| 601 | * Return value: | ||
| 602 | * 0 - Success | ||
| 603 | * Non-zero - Failure | ||
| 604 | */ | ||
| 605 | static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev, | ||
| 606 | const struct vio_device_id *id) | ||
| 607 | { | ||
| 608 | struct ibmvtpm_dev *ibmvtpm; | ||
| 609 | struct device *dev = &vio_dev->dev; | ||
| 610 | struct ibmvtpm_crq_queue *crq_q; | ||
| 611 | struct tpm_chip *chip; | ||
| 612 | int rc = -ENOMEM, rc1; | ||
| 613 | |||
| 614 | chip = tpm_register_hardware(dev, &tpm_ibmvtpm); | ||
| 615 | if (!chip) { | ||
| 616 | dev_err(dev, "tpm_register_hardware failed\n"); | ||
| 617 | return -ENODEV; | ||
| 618 | } | ||
| 619 | |||
| 620 | ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL); | ||
| 621 | if (!ibmvtpm) { | ||
| 622 | dev_err(dev, "kzalloc for ibmvtpm failed\n"); | ||
| 623 | goto cleanup; | ||
| 624 | } | ||
| 625 | |||
| 626 | crq_q = &ibmvtpm->crq_queue; | ||
| 627 | crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL); | ||
| 628 | if (!crq_q->crq_addr) { | ||
| 629 | dev_err(dev, "Unable to allocate memory for crq_addr\n"); | ||
| 630 | goto cleanup; | ||
| 631 | } | ||
| 632 | |||
| 633 | crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr); | ||
| 634 | ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr, | ||
| 635 | CRQ_RES_BUF_SIZE, | ||
| 636 | DMA_BIDIRECTIONAL); | ||
| 637 | |||
| 638 | if (dma_mapping_error(dev, ibmvtpm->crq_dma_handle)) { | ||
| 639 | dev_err(dev, "dma mapping failed\n"); | ||
| 640 | goto cleanup; | ||
| 641 | } | ||
| 642 | |||
| 643 | rc = plpar_hcall_norets(H_REG_CRQ, vio_dev->unit_address, | ||
| 644 | ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE); | ||
| 645 | if (rc == H_RESOURCE) | ||
| 646 | rc = ibmvtpm_reset_crq(ibmvtpm); | ||
| 647 | |||
| 648 | if (rc) { | ||
| 649 | dev_err(dev, "Unable to register CRQ rc=%d\n", rc); | ||
| 650 | goto reg_crq_cleanup; | ||
| 651 | } | ||
| 652 | |||
| 653 | tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet, | ||
| 654 | (unsigned long)ibmvtpm); | ||
| 655 | |||
| 656 | rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0, | ||
| 657 | tpm_ibmvtpm_driver_name, ibmvtpm); | ||
| 658 | if (rc) { | ||
| 659 | dev_err(dev, "Error %d register irq 0x%x\n", rc, vio_dev->irq); | ||
| 660 | goto init_irq_cleanup; | ||
| 661 | } | ||
| 662 | |||
| 663 | rc = vio_enable_interrupts(vio_dev); | ||
| 664 | if (rc) { | ||
| 665 | dev_err(dev, "Error %d enabling interrupts\n", rc); | ||
| 666 | goto init_irq_cleanup; | ||
| 667 | } | ||
| 668 | |||
| 669 | crq_q->index = 0; | ||
| 670 | |||
| 671 | ibmvtpm->dev = dev; | ||
| 672 | ibmvtpm->vdev = vio_dev; | ||
| 673 | chip->vendor.data = (void *)ibmvtpm; | ||
| 674 | |||
| 675 | spin_lock_init(&ibmvtpm->lock); | ||
| 676 | spin_lock_init(&ibmvtpm->rtce_lock); | ||
| 677 | |||
| 678 | rc = ibmvtpm_crq_send_init(ibmvtpm); | ||
| 679 | if (rc) | ||
| 680 | goto init_irq_cleanup; | ||
| 681 | |||
| 682 | rc = ibmvtpm_crq_get_version(ibmvtpm); | ||
| 683 | if (rc) | ||
| 684 | goto init_irq_cleanup; | ||
| 685 | |||
| 686 | rc = ibmvtpm_crq_get_rtce_size(ibmvtpm); | ||
| 687 | if (rc) | ||
| 688 | goto init_irq_cleanup; | ||
| 689 | |||
| 690 | return rc; | ||
| 691 | init_irq_cleanup: | ||
| 692 | tasklet_kill(&ibmvtpm->tasklet); | ||
| 693 | do { | ||
| 694 | rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address); | ||
| 695 | } while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1)); | ||
| 696 | reg_crq_cleanup: | ||
| 697 | dma_unmap_single(dev, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE, | ||
| 698 | DMA_BIDIRECTIONAL); | ||
| 699 | cleanup: | ||
| 700 | if (ibmvtpm) { | ||
| 701 | if (crq_q->crq_addr) | ||
| 702 | free_page((unsigned long)crq_q->crq_addr); | ||
| 703 | kfree(ibmvtpm); | ||
| 704 | } | ||
| 705 | |||
| 706 | tpm_remove_hardware(dev); | ||
| 707 | |||
| 708 | return rc; | ||
| 709 | } | ||
| 710 | |||
| 711 | static struct vio_driver ibmvtpm_driver = { | ||
| 712 | .id_table = tpm_ibmvtpm_device_table, | ||
| 713 | .probe = tpm_ibmvtpm_probe, | ||
| 714 | .remove = tpm_ibmvtpm_remove, | ||
| 715 | .get_desired_dma = tpm_ibmvtpm_get_desired_dma, | ||
| 716 | .name = tpm_ibmvtpm_driver_name, | ||
| 717 | .pm = &tpm_ibmvtpm_pm_ops, | ||
| 718 | }; | ||
| 719 | |||
| 720 | /** | ||
| 721 | * ibmvtpm_module_init - Initialize ibm vtpm module | ||
| 722 | * | ||
| 723 | * Return value: | ||
| 724 | * 0 -Success | ||
| 725 | * Non-zero - Failure | ||
| 726 | */ | ||
| 727 | static int __init ibmvtpm_module_init(void) | ||
| 728 | { | ||
| 729 | return vio_register_driver(&ibmvtpm_driver); | ||
| 730 | } | ||
| 731 | |||
| 732 | /** | ||
| 733 | * ibmvtpm_module_exit - Teardown ibm vtpm module | ||
| 734 | * | ||
| 735 | * Return value: | ||
| 736 | * Nothing | ||
| 737 | */ | ||
| 738 | static void __exit ibmvtpm_module_exit(void) | ||
| 739 | { | ||
| 740 | vio_unregister_driver(&ibmvtpm_driver); | ||
| 741 | } | ||
| 742 | |||
| 743 | module_init(ibmvtpm_module_init); | ||
| 744 | module_exit(ibmvtpm_module_exit); | ||
| 745 | |||
| 746 | MODULE_AUTHOR("adlai@us.ibm.com"); | ||
| 747 | MODULE_DESCRIPTION("IBM vTPM Driver"); | ||
| 748 | MODULE_VERSION("1.0"); | ||
| 749 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h new file mode 100644 index 000000000000..4296eb4b4d82 --- /dev/null +++ b/drivers/char/tpm/tpm_ibmvtpm.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
| 5 | * | ||
| 6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
| 7 | * | ||
| 8 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
| 9 | * Specifications at www.trustedcomputinggroup.org | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or | ||
| 12 | * modify it under the terms of the GNU General Public License as | ||
| 13 | * published by the Free Software Foundation, version 2 of the | ||
| 14 | * License. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef __TPM_IBMVTPM_H__ | ||
| 19 | #define __TPM_IBMVTPM_H__ | ||
| 20 | |||
| 21 | /* vTPM Message Format 1 */ | ||
| 22 | struct ibmvtpm_crq { | ||
| 23 | u8 valid; | ||
| 24 | u8 msg; | ||
| 25 | u16 len; | ||
| 26 | u32 data; | ||
| 27 | u64 reserved; | ||
| 28 | } __attribute__((packed, aligned(8))); | ||
| 29 | |||
| 30 | struct ibmvtpm_crq_queue { | ||
| 31 | struct ibmvtpm_crq *crq_addr; | ||
| 32 | u32 index; | ||
| 33 | u32 num_entry; | ||
| 34 | }; | ||
| 35 | |||
| 36 | struct ibmvtpm_dev { | ||
| 37 | struct device *dev; | ||
| 38 | struct vio_dev *vdev; | ||
| 39 | struct ibmvtpm_crq_queue crq_queue; | ||
| 40 | dma_addr_t crq_dma_handle; | ||
| 41 | spinlock_t lock; | ||
| 42 | struct tasklet_struct tasklet; | ||
| 43 | u32 rtce_size; | ||
| 44 | void __iomem *rtce_buf; | ||
| 45 | dma_addr_t rtce_dma_handle; | ||
| 46 | spinlock_t rtce_lock; | ||
| 47 | struct ibmvtpm_crq crq_res; | ||
| 48 | u32 vtpm_version; | ||
| 49 | }; | ||
| 50 | |||
| 51 | #define CRQ_RES_BUF_SIZE PAGE_SIZE | ||
| 52 | |||
| 53 | /* Initialize CRQ */ | ||
| 54 | #define INIT_CRQ_CMD 0xC001000000000000LL /* Init cmd */ | ||
| 55 | #define INIT_CRQ_COMP_CMD 0xC002000000000000LL /* Init complete cmd */ | ||
| 56 | #define INIT_CRQ_RES 0x01 /* Init respond */ | ||
| 57 | #define INIT_CRQ_COMP_RES 0x02 /* Init complete respond */ | ||
| 58 | #define VALID_INIT_CRQ 0xC0 /* Valid command for init crq */ | ||
| 59 | |||
| 60 | /* vTPM CRQ response is the message type | 0x80 */ | ||
| 61 | #define VTPM_MSG_RES 0x80 | ||
| 62 | #define IBMVTPM_VALID_CMD 0x80 | ||
| 63 | |||
| 64 | /* vTPM CRQ message types */ | ||
| 65 | #define VTPM_GET_VERSION 0x01 | ||
| 66 | #define VTPM_GET_VERSION_RES (0x01 | VTPM_MSG_RES) | ||
| 67 | |||
| 68 | #define VTPM_TPM_COMMAND 0x02 | ||
| 69 | #define VTPM_TPM_COMMAND_RES (0x02 | VTPM_MSG_RES) | ||
| 70 | |||
| 71 | #define VTPM_GET_RTCE_BUFFER_SIZE 0x03 | ||
| 72 | #define VTPM_GET_RTCE_BUFFER_SIZE_RES (0x03 | VTPM_MSG_RES) | ||
| 73 | |||
| 74 | #define VTPM_PREPARE_TO_SUSPEND 0x04 | ||
| 75 | #define VTPM_PREPARE_TO_SUSPEND_RES (0x04 | VTPM_MSG_RES) | ||
| 76 | |||
| 77 | #endif | ||
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c new file mode 100644 index 000000000000..98ba2bd1a355 --- /dev/null +++ b/drivers/char/tpm/tpm_of.c | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
| 5 | * | ||
| 6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
| 7 | * | ||
| 8 | * Read the event log created by the firmware on PPC64 | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU General Public License | ||
| 12 | * as published by the Free Software Foundation; either version | ||
| 13 | * 2 of the License, or (at your option) any later version. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | |||
| 20 | #include "tpm.h" | ||
| 21 | #include "tpm_eventlog.h" | ||
| 22 | |||
| 23 | int read_log(struct tpm_bios_log *log) | ||
| 24 | { | ||
| 25 | struct device_node *np; | ||
| 26 | const u32 *sizep; | ||
| 27 | const __be64 *basep; | ||
| 28 | |||
| 29 | if (log->bios_event_log != NULL) { | ||
| 30 | pr_err("%s: ERROR - Eventlog already initialized\n", __func__); | ||
| 31 | return -EFAULT; | ||
| 32 | } | ||
| 33 | |||
| 34 | np = of_find_node_by_name(NULL, "ibm,vtpm"); | ||
| 35 | if (!np) { | ||
| 36 | pr_err("%s: ERROR - IBMVTPM not supported\n", __func__); | ||
| 37 | return -ENODEV; | ||
| 38 | } | ||
| 39 | |||
| 40 | sizep = of_get_property(np, "linux,sml-size", NULL); | ||
| 41 | if (sizep == NULL) { | ||
| 42 | pr_err("%s: ERROR - SML size not found\n", __func__); | ||
| 43 | goto cleanup_eio; | ||
| 44 | } | ||
| 45 | if (*sizep == 0) { | ||
| 46 | pr_err("%s: ERROR - event log area empty\n", __func__); | ||
| 47 | goto cleanup_eio; | ||
| 48 | } | ||
| 49 | |||
| 50 | basep = of_get_property(np, "linux,sml-base", NULL); | ||
| 51 | if (basep == NULL) { | ||
| 52 | pr_err(KERN_ERR "%s: ERROR - SML not found\n", __func__); | ||
| 53 | goto cleanup_eio; | ||
| 54 | } | ||
| 55 | |||
| 56 | of_node_put(np); | ||
| 57 | log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); | ||
| 58 | if (!log->bios_event_log) { | ||
| 59 | pr_err("%s: ERROR - Not enough memory for BIOS measurements\n", | ||
| 60 | __func__); | ||
| 61 | return -ENOMEM; | ||
| 62 | } | ||
| 63 | |||
| 64 | log->bios_event_log_end = log->bios_event_log + *sizep; | ||
| 65 | |||
| 66 | memcpy(log->bios_event_log, __va(be64_to_cpup(basep)), *sizep); | ||
| 67 | |||
| 68 | return 0; | ||
| 69 | |||
| 70 | cleanup_eio: | ||
| 71 | of_node_put(np); | ||
| 72 | return -EIO; | ||
| 73 | } | ||
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c new file mode 100644 index 000000000000..f27b58cfae98 --- /dev/null +++ b/drivers/char/tpm/tpm_ppi.c | |||
| @@ -0,0 +1,461 @@ | |||
| 1 | #include <linux/acpi.h> | ||
| 2 | #include <acpi/acpi_drivers.h> | ||
| 3 | #include "tpm.h" | ||
| 4 | |||
| 5 | static const u8 tpm_ppi_uuid[] = { | ||
| 6 | 0xA6, 0xFA, 0xDD, 0x3D, | ||
| 7 | 0x1B, 0x36, | ||
| 8 | 0xB4, 0x4E, | ||
| 9 | 0xA4, 0x24, | ||
| 10 | 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 | ||
| 11 | }; | ||
| 12 | static char *tpm_device_name = "TPM"; | ||
| 13 | |||
| 14 | #define TPM_PPI_REVISION_ID 1 | ||
| 15 | #define TPM_PPI_FN_VERSION 1 | ||
| 16 | #define TPM_PPI_FN_SUBREQ 2 | ||
| 17 | #define TPM_PPI_FN_GETREQ 3 | ||
| 18 | #define TPM_PPI_FN_GETACT 4 | ||
| 19 | #define TPM_PPI_FN_GETRSP 5 | ||
| 20 | #define TPM_PPI_FN_SUBREQ2 7 | ||
| 21 | #define TPM_PPI_FN_GETOPR 8 | ||
| 22 | #define PPI_TPM_REQ_MAX 22 | ||
| 23 | #define PPI_VS_REQ_START 128 | ||
| 24 | #define PPI_VS_REQ_END 255 | ||
| 25 | #define PPI_VERSION_LEN 3 | ||
| 26 | |||
| 27 | static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, | ||
| 28 | void **return_value) | ||
| 29 | { | ||
| 30 | acpi_status status; | ||
| 31 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 32 | status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | ||
| 33 | if (strstr(buffer.pointer, context) != NULL) { | ||
| 34 | *return_value = handle; | ||
| 35 | kfree(buffer.pointer); | ||
| 36 | return AE_CTRL_TERMINATE; | ||
| 37 | } | ||
| 38 | return AE_OK; | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline void ppi_assign_params(union acpi_object params[4], | ||
| 42 | u64 function_num) | ||
| 43 | { | ||
| 44 | params[0].type = ACPI_TYPE_BUFFER; | ||
| 45 | params[0].buffer.length = sizeof(tpm_ppi_uuid); | ||
| 46 | params[0].buffer.pointer = (char *)tpm_ppi_uuid; | ||
| 47 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 48 | params[1].integer.value = TPM_PPI_REVISION_ID; | ||
| 49 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 50 | params[2].integer.value = function_num; | ||
| 51 | params[3].type = ACPI_TYPE_PACKAGE; | ||
| 52 | params[3].package.count = 0; | ||
| 53 | params[3].package.elements = NULL; | ||
| 54 | } | ||
| 55 | |||
| 56 | static ssize_t tpm_show_ppi_version(struct device *dev, | ||
| 57 | struct device_attribute *attr, char *buf) | ||
| 58 | { | ||
| 59 | acpi_handle handle; | ||
| 60 | acpi_status status; | ||
| 61 | struct acpi_object_list input; | ||
| 62 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 63 | union acpi_object params[4]; | ||
| 64 | union acpi_object *obj; | ||
| 65 | |||
| 66 | input.count = 4; | ||
| 67 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
| 68 | input.pointer = params; | ||
| 69 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 70 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 71 | tpm_device_name, &handle); | ||
| 72 | if (ACPI_FAILURE(status)) | ||
| 73 | return -ENXIO; | ||
| 74 | |||
| 75 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 76 | ACPI_TYPE_STRING); | ||
| 77 | if (ACPI_FAILURE(status)) | ||
| 78 | return -ENOMEM; | ||
| 79 | obj = (union acpi_object *)output.pointer; | ||
| 80 | status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer); | ||
| 81 | kfree(output.pointer); | ||
| 82 | return status; | ||
| 83 | } | ||
| 84 | |||
| 85 | static ssize_t tpm_show_ppi_request(struct device *dev, | ||
| 86 | struct device_attribute *attr, char *buf) | ||
| 87 | { | ||
| 88 | acpi_handle handle; | ||
| 89 | acpi_status status; | ||
| 90 | struct acpi_object_list input; | ||
| 91 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 92 | union acpi_object params[4]; | ||
| 93 | union acpi_object *ret_obj; | ||
| 94 | |||
| 95 | input.count = 4; | ||
| 96 | ppi_assign_params(params, TPM_PPI_FN_GETREQ); | ||
| 97 | input.pointer = params; | ||
| 98 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 99 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 100 | tpm_device_name, &handle); | ||
| 101 | if (ACPI_FAILURE(status)) | ||
| 102 | return -ENXIO; | ||
| 103 | |||
| 104 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 105 | ACPI_TYPE_PACKAGE); | ||
| 106 | if (ACPI_FAILURE(status)) | ||
| 107 | return -ENOMEM; | ||
| 108 | /* | ||
| 109 | * output.pointer should be of package type, including two integers. | ||
| 110 | * The first is function return code, 0 means success and 1 means | ||
| 111 | * error. The second is pending TPM operation requested by the OS, 0 | ||
| 112 | * means none and >0 means operation value. | ||
| 113 | */ | ||
| 114 | ret_obj = ((union acpi_object *)output.pointer)->package.elements; | ||
| 115 | if (ret_obj->type == ACPI_TYPE_INTEGER) { | ||
| 116 | if (ret_obj->integer.value) { | ||
| 117 | status = -EFAULT; | ||
| 118 | goto cleanup; | ||
| 119 | } | ||
| 120 | ret_obj++; | ||
| 121 | if (ret_obj->type == ACPI_TYPE_INTEGER) | ||
| 122 | status = scnprintf(buf, PAGE_SIZE, "%llu\n", | ||
| 123 | ret_obj->integer.value); | ||
| 124 | else | ||
| 125 | status = -EINVAL; | ||
| 126 | } else { | ||
| 127 | status = -EINVAL; | ||
| 128 | } | ||
| 129 | cleanup: | ||
| 130 | kfree(output.pointer); | ||
| 131 | return status; | ||
| 132 | } | ||
| 133 | |||
| 134 | static ssize_t tpm_store_ppi_request(struct device *dev, | ||
| 135 | struct device_attribute *attr, | ||
| 136 | const char *buf, size_t count) | ||
| 137 | { | ||
| 138 | char version[PPI_VERSION_LEN + 1]; | ||
| 139 | acpi_handle handle; | ||
| 140 | acpi_status status; | ||
| 141 | struct acpi_object_list input; | ||
| 142 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 143 | union acpi_object params[4]; | ||
| 144 | union acpi_object obj; | ||
| 145 | u32 req; | ||
| 146 | u64 ret; | ||
| 147 | |||
| 148 | input.count = 4; | ||
| 149 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
| 150 | input.pointer = params; | ||
| 151 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 152 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 153 | tpm_device_name, &handle); | ||
| 154 | if (ACPI_FAILURE(status)) | ||
| 155 | return -ENXIO; | ||
| 156 | |||
| 157 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 158 | ACPI_TYPE_STRING); | ||
| 159 | if (ACPI_FAILURE(status)) | ||
| 160 | return -ENOMEM; | ||
| 161 | strncpy(version, | ||
| 162 | ((union acpi_object *)output.pointer)->string.pointer, | ||
| 163 | PPI_VERSION_LEN); | ||
| 164 | kfree(output.pointer); | ||
| 165 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 166 | output.pointer = NULL; | ||
| 167 | /* | ||
| 168 | * the function to submit TPM operation request to pre-os environment | ||
| 169 | * is updated with function index from SUBREQ to SUBREQ2 since PPI | ||
| 170 | * version 1.1 | ||
| 171 | */ | ||
| 172 | if (strcmp(version, "1.1") == -1) | ||
| 173 | params[2].integer.value = TPM_PPI_FN_SUBREQ; | ||
| 174 | else | ||
| 175 | params[2].integer.value = TPM_PPI_FN_SUBREQ2; | ||
| 176 | /* | ||
| 177 | * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS | ||
| 178 | * accept buffer/string/integer type, but some BIOS accept buffer/ | ||
| 179 | * string/package type. For PPI version 1.0 and 1.1, use buffer type | ||
| 180 | * for compatibility, and use package type since 1.2 according to spec. | ||
| 181 | */ | ||
| 182 | if (strcmp(version, "1.2") == -1) { | ||
| 183 | params[3].type = ACPI_TYPE_BUFFER; | ||
| 184 | params[3].buffer.length = sizeof(req); | ||
| 185 | sscanf(buf, "%d", &req); | ||
| 186 | params[3].buffer.pointer = (char *)&req; | ||
| 187 | } else { | ||
| 188 | params[3].package.count = 1; | ||
| 189 | obj.type = ACPI_TYPE_INTEGER; | ||
| 190 | sscanf(buf, "%llu", &obj.integer.value); | ||
| 191 | params[3].package.elements = &obj; | ||
| 192 | } | ||
| 193 | |||
| 194 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 195 | ACPI_TYPE_INTEGER); | ||
| 196 | if (ACPI_FAILURE(status)) | ||
| 197 | return -ENOMEM; | ||
| 198 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
| 199 | if (ret == 0) | ||
| 200 | status = (acpi_status)count; | ||
| 201 | else if (ret == 1) | ||
| 202 | status = -EPERM; | ||
| 203 | else | ||
| 204 | status = -EFAULT; | ||
| 205 | kfree(output.pointer); | ||
| 206 | return status; | ||
| 207 | } | ||
| 208 | |||
| 209 | static ssize_t tpm_show_ppi_transition_action(struct device *dev, | ||
| 210 | struct device_attribute *attr, | ||
| 211 | char *buf) | ||
| 212 | { | ||
| 213 | char version[PPI_VERSION_LEN + 1]; | ||
| 214 | acpi_handle handle; | ||
| 215 | acpi_status status; | ||
| 216 | struct acpi_object_list input; | ||
| 217 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 218 | union acpi_object params[4]; | ||
| 219 | u32 ret; | ||
| 220 | char *info[] = { | ||
| 221 | "None", | ||
| 222 | "Shutdown", | ||
| 223 | "Reboot", | ||
| 224 | "OS Vendor-specific", | ||
| 225 | "Error", | ||
| 226 | }; | ||
| 227 | input.count = 4; | ||
| 228 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
| 229 | input.pointer = params; | ||
| 230 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 231 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 232 | tpm_device_name, &handle); | ||
| 233 | if (ACPI_FAILURE(status)) | ||
| 234 | return -ENXIO; | ||
| 235 | |||
| 236 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 237 | ACPI_TYPE_STRING); | ||
| 238 | if (ACPI_FAILURE(status)) | ||
| 239 | return -ENOMEM; | ||
| 240 | strncpy(version, | ||
| 241 | ((union acpi_object *)output.pointer)->string.pointer, | ||
| 242 | PPI_VERSION_LEN); | ||
| 243 | /* | ||
| 244 | * PPI spec defines params[3].type as empty package, but some platforms | ||
| 245 | * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for | ||
| 246 | * compatibility, define params[3].type as buffer, if PPI version < 1.2 | ||
| 247 | */ | ||
| 248 | if (strcmp(version, "1.2") == -1) { | ||
| 249 | params[3].type = ACPI_TYPE_BUFFER; | ||
| 250 | params[3].buffer.length = 0; | ||
| 251 | params[3].buffer.pointer = NULL; | ||
| 252 | } | ||
| 253 | params[2].integer.value = TPM_PPI_FN_GETACT; | ||
| 254 | kfree(output.pointer); | ||
| 255 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 256 | output.pointer = NULL; | ||
| 257 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 258 | ACPI_TYPE_INTEGER); | ||
| 259 | if (ACPI_FAILURE(status)) | ||
| 260 | return -ENOMEM; | ||
| 261 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
| 262 | if (ret < ARRAY_SIZE(info) - 1) | ||
| 263 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); | ||
| 264 | else | ||
| 265 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, | ||
| 266 | info[ARRAY_SIZE(info)-1]); | ||
| 267 | kfree(output.pointer); | ||
| 268 | return status; | ||
| 269 | } | ||
| 270 | |||
| 271 | static ssize_t tpm_show_ppi_response(struct device *dev, | ||
| 272 | struct device_attribute *attr, | ||
| 273 | char *buf) | ||
| 274 | { | ||
| 275 | acpi_handle handle; | ||
| 276 | acpi_status status; | ||
| 277 | struct acpi_object_list input; | ||
| 278 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 279 | union acpi_object params[4]; | ||
| 280 | union acpi_object *ret_obj; | ||
| 281 | u64 req; | ||
| 282 | |||
| 283 | input.count = 4; | ||
| 284 | ppi_assign_params(params, TPM_PPI_FN_GETRSP); | ||
| 285 | input.pointer = params; | ||
| 286 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 287 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 288 | tpm_device_name, &handle); | ||
| 289 | if (ACPI_FAILURE(status)) | ||
| 290 | return -ENXIO; | ||
| 291 | |||
| 292 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 293 | ACPI_TYPE_PACKAGE); | ||
| 294 | if (ACPI_FAILURE(status)) | ||
| 295 | return -ENOMEM; | ||
| 296 | /* | ||
| 297 | * parameter output.pointer should be of package type, including | ||
| 298 | * 3 integers. The first means function return code, the second means | ||
| 299 | * most recent TPM operation request, and the last means response to | ||
| 300 | * the most recent TPM operation request. Only if the first is 0, and | ||
| 301 | * the second integer is not 0, the response makes sense. | ||
| 302 | */ | ||
| 303 | ret_obj = ((union acpi_object *)output.pointer)->package.elements; | ||
| 304 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
| 305 | status = -EINVAL; | ||
| 306 | goto cleanup; | ||
| 307 | } | ||
| 308 | if (ret_obj->integer.value) { | ||
| 309 | status = -EFAULT; | ||
| 310 | goto cleanup; | ||
| 311 | } | ||
| 312 | ret_obj++; | ||
| 313 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
| 314 | status = -EINVAL; | ||
| 315 | goto cleanup; | ||
| 316 | } | ||
| 317 | if (ret_obj->integer.value) { | ||
| 318 | req = ret_obj->integer.value; | ||
| 319 | ret_obj++; | ||
| 320 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
| 321 | status = -EINVAL; | ||
| 322 | goto cleanup; | ||
| 323 | } | ||
| 324 | if (ret_obj->integer.value == 0) | ||
| 325 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
| 326 | "0: Success"); | ||
| 327 | else if (ret_obj->integer.value == 0xFFFFFFF0) | ||
| 328 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
| 329 | "0xFFFFFFF0: User Abort"); | ||
| 330 | else if (ret_obj->integer.value == 0xFFFFFFF1) | ||
| 331 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
| 332 | "0xFFFFFFF1: BIOS Failure"); | ||
| 333 | else if (ret_obj->integer.value >= 1 && | ||
| 334 | ret_obj->integer.value <= 0x00000FFF) | ||
| 335 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", | ||
| 336 | req, ret_obj->integer.value, | ||
| 337 | "Corresponding TPM error"); | ||
| 338 | else | ||
| 339 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", | ||
| 340 | req, ret_obj->integer.value, | ||
| 341 | "Error"); | ||
| 342 | } else { | ||
| 343 | status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", | ||
| 344 | ret_obj->integer.value, "No Recent Request"); | ||
| 345 | } | ||
| 346 | cleanup: | ||
| 347 | kfree(output.pointer); | ||
| 348 | return status; | ||
| 349 | } | ||
| 350 | |||
| 351 | static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) | ||
| 352 | { | ||
| 353 | char *str = buf; | ||
| 354 | char version[PPI_VERSION_LEN]; | ||
| 355 | acpi_handle handle; | ||
| 356 | acpi_status status; | ||
| 357 | struct acpi_object_list input; | ||
| 358 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 359 | union acpi_object params[4]; | ||
| 360 | union acpi_object obj; | ||
| 361 | int i; | ||
| 362 | u32 ret; | ||
| 363 | char *info[] = { | ||
| 364 | "Not implemented", | ||
| 365 | "BIOS only", | ||
| 366 | "Blocked for OS by BIOS", | ||
| 367 | "User required", | ||
| 368 | "User not required", | ||
| 369 | }; | ||
| 370 | input.count = 4; | ||
| 371 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
| 372 | input.pointer = params; | ||
| 373 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 374 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
| 375 | tpm_device_name, &handle); | ||
| 376 | if (ACPI_FAILURE(status)) | ||
| 377 | return -ENXIO; | ||
| 378 | |||
| 379 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
| 380 | ACPI_TYPE_STRING); | ||
| 381 | if (ACPI_FAILURE(status)) | ||
| 382 | return -ENOMEM; | ||
| 383 | |||
| 384 | strncpy(version, | ||
| 385 | ((union acpi_object *)output.pointer)->string.pointer, | ||
| 386 | PPI_VERSION_LEN); | ||
| 387 | kfree(output.pointer); | ||
| 388 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 389 | output.pointer = NULL; | ||
| 390 | if (strcmp(version, "1.2") == -1) | ||
| 391 | return -EPERM; | ||
| 392 | |||
| 393 | params[2].integer.value = TPM_PPI_FN_GETOPR; | ||
| 394 | params[3].package.count = 1; | ||
| 395 | obj.type = ACPI_TYPE_INTEGER; | ||
| 396 | params[3].package.elements = &obj; | ||
| 397 | for (i = start; i <= end; i++) { | ||
| 398 | obj.integer.value = i; | ||
| 399 | status = acpi_evaluate_object_typed(handle, "_DSM", | ||
| 400 | &input, &output, ACPI_TYPE_INTEGER); | ||
| 401 | if (ACPI_FAILURE(status)) | ||
| 402 | return -ENOMEM; | ||
| 403 | |||
| 404 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
| 405 | if (ret > 0 && ret < ARRAY_SIZE(info)) | ||
| 406 | str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", | ||
| 407 | i, ret, info[ret]); | ||
| 408 | kfree(output.pointer); | ||
| 409 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 410 | output.pointer = NULL; | ||
| 411 | } | ||
| 412 | return str - buf; | ||
| 413 | } | ||
| 414 | |||
| 415 | static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, | ||
| 416 | struct device_attribute *attr, | ||
| 417 | char *buf) | ||
| 418 | { | ||
| 419 | return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX); | ||
| 420 | } | ||
| 421 | |||
| 422 | static ssize_t tpm_show_ppi_vs_operations(struct device *dev, | ||
| 423 | struct device_attribute *attr, | ||
| 424 | char *buf) | ||
| 425 | { | ||
| 426 | return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END); | ||
| 427 | } | ||
| 428 | |||
| 429 | static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); | ||
| 430 | static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, | ||
| 431 | tpm_show_ppi_request, tpm_store_ppi_request); | ||
| 432 | static DEVICE_ATTR(transition_action, S_IRUGO, | ||
| 433 | tpm_show_ppi_transition_action, NULL); | ||
| 434 | static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); | ||
| 435 | static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); | ||
| 436 | static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); | ||
| 437 | |||
| 438 | static struct attribute *ppi_attrs[] = { | ||
| 439 | &dev_attr_version.attr, | ||
| 440 | &dev_attr_request.attr, | ||
| 441 | &dev_attr_transition_action.attr, | ||
| 442 | &dev_attr_response.attr, | ||
| 443 | &dev_attr_tcg_operations.attr, | ||
| 444 | &dev_attr_vs_operations.attr, NULL, | ||
| 445 | }; | ||
| 446 | static struct attribute_group ppi_attr_grp = { | ||
| 447 | .attrs = ppi_attrs | ||
| 448 | }; | ||
| 449 | |||
| 450 | ssize_t sys_add_ppi(struct kobject *parent) | ||
| 451 | { | ||
| 452 | struct kobject *ppi; | ||
| 453 | ppi = kobject_create_and_add("ppi", parent); | ||
| 454 | if (sysfs_create_group(ppi, &ppi_attr_grp)) | ||
| 455 | return -EFAULT; | ||
| 456 | else | ||
| 457 | return 0; | ||
| 458 | } | ||
| 459 | EXPORT_SYMBOL_GPL(sys_add_ppi); | ||
| 460 | |||
| 461 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index c4be3519a587..6bdf2671254f 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
| @@ -705,6 +705,7 @@ out_err: | |||
| 705 | return rc; | 705 | return rc; |
| 706 | } | 706 | } |
| 707 | 707 | ||
| 708 | #if defined(CONFIG_PNP) || defined(CONFIG_PM_SLEEP) | ||
| 708 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | 709 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) |
| 709 | { | 710 | { |
| 710 | u32 intmask; | 711 | u32 intmask; |
| @@ -725,7 +726,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | |||
| 725 | iowrite32(intmask, | 726 | iowrite32(intmask, |
| 726 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); | 727 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); |
| 727 | } | 728 | } |
| 728 | 729 | #endif | |
| 729 | 730 | ||
| 730 | #ifdef CONFIG_PNP | 731 | #ifdef CONFIG_PNP |
| 731 | static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, | 732 | static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, |
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/fcntl.h> | 14 | #include <linux/fcntl.h> |
| 15 | #include <linux/security.h> | 15 | #include <linux/security.h> |
| 16 | #include <linux/evm.h> | 16 | #include <linux/evm.h> |
| 17 | #include <linux/ima.h> | ||
| 17 | 18 | ||
| 18 | /** | 19 | /** |
| 19 | * inode_change_ok - check if attribute changes to an inode are allowed | 20 | * inode_change_ok - check if attribute changes to an inode are allowed |
| @@ -247,6 +248,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr) | |||
| 247 | 248 | ||
| 248 | if (!error) { | 249 | if (!error) { |
| 249 | fsnotify_change(dentry, ia_valid); | 250 | fsnotify_change(dentry, ia_valid); |
| 251 | ima_inode_post_setattr(dentry); | ||
| 250 | evm_inode_post_setattr(dentry, ia_valid); | 252 | evm_inode_post_setattr(dentry, ia_valid); |
| 251 | } | 253 | } |
| 252 | 254 | ||
diff --git a/fs/file_table.c b/fs/file_table.c index c6780163bf3e..dac67923330f 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
| @@ -243,10 +243,10 @@ static void __fput(struct file *file) | |||
| 243 | if (file->f_op && file->f_op->fasync) | 243 | if (file->f_op && file->f_op->fasync) |
| 244 | file->f_op->fasync(-1, file, 0); | 244 | file->f_op->fasync(-1, file, 0); |
| 245 | } | 245 | } |
| 246 | ima_file_free(file); | ||
| 246 | if (file->f_op && file->f_op->release) | 247 | if (file->f_op && file->f_op->release) |
| 247 | file->f_op->release(inode, file); | 248 | file->f_op->release(inode, file); |
| 248 | security_file_free(file); | 249 | security_file_free(file); |
| 249 | ima_file_free(file); | ||
| 250 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && | 250 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && |
| 251 | !(file->f_mode & FMODE_PATH))) { | 251 | !(file->f_mode & FMODE_PATH))) { |
| 252 | cdev_put(inode->i_cdev); | 252 | cdev_put(inode->i_cdev); |
diff --git a/fs/xattr.c b/fs/xattr.c index ca15fbd391c8..1780f062dbaf 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
| @@ -296,11 +296,13 @@ vfs_removexattr(struct dentry *dentry, const char *name) | |||
| 296 | if (error) | 296 | if (error) |
| 297 | return error; | 297 | return error; |
| 298 | 298 | ||
| 299 | mutex_lock(&inode->i_mutex); | ||
| 299 | error = security_inode_removexattr(dentry, name); | 300 | error = security_inode_removexattr(dentry, name); |
| 300 | if (error) | 301 | if (error) { |
| 302 | mutex_unlock(&inode->i_mutex); | ||
| 301 | return error; | 303 | return error; |
| 304 | } | ||
| 302 | 305 | ||
| 303 | mutex_lock(&inode->i_mutex); | ||
| 304 | error = inode->i_op->removexattr(dentry, name); | 306 | error = inode->i_op->removexattr(dentry, name); |
| 305 | mutex_unlock(&inode->i_mutex); | 307 | mutex_unlock(&inode->i_mutex); |
| 306 | 308 | ||
diff --git a/include/linux/audit.h b/include/linux/audit.h index 12367cbadfe1..e7c836d961ea 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
| @@ -531,6 +531,7 @@ extern int audit_set_loginuid(kuid_t loginuid); | |||
| 531 | #define audit_get_loginuid(t) ((t)->loginuid) | 531 | #define audit_get_loginuid(t) ((t)->loginuid) |
| 532 | #define audit_get_sessionid(t) ((t)->sessionid) | 532 | #define audit_get_sessionid(t) ((t)->sessionid) |
| 533 | extern void audit_log_task_context(struct audit_buffer *ab); | 533 | extern void audit_log_task_context(struct audit_buffer *ab); |
| 534 | extern void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk); | ||
| 534 | extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp); | 535 | extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp); |
| 535 | extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode); | 536 | extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode); |
| 536 | extern int __audit_bprm(struct linux_binprm *bprm); | 537 | extern int __audit_bprm(struct linux_binprm *bprm); |
| @@ -642,6 +643,7 @@ extern int audit_signals; | |||
| 642 | #define audit_get_loginuid(t) (INVALID_UID) | 643 | #define audit_get_loginuid(t) (INVALID_UID) |
| 643 | #define audit_get_sessionid(t) (-1) | 644 | #define audit_get_sessionid(t) (-1) |
| 644 | #define audit_log_task_context(b) do { ; } while (0) | 645 | #define audit_log_task_context(b) do { ; } while (0) |
| 646 | #define audit_log_task_info(b, t) do { ; } while (0) | ||
| 645 | #define audit_ipc_obj(i) ((void)0) | 647 | #define audit_ipc_obj(i) ((void)0) |
| 646 | #define audit_ipc_set_perm(q,u,g,m) ((void)0) | 648 | #define audit_ipc_set_perm(q,u,g,m) ((void)0) |
| 647 | #define audit_bprm(p) ({ 0; }) | 649 | #define audit_bprm(p) ({ 0; }) |
diff --git a/include/linux/ima.h b/include/linux/ima.h index 6ac8e50c6cf5..2c7223d7e73b 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h | |||
| @@ -39,5 +39,32 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot) | |||
| 39 | { | 39 | { |
| 40 | return 0; | 40 | return 0; |
| 41 | } | 41 | } |
| 42 | |||
| 42 | #endif /* CONFIG_IMA_H */ | 43 | #endif /* CONFIG_IMA_H */ |
| 44 | |||
| 45 | #ifdef CONFIG_IMA_APPRAISE | ||
| 46 | extern void ima_inode_post_setattr(struct dentry *dentry); | ||
| 47 | extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, | ||
| 48 | const void *xattr_value, size_t xattr_value_len); | ||
| 49 | extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name); | ||
| 50 | #else | ||
| 51 | static inline void ima_inode_post_setattr(struct dentry *dentry) | ||
| 52 | { | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline int ima_inode_setxattr(struct dentry *dentry, | ||
| 57 | const char *xattr_name, | ||
| 58 | const void *xattr_value, | ||
| 59 | size_t xattr_value_len) | ||
| 60 | { | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | static inline int ima_inode_removexattr(struct dentry *dentry, | ||
| 65 | const char *xattr_name) | ||
| 66 | { | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | #endif /* CONFIG_IMA_APPRAISE_H */ | ||
| 43 | #endif /* _LINUX_IMA_H */ | 70 | #endif /* _LINUX_IMA_H */ |
diff --git a/include/linux/integrity.h b/include/linux/integrity.h index a0c41256cb92..66c5fe9550a5 100644 --- a/include/linux/integrity.h +++ b/include/linux/integrity.h | |||
| @@ -22,13 +22,14 @@ enum integrity_status { | |||
| 22 | 22 | ||
| 23 | /* List of EVM protected security xattrs */ | 23 | /* List of EVM protected security xattrs */ |
| 24 | #ifdef CONFIG_INTEGRITY | 24 | #ifdef CONFIG_INTEGRITY |
| 25 | extern int integrity_inode_alloc(struct inode *inode); | 25 | extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode); |
| 26 | extern void integrity_inode_free(struct inode *inode); | 26 | extern void integrity_inode_free(struct inode *inode); |
| 27 | 27 | ||
| 28 | #else | 28 | #else |
| 29 | static inline int integrity_inode_alloc(struct inode *inode) | 29 | static inline struct integrity_iint_cache * |
| 30 | integrity_inode_get(struct inode *inode) | ||
| 30 | { | 31 | { |
| 31 | return 0; | 32 | return NULL; |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | static inline void integrity_inode_free(struct inode *inode) | 35 | static inline void integrity_inode_free(struct inode *inode) |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 597e4fdb97fe..3db698aee34c 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
| @@ -130,8 +130,6 @@ extern void exit_ptrace(struct task_struct *tracer); | |||
| 130 | #define PTRACE_MODE_READ 0x01 | 130 | #define PTRACE_MODE_READ 0x01 |
| 131 | #define PTRACE_MODE_ATTACH 0x02 | 131 | #define PTRACE_MODE_ATTACH 0x02 |
| 132 | #define PTRACE_MODE_NOAUDIT 0x04 | 132 | #define PTRACE_MODE_NOAUDIT 0x04 |
| 133 | /* Returns 0 on success, -errno on denial. */ | ||
| 134 | extern int __ptrace_may_access(struct task_struct *task, unsigned int mode); | ||
| 135 | /* Returns true on success, false on denial. */ | 133 | /* Returns true on success, false on denial. */ |
| 136 | extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); | 134 | extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); |
| 137 | 135 | ||
diff --git a/include/linux/security.h b/include/linux/security.h index 145accee9236..5b50c4e1a7c2 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
| @@ -3022,5 +3022,36 @@ static inline void free_secdata(void *secdata) | |||
| 3022 | { } | 3022 | { } |
| 3023 | #endif /* CONFIG_SECURITY */ | 3023 | #endif /* CONFIG_SECURITY */ |
| 3024 | 3024 | ||
| 3025 | #ifdef CONFIG_SECURITY_YAMA | ||
| 3026 | extern int yama_ptrace_access_check(struct task_struct *child, | ||
| 3027 | unsigned int mode); | ||
| 3028 | extern int yama_ptrace_traceme(struct task_struct *parent); | ||
| 3029 | extern void yama_task_free(struct task_struct *task); | ||
| 3030 | extern int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, | ||
| 3031 | unsigned long arg4, unsigned long arg5); | ||
| 3032 | #else | ||
| 3033 | static inline int yama_ptrace_access_check(struct task_struct *child, | ||
| 3034 | unsigned int mode) | ||
| 3035 | { | ||
| 3036 | return 0; | ||
| 3037 | } | ||
| 3038 | |||
| 3039 | static inline int yama_ptrace_traceme(struct task_struct *parent) | ||
| 3040 | { | ||
| 3041 | return 0; | ||
| 3042 | } | ||
| 3043 | |||
| 3044 | static inline void yama_task_free(struct task_struct *task) | ||
| 3045 | { | ||
| 3046 | } | ||
| 3047 | |||
| 3048 | static inline int yama_task_prctl(int option, unsigned long arg2, | ||
| 3049 | unsigned long arg3, unsigned long arg4, | ||
| 3050 | unsigned long arg5) | ||
| 3051 | { | ||
| 3052 | return -ENOSYS; | ||
| 3053 | } | ||
| 3054 | #endif /* CONFIG_SECURITY_YAMA */ | ||
| 3055 | |||
| 3025 | #endif /* ! __LINUX_SECURITY_H */ | 3056 | #endif /* ! __LINUX_SECURITY_H */ |
| 3026 | 3057 | ||
diff --git a/include/linux/tpm.h b/include/linux/tpm.h index fdc718abf83b..fcb627ff8d3e 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); | 32 | extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); |
| 33 | extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); | 33 | extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); |
| 34 | extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); | 34 | extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); |
| 35 | extern int tpm_get_random(u32 chip_num, u8 *data, size_t max); | ||
| 35 | #else | 36 | #else |
| 36 | static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { | 37 | static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { |
| 37 | return -ENODEV; | 38 | return -ENODEV; |
| @@ -42,5 +43,8 @@ static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) { | |||
| 42 | static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) { | 43 | static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) { |
| 43 | return -ENODEV; | 44 | return -ENODEV; |
| 44 | } | 45 | } |
| 46 | static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) { | ||
| 47 | return -ENODEV; | ||
| 48 | } | ||
| 45 | #endif | 49 | #endif |
| 46 | #endif | 50 | #endif |
diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 2ace7a60316d..cc13e1115970 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h | |||
| @@ -33,6 +33,9 @@ | |||
| 33 | #define XATTR_EVM_SUFFIX "evm" | 33 | #define XATTR_EVM_SUFFIX "evm" |
| 34 | #define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX | 34 | #define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX |
| 35 | 35 | ||
| 36 | #define XATTR_IMA_SUFFIX "ima" | ||
| 37 | #define XATTR_NAME_IMA XATTR_SECURITY_PREFIX XATTR_IMA_SUFFIX | ||
| 38 | |||
| 36 | #define XATTR_SELINUX_SUFFIX "selinux" | 39 | #define XATTR_SELINUX_SUFFIX "selinux" |
| 37 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX | 40 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX |
| 38 | 41 | ||
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index ff4798fcb488..29e090cc0e46 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -1146,13 +1146,44 @@ error_path: | |||
| 1146 | 1146 | ||
| 1147 | EXPORT_SYMBOL(audit_log_task_context); | 1147 | EXPORT_SYMBOL(audit_log_task_context); |
| 1148 | 1148 | ||
| 1149 | static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) | 1149 | void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) |
| 1150 | { | 1150 | { |
| 1151 | const struct cred *cred; | ||
| 1151 | char name[sizeof(tsk->comm)]; | 1152 | char name[sizeof(tsk->comm)]; |
| 1152 | struct mm_struct *mm = tsk->mm; | 1153 | struct mm_struct *mm = tsk->mm; |
| 1153 | struct vm_area_struct *vma; | 1154 | struct vm_area_struct *vma; |
| 1155 | char *tty; | ||
| 1156 | |||
| 1157 | if (!ab) | ||
| 1158 | return; | ||
| 1154 | 1159 | ||
| 1155 | /* tsk == current */ | 1160 | /* tsk == current */ |
| 1161 | cred = current_cred(); | ||
| 1162 | |||
| 1163 | spin_lock_irq(&tsk->sighand->siglock); | ||
| 1164 | if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) | ||
| 1165 | tty = tsk->signal->tty->name; | ||
| 1166 | else | ||
| 1167 | tty = "(none)"; | ||
| 1168 | spin_unlock_irq(&tsk->sighand->siglock); | ||
| 1169 | |||
| 1170 | |||
| 1171 | audit_log_format(ab, | ||
| 1172 | " ppid=%ld pid=%d auid=%u uid=%u gid=%u" | ||
| 1173 | " euid=%u suid=%u fsuid=%u" | ||
| 1174 | " egid=%u sgid=%u fsgid=%u ses=%u tty=%s", | ||
| 1175 | sys_getppid(), | ||
| 1176 | tsk->pid, | ||
| 1177 | from_kuid(&init_user_ns, tsk->loginuid), | ||
| 1178 | from_kuid(&init_user_ns, cred->uid), | ||
| 1179 | from_kgid(&init_user_ns, cred->gid), | ||
| 1180 | from_kuid(&init_user_ns, cred->euid), | ||
| 1181 | from_kuid(&init_user_ns, cred->suid), | ||
| 1182 | from_kuid(&init_user_ns, cred->fsuid), | ||
| 1183 | from_kgid(&init_user_ns, cred->egid), | ||
| 1184 | from_kgid(&init_user_ns, cred->sgid), | ||
| 1185 | from_kgid(&init_user_ns, cred->fsgid), | ||
| 1186 | tsk->sessionid, tty); | ||
| 1156 | 1187 | ||
| 1157 | get_task_comm(name, tsk); | 1188 | get_task_comm(name, tsk); |
| 1158 | audit_log_format(ab, " comm="); | 1189 | audit_log_format(ab, " comm="); |
| @@ -1175,6 +1206,8 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk | |||
| 1175 | audit_log_task_context(ab); | 1206 | audit_log_task_context(ab); |
| 1176 | } | 1207 | } |
| 1177 | 1208 | ||
| 1209 | EXPORT_SYMBOL(audit_log_task_info); | ||
| 1210 | |||
| 1178 | static int audit_log_pid_context(struct audit_context *context, pid_t pid, | 1211 | static int audit_log_pid_context(struct audit_context *context, pid_t pid, |
| 1179 | kuid_t auid, kuid_t uid, unsigned int sessionid, | 1212 | kuid_t auid, kuid_t uid, unsigned int sessionid, |
| 1180 | u32 sid, char *comm) | 1213 | u32 sid, char *comm) |
| @@ -1580,26 +1613,12 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n, | |||
| 1580 | 1613 | ||
| 1581 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) | 1614 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) |
| 1582 | { | 1615 | { |
| 1583 | const struct cred *cred; | ||
| 1584 | int i, call_panic = 0; | 1616 | int i, call_panic = 0; |
| 1585 | struct audit_buffer *ab; | 1617 | struct audit_buffer *ab; |
| 1586 | struct audit_aux_data *aux; | 1618 | struct audit_aux_data *aux; |
| 1587 | const char *tty; | ||
| 1588 | struct audit_names *n; | 1619 | struct audit_names *n; |
| 1589 | 1620 | ||
| 1590 | /* tsk == current */ | 1621 | /* tsk == current */ |
| 1591 | context->pid = tsk->pid; | ||
| 1592 | if (!context->ppid) | ||
| 1593 | context->ppid = sys_getppid(); | ||
| 1594 | cred = current_cred(); | ||
| 1595 | context->uid = cred->uid; | ||
| 1596 | context->gid = cred->gid; | ||
| 1597 | context->euid = cred->euid; | ||
| 1598 | context->suid = cred->suid; | ||
| 1599 | context->fsuid = cred->fsuid; | ||
| 1600 | context->egid = cred->egid; | ||
| 1601 | context->sgid = cred->sgid; | ||
| 1602 | context->fsgid = cred->fsgid; | ||
| 1603 | context->personality = tsk->personality; | 1622 | context->personality = tsk->personality; |
| 1604 | 1623 | ||
| 1605 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL); | 1624 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL); |
| @@ -1614,37 +1633,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 1614 | (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", | 1633 | (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", |
| 1615 | context->return_code); | 1634 | context->return_code); |
| 1616 | 1635 | ||
| 1617 | spin_lock_irq(&tsk->sighand->siglock); | ||
| 1618 | if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) | ||
| 1619 | tty = tsk->signal->tty->name; | ||
| 1620 | else | ||
| 1621 | tty = "(none)"; | ||
| 1622 | spin_unlock_irq(&tsk->sighand->siglock); | ||
| 1623 | |||
| 1624 | audit_log_format(ab, | 1636 | audit_log_format(ab, |
| 1625 | " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" | 1637 | " a0=%lx a1=%lx a2=%lx a3=%lx items=%d", |
| 1626 | " ppid=%d pid=%d auid=%u uid=%u gid=%u" | 1638 | context->argv[0], |
| 1627 | " euid=%u suid=%u fsuid=%u" | 1639 | context->argv[1], |
| 1628 | " egid=%u sgid=%u fsgid=%u tty=%s ses=%u", | 1640 | context->argv[2], |
| 1629 | context->argv[0], | 1641 | context->argv[3], |
| 1630 | context->argv[1], | 1642 | context->name_count); |
| 1631 | context->argv[2], | ||
| 1632 | context->argv[3], | ||
| 1633 | context->name_count, | ||
| 1634 | context->ppid, | ||
| 1635 | context->pid, | ||
| 1636 | from_kuid(&init_user_ns, tsk->loginuid), | ||
| 1637 | from_kuid(&init_user_ns, context->uid), | ||
| 1638 | from_kgid(&init_user_ns, context->gid), | ||
| 1639 | from_kuid(&init_user_ns, context->euid), | ||
| 1640 | from_kuid(&init_user_ns, context->suid), | ||
| 1641 | from_kuid(&init_user_ns, context->fsuid), | ||
| 1642 | from_kgid(&init_user_ns, context->egid), | ||
| 1643 | from_kgid(&init_user_ns, context->sgid), | ||
| 1644 | from_kgid(&init_user_ns, context->fsgid), | ||
| 1645 | tty, | ||
| 1646 | tsk->sessionid); | ||
| 1647 | |||
| 1648 | 1643 | ||
| 1649 | audit_log_task_info(ab, tsk); | 1644 | audit_log_task_info(ab, tsk); |
| 1650 | audit_log_key(ab, context->filterkey); | 1645 | audit_log_key(ab, context->filterkey); |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index a232bb59d93f..1f5e55dda955 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -180,7 +180,8 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) | |||
| 180 | return has_ns_capability(current, ns, CAP_SYS_PTRACE); | 180 | return has_ns_capability(current, ns, CAP_SYS_PTRACE); |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) | 183 | /* Returns 0 on success, -errno on denial. */ |
| 184 | static int __ptrace_may_access(struct task_struct *task, unsigned int mode) | ||
| 184 | { | 185 | { |
| 185 | const struct cred *cred = current_cred(), *tcred; | 186 | const struct cred *cred = current_cred(), *tcred; |
| 186 | 187 | ||
diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile index 16aa2d424985..bbbd276659ba 100644 --- a/samples/seccomp/Makefile +++ b/samples/seccomp/Makefile | |||
| @@ -18,14 +18,22 @@ HOSTCFLAGS_bpf-direct.o += -idirafter $(objtree)/include | |||
| 18 | bpf-direct-objs := bpf-direct.o | 18 | bpf-direct-objs := bpf-direct.o |
| 19 | 19 | ||
| 20 | # Try to match the kernel target. | 20 | # Try to match the kernel target. |
| 21 | ifeq ($(CONFIG_64BIT),) | 21 | ifndef CONFIG_64BIT |
| 22 | HOSTCFLAGS_bpf-direct.o += -m32 | 22 | |
| 23 | HOSTCFLAGS_dropper.o += -m32 | 23 | # s390 has -m31 flag to build 31 bit binaries |
| 24 | HOSTCFLAGS_bpf-helper.o += -m32 | 24 | ifndef CONFIG_S390 |
| 25 | HOSTCFLAGS_bpf-fancy.o += -m32 | 25 | MFLAG = -m32 |
| 26 | HOSTLOADLIBES_bpf-direct += -m32 | 26 | else |
| 27 | HOSTLOADLIBES_bpf-fancy += -m32 | 27 | MFLAG = -m31 |
| 28 | HOSTLOADLIBES_dropper += -m32 | 28 | endif |
| 29 | |||
| 30 | HOSTCFLAGS_bpf-direct.o += $(MFLAG) | ||
| 31 | HOSTCFLAGS_dropper.o += $(MFLAG) | ||
| 32 | HOSTCFLAGS_bpf-helper.o += $(MFLAG) | ||
| 33 | HOSTCFLAGS_bpf-fancy.o += $(MFLAG) | ||
| 34 | HOSTLOADLIBES_bpf-direct += $(MFLAG) | ||
| 35 | HOSTLOADLIBES_bpf-fancy += $(MFLAG) | ||
| 36 | HOSTLOADLIBES_dropper += $(MFLAG) | ||
| 29 | endif | 37 | endif |
| 30 | 38 | ||
| 31 | # Tell kbuild to always build the programs | 39 | # Tell kbuild to always build the programs |
diff --git a/samples/seccomp/bpf-helper.h b/samples/seccomp/bpf-helper.h index 643279dd30fb..38ee70f3cd5b 100644 --- a/samples/seccomp/bpf-helper.h +++ b/samples/seccomp/bpf-helper.h | |||
| @@ -59,6 +59,16 @@ void seccomp_bpf_print(struct sock_filter *filter, size_t count); | |||
| 59 | #define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label) | 59 | #define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label) |
| 60 | 60 | ||
| 61 | #define EXPAND(...) __VA_ARGS__ | 61 | #define EXPAND(...) __VA_ARGS__ |
| 62 | |||
| 63 | /* Ensure that we load the logically correct offset. */ | ||
| 64 | #if __BYTE_ORDER == __LITTLE_ENDIAN | ||
| 65 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) | ||
| 66 | #elif __BYTE_ORDER == __BIG_ENDIAN | ||
| 67 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) | ||
| 68 | #else | ||
| 69 | #error "Unknown endianness" | ||
| 70 | #endif | ||
| 71 | |||
| 62 | /* Map all width-sensitive operations */ | 72 | /* Map all width-sensitive operations */ |
| 63 | #if __BITS_PER_LONG == 32 | 73 | #if __BITS_PER_LONG == 32 |
| 64 | 74 | ||
| @@ -70,21 +80,16 @@ void seccomp_bpf_print(struct sock_filter *filter, size_t count); | |||
| 70 | #define JLE(x, jt) JLE32(x, EXPAND(jt)) | 80 | #define JLE(x, jt) JLE32(x, EXPAND(jt)) |
| 71 | #define JA(x, jt) JA32(x, EXPAND(jt)) | 81 | #define JA(x, jt) JA32(x, EXPAND(jt)) |
| 72 | #define ARG(i) ARG_32(i) | 82 | #define ARG(i) ARG_32(i) |
| 73 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) | ||
| 74 | 83 | ||
| 75 | #elif __BITS_PER_LONG == 64 | 84 | #elif __BITS_PER_LONG == 64 |
| 76 | 85 | ||
| 77 | /* Ensure that we load the logically correct offset. */ | 86 | /* Ensure that we load the logically correct offset. */ |
| 78 | #if __BYTE_ORDER == __LITTLE_ENDIAN | 87 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
| 79 | #define ENDIAN(_lo, _hi) _lo, _hi | 88 | #define ENDIAN(_lo, _hi) _lo, _hi |
| 80 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) | ||
| 81 | #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) | 89 | #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) |
| 82 | #elif __BYTE_ORDER == __BIG_ENDIAN | 90 | #elif __BYTE_ORDER == __BIG_ENDIAN |
| 83 | #define ENDIAN(_lo, _hi) _hi, _lo | 91 | #define ENDIAN(_lo, _hi) _hi, _lo |
| 84 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) | ||
| 85 | #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) | 92 | #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) |
| 86 | #else | ||
| 87 | #error "Unknown endianness" | ||
| 88 | #endif | 93 | #endif |
| 89 | 94 | ||
| 90 | union arg64 { | 95 | union arg64 { |
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 8901501425f4..eb5484504f50 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
| @@ -34,6 +34,9 @@ char *evm_config_xattrnames[] = { | |||
| 34 | #ifdef CONFIG_SECURITY_SMACK | 34 | #ifdef CONFIG_SECURITY_SMACK |
| 35 | XATTR_NAME_SMACK, | 35 | XATTR_NAME_SMACK, |
| 36 | #endif | 36 | #endif |
| 37 | #ifdef CONFIG_IMA_APPRAISE | ||
| 38 | XATTR_NAME_IMA, | ||
| 39 | #endif | ||
| 37 | XATTR_NAME_CAPS, | 40 | XATTR_NAME_CAPS, |
| 38 | NULL | 41 | NULL |
| 39 | }; | 42 | }; |
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 399641c3e846..d82a5a13d855 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | #include "integrity.h" | 22 | #include "integrity.h" |
| 23 | 23 | ||
| 24 | static struct rb_root integrity_iint_tree = RB_ROOT; | 24 | static struct rb_root integrity_iint_tree = RB_ROOT; |
| 25 | static DEFINE_SPINLOCK(integrity_iint_lock); | 25 | static DEFINE_RWLOCK(integrity_iint_lock); |
| 26 | static struct kmem_cache *iint_cache __read_mostly; | 26 | static struct kmem_cache *iint_cache __read_mostly; |
| 27 | 27 | ||
| 28 | int iint_initialized; | 28 | int iint_initialized; |
| @@ -35,8 +35,6 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode) | |||
| 35 | struct integrity_iint_cache *iint; | 35 | struct integrity_iint_cache *iint; |
| 36 | struct rb_node *n = integrity_iint_tree.rb_node; | 36 | struct rb_node *n = integrity_iint_tree.rb_node; |
| 37 | 37 | ||
| 38 | assert_spin_locked(&integrity_iint_lock); | ||
| 39 | |||
| 40 | while (n) { | 38 | while (n) { |
| 41 | iint = rb_entry(n, struct integrity_iint_cache, rb_node); | 39 | iint = rb_entry(n, struct integrity_iint_cache, rb_node); |
| 42 | 40 | ||
| @@ -63,9 +61,9 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode) | |||
| 63 | if (!IS_IMA(inode)) | 61 | if (!IS_IMA(inode)) |
| 64 | return NULL; | 62 | return NULL; |
| 65 | 63 | ||
| 66 | spin_lock(&integrity_iint_lock); | 64 | read_lock(&integrity_iint_lock); |
| 67 | iint = __integrity_iint_find(inode); | 65 | iint = __integrity_iint_find(inode); |
| 68 | spin_unlock(&integrity_iint_lock); | 66 | read_unlock(&integrity_iint_lock); |
| 69 | 67 | ||
| 70 | return iint; | 68 | return iint; |
| 71 | } | 69 | } |
| @@ -74,59 +72,53 @@ static void iint_free(struct integrity_iint_cache *iint) | |||
| 74 | { | 72 | { |
| 75 | iint->version = 0; | 73 | iint->version = 0; |
| 76 | iint->flags = 0UL; | 74 | iint->flags = 0UL; |
| 75 | iint->ima_status = INTEGRITY_UNKNOWN; | ||
| 77 | iint->evm_status = INTEGRITY_UNKNOWN; | 76 | iint->evm_status = INTEGRITY_UNKNOWN; |
| 78 | kmem_cache_free(iint_cache, iint); | 77 | kmem_cache_free(iint_cache, iint); |
| 79 | } | 78 | } |
| 80 | 79 | ||
| 81 | /** | 80 | /** |
| 82 | * integrity_inode_alloc - allocate an iint associated with an inode | 81 | * integrity_inode_get - find or allocate an iint associated with an inode |
| 83 | * @inode: pointer to the inode | 82 | * @inode: pointer to the inode |
| 83 | * @return: allocated iint | ||
| 84 | * | ||
| 85 | * Caller must lock i_mutex | ||
| 84 | */ | 86 | */ |
| 85 | int integrity_inode_alloc(struct inode *inode) | 87 | struct integrity_iint_cache *integrity_inode_get(struct inode *inode) |
| 86 | { | 88 | { |
| 87 | struct rb_node **p; | 89 | struct rb_node **p; |
| 88 | struct rb_node *new_node, *parent = NULL; | 90 | struct rb_node *node, *parent = NULL; |
| 89 | struct integrity_iint_cache *new_iint, *test_iint; | 91 | struct integrity_iint_cache *iint, *test_iint; |
| 90 | int rc; | ||
| 91 | 92 | ||
| 92 | new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | 93 | iint = integrity_iint_find(inode); |
| 93 | if (!new_iint) | 94 | if (iint) |
| 94 | return -ENOMEM; | 95 | return iint; |
| 95 | 96 | ||
| 96 | new_iint->inode = inode; | 97 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); |
| 97 | new_node = &new_iint->rb_node; | 98 | if (!iint) |
| 99 | return NULL; | ||
| 98 | 100 | ||
| 99 | mutex_lock(&inode->i_mutex); /* i_flags */ | 101 | write_lock(&integrity_iint_lock); |
| 100 | spin_lock(&integrity_iint_lock); | ||
| 101 | 102 | ||
| 102 | p = &integrity_iint_tree.rb_node; | 103 | p = &integrity_iint_tree.rb_node; |
| 103 | while (*p) { | 104 | while (*p) { |
| 104 | parent = *p; | 105 | parent = *p; |
| 105 | test_iint = rb_entry(parent, struct integrity_iint_cache, | 106 | test_iint = rb_entry(parent, struct integrity_iint_cache, |
| 106 | rb_node); | 107 | rb_node); |
| 107 | rc = -EEXIST; | ||
| 108 | if (inode < test_iint->inode) | 108 | if (inode < test_iint->inode) |
| 109 | p = &(*p)->rb_left; | 109 | p = &(*p)->rb_left; |
| 110 | else if (inode > test_iint->inode) | ||
| 111 | p = &(*p)->rb_right; | ||
| 112 | else | 110 | else |
| 113 | goto out_err; | 111 | p = &(*p)->rb_right; |
| 114 | } | 112 | } |
| 115 | 113 | ||
| 114 | iint->inode = inode; | ||
| 115 | node = &iint->rb_node; | ||
| 116 | inode->i_flags |= S_IMA; | 116 | inode->i_flags |= S_IMA; |
| 117 | rb_link_node(new_node, parent, p); | 117 | rb_link_node(node, parent, p); |
| 118 | rb_insert_color(new_node, &integrity_iint_tree); | 118 | rb_insert_color(node, &integrity_iint_tree); |
| 119 | 119 | ||
| 120 | spin_unlock(&integrity_iint_lock); | 120 | write_unlock(&integrity_iint_lock); |
| 121 | mutex_unlock(&inode->i_mutex); /* i_flags */ | 121 | return iint; |
| 122 | |||
| 123 | return 0; | ||
| 124 | out_err: | ||
| 125 | spin_unlock(&integrity_iint_lock); | ||
| 126 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
| 127 | iint_free(new_iint); | ||
| 128 | |||
| 129 | return rc; | ||
| 130 | } | 122 | } |
| 131 | 123 | ||
| 132 | /** | 124 | /** |
| @@ -142,10 +134,10 @@ void integrity_inode_free(struct inode *inode) | |||
| 142 | if (!IS_IMA(inode)) | 134 | if (!IS_IMA(inode)) |
| 143 | return; | 135 | return; |
| 144 | 136 | ||
| 145 | spin_lock(&integrity_iint_lock); | 137 | write_lock(&integrity_iint_lock); |
| 146 | iint = __integrity_iint_find(inode); | 138 | iint = __integrity_iint_find(inode); |
| 147 | rb_erase(&iint->rb_node, &integrity_iint_tree); | 139 | rb_erase(&iint->rb_node, &integrity_iint_tree); |
| 148 | spin_unlock(&integrity_iint_lock); | 140 | write_unlock(&integrity_iint_lock); |
| 149 | 141 | ||
| 150 | iint_free(iint); | 142 | iint_free(iint); |
| 151 | } | 143 | } |
| @@ -157,7 +149,7 @@ static void init_once(void *foo) | |||
| 157 | memset(iint, 0, sizeof *iint); | 149 | memset(iint, 0, sizeof *iint); |
| 158 | iint->version = 0; | 150 | iint->version = 0; |
| 159 | iint->flags = 0UL; | 151 | iint->flags = 0UL; |
| 160 | mutex_init(&iint->mutex); | 152 | iint->ima_status = INTEGRITY_UNKNOWN; |
| 161 | iint->evm_status = INTEGRITY_UNKNOWN; | 153 | iint->evm_status = INTEGRITY_UNKNOWN; |
| 162 | } | 154 | } |
| 163 | 155 | ||
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index b9c1219924f1..d232c73647ae 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
| @@ -11,6 +11,7 @@ config IMA | |||
| 11 | select CRYPTO_SHA1 | 11 | select CRYPTO_SHA1 |
| 12 | select TCG_TPM if HAS_IOMEM && !UML | 12 | select TCG_TPM if HAS_IOMEM && !UML |
| 13 | select TCG_TIS if TCG_TPM && X86 | 13 | select TCG_TIS if TCG_TPM && X86 |
| 14 | select TCG_IBMVTPM if TCG_TPM && PPC64 | ||
| 14 | help | 15 | help |
| 15 | The Trusted Computing Group(TCG) runtime Integrity | 16 | The Trusted Computing Group(TCG) runtime Integrity |
| 16 | Measurement Architecture(IMA) maintains a list of hash | 17 | Measurement Architecture(IMA) maintains a list of hash |
| @@ -55,3 +56,18 @@ config IMA_LSM_RULES | |||
| 55 | default y | 56 | default y |
| 56 | help | 57 | help |
| 57 | Disabling this option will disregard LSM based policy rules. | 58 | Disabling this option will disregard LSM based policy rules. |
| 59 | |||
| 60 | config IMA_APPRAISE | ||
| 61 | bool "Appraise integrity measurements" | ||
| 62 | depends on IMA | ||
| 63 | default n | ||
| 64 | help | ||
| 65 | This option enables local measurement integrity appraisal. | ||
| 66 | It requires the system to be labeled with a security extended | ||
| 67 | attribute containing the file hash measurement. To protect | ||
| 68 | the security extended attributes from offline attack, enable | ||
| 69 | and configure EVM. | ||
| 70 | |||
| 71 | For more information on integrity appraisal refer to: | ||
| 72 | <http://linux-ima.sourceforge.net> | ||
| 73 | If unsure, say N. | ||
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index 5f740f6971e1..3f2ca6bdc384 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile | |||
| @@ -8,3 +8,4 @@ obj-$(CONFIG_IMA) += ima.o | |||
| 8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ | 8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ |
| 9 | ima_policy.o | 9 | ima_policy.o |
| 10 | ima-$(CONFIG_IMA_AUDIT) += ima_audit.o | 10 | ima-$(CONFIG_IMA_AUDIT) += ima_audit.o |
| 11 | ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e7c99fd0d223..8180adde10b7 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -40,6 +40,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; | |||
| 40 | extern int ima_initialized; | 40 | extern int ima_initialized; |
| 41 | extern int ima_used_chip; | 41 | extern int ima_used_chip; |
| 42 | extern char *ima_hash; | 42 | extern char *ima_hash; |
| 43 | extern int ima_appraise; | ||
| 43 | 44 | ||
| 44 | /* IMA inode template definition */ | 45 | /* IMA inode template definition */ |
| 45 | struct ima_template_data { | 46 | struct ima_template_data { |
| @@ -107,11 +108,14 @@ static inline unsigned long ima_hash_key(u8 *digest) | |||
| 107 | } | 108 | } |
| 108 | 109 | ||
| 109 | /* LIM API function definitions */ | 110 | /* LIM API function definitions */ |
| 111 | int ima_get_action(struct inode *inode, int mask, int function); | ||
| 110 | int ima_must_measure(struct inode *inode, int mask, int function); | 112 | int ima_must_measure(struct inode *inode, int mask, int function); |
| 111 | int ima_collect_measurement(struct integrity_iint_cache *iint, | 113 | int ima_collect_measurement(struct integrity_iint_cache *iint, |
| 112 | struct file *file); | 114 | struct file *file); |
| 113 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, | 115 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, |
| 114 | const unsigned char *filename); | 116 | const unsigned char *filename); |
| 117 | void ima_audit_measurement(struct integrity_iint_cache *iint, | ||
| 118 | const unsigned char *filename); | ||
| 115 | int ima_store_template(struct ima_template_entry *entry, int violation, | 119 | int ima_store_template(struct ima_template_entry *entry, int violation, |
| 116 | struct inode *inode); | 120 | struct inode *inode); |
| 117 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show); | 121 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show); |
| @@ -123,14 +127,45 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); | |||
| 123 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | 127 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); |
| 124 | 128 | ||
| 125 | /* IMA policy related functions */ | 129 | /* IMA policy related functions */ |
| 126 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | 130 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR }; |
| 127 | 131 | ||
| 128 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | 132 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
| 133 | int flags); | ||
| 129 | void ima_init_policy(void); | 134 | void ima_init_policy(void); |
| 130 | void ima_update_policy(void); | 135 | void ima_update_policy(void); |
| 131 | ssize_t ima_parse_add_rule(char *); | 136 | ssize_t ima_parse_add_rule(char *); |
| 132 | void ima_delete_rules(void); | 137 | void ima_delete_rules(void); |
| 133 | 138 | ||
| 139 | /* Appraise integrity measurements */ | ||
| 140 | #define IMA_APPRAISE_ENFORCE 0x01 | ||
| 141 | #define IMA_APPRAISE_FIX 0x02 | ||
| 142 | |||
| 143 | #ifdef CONFIG_IMA_APPRAISE | ||
| 144 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
| 145 | struct file *file, const unsigned char *filename); | ||
| 146 | int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask); | ||
| 147 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); | ||
| 148 | |||
| 149 | #else | ||
| 150 | static inline int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
| 151 | struct file *file, | ||
| 152 | const unsigned char *filename) | ||
| 153 | { | ||
| 154 | return INTEGRITY_UNKNOWN; | ||
| 155 | } | ||
| 156 | |||
| 157 | static inline int ima_must_appraise(struct inode *inode, | ||
| 158 | enum ima_hooks func, int mask) | ||
| 159 | { | ||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | static inline void ima_update_xattr(struct integrity_iint_cache *iint, | ||
| 164 | struct file *file) | ||
| 165 | { | ||
| 166 | } | ||
| 167 | #endif | ||
| 168 | |||
| 134 | /* LSM based policy rules require audit */ | 169 | /* LSM based policy rules require audit */ |
| 135 | #ifdef CONFIG_IMA_LSM_RULES | 170 | #ifdef CONFIG_IMA_LSM_RULES |
| 136 | 171 | ||
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 032ff03ad907..b356884fb3ef 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
| @@ -9,13 +9,17 @@ | |||
| 9 | * License. | 9 | * License. |
| 10 | * | 10 | * |
| 11 | * File: ima_api.c | 11 | * File: ima_api.c |
| 12 | * Implements must_measure, collect_measurement, store_measurement, | 12 | * Implements must_appraise_or_measure, collect_measurement, |
| 13 | * and store_template. | 13 | * appraise_measurement, store_measurement and store_template. |
| 14 | */ | 14 | */ |
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | 17 | #include <linux/file.h> | |
| 18 | #include <linux/fs.h> | ||
| 19 | #include <linux/xattr.h> | ||
| 20 | #include <linux/evm.h> | ||
| 18 | #include "ima.h" | 21 | #include "ima.h" |
| 22 | |||
| 19 | static const char *IMA_TEMPLATE_NAME = "ima"; | 23 | static const char *IMA_TEMPLATE_NAME = "ima"; |
| 20 | 24 | ||
| 21 | /* | 25 | /* |
| @@ -93,7 +97,7 @@ err_out: | |||
| 93 | } | 97 | } |
| 94 | 98 | ||
| 95 | /** | 99 | /** |
| 96 | * ima_must_measure - measure decision based on policy. | 100 | * ima_get_action - appraise & measure decision based on policy. |
| 97 | * @inode: pointer to inode to measure | 101 | * @inode: pointer to inode to measure |
| 98 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) | 102 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) |
| 99 | * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) | 103 | * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) |
| @@ -105,15 +109,22 @@ err_out: | |||
| 105 | * mask: contains the permission mask | 109 | * mask: contains the permission mask |
| 106 | * fsmagic: hex value | 110 | * fsmagic: hex value |
| 107 | * | 111 | * |
| 108 | * Return 0 to measure. For matching a DONT_MEASURE policy, no policy, | 112 | * Returns IMA_MEASURE, IMA_APPRAISE mask. |
| 109 | * or other error, return an error code. | 113 | * |
| 110 | */ | 114 | */ |
| 111 | int ima_must_measure(struct inode *inode, int mask, int function) | 115 | int ima_get_action(struct inode *inode, int mask, int function) |
| 112 | { | 116 | { |
| 113 | int must_measure; | 117 | int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; |
| 118 | |||
| 119 | if (!ima_appraise) | ||
| 120 | flags &= ~IMA_APPRAISE; | ||
| 114 | 121 | ||
| 115 | must_measure = ima_match_policy(inode, function, mask); | 122 | return ima_match_policy(inode, function, mask, flags); |
| 116 | return must_measure ? 0 : -EACCES; | 123 | } |
| 124 | |||
| 125 | int ima_must_measure(struct inode *inode, int mask, int function) | ||
| 126 | { | ||
| 127 | return ima_match_policy(inode, function, mask, IMA_MEASURE); | ||
| 117 | } | 128 | } |
| 118 | 129 | ||
| 119 | /* | 130 | /* |
| @@ -129,16 +140,24 @@ int ima_must_measure(struct inode *inode, int mask, int function) | |||
| 129 | int ima_collect_measurement(struct integrity_iint_cache *iint, | 140 | int ima_collect_measurement(struct integrity_iint_cache *iint, |
| 130 | struct file *file) | 141 | struct file *file) |
| 131 | { | 142 | { |
| 132 | int result = -EEXIST; | 143 | struct inode *inode = file->f_dentry->d_inode; |
| 144 | const char *filename = file->f_dentry->d_name.name; | ||
| 145 | int result = 0; | ||
| 133 | 146 | ||
| 134 | if (!(iint->flags & IMA_MEASURED)) { | 147 | if (!(iint->flags & IMA_COLLECTED)) { |
| 135 | u64 i_version = file->f_dentry->d_inode->i_version; | 148 | u64 i_version = file->f_dentry->d_inode->i_version; |
| 136 | 149 | ||
| 137 | memset(iint->digest, 0, IMA_DIGEST_SIZE); | 150 | iint->ima_xattr.type = IMA_XATTR_DIGEST; |
| 138 | result = ima_calc_hash(file, iint->digest); | 151 | result = ima_calc_hash(file, iint->ima_xattr.digest); |
| 139 | if (!result) | 152 | if (!result) { |
| 140 | iint->version = i_version; | 153 | iint->version = i_version; |
| 154 | iint->flags |= IMA_COLLECTED; | ||
| 155 | } | ||
| 141 | } | 156 | } |
| 157 | if (result) | ||
| 158 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, | ||
| 159 | filename, "collect_data", "failed", | ||
| 160 | result, 0); | ||
| 142 | return result; | 161 | return result; |
| 143 | } | 162 | } |
| 144 | 163 | ||
| @@ -167,6 +186,9 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
| 167 | struct ima_template_entry *entry; | 186 | struct ima_template_entry *entry; |
| 168 | int violation = 0; | 187 | int violation = 0; |
| 169 | 188 | ||
| 189 | if (iint->flags & IMA_MEASURED) | ||
| 190 | return; | ||
| 191 | |||
| 170 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 192 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
| 171 | if (!entry) { | 193 | if (!entry) { |
| 172 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | 194 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, |
| @@ -174,7 +196,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
| 174 | return; | 196 | return; |
| 175 | } | 197 | } |
| 176 | memset(&entry->template, 0, sizeof(entry->template)); | 198 | memset(&entry->template, 0, sizeof(entry->template)); |
| 177 | memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE); | 199 | memcpy(entry->template.digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE); |
| 178 | strcpy(entry->template.file_name, | 200 | strcpy(entry->template.file_name, |
| 179 | (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ? | 201 | (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ? |
| 180 | file->f_dentry->d_name.name : filename); | 202 | file->f_dentry->d_name.name : filename); |
| @@ -185,3 +207,33 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
| 185 | if (result < 0) | 207 | if (result < 0) |
| 186 | kfree(entry); | 208 | kfree(entry); |
| 187 | } | 209 | } |
| 210 | |||
| 211 | void ima_audit_measurement(struct integrity_iint_cache *iint, | ||
| 212 | const unsigned char *filename) | ||
| 213 | { | ||
| 214 | struct audit_buffer *ab; | ||
| 215 | char hash[(IMA_DIGEST_SIZE * 2) + 1]; | ||
| 216 | int i; | ||
| 217 | |||
| 218 | if (iint->flags & IMA_AUDITED) | ||
| 219 | return; | ||
| 220 | |||
| 221 | for (i = 0; i < IMA_DIGEST_SIZE; i++) | ||
| 222 | hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]); | ||
| 223 | hash[i * 2] = '\0'; | ||
| 224 | |||
| 225 | ab = audit_log_start(current->audit_context, GFP_KERNEL, | ||
| 226 | AUDIT_INTEGRITY_RULE); | ||
| 227 | if (!ab) | ||
| 228 | return; | ||
| 229 | |||
| 230 | audit_log_format(ab, "file="); | ||
| 231 | audit_log_untrustedstring(ab, filename); | ||
| 232 | audit_log_format(ab, " hash="); | ||
| 233 | audit_log_untrustedstring(ab, hash); | ||
| 234 | |||
| 235 | audit_log_task_info(ab, current); | ||
| 236 | audit_log_end(ab); | ||
| 237 | |||
| 238 | iint->flags |= IMA_AUDITED; | ||
| 239 | } | ||
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c new file mode 100644 index 000000000000..0aa43bde441c --- /dev/null +++ b/security/integrity/ima/ima_appraise.c | |||
| @@ -0,0 +1,263 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: | ||
| 5 | * Mimi Zohar <zohar@us.ibm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation, version 2 of the License. | ||
| 10 | */ | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/file.h> | ||
| 13 | #include <linux/fs.h> | ||
| 14 | #include <linux/xattr.h> | ||
| 15 | #include <linux/magic.h> | ||
| 16 | #include <linux/ima.h> | ||
| 17 | #include <linux/evm.h> | ||
| 18 | |||
| 19 | #include "ima.h" | ||
| 20 | |||
| 21 | static int __init default_appraise_setup(char *str) | ||
| 22 | { | ||
| 23 | if (strncmp(str, "off", 3) == 0) | ||
| 24 | ima_appraise = 0; | ||
| 25 | else if (strncmp(str, "fix", 3) == 0) | ||
| 26 | ima_appraise = IMA_APPRAISE_FIX; | ||
| 27 | return 1; | ||
| 28 | } | ||
| 29 | |||
| 30 | __setup("ima_appraise=", default_appraise_setup); | ||
| 31 | |||
| 32 | /* | ||
| 33 | * ima_must_appraise - set appraise flag | ||
| 34 | * | ||
| 35 | * Return 1 to appraise | ||
| 36 | */ | ||
| 37 | int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask) | ||
| 38 | { | ||
| 39 | if (!ima_appraise) | ||
| 40 | return 0; | ||
| 41 | |||
| 42 | return ima_match_policy(inode, func, mask, IMA_APPRAISE); | ||
| 43 | } | ||
| 44 | |||
| 45 | static void ima_fix_xattr(struct dentry *dentry, | ||
| 46 | struct integrity_iint_cache *iint) | ||
| 47 | { | ||
| 48 | iint->ima_xattr.type = IMA_XATTR_DIGEST; | ||
| 49 | __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, (u8 *)&iint->ima_xattr, | ||
| 50 | sizeof iint->ima_xattr, 0); | ||
| 51 | } | ||
| 52 | |||
| 53 | /* | ||
| 54 | * ima_appraise_measurement - appraise file measurement | ||
| 55 | * | ||
| 56 | * Call evm_verifyxattr() to verify the integrity of 'security.ima'. | ||
| 57 | * Assuming success, compare the xattr hash with the collected measurement. | ||
| 58 | * | ||
| 59 | * Return 0 on success, error code otherwise | ||
| 60 | */ | ||
| 61 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | ||
| 62 | struct file *file, const unsigned char *filename) | ||
| 63 | { | ||
| 64 | struct dentry *dentry = file->f_dentry; | ||
| 65 | struct inode *inode = dentry->d_inode; | ||
| 66 | struct evm_ima_xattr_data *xattr_value = NULL; | ||
| 67 | enum integrity_status status = INTEGRITY_UNKNOWN; | ||
| 68 | const char *op = "appraise_data"; | ||
| 69 | char *cause = "unknown"; | ||
| 70 | int rc; | ||
| 71 | |||
| 72 | if (!ima_appraise) | ||
| 73 | return 0; | ||
| 74 | if (!inode->i_op->getxattr) | ||
| 75 | return INTEGRITY_UNKNOWN; | ||
| 76 | |||
| 77 | if (iint->flags & IMA_APPRAISED) | ||
| 78 | return iint->ima_status; | ||
| 79 | |||
| 80 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, | ||
| 81 | 0, GFP_NOFS); | ||
| 82 | if (rc <= 0) { | ||
| 83 | if (rc && rc != -ENODATA) | ||
| 84 | goto out; | ||
| 85 | |||
| 86 | cause = "missing-hash"; | ||
| 87 | status = | ||
| 88 | (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL; | ||
| 89 | goto out; | ||
| 90 | } | ||
| 91 | |||
| 92 | status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); | ||
| 93 | if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { | ||
| 94 | if ((status == INTEGRITY_NOLABEL) | ||
| 95 | || (status == INTEGRITY_NOXATTRS)) | ||
| 96 | cause = "missing-HMAC"; | ||
| 97 | else if (status == INTEGRITY_FAIL) | ||
| 98 | cause = "invalid-HMAC"; | ||
| 99 | goto out; | ||
| 100 | } | ||
| 101 | |||
| 102 | switch (xattr_value->type) { | ||
| 103 | case IMA_XATTR_DIGEST: | ||
| 104 | rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, | ||
| 105 | IMA_DIGEST_SIZE); | ||
| 106 | if (rc) { | ||
| 107 | cause = "invalid-hash"; | ||
| 108 | status = INTEGRITY_FAIL; | ||
| 109 | print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE, | ||
| 110 | xattr_value, sizeof(*xattr_value)); | ||
| 111 | print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE, | ||
| 112 | (u8 *)&iint->ima_xattr, | ||
| 113 | sizeof iint->ima_xattr); | ||
| 114 | break; | ||
| 115 | } | ||
| 116 | status = INTEGRITY_PASS; | ||
| 117 | break; | ||
| 118 | case EVM_IMA_XATTR_DIGSIG: | ||
| 119 | iint->flags |= IMA_DIGSIG; | ||
| 120 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, | ||
| 121 | xattr_value->digest, rc - 1, | ||
| 122 | iint->ima_xattr.digest, | ||
| 123 | IMA_DIGEST_SIZE); | ||
| 124 | if (rc == -EOPNOTSUPP) { | ||
| 125 | status = INTEGRITY_UNKNOWN; | ||
| 126 | } else if (rc) { | ||
| 127 | cause = "invalid-signature"; | ||
| 128 | status = INTEGRITY_FAIL; | ||
| 129 | } else { | ||
| 130 | status = INTEGRITY_PASS; | ||
| 131 | } | ||
| 132 | break; | ||
| 133 | default: | ||
| 134 | status = INTEGRITY_UNKNOWN; | ||
| 135 | cause = "unknown-ima-data"; | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | |||
| 139 | out: | ||
| 140 | if (status != INTEGRITY_PASS) { | ||
| 141 | if ((ima_appraise & IMA_APPRAISE_FIX) && | ||
| 142 | (!xattr_value || | ||
| 143 | xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { | ||
| 144 | ima_fix_xattr(dentry, iint); | ||
| 145 | status = INTEGRITY_PASS; | ||
| 146 | } | ||
| 147 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, | ||
| 148 | op, cause, rc, 0); | ||
| 149 | } else { | ||
| 150 | iint->flags |= IMA_APPRAISED; | ||
| 151 | } | ||
| 152 | iint->ima_status = status; | ||
| 153 | kfree(xattr_value); | ||
| 154 | return status; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* | ||
| 158 | * ima_update_xattr - update 'security.ima' hash value | ||
| 159 | */ | ||
| 160 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | ||
| 161 | { | ||
| 162 | struct dentry *dentry = file->f_dentry; | ||
| 163 | int rc = 0; | ||
| 164 | |||
| 165 | /* do not collect and update hash for digital signatures */ | ||
| 166 | if (iint->flags & IMA_DIGSIG) | ||
| 167 | return; | ||
| 168 | |||
| 169 | rc = ima_collect_measurement(iint, file); | ||
| 170 | if (rc < 0) | ||
| 171 | return; | ||
| 172 | |||
| 173 | ima_fix_xattr(dentry, iint); | ||
| 174 | } | ||
| 175 | |||
| 176 | /** | ||
| 177 | * ima_inode_post_setattr - reflect file metadata changes | ||
| 178 | * @dentry: pointer to the affected dentry | ||
| 179 | * | ||
| 180 | * Changes to a dentry's metadata might result in needing to appraise. | ||
| 181 | * | ||
| 182 | * This function is called from notify_change(), which expects the caller | ||
| 183 | * to lock the inode's i_mutex. | ||
| 184 | */ | ||
| 185 | void ima_inode_post_setattr(struct dentry *dentry) | ||
| 186 | { | ||
| 187 | struct inode *inode = dentry->d_inode; | ||
| 188 | struct integrity_iint_cache *iint; | ||
| 189 | int must_appraise, rc; | ||
| 190 | |||
| 191 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode) | ||
| 192 | || !inode->i_op->removexattr) | ||
| 193 | return; | ||
| 194 | |||
| 195 | must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); | ||
| 196 | iint = integrity_iint_find(inode); | ||
| 197 | if (iint) { | ||
| 198 | if (must_appraise) | ||
| 199 | iint->flags |= IMA_APPRAISE; | ||
| 200 | else | ||
| 201 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); | ||
| 202 | } | ||
| 203 | if (!must_appraise) | ||
| 204 | rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); | ||
| 205 | return; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 209 | * ima_protect_xattr - protect 'security.ima' | ||
| 210 | * | ||
| 211 | * Ensure that not just anyone can modify or remove 'security.ima'. | ||
| 212 | */ | ||
| 213 | static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, | ||
| 214 | const void *xattr_value, size_t xattr_value_len) | ||
| 215 | { | ||
| 216 | if (strcmp(xattr_name, XATTR_NAME_IMA) == 0) { | ||
| 217 | if (!capable(CAP_SYS_ADMIN)) | ||
| 218 | return -EPERM; | ||
| 219 | return 1; | ||
| 220 | } | ||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | static void ima_reset_appraise_flags(struct inode *inode) | ||
| 225 | { | ||
| 226 | struct integrity_iint_cache *iint; | ||
| 227 | |||
| 228 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)) | ||
| 229 | return; | ||
| 230 | |||
| 231 | iint = integrity_iint_find(inode); | ||
| 232 | if (!iint) | ||
| 233 | return; | ||
| 234 | |||
| 235 | iint->flags &= ~IMA_DONE_MASK; | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | |||
| 239 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, | ||
| 240 | const void *xattr_value, size_t xattr_value_len) | ||
| 241 | { | ||
| 242 | int result; | ||
| 243 | |||
| 244 | result = ima_protect_xattr(dentry, xattr_name, xattr_value, | ||
| 245 | xattr_value_len); | ||
| 246 | if (result == 1) { | ||
| 247 | ima_reset_appraise_flags(dentry->d_inode); | ||
| 248 | result = 0; | ||
| 249 | } | ||
| 250 | return result; | ||
| 251 | } | ||
| 252 | |||
| 253 | int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) | ||
| 254 | { | ||
| 255 | int result; | ||
| 256 | |||
| 257 | result = ima_protect_xattr(dentry, xattr_name, NULL, 0); | ||
| 258 | if (result == 1) { | ||
| 259 | ima_reset_appraise_flags(dentry->d_inode); | ||
| 260 | result = 0; | ||
| 261 | } | ||
| 262 | return result; | ||
| 263 | } | ||
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 9b3ade7468b2..b21ee5b5495a 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
| @@ -48,7 +48,7 @@ int ima_calc_hash(struct file *file, char *digest) | |||
| 48 | struct scatterlist sg[1]; | 48 | struct scatterlist sg[1]; |
| 49 | loff_t i_size, offset = 0; | 49 | loff_t i_size, offset = 0; |
| 50 | char *rbuf; | 50 | char *rbuf; |
| 51 | int rc; | 51 | int rc, read = 0; |
| 52 | 52 | ||
| 53 | rc = init_desc(&desc); | 53 | rc = init_desc(&desc); |
| 54 | if (rc != 0) | 54 | if (rc != 0) |
| @@ -59,6 +59,10 @@ int ima_calc_hash(struct file *file, char *digest) | |||
| 59 | rc = -ENOMEM; | 59 | rc = -ENOMEM; |
| 60 | goto out; | 60 | goto out; |
| 61 | } | 61 | } |
| 62 | if (!(file->f_mode & FMODE_READ)) { | ||
| 63 | file->f_mode |= FMODE_READ; | ||
| 64 | read = 1; | ||
| 65 | } | ||
| 62 | i_size = i_size_read(file->f_dentry->d_inode); | 66 | i_size = i_size_read(file->f_dentry->d_inode); |
| 63 | while (offset < i_size) { | 67 | while (offset < i_size) { |
| 64 | int rbuf_len; | 68 | int rbuf_len; |
| @@ -80,6 +84,8 @@ int ima_calc_hash(struct file *file, char *digest) | |||
| 80 | kfree(rbuf); | 84 | kfree(rbuf); |
| 81 | if (!rc) | 85 | if (!rc) |
| 82 | rc = crypto_hash_final(&desc, digest); | 86 | rc = crypto_hash_final(&desc, digest); |
| 87 | if (read) | ||
| 88 | file->f_mode &= ~FMODE_READ; | ||
| 83 | out: | 89 | out: |
| 84 | crypto_free_hash(desc.tfm); | 90 | crypto_free_hash(desc.tfm); |
| 85 | return rc; | 91 | return rc; |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index be8294915cf7..73c9a268253e 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -22,12 +22,19 @@ | |||
| 22 | #include <linux/mount.h> | 22 | #include <linux/mount.h> |
| 23 | #include <linux/mman.h> | 23 | #include <linux/mman.h> |
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/xattr.h> | ||
| 25 | #include <linux/ima.h> | 26 | #include <linux/ima.h> |
| 26 | 27 | ||
| 27 | #include "ima.h" | 28 | #include "ima.h" |
| 28 | 29 | ||
| 29 | int ima_initialized; | 30 | int ima_initialized; |
| 30 | 31 | ||
| 32 | #ifdef CONFIG_IMA_APPRAISE | ||
| 33 | int ima_appraise = IMA_APPRAISE_ENFORCE; | ||
| 34 | #else | ||
| 35 | int ima_appraise; | ||
| 36 | #endif | ||
| 37 | |||
| 31 | char *ima_hash = "sha1"; | 38 | char *ima_hash = "sha1"; |
| 32 | static int __init hash_setup(char *str) | 39 | static int __init hash_setup(char *str) |
| 33 | { | 40 | { |
| @@ -52,7 +59,7 @@ static void ima_rdwr_violation_check(struct file *file) | |||
| 52 | struct dentry *dentry = file->f_path.dentry; | 59 | struct dentry *dentry = file->f_path.dentry; |
| 53 | struct inode *inode = dentry->d_inode; | 60 | struct inode *inode = dentry->d_inode; |
| 54 | fmode_t mode = file->f_mode; | 61 | fmode_t mode = file->f_mode; |
| 55 | int rc; | 62 | int must_measure; |
| 56 | bool send_tomtou = false, send_writers = false; | 63 | bool send_tomtou = false, send_writers = false; |
| 57 | unsigned char *pathname = NULL, *pathbuf = NULL; | 64 | unsigned char *pathname = NULL, *pathbuf = NULL; |
| 58 | 65 | ||
| @@ -67,8 +74,8 @@ static void ima_rdwr_violation_check(struct file *file) | |||
| 67 | goto out; | 74 | goto out; |
| 68 | } | 75 | } |
| 69 | 76 | ||
| 70 | rc = ima_must_measure(inode, MAY_READ, FILE_CHECK); | 77 | must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK); |
| 71 | if (rc < 0) | 78 | if (!must_measure) |
| 72 | goto out; | 79 | goto out; |
| 73 | 80 | ||
| 74 | if (atomic_read(&inode->i_writecount) > 0) | 81 | if (atomic_read(&inode->i_writecount) > 0) |
| @@ -100,17 +107,21 @@ out: | |||
| 100 | } | 107 | } |
| 101 | 108 | ||
| 102 | static void ima_check_last_writer(struct integrity_iint_cache *iint, | 109 | static void ima_check_last_writer(struct integrity_iint_cache *iint, |
| 103 | struct inode *inode, | 110 | struct inode *inode, struct file *file) |
| 104 | struct file *file) | ||
| 105 | { | 111 | { |
| 106 | fmode_t mode = file->f_mode; | 112 | fmode_t mode = file->f_mode; |
| 107 | 113 | ||
| 108 | mutex_lock(&iint->mutex); | 114 | if (!(mode & FMODE_WRITE)) |
| 109 | if (mode & FMODE_WRITE && | 115 | return; |
| 110 | atomic_read(&inode->i_writecount) == 1 && | 116 | |
| 111 | iint->version != inode->i_version) | 117 | mutex_lock(&inode->i_mutex); |
| 112 | iint->flags &= ~IMA_MEASURED; | 118 | if (atomic_read(&inode->i_writecount) == 1 && |
| 113 | mutex_unlock(&iint->mutex); | 119 | iint->version != inode->i_version) { |
| 120 | iint->flags &= ~IMA_DONE_MASK; | ||
| 121 | if (iint->flags & IMA_APPRAISE) | ||
| 122 | ima_update_xattr(iint, file); | ||
| 123 | } | ||
| 124 | mutex_unlock(&inode->i_mutex); | ||
| 114 | } | 125 | } |
| 115 | 126 | ||
| 116 | /** | 127 | /** |
| @@ -140,28 +151,37 @@ static int process_measurement(struct file *file, const unsigned char *filename, | |||
| 140 | struct inode *inode = file->f_dentry->d_inode; | 151 | struct inode *inode = file->f_dentry->d_inode; |
| 141 | struct integrity_iint_cache *iint; | 152 | struct integrity_iint_cache *iint; |
| 142 | unsigned char *pathname = NULL, *pathbuf = NULL; | 153 | unsigned char *pathname = NULL, *pathbuf = NULL; |
| 143 | int rc = 0; | 154 | int rc = -ENOMEM, action, must_appraise; |
| 144 | 155 | ||
| 145 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 156 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
| 146 | return 0; | 157 | return 0; |
| 147 | 158 | ||
| 148 | rc = ima_must_measure(inode, mask, function); | 159 | /* Determine if in appraise/audit/measurement policy, |
| 149 | if (rc != 0) | 160 | * returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask. */ |
| 150 | return rc; | 161 | action = ima_get_action(inode, mask, function); |
| 151 | retry: | 162 | if (!action) |
| 152 | iint = integrity_iint_find(inode); | 163 | return 0; |
| 153 | if (!iint) { | ||
| 154 | rc = integrity_inode_alloc(inode); | ||
| 155 | if (!rc || rc == -EEXIST) | ||
| 156 | goto retry; | ||
| 157 | return rc; | ||
| 158 | } | ||
| 159 | 164 | ||
| 160 | mutex_lock(&iint->mutex); | 165 | must_appraise = action & IMA_APPRAISE; |
| 161 | 166 | ||
| 162 | rc = iint->flags & IMA_MEASURED ? 1 : 0; | 167 | mutex_lock(&inode->i_mutex); |
| 163 | if (rc != 0) | 168 | |
| 169 | iint = integrity_inode_get(inode); | ||
| 170 | if (!iint) | ||
| 171 | goto out; | ||
| 172 | |||
| 173 | /* Determine if already appraised/measured based on bitmask | ||
| 174 | * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED, | ||
| 175 | * IMA_AUDIT, IMA_AUDITED) */ | ||
| 176 | iint->flags |= action; | ||
| 177 | action &= ~((iint->flags & IMA_DONE_MASK) >> 1); | ||
| 178 | |||
| 179 | /* Nothing to do, just return existing appraised status */ | ||
| 180 | if (!action) { | ||
| 181 | if (iint->flags & IMA_APPRAISED) | ||
| 182 | rc = iint->ima_status; | ||
| 164 | goto out; | 183 | goto out; |
| 184 | } | ||
| 165 | 185 | ||
| 166 | rc = ima_collect_measurement(iint, file); | 186 | rc = ima_collect_measurement(iint, file); |
| 167 | if (rc != 0) | 187 | if (rc != 0) |
| @@ -177,11 +197,18 @@ retry: | |||
| 177 | pathname = NULL; | 197 | pathname = NULL; |
| 178 | } | 198 | } |
| 179 | } | 199 | } |
| 180 | ima_store_measurement(iint, file, !pathname ? filename : pathname); | 200 | if (action & IMA_MEASURE) |
| 201 | ima_store_measurement(iint, file, | ||
| 202 | !pathname ? filename : pathname); | ||
| 203 | if (action & IMA_APPRAISE) | ||
| 204 | rc = ima_appraise_measurement(iint, file, | ||
| 205 | !pathname ? filename : pathname); | ||
| 206 | if (action & IMA_AUDIT) | ||
| 207 | ima_audit_measurement(iint, !pathname ? filename : pathname); | ||
| 181 | kfree(pathbuf); | 208 | kfree(pathbuf); |
| 182 | out: | 209 | out: |
| 183 | mutex_unlock(&iint->mutex); | 210 | mutex_unlock(&inode->i_mutex); |
| 184 | return rc; | 211 | return (rc && must_appraise) ? -EACCES : 0; |
| 185 | } | 212 | } |
| 186 | 213 | ||
| 187 | /** | 214 | /** |
| @@ -197,14 +224,14 @@ out: | |||
| 197 | */ | 224 | */ |
| 198 | int ima_file_mmap(struct file *file, unsigned long prot) | 225 | int ima_file_mmap(struct file *file, unsigned long prot) |
| 199 | { | 226 | { |
| 200 | int rc; | 227 | int rc = 0; |
| 201 | 228 | ||
| 202 | if (!file) | 229 | if (!file) |
| 203 | return 0; | 230 | return 0; |
| 204 | if (prot & PROT_EXEC) | 231 | if (prot & PROT_EXEC) |
| 205 | rc = process_measurement(file, file->f_dentry->d_name.name, | 232 | rc = process_measurement(file, file->f_dentry->d_name.name, |
| 206 | MAY_EXEC, FILE_MMAP); | 233 | MAY_EXEC, FILE_MMAP); |
| 207 | return 0; | 234 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
| 208 | } | 235 | } |
| 209 | 236 | ||
| 210 | /** | 237 | /** |
| @@ -228,7 +255,7 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
| 228 | (strcmp(bprm->filename, bprm->interp) == 0) ? | 255 | (strcmp(bprm->filename, bprm->interp) == 0) ? |
| 229 | bprm->filename : bprm->interp, | 256 | bprm->filename : bprm->interp, |
| 230 | MAY_EXEC, BPRM_CHECK); | 257 | MAY_EXEC, BPRM_CHECK); |
| 231 | return 0; | 258 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
| 232 | } | 259 | } |
| 233 | 260 | ||
| 234 | /** | 261 | /** |
| @@ -249,7 +276,7 @@ int ima_file_check(struct file *file, int mask) | |||
| 249 | rc = process_measurement(file, file->f_dentry->d_name.name, | 276 | rc = process_measurement(file, file->f_dentry->d_name.name, |
| 250 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | 277 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), |
| 251 | FILE_CHECK); | 278 | FILE_CHECK); |
| 252 | return 0; | 279 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; |
| 253 | } | 280 | } |
| 254 | EXPORT_SYMBOL_GPL(ima_file_check); | 281 | EXPORT_SYMBOL_GPL(ima_file_check); |
| 255 | 282 | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index c84df05180cb..c7dacd2eab7a 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
| @@ -24,22 +24,29 @@ | |||
| 24 | #define IMA_MASK 0x0002 | 24 | #define IMA_MASK 0x0002 |
| 25 | #define IMA_FSMAGIC 0x0004 | 25 | #define IMA_FSMAGIC 0x0004 |
| 26 | #define IMA_UID 0x0008 | 26 | #define IMA_UID 0x0008 |
| 27 | #define IMA_FOWNER 0x0010 | ||
| 27 | 28 | ||
| 28 | enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; | 29 | #define UNKNOWN 0 |
| 30 | #define MEASURE 0x0001 /* same as IMA_MEASURE */ | ||
| 31 | #define DONT_MEASURE 0x0002 | ||
| 32 | #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ | ||
| 33 | #define DONT_APPRAISE 0x0008 | ||
| 34 | #define AUDIT 0x0040 | ||
| 29 | 35 | ||
| 30 | #define MAX_LSM_RULES 6 | 36 | #define MAX_LSM_RULES 6 |
| 31 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | 37 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, |
| 32 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | 38 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE |
| 33 | }; | 39 | }; |
| 34 | 40 | ||
| 35 | struct ima_measure_rule_entry { | 41 | struct ima_rule_entry { |
| 36 | struct list_head list; | 42 | struct list_head list; |
| 37 | enum ima_action action; | 43 | int action; |
| 38 | unsigned int flags; | 44 | unsigned int flags; |
| 39 | enum ima_hooks func; | 45 | enum ima_hooks func; |
| 40 | int mask; | 46 | int mask; |
| 41 | unsigned long fsmagic; | 47 | unsigned long fsmagic; |
| 42 | kuid_t uid; | 48 | kuid_t uid; |
| 49 | kuid_t fowner; | ||
| 43 | struct { | 50 | struct { |
| 44 | void *rule; /* LSM file metadata specific */ | 51 | void *rule; /* LSM file metadata specific */ |
| 45 | int type; /* audit type */ | 52 | int type; /* audit type */ |
| @@ -48,7 +55,7 @@ struct ima_measure_rule_entry { | |||
| 48 | 55 | ||
| 49 | /* | 56 | /* |
| 50 | * Without LSM specific knowledge, the default policy can only be | 57 | * Without LSM specific knowledge, the default policy can only be |
| 51 | * written in terms of .action, .func, .mask, .fsmagic, and .uid | 58 | * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner |
| 52 | */ | 59 | */ |
| 53 | 60 | ||
| 54 | /* | 61 | /* |
| @@ -57,7 +64,7 @@ struct ima_measure_rule_entry { | |||
| 57 | * normal users can easily run the machine out of memory simply building | 64 | * normal users can easily run the machine out of memory simply building |
| 58 | * and running executables. | 65 | * and running executables. |
| 59 | */ | 66 | */ |
| 60 | static struct ima_measure_rule_entry default_rules[] = { | 67 | static struct ima_rule_entry default_rules[] = { |
| 61 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | 68 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, |
| 62 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, | 69 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, |
| 63 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | 70 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, |
| @@ -75,19 +82,41 @@ static struct ima_measure_rule_entry default_rules[] = { | |||
| 75 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | 82 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
| 76 | }; | 83 | }; |
| 77 | 84 | ||
| 78 | static LIST_HEAD(measure_default_rules); | 85 | static struct ima_rule_entry default_appraise_rules[] = { |
| 79 | static LIST_HEAD(measure_policy_rules); | 86 | {.action = DONT_APPRAISE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, |
| 80 | static struct list_head *ima_measure; | 87 | {.action = DONT_APPRAISE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, |
| 88 | {.action = DONT_APPRAISE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 89 | {.action = DONT_APPRAISE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 90 | {.action = DONT_APPRAISE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 91 | {.action = DONT_APPRAISE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 92 | {.action = DONT_APPRAISE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 93 | {.action = DONT_APPRAISE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 94 | {.action = DONT_APPRAISE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 95 | {.action = DONT_APPRAISE,.fsmagic = CGROUP_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 96 | {.action = APPRAISE,.fowner = GLOBAL_ROOT_UID,.flags = IMA_FOWNER}, | ||
| 97 | }; | ||
| 98 | |||
| 99 | static LIST_HEAD(ima_default_rules); | ||
| 100 | static LIST_HEAD(ima_policy_rules); | ||
| 101 | static struct list_head *ima_rules; | ||
| 81 | 102 | ||
| 82 | static DEFINE_MUTEX(ima_measure_mutex); | 103 | static DEFINE_MUTEX(ima_rules_mutex); |
| 83 | 104 | ||
| 84 | static bool ima_use_tcb __initdata; | 105 | static bool ima_use_tcb __initdata; |
| 85 | static int __init default_policy_setup(char *str) | 106 | static int __init default_measure_policy_setup(char *str) |
| 86 | { | 107 | { |
| 87 | ima_use_tcb = 1; | 108 | ima_use_tcb = 1; |
| 88 | return 1; | 109 | return 1; |
| 89 | } | 110 | } |
| 90 | __setup("ima_tcb", default_policy_setup); | 111 | __setup("ima_tcb", default_measure_policy_setup); |
| 112 | |||
| 113 | static bool ima_use_appraise_tcb __initdata; | ||
| 114 | static int __init default_appraise_policy_setup(char *str) | ||
| 115 | { | ||
| 116 | ima_use_appraise_tcb = 1; | ||
| 117 | return 1; | ||
| 118 | } | ||
| 119 | __setup("ima_appraise_tcb", default_appraise_policy_setup); | ||
| 91 | 120 | ||
| 92 | /** | 121 | /** |
| 93 | * ima_match_rules - determine whether an inode matches the measure rule. | 122 | * ima_match_rules - determine whether an inode matches the measure rule. |
| @@ -98,7 +127,7 @@ __setup("ima_tcb", default_policy_setup); | |||
| 98 | * | 127 | * |
| 99 | * Returns true on rule match, false on failure. | 128 | * Returns true on rule match, false on failure. |
| 100 | */ | 129 | */ |
| 101 | static bool ima_match_rules(struct ima_measure_rule_entry *rule, | 130 | static bool ima_match_rules(struct ima_rule_entry *rule, |
| 102 | struct inode *inode, enum ima_hooks func, int mask) | 131 | struct inode *inode, enum ima_hooks func, int mask) |
| 103 | { | 132 | { |
| 104 | struct task_struct *tsk = current; | 133 | struct task_struct *tsk = current; |
| @@ -114,6 +143,8 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
| 114 | return false; | 143 | return false; |
| 115 | if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) | 144 | if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) |
| 116 | return false; | 145 | return false; |
| 146 | if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid)) | ||
| 147 | return false; | ||
| 117 | for (i = 0; i < MAX_LSM_RULES; i++) { | 148 | for (i = 0; i < MAX_LSM_RULES; i++) { |
| 118 | int rc = 0; | 149 | int rc = 0; |
| 119 | u32 osid, sid; | 150 | u32 osid, sid; |
| @@ -163,39 +194,61 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
| 163 | * as elements in the list are never deleted, nor does the list | 194 | * as elements in the list are never deleted, nor does the list |
| 164 | * change.) | 195 | * change.) |
| 165 | */ | 196 | */ |
| 166 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) | 197 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
| 198 | int flags) | ||
| 167 | { | 199 | { |
| 168 | struct ima_measure_rule_entry *entry; | 200 | struct ima_rule_entry *entry; |
| 201 | int action = 0, actmask = flags | (flags << 1); | ||
| 202 | |||
| 203 | list_for_each_entry(entry, ima_rules, list) { | ||
| 204 | |||
| 205 | if (!(entry->action & actmask)) | ||
| 206 | continue; | ||
| 207 | |||
| 208 | if (!ima_match_rules(entry, inode, func, mask)) | ||
| 209 | continue; | ||
| 169 | 210 | ||
| 170 | list_for_each_entry(entry, ima_measure, list) { | 211 | action |= entry->action & IMA_DO_MASK; |
| 171 | bool rc; | 212 | if (entry->action & IMA_DO_MASK) |
| 213 | actmask &= ~(entry->action | entry->action << 1); | ||
| 214 | else | ||
| 215 | actmask &= ~(entry->action | entry->action >> 1); | ||
| 172 | 216 | ||
| 173 | rc = ima_match_rules(entry, inode, func, mask); | 217 | if (!actmask) |
| 174 | if (rc) | 218 | break; |
| 175 | return entry->action; | ||
| 176 | } | 219 | } |
| 177 | return 0; | 220 | |
| 221 | return action; | ||
| 178 | } | 222 | } |
| 179 | 223 | ||
| 180 | /** | 224 | /** |
| 181 | * ima_init_policy - initialize the default measure rules. | 225 | * ima_init_policy - initialize the default measure rules. |
| 182 | * | 226 | * |
| 183 | * ima_measure points to either the measure_default_rules or the | 227 | * ima_rules points to either the ima_default_rules or the |
| 184 | * the new measure_policy_rules. | 228 | * the new ima_policy_rules. |
| 185 | */ | 229 | */ |
| 186 | void __init ima_init_policy(void) | 230 | void __init ima_init_policy(void) |
| 187 | { | 231 | { |
| 188 | int i, entries; | 232 | int i, measure_entries, appraise_entries; |
| 189 | 233 | ||
| 190 | /* if !ima_use_tcb set entries = 0 so we load NO default rules */ | 234 | /* if !ima_use_tcb set entries = 0 so we load NO default rules */ |
| 191 | if (ima_use_tcb) | 235 | measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0; |
| 192 | entries = ARRAY_SIZE(default_rules); | 236 | appraise_entries = ima_use_appraise_tcb ? |
| 193 | else | 237 | ARRAY_SIZE(default_appraise_rules) : 0; |
| 194 | entries = 0; | 238 | |
| 195 | 239 | for (i = 0; i < measure_entries + appraise_entries; i++) { | |
| 196 | for (i = 0; i < entries; i++) | 240 | if (i < measure_entries) |
| 197 | list_add_tail(&default_rules[i].list, &measure_default_rules); | 241 | list_add_tail(&default_rules[i].list, |
| 198 | ima_measure = &measure_default_rules; | 242 | &ima_default_rules); |
| 243 | else { | ||
| 244 | int j = i - measure_entries; | ||
| 245 | |||
| 246 | list_add_tail(&default_appraise_rules[j].list, | ||
| 247 | &ima_default_rules); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | ima_rules = &ima_default_rules; | ||
| 199 | } | 252 | } |
| 200 | 253 | ||
| 201 | /** | 254 | /** |
| @@ -212,8 +265,8 @@ void ima_update_policy(void) | |||
| 212 | int result = 1; | 265 | int result = 1; |
| 213 | int audit_info = 0; | 266 | int audit_info = 0; |
| 214 | 267 | ||
| 215 | if (ima_measure == &measure_default_rules) { | 268 | if (ima_rules == &ima_default_rules) { |
| 216 | ima_measure = &measure_policy_rules; | 269 | ima_rules = &ima_policy_rules; |
| 217 | cause = "complete"; | 270 | cause = "complete"; |
| 218 | result = 0; | 271 | result = 0; |
| 219 | } | 272 | } |
| @@ -224,14 +277,19 @@ void ima_update_policy(void) | |||
| 224 | enum { | 277 | enum { |
| 225 | Opt_err = -1, | 278 | Opt_err = -1, |
| 226 | Opt_measure = 1, Opt_dont_measure, | 279 | Opt_measure = 1, Opt_dont_measure, |
| 280 | Opt_appraise, Opt_dont_appraise, | ||
| 281 | Opt_audit, | ||
| 227 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | 282 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
| 228 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | 283 | Opt_subj_user, Opt_subj_role, Opt_subj_type, |
| 229 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid | 284 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner |
| 230 | }; | 285 | }; |
| 231 | 286 | ||
| 232 | static match_table_t policy_tokens = { | 287 | static match_table_t policy_tokens = { |
| 233 | {Opt_measure, "measure"}, | 288 | {Opt_measure, "measure"}, |
| 234 | {Opt_dont_measure, "dont_measure"}, | 289 | {Opt_dont_measure, "dont_measure"}, |
| 290 | {Opt_appraise, "appraise"}, | ||
| 291 | {Opt_dont_appraise, "dont_appraise"}, | ||
| 292 | {Opt_audit, "audit"}, | ||
| 235 | {Opt_obj_user, "obj_user=%s"}, | 293 | {Opt_obj_user, "obj_user=%s"}, |
| 236 | {Opt_obj_role, "obj_role=%s"}, | 294 | {Opt_obj_role, "obj_role=%s"}, |
| 237 | {Opt_obj_type, "obj_type=%s"}, | 295 | {Opt_obj_type, "obj_type=%s"}, |
| @@ -242,10 +300,11 @@ static match_table_t policy_tokens = { | |||
| 242 | {Opt_mask, "mask=%s"}, | 300 | {Opt_mask, "mask=%s"}, |
| 243 | {Opt_fsmagic, "fsmagic=%s"}, | 301 | {Opt_fsmagic, "fsmagic=%s"}, |
| 244 | {Opt_uid, "uid=%s"}, | 302 | {Opt_uid, "uid=%s"}, |
| 303 | {Opt_fowner, "fowner=%s"}, | ||
| 245 | {Opt_err, NULL} | 304 | {Opt_err, NULL} |
| 246 | }; | 305 | }; |
| 247 | 306 | ||
| 248 | static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | 307 | static int ima_lsm_rule_init(struct ima_rule_entry *entry, |
| 249 | char *args, int lsm_rule, int audit_type) | 308 | char *args, int lsm_rule, int audit_type) |
| 250 | { | 309 | { |
| 251 | int result; | 310 | int result; |
| @@ -269,7 +328,7 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value) | |||
| 269 | audit_log_format(ab, " "); | 328 | audit_log_format(ab, " "); |
| 270 | } | 329 | } |
| 271 | 330 | ||
| 272 | static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | 331 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) |
| 273 | { | 332 | { |
| 274 | struct audit_buffer *ab; | 333 | struct audit_buffer *ab; |
| 275 | char *p; | 334 | char *p; |
| @@ -278,6 +337,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 278 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); | 337 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); |
| 279 | 338 | ||
| 280 | entry->uid = INVALID_UID; | 339 | entry->uid = INVALID_UID; |
| 340 | entry->fowner = INVALID_UID; | ||
| 281 | entry->action = UNKNOWN; | 341 | entry->action = UNKNOWN; |
| 282 | while ((p = strsep(&rule, " \t")) != NULL) { | 342 | while ((p = strsep(&rule, " \t")) != NULL) { |
| 283 | substring_t args[MAX_OPT_ARGS]; | 343 | substring_t args[MAX_OPT_ARGS]; |
| @@ -306,11 +366,35 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 306 | 366 | ||
| 307 | entry->action = DONT_MEASURE; | 367 | entry->action = DONT_MEASURE; |
| 308 | break; | 368 | break; |
| 369 | case Opt_appraise: | ||
| 370 | ima_log_string(ab, "action", "appraise"); | ||
| 371 | |||
| 372 | if (entry->action != UNKNOWN) | ||
| 373 | result = -EINVAL; | ||
| 374 | |||
| 375 | entry->action = APPRAISE; | ||
| 376 | break; | ||
| 377 | case Opt_dont_appraise: | ||
| 378 | ima_log_string(ab, "action", "dont_appraise"); | ||
| 379 | |||
| 380 | if (entry->action != UNKNOWN) | ||
| 381 | result = -EINVAL; | ||
| 382 | |||
| 383 | entry->action = DONT_APPRAISE; | ||
| 384 | break; | ||
| 385 | case Opt_audit: | ||
| 386 | ima_log_string(ab, "action", "audit"); | ||
| 387 | |||
| 388 | if (entry->action != UNKNOWN) | ||
| 389 | result = -EINVAL; | ||
| 390 | |||
| 391 | entry->action = AUDIT; | ||
| 392 | break; | ||
| 309 | case Opt_func: | 393 | case Opt_func: |
| 310 | ima_log_string(ab, "func", args[0].from); | 394 | ima_log_string(ab, "func", args[0].from); |
| 311 | 395 | ||
| 312 | if (entry->func) | 396 | if (entry->func) |
| 313 | result = -EINVAL; | 397 | result = -EINVAL; |
| 314 | 398 | ||
| 315 | if (strcmp(args[0].from, "FILE_CHECK") == 0) | 399 | if (strcmp(args[0].from, "FILE_CHECK") == 0) |
| 316 | entry->func = FILE_CHECK; | 400 | entry->func = FILE_CHECK; |
| @@ -375,6 +459,23 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 375 | entry->flags |= IMA_UID; | 459 | entry->flags |= IMA_UID; |
| 376 | } | 460 | } |
| 377 | break; | 461 | break; |
| 462 | case Opt_fowner: | ||
| 463 | ima_log_string(ab, "fowner", args[0].from); | ||
| 464 | |||
| 465 | if (uid_valid(entry->fowner)) { | ||
| 466 | result = -EINVAL; | ||
| 467 | break; | ||
| 468 | } | ||
| 469 | |||
| 470 | result = strict_strtoul(args[0].from, 10, &lnum); | ||
| 471 | if (!result) { | ||
| 472 | entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum); | ||
| 473 | if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum)) | ||
| 474 | result = -EINVAL; | ||
| 475 | else | ||
| 476 | entry->flags |= IMA_FOWNER; | ||
| 477 | } | ||
| 478 | break; | ||
| 378 | case Opt_obj_user: | 479 | case Opt_obj_user: |
| 379 | ima_log_string(ab, "obj_user", args[0].from); | 480 | ima_log_string(ab, "obj_user", args[0].from); |
| 380 | result = ima_lsm_rule_init(entry, args[0].from, | 481 | result = ima_lsm_rule_init(entry, args[0].from, |
| @@ -426,7 +527,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 426 | } | 527 | } |
| 427 | 528 | ||
| 428 | /** | 529 | /** |
| 429 | * ima_parse_add_rule - add a rule to measure_policy_rules | 530 | * ima_parse_add_rule - add a rule to ima_policy_rules |
| 430 | * @rule - ima measurement policy rule | 531 | * @rule - ima measurement policy rule |
| 431 | * | 532 | * |
| 432 | * Uses a mutex to protect the policy list from multiple concurrent writers. | 533 | * Uses a mutex to protect the policy list from multiple concurrent writers. |
| @@ -436,12 +537,12 @@ ssize_t ima_parse_add_rule(char *rule) | |||
| 436 | { | 537 | { |
| 437 | const char *op = "update_policy"; | 538 | const char *op = "update_policy"; |
| 438 | char *p; | 539 | char *p; |
| 439 | struct ima_measure_rule_entry *entry; | 540 | struct ima_rule_entry *entry; |
| 440 | ssize_t result, len; | 541 | ssize_t result, len; |
| 441 | int audit_info = 0; | 542 | int audit_info = 0; |
| 442 | 543 | ||
| 443 | /* Prevent installed policy from changing */ | 544 | /* Prevent installed policy from changing */ |
| 444 | if (ima_measure != &measure_default_rules) { | 545 | if (ima_rules != &ima_default_rules) { |
| 445 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 546 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
| 446 | NULL, op, "already exists", | 547 | NULL, op, "already exists", |
| 447 | -EACCES, audit_info); | 548 | -EACCES, audit_info); |
| @@ -474,9 +575,9 @@ ssize_t ima_parse_add_rule(char *rule) | |||
| 474 | return result; | 575 | return result; |
| 475 | } | 576 | } |
| 476 | 577 | ||
| 477 | mutex_lock(&ima_measure_mutex); | 578 | mutex_lock(&ima_rules_mutex); |
| 478 | list_add_tail(&entry->list, &measure_policy_rules); | 579 | list_add_tail(&entry->list, &ima_policy_rules); |
| 479 | mutex_unlock(&ima_measure_mutex); | 580 | mutex_unlock(&ima_rules_mutex); |
| 480 | 581 | ||
| 481 | return len; | 582 | return len; |
| 482 | } | 583 | } |
| @@ -484,12 +585,12 @@ ssize_t ima_parse_add_rule(char *rule) | |||
| 484 | /* ima_delete_rules called to cleanup invalid policy */ | 585 | /* ima_delete_rules called to cleanup invalid policy */ |
| 485 | void ima_delete_rules(void) | 586 | void ima_delete_rules(void) |
| 486 | { | 587 | { |
| 487 | struct ima_measure_rule_entry *entry, *tmp; | 588 | struct ima_rule_entry *entry, *tmp; |
| 488 | 589 | ||
| 489 | mutex_lock(&ima_measure_mutex); | 590 | mutex_lock(&ima_rules_mutex); |
| 490 | list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) { | 591 | list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) { |
| 491 | list_del(&entry->list); | 592 | list_del(&entry->list); |
| 492 | kfree(entry); | 593 | kfree(entry); |
| 493 | } | 594 | } |
| 494 | mutex_unlock(&ima_measure_mutex); | 595 | mutex_unlock(&ima_rules_mutex); |
| 495 | } | 596 | } |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 7a25ecec5aaa..e9db763a875e 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
| @@ -15,8 +15,22 @@ | |||
| 15 | #include <linux/integrity.h> | 15 | #include <linux/integrity.h> |
| 16 | #include <crypto/sha.h> | 16 | #include <crypto/sha.h> |
| 17 | 17 | ||
| 18 | /* iint action cache flags */ | ||
| 19 | #define IMA_MEASURE 0x0001 | ||
| 20 | #define IMA_MEASURED 0x0002 | ||
| 21 | #define IMA_APPRAISE 0x0004 | ||
| 22 | #define IMA_APPRAISED 0x0008 | ||
| 23 | /*#define IMA_COLLECT 0x0010 do not use this flag */ | ||
| 24 | #define IMA_COLLECTED 0x0020 | ||
| 25 | #define IMA_AUDIT 0x0040 | ||
| 26 | #define IMA_AUDITED 0x0080 | ||
| 27 | |||
| 18 | /* iint cache flags */ | 28 | /* iint cache flags */ |
| 19 | #define IMA_MEASURED 0x01 | 29 | #define IMA_DIGSIG 0x0100 |
| 30 | |||
| 31 | #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT) | ||
| 32 | #define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \ | ||
| 33 | | IMA_COLLECTED) | ||
| 20 | 34 | ||
| 21 | enum evm_ima_xattr_type { | 35 | enum evm_ima_xattr_type { |
| 22 | IMA_XATTR_DIGEST = 0x01, | 36 | IMA_XATTR_DIGEST = 0x01, |
| @@ -34,9 +48,9 @@ struct integrity_iint_cache { | |||
| 34 | struct rb_node rb_node; /* rooted in integrity_iint_tree */ | 48 | struct rb_node rb_node; /* rooted in integrity_iint_tree */ |
| 35 | struct inode *inode; /* back pointer to inode in question */ | 49 | struct inode *inode; /* back pointer to inode in question */ |
| 36 | u64 version; /* track inode changes */ | 50 | u64 version; /* track inode changes */ |
| 37 | unsigned char flags; | 51 | unsigned short flags; |
| 38 | u8 digest[SHA1_DIGEST_SIZE]; | 52 | struct evm_ima_xattr_data ima_xattr; |
| 39 | struct mutex mutex; /* protects: version, flags, digest */ | 53 | enum integrity_status ima_status; |
| 40 | enum integrity_status evm_status; | 54 | enum integrity_status evm_status; |
| 41 | }; | 55 | }; |
| 42 | 56 | ||
diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 2d5d041f2049..3f163d0489ad 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c | |||
| @@ -369,38 +369,6 @@ static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, | |||
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | /* | 371 | /* |
| 372 | * get a random value from TPM | ||
| 373 | */ | ||
| 374 | static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len) | ||
| 375 | { | ||
| 376 | int ret; | ||
| 377 | |||
| 378 | INIT_BUF(tb); | ||
| 379 | store16(tb, TPM_TAG_RQU_COMMAND); | ||
| 380 | store32(tb, TPM_GETRANDOM_SIZE); | ||
| 381 | store32(tb, TPM_ORD_GETRANDOM); | ||
| 382 | store32(tb, len); | ||
| 383 | ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data); | ||
| 384 | if (!ret) | ||
| 385 | memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len); | ||
| 386 | return ret; | ||
| 387 | } | ||
| 388 | |||
| 389 | static int my_get_random(unsigned char *buf, int len) | ||
| 390 | { | ||
| 391 | struct tpm_buf *tb; | ||
| 392 | int ret; | ||
| 393 | |||
| 394 | tb = kmalloc(sizeof *tb, GFP_KERNEL); | ||
| 395 | if (!tb) | ||
| 396 | return -ENOMEM; | ||
| 397 | ret = tpm_get_random(tb, buf, len); | ||
| 398 | |||
| 399 | kfree(tb); | ||
| 400 | return ret; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* | ||
| 404 | * Lock a trusted key, by extending a selected PCR. | 372 | * Lock a trusted key, by extending a selected PCR. |
| 405 | * | 373 | * |
| 406 | * Prevents a trusted key that is sealed to PCRs from being accessed. | 374 | * Prevents a trusted key that is sealed to PCRs from being accessed. |
| @@ -413,8 +381,8 @@ static int pcrlock(const int pcrnum) | |||
| 413 | 381 | ||
| 414 | if (!capable(CAP_SYS_ADMIN)) | 382 | if (!capable(CAP_SYS_ADMIN)) |
| 415 | return -EPERM; | 383 | return -EPERM; |
| 416 | ret = my_get_random(hash, SHA1_DIGEST_SIZE); | 384 | ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE); |
| 417 | if (ret < 0) | 385 | if (ret != SHA1_DIGEST_SIZE) |
| 418 | return ret; | 386 | return ret; |
| 419 | return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; | 387 | return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; |
| 420 | } | 388 | } |
| @@ -429,8 +397,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, | |||
| 429 | unsigned char ononce[TPM_NONCE_SIZE]; | 397 | unsigned char ononce[TPM_NONCE_SIZE]; |
| 430 | int ret; | 398 | int ret; |
| 431 | 399 | ||
| 432 | ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE); | 400 | ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE); |
| 433 | if (ret < 0) | 401 | if (ret != TPM_NONCE_SIZE) |
| 434 | return ret; | 402 | return ret; |
| 435 | 403 | ||
| 436 | INIT_BUF(tb); | 404 | INIT_BUF(tb); |
| @@ -524,8 +492,8 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, | |||
| 524 | if (ret < 0) | 492 | if (ret < 0) |
| 525 | goto out; | 493 | goto out; |
| 526 | 494 | ||
| 527 | ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE); | 495 | ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE); |
| 528 | if (ret < 0) | 496 | if (ret != TPM_NONCE_SIZE) |
| 529 | goto out; | 497 | goto out; |
| 530 | ordinal = htonl(TPM_ORD_SEAL); | 498 | ordinal = htonl(TPM_ORD_SEAL); |
| 531 | datsize = htonl(datalen); | 499 | datsize = htonl(datalen); |
| @@ -634,8 +602,8 @@ static int tpm_unseal(struct tpm_buf *tb, | |||
| 634 | 602 | ||
| 635 | ordinal = htonl(TPM_ORD_UNSEAL); | 603 | ordinal = htonl(TPM_ORD_UNSEAL); |
| 636 | keyhndl = htonl(SRKHANDLE); | 604 | keyhndl = htonl(SRKHANDLE); |
| 637 | ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE); | 605 | ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE); |
| 638 | if (ret < 0) { | 606 | if (ret != TPM_NONCE_SIZE) { |
| 639 | pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); | 607 | pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); |
| 640 | return ret; | 608 | return ret; |
| 641 | } | 609 | } |
| @@ -935,6 +903,7 @@ static int trusted_instantiate(struct key *key, const void *data, | |||
| 935 | char *datablob; | 903 | char *datablob; |
| 936 | int ret = 0; | 904 | int ret = 0; |
| 937 | int key_cmd; | 905 | int key_cmd; |
| 906 | size_t key_len; | ||
| 938 | 907 | ||
| 939 | if (datalen <= 0 || datalen > 32767 || !data) | 908 | if (datalen <= 0 || datalen > 32767 || !data) |
| 940 | return -EINVAL; | 909 | return -EINVAL; |
| @@ -974,8 +943,9 @@ static int trusted_instantiate(struct key *key, const void *data, | |||
| 974 | pr_info("trusted_key: key_unseal failed (%d)\n", ret); | 943 | pr_info("trusted_key: key_unseal failed (%d)\n", ret); |
| 975 | break; | 944 | break; |
| 976 | case Opt_new: | 945 | case Opt_new: |
| 977 | ret = my_get_random(payload->key, payload->key_len); | 946 | key_len = payload->key_len; |
| 978 | if (ret < 0) { | 947 | ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len); |
| 948 | if (ret != key_len) { | ||
| 979 | pr_info("trusted_key: key_create failed (%d)\n", ret); | 949 | pr_info("trusted_key: key_create failed (%d)\n", ret); |
| 980 | goto out; | 950 | goto out; |
| 981 | } | 951 | } |
diff --git a/security/security.c b/security/security.c index f9a2f2ef2454..3724029d0f6d 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -136,11 +136,23 @@ int __init register_security(struct security_operations *ops) | |||
| 136 | 136 | ||
| 137 | int security_ptrace_access_check(struct task_struct *child, unsigned int mode) | 137 | int security_ptrace_access_check(struct task_struct *child, unsigned int mode) |
| 138 | { | 138 | { |
| 139 | #ifdef CONFIG_SECURITY_YAMA_STACKED | ||
| 140 | int rc; | ||
| 141 | rc = yama_ptrace_access_check(child, mode); | ||
| 142 | if (rc) | ||
| 143 | return rc; | ||
| 144 | #endif | ||
| 139 | return security_ops->ptrace_access_check(child, mode); | 145 | return security_ops->ptrace_access_check(child, mode); |
| 140 | } | 146 | } |
| 141 | 147 | ||
| 142 | int security_ptrace_traceme(struct task_struct *parent) | 148 | int security_ptrace_traceme(struct task_struct *parent) |
| 143 | { | 149 | { |
| 150 | #ifdef CONFIG_SECURITY_YAMA_STACKED | ||
| 151 | int rc; | ||
| 152 | rc = yama_ptrace_traceme(parent); | ||
| 153 | if (rc) | ||
| 154 | return rc; | ||
| 155 | #endif | ||
| 144 | return security_ops->ptrace_traceme(parent); | 156 | return security_ops->ptrace_traceme(parent); |
| 145 | } | 157 | } |
| 146 | 158 | ||
| @@ -561,6 +573,9 @@ int security_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 561 | ret = security_ops->inode_setxattr(dentry, name, value, size, flags); | 573 | ret = security_ops->inode_setxattr(dentry, name, value, size, flags); |
| 562 | if (ret) | 574 | if (ret) |
| 563 | return ret; | 575 | return ret; |
| 576 | ret = ima_inode_setxattr(dentry, name, value, size); | ||
| 577 | if (ret) | ||
| 578 | return ret; | ||
| 564 | return evm_inode_setxattr(dentry, name, value, size); | 579 | return evm_inode_setxattr(dentry, name, value, size); |
| 565 | } | 580 | } |
| 566 | 581 | ||
| @@ -596,6 +611,9 @@ int security_inode_removexattr(struct dentry *dentry, const char *name) | |||
| 596 | ret = security_ops->inode_removexattr(dentry, name); | 611 | ret = security_ops->inode_removexattr(dentry, name); |
| 597 | if (ret) | 612 | if (ret) |
| 598 | return ret; | 613 | return ret; |
| 614 | ret = ima_inode_removexattr(dentry, name); | ||
| 615 | if (ret) | ||
| 616 | return ret; | ||
| 599 | return evm_inode_removexattr(dentry, name); | 617 | return evm_inode_removexattr(dentry, name); |
| 600 | } | 618 | } |
| 601 | 619 | ||
| @@ -761,6 +779,9 @@ int security_task_create(unsigned long clone_flags) | |||
| 761 | 779 | ||
| 762 | void security_task_free(struct task_struct *task) | 780 | void security_task_free(struct task_struct *task) |
| 763 | { | 781 | { |
| 782 | #ifdef CONFIG_SECURITY_YAMA_STACKED | ||
| 783 | yama_task_free(task); | ||
| 784 | #endif | ||
| 764 | security_ops->task_free(task); | 785 | security_ops->task_free(task); |
| 765 | } | 786 | } |
| 766 | 787 | ||
| @@ -876,6 +897,12 @@ int security_task_wait(struct task_struct *p) | |||
| 876 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 897 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
| 877 | unsigned long arg4, unsigned long arg5) | 898 | unsigned long arg4, unsigned long arg5) |
| 878 | { | 899 | { |
| 900 | #ifdef CONFIG_SECURITY_YAMA_STACKED | ||
| 901 | int rc; | ||
| 902 | rc = yama_task_prctl(option, arg2, arg3, arg4, arg5); | ||
| 903 | if (rc != -ENOSYS) | ||
| 904 | return rc; | ||
| 905 | #endif | ||
| 879 | return security_ops->task_prctl(option, arg2, arg3, arg4, arg5); | 906 | return security_ops->task_prctl(option, arg2, arg3, arg4, arg5); |
| 880 | } | 907 | } |
| 881 | 908 | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 8221514cc997..2874c7316783 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -1691,40 +1691,19 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, | |||
| 1691 | * smack_task_wait - Smack access check for waiting | 1691 | * smack_task_wait - Smack access check for waiting |
| 1692 | * @p: task to wait for | 1692 | * @p: task to wait for |
| 1693 | * | 1693 | * |
| 1694 | * Returns 0 if current can wait for p, error code otherwise | 1694 | * Returns 0 |
| 1695 | */ | 1695 | */ |
| 1696 | static int smack_task_wait(struct task_struct *p) | 1696 | static int smack_task_wait(struct task_struct *p) |
| 1697 | { | 1697 | { |
| 1698 | struct smk_audit_info ad; | ||
| 1699 | char *sp = smk_of_current(); | ||
| 1700 | char *tsp = smk_of_forked(task_security(p)); | ||
| 1701 | int rc; | ||
| 1702 | |||
| 1703 | /* we don't log here, we can be overriden */ | ||
| 1704 | rc = smk_access(tsp, sp, MAY_WRITE, NULL); | ||
| 1705 | if (rc == 0) | ||
| 1706 | goto out_log; | ||
| 1707 | |||
| 1708 | /* | 1698 | /* |
| 1709 | * Allow the operation to succeed if either task | 1699 | * Allow the operation to succeed. |
| 1710 | * has privilege to perform operations that might | 1700 | * Zombies are bad. |
| 1711 | * account for the smack labels having gotten to | 1701 | * In userless environments (e.g. phones) programs |
| 1712 | * be different in the first place. | 1702 | * get marked with SMACK64EXEC and even if the parent |
| 1713 | * | 1703 | * and child shouldn't be talking the parent still |
| 1714 | * This breaks the strict subject/object access | 1704 | * may expect to know when the child exits. |
| 1715 | * control ideal, taking the object's privilege | ||
| 1716 | * state into account in the decision as well as | ||
| 1717 | * the smack value. | ||
| 1718 | */ | 1705 | */ |
| 1719 | if (smack_privileged(CAP_MAC_OVERRIDE) || | 1706 | return 0; |
| 1720 | has_capability(p, CAP_MAC_OVERRIDE)) | ||
| 1721 | rc = 0; | ||
| 1722 | /* we log only if we didn't get overriden */ | ||
| 1723 | out_log: | ||
| 1724 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
| 1725 | smk_ad_setfield_u_tsk(&ad, p); | ||
| 1726 | smack_log(tsp, sp, MAY_WRITE, rc, &ad); | ||
| 1727 | return rc; | ||
| 1728 | } | 1707 | } |
| 1729 | 1708 | ||
| 1730 | /** | 1709 | /** |
| @@ -2705,9 +2684,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) | |||
| 2705 | static int smack_setprocattr(struct task_struct *p, char *name, | 2684 | static int smack_setprocattr(struct task_struct *p, char *name, |
| 2706 | void *value, size_t size) | 2685 | void *value, size_t size) |
| 2707 | { | 2686 | { |
| 2708 | int rc; | ||
| 2709 | struct task_smack *tsp; | 2687 | struct task_smack *tsp; |
| 2710 | struct task_smack *oldtsp; | ||
| 2711 | struct cred *new; | 2688 | struct cred *new; |
| 2712 | char *newsmack; | 2689 | char *newsmack; |
| 2713 | 2690 | ||
| @@ -2737,21 +2714,13 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
| 2737 | if (newsmack == smack_known_web.smk_known) | 2714 | if (newsmack == smack_known_web.smk_known) |
| 2738 | return -EPERM; | 2715 | return -EPERM; |
| 2739 | 2716 | ||
| 2740 | oldtsp = p->cred->security; | ||
| 2741 | new = prepare_creds(); | 2717 | new = prepare_creds(); |
| 2742 | if (new == NULL) | 2718 | if (new == NULL) |
| 2743 | return -ENOMEM; | 2719 | return -ENOMEM; |
| 2744 | 2720 | ||
| 2745 | tsp = new_task_smack(newsmack, oldtsp->smk_forked, GFP_KERNEL); | 2721 | tsp = new->security; |
| 2746 | if (tsp == NULL) { | 2722 | tsp->smk_task = newsmack; |
| 2747 | kfree(new); | ||
| 2748 | return -ENOMEM; | ||
| 2749 | } | ||
| 2750 | rc = smk_copy_rules(&tsp->smk_rules, &oldtsp->smk_rules, GFP_KERNEL); | ||
| 2751 | if (rc != 0) | ||
| 2752 | return rc; | ||
| 2753 | 2723 | ||
| 2754 | new->security = tsp; | ||
| 2755 | commit_creds(new); | 2724 | commit_creds(new); |
| 2756 | return size; | 2725 | return size; |
| 2757 | } | 2726 | } |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index b1b768e4049a..99929a50093a 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -49,6 +49,7 @@ enum smk_inos { | |||
| 49 | SMK_LOAD_SELF2 = 15, /* load task specific rules with long labels */ | 49 | SMK_LOAD_SELF2 = 15, /* load task specific rules with long labels */ |
| 50 | SMK_ACCESS2 = 16, /* make an access check with long labels */ | 50 | SMK_ACCESS2 = 16, /* make an access check with long labels */ |
| 51 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ | 51 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ |
| 52 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ | ||
| 52 | }; | 53 | }; |
| 53 | 54 | ||
| 54 | /* | 55 | /* |
| @@ -1992,6 +1993,77 @@ static const struct file_operations smk_access2_ops = { | |||
| 1992 | }; | 1993 | }; |
| 1993 | 1994 | ||
| 1994 | /** | 1995 | /** |
| 1996 | * smk_write_revoke_subj - write() for /smack/revoke-subject | ||
| 1997 | * @file: file pointer | ||
| 1998 | * @buf: data from user space | ||
| 1999 | * @count: bytes sent | ||
| 2000 | * @ppos: where to start - must be 0 | ||
| 2001 | */ | ||
| 2002 | static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, | ||
| 2003 | size_t count, loff_t *ppos) | ||
| 2004 | { | ||
| 2005 | char *data = NULL; | ||
| 2006 | const char *cp = NULL; | ||
| 2007 | struct smack_known *skp; | ||
| 2008 | struct smack_rule *sp; | ||
| 2009 | struct list_head *rule_list; | ||
| 2010 | struct mutex *rule_lock; | ||
| 2011 | int rc = count; | ||
| 2012 | |||
| 2013 | if (*ppos != 0) | ||
| 2014 | return -EINVAL; | ||
| 2015 | |||
| 2016 | if (!smack_privileged(CAP_MAC_ADMIN)) | ||
| 2017 | return -EPERM; | ||
| 2018 | |||
| 2019 | if (count == 0 || count > SMK_LONGLABEL) | ||
| 2020 | return -EINVAL; | ||
| 2021 | |||
| 2022 | data = kzalloc(count, GFP_KERNEL); | ||
| 2023 | if (data == NULL) | ||
| 2024 | return -ENOMEM; | ||
| 2025 | |||
| 2026 | if (copy_from_user(data, buf, count) != 0) { | ||
| 2027 | rc = -EFAULT; | ||
| 2028 | goto free_out; | ||
| 2029 | } | ||
| 2030 | |||
| 2031 | cp = smk_parse_smack(data, count); | ||
| 2032 | if (cp == NULL) { | ||
| 2033 | rc = -EINVAL; | ||
| 2034 | goto free_out; | ||
| 2035 | } | ||
| 2036 | |||
| 2037 | skp = smk_find_entry(cp); | ||
| 2038 | if (skp == NULL) { | ||
| 2039 | rc = -EINVAL; | ||
| 2040 | goto free_out; | ||
| 2041 | } | ||
| 2042 | |||
| 2043 | rule_list = &skp->smk_rules; | ||
| 2044 | rule_lock = &skp->smk_rules_lock; | ||
| 2045 | |||
| 2046 | mutex_lock(rule_lock); | ||
| 2047 | |||
| 2048 | list_for_each_entry_rcu(sp, rule_list, list) | ||
| 2049 | sp->smk_access = 0; | ||
| 2050 | |||
| 2051 | mutex_unlock(rule_lock); | ||
| 2052 | |||
| 2053 | free_out: | ||
| 2054 | kfree(data); | ||
| 2055 | kfree(cp); | ||
| 2056 | return rc; | ||
| 2057 | } | ||
| 2058 | |||
| 2059 | static const struct file_operations smk_revoke_subj_ops = { | ||
| 2060 | .write = smk_write_revoke_subj, | ||
| 2061 | .read = simple_transaction_read, | ||
| 2062 | .release = simple_transaction_release, | ||
| 2063 | .llseek = generic_file_llseek, | ||
| 2064 | }; | ||
| 2065 | |||
| 2066 | /** | ||
| 1995 | * smk_fill_super - fill the /smackfs superblock | 2067 | * smk_fill_super - fill the /smackfs superblock |
| 1996 | * @sb: the empty superblock | 2068 | * @sb: the empty superblock |
| 1997 | * @data: unused | 2069 | * @data: unused |
| @@ -2037,6 +2109,9 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2037 | "access2", &smk_access2_ops, S_IRUGO|S_IWUGO}, | 2109 | "access2", &smk_access2_ops, S_IRUGO|S_IWUGO}, |
| 2038 | [SMK_CIPSO2] = { | 2110 | [SMK_CIPSO2] = { |
| 2039 | "cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR}, | 2111 | "cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR}, |
| 2112 | [SMK_REVOKE_SUBJ] = { | ||
| 2113 | "revoke-subject", &smk_revoke_subj_ops, | ||
| 2114 | S_IRUGO|S_IWUSR}, | ||
| 2040 | /* last one */ | 2115 | /* last one */ |
| 2041 | {""} | 2116 | {""} |
| 2042 | }; | 2117 | }; |
diff --git a/security/yama/Kconfig b/security/yama/Kconfig index 51d6709d8bbd..20ef5143c0c0 100644 --- a/security/yama/Kconfig +++ b/security/yama/Kconfig | |||
| @@ -11,3 +11,11 @@ config SECURITY_YAMA | |||
| 11 | Further information can be found in Documentation/security/Yama.txt. | 11 | Further information can be found in Documentation/security/Yama.txt. |
| 12 | 12 | ||
| 13 | If you are unsure how to answer this question, answer N. | 13 | If you are unsure how to answer this question, answer N. |
| 14 | |||
| 15 | config SECURITY_YAMA_STACKED | ||
| 16 | bool "Yama stacked with other LSMs" | ||
| 17 | depends on SECURITY_YAMA | ||
| 18 | default n | ||
| 19 | help | ||
| 20 | When Yama is built into the kernel, force it to stack with the | ||
| 21 | selected primary LSM. | ||
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 0cc99a3ea42d..b4c29848b49d 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
| @@ -100,7 +100,7 @@ static void yama_ptracer_del(struct task_struct *tracer, | |||
| 100 | * yama_task_free - check for task_pid to remove from exception list | 100 | * yama_task_free - check for task_pid to remove from exception list |
| 101 | * @task: task being removed | 101 | * @task: task being removed |
| 102 | */ | 102 | */ |
| 103 | static void yama_task_free(struct task_struct *task) | 103 | void yama_task_free(struct task_struct *task) |
| 104 | { | 104 | { |
| 105 | yama_ptracer_del(task, task); | 105 | yama_ptracer_del(task, task); |
| 106 | } | 106 | } |
| @@ -116,7 +116,7 @@ static void yama_task_free(struct task_struct *task) | |||
| 116 | * Return 0 on success, -ve on error. -ENOSYS is returned when Yama | 116 | * Return 0 on success, -ve on error. -ENOSYS is returned when Yama |
| 117 | * does not handle the given option. | 117 | * does not handle the given option. |
| 118 | */ | 118 | */ |
| 119 | static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 119 | int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
| 120 | unsigned long arg4, unsigned long arg5) | 120 | unsigned long arg4, unsigned long arg5) |
| 121 | { | 121 | { |
| 122 | int rc; | 122 | int rc; |
| @@ -143,7 +143,7 @@ static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 143 | if (arg2 == 0) { | 143 | if (arg2 == 0) { |
| 144 | yama_ptracer_del(NULL, myself); | 144 | yama_ptracer_del(NULL, myself); |
| 145 | rc = 0; | 145 | rc = 0; |
| 146 | } else if (arg2 == PR_SET_PTRACER_ANY) { | 146 | } else if (arg2 == PR_SET_PTRACER_ANY || (int)arg2 == -1) { |
| 147 | rc = yama_ptracer_add(NULL, myself); | 147 | rc = yama_ptracer_add(NULL, myself); |
| 148 | } else { | 148 | } else { |
| 149 | struct task_struct *tracer; | 149 | struct task_struct *tracer; |
| @@ -243,7 +243,7 @@ static int ptracer_exception_found(struct task_struct *tracer, | |||
| 243 | * | 243 | * |
| 244 | * Returns 0 if following the ptrace is allowed, -ve on error. | 244 | * Returns 0 if following the ptrace is allowed, -ve on error. |
| 245 | */ | 245 | */ |
| 246 | static int yama_ptrace_access_check(struct task_struct *child, | 246 | int yama_ptrace_access_check(struct task_struct *child, |
| 247 | unsigned int mode) | 247 | unsigned int mode) |
| 248 | { | 248 | { |
| 249 | int rc; | 249 | int rc; |
| @@ -293,7 +293,7 @@ static int yama_ptrace_access_check(struct task_struct *child, | |||
| 293 | * | 293 | * |
| 294 | * Returns 0 if following the ptrace is allowed, -ve on error. | 294 | * Returns 0 if following the ptrace is allowed, -ve on error. |
| 295 | */ | 295 | */ |
| 296 | static int yama_ptrace_traceme(struct task_struct *parent) | 296 | int yama_ptrace_traceme(struct task_struct *parent) |
| 297 | { | 297 | { |
| 298 | int rc; | 298 | int rc; |
| 299 | 299 | ||
| @@ -324,6 +324,7 @@ static int yama_ptrace_traceme(struct task_struct *parent) | |||
| 324 | return rc; | 324 | return rc; |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | #ifndef CONFIG_SECURITY_YAMA_STACKED | ||
| 327 | static struct security_operations yama_ops = { | 328 | static struct security_operations yama_ops = { |
| 328 | .name = "yama", | 329 | .name = "yama", |
| 329 | 330 | ||
| @@ -332,6 +333,7 @@ static struct security_operations yama_ops = { | |||
| 332 | .task_prctl = yama_task_prctl, | 333 | .task_prctl = yama_task_prctl, |
| 333 | .task_free = yama_task_free, | 334 | .task_free = yama_task_free, |
| 334 | }; | 335 | }; |
| 336 | #endif | ||
| 335 | 337 | ||
| 336 | #ifdef CONFIG_SYSCTL | 338 | #ifdef CONFIG_SYSCTL |
| 337 | static int yama_dointvec_minmax(struct ctl_table *table, int write, | 339 | static int yama_dointvec_minmax(struct ctl_table *table, int write, |
| @@ -378,13 +380,17 @@ static struct ctl_table yama_sysctl_table[] = { | |||
| 378 | 380 | ||
| 379 | static __init int yama_init(void) | 381 | static __init int yama_init(void) |
| 380 | { | 382 | { |
| 383 | #ifndef CONFIG_SECURITY_YAMA_STACKED | ||
| 381 | if (!security_module_enable(&yama_ops)) | 384 | if (!security_module_enable(&yama_ops)) |
| 382 | return 0; | 385 | return 0; |
| 386 | #endif | ||
| 383 | 387 | ||
| 384 | printk(KERN_INFO "Yama: becoming mindful.\n"); | 388 | printk(KERN_INFO "Yama: becoming mindful.\n"); |
| 385 | 389 | ||
| 390 | #ifndef CONFIG_SECURITY_YAMA_STACKED | ||
| 386 | if (register_security(&yama_ops)) | 391 | if (register_security(&yama_ops)) |
| 387 | panic("Yama: kernel registration failed.\n"); | 392 | panic("Yama: kernel registration failed.\n"); |
| 393 | #endif | ||
| 388 | 394 | ||
| 389 | #ifdef CONFIG_SYSCTL | 395 | #ifdef CONFIG_SYSCTL |
| 390 | if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) | 396 | if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) |
