diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-21 12:06:02 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-21 12:06:02 -0500 |
| commit | fb2e2c85375a0380d6818f153ffa2ae9ebbd055f (patch) | |
| tree | cf8498a01357c220e4d664ff67125f60146f0da3 | |
| parent | ec513b16c480c6cdda1e3d597e611eafca05227b (diff) | |
| parent | 923b49ff69fcbffe6f8b2739de218c45544392a7 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris:
"Changes for this kernel include maintenance updates for Smack, SELinux
(and several networking fixes), IMA and TPM"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (39 commits)
SELinux: Fix memory leak upon loading policy
tpm/tpm-sysfs: active_show() can be static
tpm: tpm_tis: Fix compile problems with CONFIG_PM_SLEEP/CONFIG_PNP
tpm: Make tpm-dev allocate a per-file structure
tpm: Use the ops structure instead of a copy in tpm_vendor_specific
tpm: Create a tpm_class_ops structure and use it in the drivers
tpm: Pull all driver sysfs code into tpm-sysfs.c
tpm: Move sysfs functions from tpm-interface to tpm-sysfs
tpm: Pull everything related to /dev/tpmX into tpm-dev.c
char: tpm: nuvoton: remove unused variable
tpm: MAINTAINERS: Cleanup TPM Maintainers file
tpm/tpm_i2c_atmel: fix coccinelle warnings
tpm/tpm_ibmvtpm: fix unreachable code warning (smatch warning)
tpm/tpm_i2c_stm_st33: Check return code of get_burstcount
tpm/tpm_ppi: Check return value of acpi_get_name
tpm/tpm_ppi: Do not compare strcmp(a,b) == -1
ima: remove unneeded size_limit argument from ima_eventdigest_init_common()
ima: update IMA-templates.txt documentation
ima: pass HASH_ALGO__LAST as hash algo in ima_eventdigest_init()
ima: change the default hash algorithm to SHA1 in ima_eventdigest_ng_init()
...
30 files changed, 1007 insertions, 1041 deletions
diff --git a/Documentation/security/IMA-templates.txt b/Documentation/security/IMA-templates.txt index a777e5f1df5b..a4e102dddfea 100644 --- a/Documentation/security/IMA-templates.txt +++ b/Documentation/security/IMA-templates.txt | |||
| @@ -67,12 +67,14 @@ descriptors by adding their identifier to the format string | |||
| 67 | - 'd-ng': the digest of the event, calculated with an arbitrary hash | 67 | - 'd-ng': the digest of the event, calculated with an arbitrary hash |
| 68 | algorithm (field format: [<hash algo>:]digest, where the digest | 68 | algorithm (field format: [<hash algo>:]digest, where the digest |
| 69 | prefix is shown only if the hash algorithm is not SHA1 or MD5); | 69 | prefix is shown only if the hash algorithm is not SHA1 or MD5); |
| 70 | - 'n-ng': the name of the event, without size limitations. | 70 | - 'n-ng': the name of the event, without size limitations; |
| 71 | - 'sig': the file signature. | ||
| 71 | 72 | ||
| 72 | 73 | ||
| 73 | Below, there is the list of defined template descriptors: | 74 | Below, there is the list of defined template descriptors: |
| 74 | - "ima": its format is 'd|n'; | 75 | - "ima": its format is 'd|n'; |
| 75 | - "ima-ng" (default): its format is 'd-ng|n-ng'. | 76 | - "ima-ng" (default): its format is 'd-ng|n-ng'; |
| 77 | - "ima-sig": its format is 'd-ng|n-ng|sig'. | ||
| 76 | 78 | ||
| 77 | 79 | ||
| 78 | 80 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 88ae0eca7cd8..5c214024f60a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -8746,14 +8746,10 @@ S: Odd fixes | |||
| 8746 | F: drivers/media/usb/tm6000/ | 8746 | F: drivers/media/usb/tm6000/ |
| 8747 | 8747 | ||
| 8748 | TPM DEVICE DRIVER | 8748 | TPM DEVICE DRIVER |
| 8749 | M: Leonidas Da Silva Barbosa <leosilva@linux.vnet.ibm.com> | ||
| 8750 | M: Ashley Lai <ashley@ashleylai.com> | ||
| 8751 | M: Peter Huewe <peterhuewe@gmx.de> | 8749 | M: Peter Huewe <peterhuewe@gmx.de> |
| 8752 | M: Rajiv Andrade <mail@srajiv.net> | 8750 | M: Ashley Lai <ashley@ashleylai.com> |
| 8753 | W: http://tpmdd.sourceforge.net | ||
| 8754 | M: Marcel Selhorst <tpmdd@selhorst.net> | 8751 | M: Marcel Selhorst <tpmdd@selhorst.net> |
| 8755 | M: Sirrix AG <tpmdd@sirrix.com> | 8752 | W: http://tpmdd.sourceforge.net |
| 8756 | W: http://www.sirrix.com | ||
| 8757 | L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers) | 8753 | L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers) |
| 8758 | S: Maintained | 8754 | S: Maintained |
| 8759 | F: drivers/char/tpm/ | 8755 | F: drivers/char/tpm/ |
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index b80a4000daee..4d85dd681b81 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # Makefile for the kernel tpm device drivers. | 2 | # Makefile for the kernel tpm device drivers. |
| 3 | # | 3 | # |
| 4 | obj-$(CONFIG_TCG_TPM) += tpm.o | 4 | obj-$(CONFIG_TCG_TPM) += tpm.o |
| 5 | tpm-y := tpm-interface.o | 5 | tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o |
| 6 | tpm-$(CONFIG_ACPI) += tpm_ppi.o | 6 | tpm-$(CONFIG_ACPI) += tpm_ppi.o |
| 7 | 7 | ||
| 8 | ifdef CONFIG_ACPI | 8 | ifdef CONFIG_ACPI |
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c new file mode 100644 index 000000000000..d9b774e02a1f --- /dev/null +++ b/drivers/char/tpm/tpm-dev.c | |||
| @@ -0,0 +1,213 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2004 IBM Corporation | ||
| 3 | * Authors: | ||
| 4 | * Leendert van Doorn <leendert@watson.ibm.com> | ||
| 5 | * Dave Safford <safford@watson.ibm.com> | ||
| 6 | * Reiner Sailer <sailer@watson.ibm.com> | ||
| 7 | * Kylene Hall <kjhall@us.ibm.com> | ||
| 8 | * | ||
| 9 | * Copyright (C) 2013 Obsidian Research Corp | ||
| 10 | * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> | ||
| 11 | * | ||
| 12 | * Device file system interface to the TPM | ||
| 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 as | ||
| 16 | * published by the Free Software Foundation, version 2 of the | ||
| 17 | * License. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | #include <linux/miscdevice.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/uaccess.h> | ||
| 23 | #include "tpm.h" | ||
| 24 | |||
| 25 | struct file_priv { | ||
| 26 | struct tpm_chip *chip; | ||
| 27 | |||
| 28 | /* Data passed to and from the tpm via the read/write calls */ | ||
| 29 | atomic_t data_pending; | ||
| 30 | struct mutex buffer_mutex; | ||
| 31 | |||
| 32 | struct timer_list user_read_timer; /* user needs to claim result */ | ||
| 33 | struct work_struct work; | ||
| 34 | |||
| 35 | u8 data_buffer[TPM_BUFSIZE]; | ||
| 36 | }; | ||
| 37 | |||
| 38 | static void user_reader_timeout(unsigned long ptr) | ||
| 39 | { | ||
| 40 | struct file_priv *priv = (struct file_priv *)ptr; | ||
| 41 | |||
| 42 | schedule_work(&priv->work); | ||
| 43 | } | ||
| 44 | |||
| 45 | static void timeout_work(struct work_struct *work) | ||
| 46 | { | ||
| 47 | struct file_priv *priv = container_of(work, struct file_priv, work); | ||
| 48 | |||
| 49 | mutex_lock(&priv->buffer_mutex); | ||
| 50 | atomic_set(&priv->data_pending, 0); | ||
| 51 | memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); | ||
| 52 | mutex_unlock(&priv->buffer_mutex); | ||
| 53 | } | ||
| 54 | |||
| 55 | static int tpm_open(struct inode *inode, struct file *file) | ||
| 56 | { | ||
| 57 | struct miscdevice *misc = file->private_data; | ||
| 58 | struct tpm_chip *chip = container_of(misc, struct tpm_chip, | ||
| 59 | vendor.miscdev); | ||
| 60 | struct file_priv *priv; | ||
| 61 | |||
| 62 | /* It's assured that the chip will be opened just once, | ||
| 63 | * by the check of is_open variable, which is protected | ||
| 64 | * by driver_lock. */ | ||
| 65 | if (test_and_set_bit(0, &chip->is_open)) { | ||
| 66 | dev_dbg(chip->dev, "Another process owns this TPM\n"); | ||
| 67 | return -EBUSY; | ||
| 68 | } | ||
| 69 | |||
| 70 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
| 71 | if (priv == NULL) { | ||
| 72 | clear_bit(0, &chip->is_open); | ||
| 73 | return -ENOMEM; | ||
| 74 | } | ||
| 75 | |||
| 76 | priv->chip = chip; | ||
| 77 | atomic_set(&priv->data_pending, 0); | ||
| 78 | mutex_init(&priv->buffer_mutex); | ||
| 79 | setup_timer(&priv->user_read_timer, user_reader_timeout, | ||
| 80 | (unsigned long)priv); | ||
| 81 | INIT_WORK(&priv->work, timeout_work); | ||
| 82 | |||
| 83 | file->private_data = priv; | ||
| 84 | get_device(chip->dev); | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | static ssize_t tpm_read(struct file *file, char __user *buf, | ||
| 89 | size_t size, loff_t *off) | ||
| 90 | { | ||
| 91 | struct file_priv *priv = file->private_data; | ||
| 92 | ssize_t ret_size; | ||
| 93 | int rc; | ||
| 94 | |||
| 95 | del_singleshot_timer_sync(&priv->user_read_timer); | ||
| 96 | flush_work(&priv->work); | ||
| 97 | ret_size = atomic_read(&priv->data_pending); | ||
| 98 | if (ret_size > 0) { /* relay data */ | ||
| 99 | ssize_t orig_ret_size = ret_size; | ||
| 100 | if (size < ret_size) | ||
| 101 | ret_size = size; | ||
| 102 | |||
| 103 | mutex_lock(&priv->buffer_mutex); | ||
| 104 | rc = copy_to_user(buf, priv->data_buffer, ret_size); | ||
| 105 | memset(priv->data_buffer, 0, orig_ret_size); | ||
| 106 | if (rc) | ||
| 107 | ret_size = -EFAULT; | ||
| 108 | |||
| 109 | mutex_unlock(&priv->buffer_mutex); | ||
| 110 | } | ||
| 111 | |||
| 112 | atomic_set(&priv->data_pending, 0); | ||
| 113 | |||
| 114 | return ret_size; | ||
| 115 | } | ||
| 116 | |||
| 117 | static ssize_t tpm_write(struct file *file, const char __user *buf, | ||
| 118 | size_t size, loff_t *off) | ||
| 119 | { | ||
| 120 | struct file_priv *priv = file->private_data; | ||
| 121 | size_t in_size = size; | ||
| 122 | ssize_t out_size; | ||
| 123 | |||
| 124 | /* cannot perform a write until the read has cleared | ||
| 125 | either via tpm_read or a user_read_timer timeout. | ||
| 126 | This also prevents splitted buffered writes from blocking here. | ||
| 127 | */ | ||
| 128 | if (atomic_read(&priv->data_pending) != 0) | ||
| 129 | return -EBUSY; | ||
| 130 | |||
| 131 | if (in_size > TPM_BUFSIZE) | ||
| 132 | return -E2BIG; | ||
| 133 | |||
| 134 | mutex_lock(&priv->buffer_mutex); | ||
| 135 | |||
| 136 | if (copy_from_user | ||
| 137 | (priv->data_buffer, (void __user *) buf, in_size)) { | ||
| 138 | mutex_unlock(&priv->buffer_mutex); | ||
| 139 | return -EFAULT; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* atomic tpm command send and result receive */ | ||
| 143 | out_size = tpm_transmit(priv->chip, priv->data_buffer, | ||
| 144 | sizeof(priv->data_buffer)); | ||
| 145 | if (out_size < 0) { | ||
| 146 | mutex_unlock(&priv->buffer_mutex); | ||
| 147 | return out_size; | ||
| 148 | } | ||
| 149 | |||
| 150 | atomic_set(&priv->data_pending, out_size); | ||
| 151 | mutex_unlock(&priv->buffer_mutex); | ||
| 152 | |||
| 153 | /* Set a timeout by which the reader must come claim the result */ | ||
| 154 | mod_timer(&priv->user_read_timer, jiffies + (60 * HZ)); | ||
| 155 | |||
| 156 | return in_size; | ||
| 157 | } | ||
| 158 | |||
| 159 | /* | ||
| 160 | * Called on file close | ||
| 161 | */ | ||
| 162 | static int tpm_release(struct inode *inode, struct file *file) | ||
| 163 | { | ||
| 164 | struct file_priv *priv = file->private_data; | ||
| 165 | |||
| 166 | del_singleshot_timer_sync(&priv->user_read_timer); | ||
| 167 | flush_work(&priv->work); | ||
| 168 | file->private_data = NULL; | ||
| 169 | atomic_set(&priv->data_pending, 0); | ||
| 170 | clear_bit(0, &priv->chip->is_open); | ||
| 171 | put_device(priv->chip->dev); | ||
| 172 | kfree(priv); | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | static const struct file_operations tpm_fops = { | ||
| 177 | .owner = THIS_MODULE, | ||
| 178 | .llseek = no_llseek, | ||
| 179 | .open = tpm_open, | ||
| 180 | .read = tpm_read, | ||
| 181 | .write = tpm_write, | ||
| 182 | .release = tpm_release, | ||
| 183 | }; | ||
| 184 | |||
| 185 | int tpm_dev_add_device(struct tpm_chip *chip) | ||
| 186 | { | ||
| 187 | int rc; | ||
| 188 | |||
| 189 | chip->vendor.miscdev.fops = &tpm_fops; | ||
| 190 | if (chip->dev_num == 0) | ||
| 191 | chip->vendor.miscdev.minor = TPM_MINOR; | ||
| 192 | else | ||
| 193 | chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; | ||
| 194 | |||
| 195 | chip->vendor.miscdev.name = chip->devname; | ||
| 196 | chip->vendor.miscdev.parent = chip->dev; | ||
| 197 | |||
| 198 | rc = misc_register(&chip->vendor.miscdev); | ||
| 199 | if (rc) { | ||
| 200 | chip->vendor.miscdev.name = NULL; | ||
| 201 | dev_err(chip->dev, | ||
| 202 | "unable to misc_register %s, minor %d err=%d\n", | ||
| 203 | chip->vendor.miscdev.name, | ||
| 204 | chip->vendor.miscdev.minor, rc); | ||
| 205 | } | ||
| 206 | return rc; | ||
| 207 | } | ||
| 208 | |||
| 209 | void tpm_dev_del_device(struct tpm_chip *chip) | ||
| 210 | { | ||
| 211 | if (chip->vendor.miscdev.name) | ||
| 212 | misc_deregister(&chip->vendor.miscdev); | ||
| 213 | } | ||
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 6ae41d337630..62e10fd1e1cb 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c | |||
| @@ -32,13 +32,6 @@ | |||
| 32 | #include "tpm.h" | 32 | #include "tpm.h" |
| 33 | #include "tpm_eventlog.h" | 33 | #include "tpm_eventlog.h" |
| 34 | 34 | ||
| 35 | enum tpm_duration { | ||
| 36 | TPM_SHORT = 0, | ||
| 37 | TPM_MEDIUM = 1, | ||
| 38 | TPM_LONG = 2, | ||
| 39 | TPM_UNDEFINED, | ||
| 40 | }; | ||
| 41 | |||
| 42 | #define TPM_MAX_ORDINAL 243 | 35 | #define TPM_MAX_ORDINAL 243 |
| 43 | #define TSC_MAX_ORDINAL 12 | 36 | #define TSC_MAX_ORDINAL 12 |
| 44 | #define TPM_PROTECTED_COMMAND 0x00 | 37 | #define TPM_PROTECTED_COMMAND 0x00 |
| @@ -312,23 +305,6 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { | |||
| 312 | TPM_MEDIUM, | 305 | TPM_MEDIUM, |
| 313 | }; | 306 | }; |
| 314 | 307 | ||
| 315 | static void user_reader_timeout(unsigned long ptr) | ||
| 316 | { | ||
| 317 | struct tpm_chip *chip = (struct tpm_chip *) ptr; | ||
| 318 | |||
| 319 | schedule_work(&chip->work); | ||
| 320 | } | ||
| 321 | |||
| 322 | static void timeout_work(struct work_struct *work) | ||
| 323 | { | ||
| 324 | struct tpm_chip *chip = container_of(work, struct tpm_chip, work); | ||
| 325 | |||
| 326 | mutex_lock(&chip->buffer_mutex); | ||
| 327 | atomic_set(&chip->data_pending, 0); | ||
| 328 | memset(chip->data_buffer, 0, TPM_BUFSIZE); | ||
| 329 | mutex_unlock(&chip->buffer_mutex); | ||
| 330 | } | ||
| 331 | |||
| 332 | /* | 308 | /* |
| 333 | * Returns max number of jiffies to wait | 309 | * Returns max number of jiffies to wait |
| 334 | */ | 310 | */ |
| @@ -355,8 +331,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); | |||
| 355 | /* | 331 | /* |
| 356 | * Internal kernel interface to transmit TPM commands | 332 | * Internal kernel interface to transmit TPM commands |
| 357 | */ | 333 | */ |
| 358 | static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | 334 | ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, |
| 359 | size_t bufsiz) | 335 | size_t bufsiz) |
| 360 | { | 336 | { |
| 361 | ssize_t rc; | 337 | ssize_t rc; |
| 362 | u32 count, ordinal; | 338 | u32 count, ordinal; |
| @@ -377,7 +353,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | |||
| 377 | 353 | ||
| 378 | mutex_lock(&chip->tpm_mutex); | 354 | mutex_lock(&chip->tpm_mutex); |
| 379 | 355 | ||
| 380 | rc = chip->vendor.send(chip, (u8 *) buf, count); | 356 | rc = chip->ops->send(chip, (u8 *) buf, count); |
| 381 | if (rc < 0) { | 357 | if (rc < 0) { |
| 382 | dev_err(chip->dev, | 358 | dev_err(chip->dev, |
| 383 | "tpm_transmit: tpm_send: error %zd\n", rc); | 359 | "tpm_transmit: tpm_send: error %zd\n", rc); |
| @@ -389,12 +365,12 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | |||
| 389 | 365 | ||
| 390 | stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); | 366 | stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); |
| 391 | do { | 367 | do { |
| 392 | u8 status = chip->vendor.status(chip); | 368 | u8 status = chip->ops->status(chip); |
| 393 | if ((status & chip->vendor.req_complete_mask) == | 369 | if ((status & chip->ops->req_complete_mask) == |
| 394 | chip->vendor.req_complete_val) | 370 | chip->ops->req_complete_val) |
| 395 | goto out_recv; | 371 | goto out_recv; |
| 396 | 372 | ||
| 397 | if (chip->vendor.req_canceled(chip, status)) { | 373 | if (chip->ops->req_canceled(chip, status)) { |
| 398 | dev_err(chip->dev, "Operation Canceled\n"); | 374 | dev_err(chip->dev, "Operation Canceled\n"); |
| 399 | rc = -ECANCELED; | 375 | rc = -ECANCELED; |
| 400 | goto out; | 376 | goto out; |
| @@ -404,13 +380,13 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | |||
| 404 | rmb(); | 380 | rmb(); |
| 405 | } while (time_before(jiffies, stop)); | 381 | } while (time_before(jiffies, stop)); |
| 406 | 382 | ||
| 407 | chip->vendor.cancel(chip); | 383 | chip->ops->cancel(chip); |
| 408 | dev_err(chip->dev, "Operation Timed out\n"); | 384 | dev_err(chip->dev, "Operation Timed out\n"); |
| 409 | rc = -ETIME; | 385 | rc = -ETIME; |
| 410 | goto out; | 386 | goto out; |
| 411 | 387 | ||
| 412 | out_recv: | 388 | out_recv: |
| 413 | rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz); | 389 | rc = chip->ops->recv(chip, (u8 *) buf, bufsiz); |
| 414 | if (rc < 0) | 390 | if (rc < 0) |
| 415 | dev_err(chip->dev, | 391 | dev_err(chip->dev, |
| 416 | "tpm_transmit: tpm_recv: error %zd\n", rc); | 392 | "tpm_transmit: tpm_recv: error %zd\n", rc); |
| @@ -422,24 +398,6 @@ out: | |||
| 422 | #define TPM_DIGEST_SIZE 20 | 398 | #define TPM_DIGEST_SIZE 20 |
| 423 | #define TPM_RET_CODE_IDX 6 | 399 | #define TPM_RET_CODE_IDX 6 |
| 424 | 400 | ||
| 425 | enum tpm_capabilities { | ||
| 426 | TPM_CAP_FLAG = cpu_to_be32(4), | ||
| 427 | TPM_CAP_PROP = cpu_to_be32(5), | ||
| 428 | CAP_VERSION_1_1 = cpu_to_be32(0x06), | ||
| 429 | CAP_VERSION_1_2 = cpu_to_be32(0x1A) | ||
| 430 | }; | ||
| 431 | |||
| 432 | enum tpm_sub_capabilities { | ||
| 433 | TPM_CAP_PROP_PCR = cpu_to_be32(0x101), | ||
| 434 | TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), | ||
| 435 | TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), | ||
| 436 | TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), | ||
| 437 | TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), | ||
| 438 | TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), | ||
| 439 | TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), | ||
| 440 | |||
| 441 | }; | ||
| 442 | |||
| 443 | static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, | 401 | static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, |
| 444 | int len, const char *desc) | 402 | int len, const char *desc) |
| 445 | { | 403 | { |
| @@ -459,7 +417,6 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, | |||
| 459 | } | 417 | } |
| 460 | 418 | ||
| 461 | #define TPM_INTERNAL_RESULT_SIZE 200 | 419 | #define TPM_INTERNAL_RESULT_SIZE 200 |
| 462 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) | ||
| 463 | #define TPM_ORD_GET_CAP cpu_to_be32(101) | 420 | #define TPM_ORD_GET_CAP cpu_to_be32(101) |
| 464 | #define TPM_ORD_GET_RANDOM cpu_to_be32(70) | 421 | #define TPM_ORD_GET_RANDOM cpu_to_be32(70) |
| 465 | 422 | ||
| @@ -659,70 +616,6 @@ static int tpm_continue_selftest(struct tpm_chip *chip) | |||
| 659 | return rc; | 616 | return rc; |
| 660 | } | 617 | } |
| 661 | 618 | ||
| 662 | ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr, | ||
| 663 | char *buf) | ||
| 664 | { | ||
| 665 | cap_t cap; | ||
| 666 | ssize_t rc; | ||
| 667 | |||
| 668 | rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, | ||
| 669 | "attempting to determine the permanent enabled state"); | ||
| 670 | if (rc) | ||
| 671 | return 0; | ||
| 672 | |||
| 673 | rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); | ||
| 674 | return rc; | ||
| 675 | } | ||
| 676 | EXPORT_SYMBOL_GPL(tpm_show_enabled); | ||
| 677 | |||
| 678 | ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr, | ||
| 679 | char *buf) | ||
| 680 | { | ||
| 681 | cap_t cap; | ||
| 682 | ssize_t rc; | ||
| 683 | |||
| 684 | rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, | ||
| 685 | "attempting to determine the permanent active state"); | ||
| 686 | if (rc) | ||
| 687 | return 0; | ||
| 688 | |||
| 689 | rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); | ||
| 690 | return rc; | ||
| 691 | } | ||
| 692 | EXPORT_SYMBOL_GPL(tpm_show_active); | ||
| 693 | |||
| 694 | ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr, | ||
| 695 | char *buf) | ||
| 696 | { | ||
| 697 | cap_t cap; | ||
| 698 | ssize_t rc; | ||
| 699 | |||
| 700 | rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap, | ||
| 701 | "attempting to determine the owner state"); | ||
| 702 | if (rc) | ||
| 703 | return 0; | ||
| 704 | |||
| 705 | rc = sprintf(buf, "%d\n", cap.owned); | ||
| 706 | return rc; | ||
| 707 | } | ||
| 708 | EXPORT_SYMBOL_GPL(tpm_show_owned); | ||
| 709 | |||
| 710 | ssize_t tpm_show_temp_deactivated(struct device *dev, | ||
| 711 | struct device_attribute *attr, char *buf) | ||
| 712 | { | ||
| 713 | cap_t cap; | ||
| 714 | ssize_t rc; | ||
| 715 | |||
| 716 | rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap, | ||
| 717 | "attempting to determine the temporary state"); | ||
| 718 | if (rc) | ||
| 719 | return 0; | ||
| 720 | |||
| 721 | rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); | ||
| 722 | return rc; | ||
| 723 | } | ||
| 724 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
| 725 | |||
| 726 | /* | 619 | /* |
| 727 | * tpm_chip_find_get - return tpm_chip for given chip number | 620 | * tpm_chip_find_get - return tpm_chip for given chip number |
| 728 | */ | 621 | */ |
| @@ -752,7 +645,7 @@ static struct tpm_input_header pcrread_header = { | |||
| 752 | .ordinal = TPM_ORDINAL_PCRREAD | 645 | .ordinal = TPM_ORDINAL_PCRREAD |
| 753 | }; | 646 | }; |
| 754 | 647 | ||
| 755 | static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) | 648 | int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) |
| 756 | { | 649 | { |
| 757 | int rc; | 650 | int rc; |
| 758 | struct tpm_cmd_t cmd; | 651 | struct tpm_cmd_t cmd; |
| @@ -787,7 +680,7 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) | |||
| 787 | chip = tpm_chip_find_get(chip_num); | 680 | chip = tpm_chip_find_get(chip_num); |
| 788 | if (chip == NULL) | 681 | if (chip == NULL) |
| 789 | return -ENODEV; | 682 | return -ENODEV; |
| 790 | rc = __tpm_pcr_read(chip, pcr_idx, res_buf); | 683 | rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); |
| 791 | tpm_chip_put(chip); | 684 | tpm_chip_put(chip); |
| 792 | return rc; | 685 | return rc; |
| 793 | } | 686 | } |
| @@ -911,196 +804,15 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) | |||
| 911 | } | 804 | } |
| 912 | EXPORT_SYMBOL_GPL(tpm_send); | 805 | EXPORT_SYMBOL_GPL(tpm_send); |
| 913 | 806 | ||
| 914 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | ||
| 915 | char *buf) | ||
| 916 | { | ||
| 917 | cap_t cap; | ||
| 918 | u8 digest[TPM_DIGEST_SIZE]; | ||
| 919 | ssize_t rc; | ||
| 920 | int i, j, num_pcrs; | ||
| 921 | char *str = buf; | ||
| 922 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 923 | |||
| 924 | rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, | ||
| 925 | "attempting to determine the number of PCRS"); | ||
| 926 | if (rc) | ||
| 927 | return 0; | ||
| 928 | |||
| 929 | num_pcrs = be32_to_cpu(cap.num_pcrs); | ||
| 930 | for (i = 0; i < num_pcrs; i++) { | ||
| 931 | rc = __tpm_pcr_read(chip, i, digest); | ||
| 932 | if (rc) | ||
| 933 | break; | ||
| 934 | str += sprintf(str, "PCR-%02d: ", i); | ||
| 935 | for (j = 0; j < TPM_DIGEST_SIZE; j++) | ||
| 936 | str += sprintf(str, "%02X ", digest[j]); | ||
| 937 | str += sprintf(str, "\n"); | ||
| 938 | } | ||
| 939 | return str - buf; | ||
| 940 | } | ||
| 941 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); | ||
| 942 | |||
| 943 | #define READ_PUBEK_RESULT_SIZE 314 | ||
| 944 | #define TPM_ORD_READPUBEK cpu_to_be32(124) | ||
| 945 | static struct tpm_input_header tpm_readpubek_header = { | ||
| 946 | .tag = TPM_TAG_RQU_COMMAND, | ||
| 947 | .length = cpu_to_be32(30), | ||
| 948 | .ordinal = TPM_ORD_READPUBEK | ||
| 949 | }; | ||
| 950 | |||
| 951 | ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | ||
| 952 | char *buf) | ||
| 953 | { | ||
| 954 | u8 *data; | ||
| 955 | struct tpm_cmd_t tpm_cmd; | ||
| 956 | ssize_t err; | ||
| 957 | int i, rc; | ||
| 958 | char *str = buf; | ||
| 959 | |||
| 960 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 961 | |||
| 962 | tpm_cmd.header.in = tpm_readpubek_header; | ||
| 963 | err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, | ||
| 964 | "attempting to read the PUBEK"); | ||
| 965 | if (err) | ||
| 966 | goto out; | ||
| 967 | |||
| 968 | /* | ||
| 969 | ignore header 10 bytes | ||
| 970 | algorithm 32 bits (1 == RSA ) | ||
| 971 | encscheme 16 bits | ||
| 972 | sigscheme 16 bits | ||
| 973 | parameters (RSA 12->bytes: keybit, #primes, expbit) | ||
| 974 | keylenbytes 32 bits | ||
| 975 | 256 byte modulus | ||
| 976 | ignore checksum 20 bytes | ||
| 977 | */ | ||
| 978 | data = tpm_cmd.params.readpubek_out_buffer; | ||
| 979 | str += | ||
| 980 | sprintf(str, | ||
| 981 | "Algorithm: %02X %02X %02X %02X\n" | ||
| 982 | "Encscheme: %02X %02X\n" | ||
| 983 | "Sigscheme: %02X %02X\n" | ||
| 984 | "Parameters: %02X %02X %02X %02X " | ||
| 985 | "%02X %02X %02X %02X " | ||
| 986 | "%02X %02X %02X %02X\n" | ||
| 987 | "Modulus length: %d\n" | ||
| 988 | "Modulus:\n", | ||
| 989 | data[0], data[1], data[2], data[3], | ||
| 990 | data[4], data[5], | ||
| 991 | data[6], data[7], | ||
| 992 | data[12], data[13], data[14], data[15], | ||
| 993 | data[16], data[17], data[18], data[19], | ||
| 994 | data[20], data[21], data[22], data[23], | ||
| 995 | be32_to_cpu(*((__be32 *) (data + 24)))); | ||
| 996 | |||
| 997 | for (i = 0; i < 256; i++) { | ||
| 998 | str += sprintf(str, "%02X ", data[i + 28]); | ||
| 999 | if ((i + 1) % 16 == 0) | ||
| 1000 | str += sprintf(str, "\n"); | ||
| 1001 | } | ||
| 1002 | out: | ||
| 1003 | rc = str - buf; | ||
| 1004 | return rc; | ||
| 1005 | } | ||
| 1006 | EXPORT_SYMBOL_GPL(tpm_show_pubek); | ||
| 1007 | |||
| 1008 | |||
| 1009 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | ||
| 1010 | char *buf) | ||
| 1011 | { | ||
| 1012 | cap_t cap; | ||
| 1013 | ssize_t rc; | ||
| 1014 | char *str = buf; | ||
| 1015 | |||
| 1016 | rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, | ||
| 1017 | "attempting to determine the manufacturer"); | ||
| 1018 | if (rc) | ||
| 1019 | return 0; | ||
| 1020 | str += sprintf(str, "Manufacturer: 0x%x\n", | ||
| 1021 | be32_to_cpu(cap.manufacturer_id)); | ||
| 1022 | |||
| 1023 | /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ | ||
| 1024 | rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, | ||
| 1025 | "attempting to determine the 1.2 version"); | ||
| 1026 | if (!rc) { | ||
| 1027 | str += sprintf(str, | ||
| 1028 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | ||
| 1029 | cap.tpm_version_1_2.Major, | ||
| 1030 | cap.tpm_version_1_2.Minor, | ||
| 1031 | cap.tpm_version_1_2.revMajor, | ||
| 1032 | cap.tpm_version_1_2.revMinor); | ||
| 1033 | } else { | ||
| 1034 | /* Otherwise just use TPM_STRUCT_VER */ | ||
| 1035 | rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, | ||
| 1036 | "attempting to determine the 1.1 version"); | ||
| 1037 | if (rc) | ||
| 1038 | return 0; | ||
| 1039 | str += sprintf(str, | ||
| 1040 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | ||
| 1041 | cap.tpm_version.Major, | ||
| 1042 | cap.tpm_version.Minor, | ||
| 1043 | cap.tpm_version.revMajor, | ||
| 1044 | cap.tpm_version.revMinor); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | return str - buf; | ||
| 1048 | } | ||
| 1049 | EXPORT_SYMBOL_GPL(tpm_show_caps); | ||
| 1050 | |||
| 1051 | ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr, | ||
| 1052 | char *buf) | ||
| 1053 | { | ||
| 1054 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 1055 | |||
| 1056 | if (chip->vendor.duration[TPM_LONG] == 0) | ||
| 1057 | return 0; | ||
| 1058 | |||
| 1059 | return sprintf(buf, "%d %d %d [%s]\n", | ||
| 1060 | jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), | ||
| 1061 | jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), | ||
| 1062 | jiffies_to_usecs(chip->vendor.duration[TPM_LONG]), | ||
| 1063 | chip->vendor.duration_adjusted | ||
| 1064 | ? "adjusted" : "original"); | ||
| 1065 | } | ||
| 1066 | EXPORT_SYMBOL_GPL(tpm_show_durations); | ||
| 1067 | |||
| 1068 | ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr, | ||
| 1069 | char *buf) | ||
| 1070 | { | ||
| 1071 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 1072 | |||
| 1073 | return sprintf(buf, "%d %d %d %d [%s]\n", | ||
| 1074 | jiffies_to_usecs(chip->vendor.timeout_a), | ||
| 1075 | jiffies_to_usecs(chip->vendor.timeout_b), | ||
| 1076 | jiffies_to_usecs(chip->vendor.timeout_c), | ||
| 1077 | jiffies_to_usecs(chip->vendor.timeout_d), | ||
| 1078 | chip->vendor.timeout_adjusted | ||
| 1079 | ? "adjusted" : "original"); | ||
| 1080 | } | ||
| 1081 | EXPORT_SYMBOL_GPL(tpm_show_timeouts); | ||
| 1082 | |||
| 1083 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, | ||
| 1084 | const char *buf, size_t count) | ||
| 1085 | { | ||
| 1086 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 1087 | if (chip == NULL) | ||
| 1088 | return 0; | ||
| 1089 | |||
| 1090 | chip->vendor.cancel(chip); | ||
| 1091 | return count; | ||
| 1092 | } | ||
| 1093 | EXPORT_SYMBOL_GPL(tpm_store_cancel); | ||
| 1094 | |||
| 1095 | static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, | 807 | static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, |
| 1096 | bool check_cancel, bool *canceled) | 808 | bool check_cancel, bool *canceled) |
| 1097 | { | 809 | { |
| 1098 | u8 status = chip->vendor.status(chip); | 810 | u8 status = chip->ops->status(chip); |
| 1099 | 811 | ||
| 1100 | *canceled = false; | 812 | *canceled = false; |
| 1101 | if ((status & mask) == mask) | 813 | if ((status & mask) == mask) |
| 1102 | return true; | 814 | return true; |
| 1103 | if (check_cancel && chip->vendor.req_canceled(chip, status)) { | 815 | if (check_cancel && chip->ops->req_canceled(chip, status)) { |
| 1104 | *canceled = true; | 816 | *canceled = true; |
| 1105 | return true; | 817 | return true; |
| 1106 | } | 818 | } |
| @@ -1116,7 +828,7 @@ int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | |||
| 1116 | bool canceled = false; | 828 | bool canceled = false; |
| 1117 | 829 | ||
| 1118 | /* check current status */ | 830 | /* check current status */ |
| 1119 | status = chip->vendor.status(chip); | 831 | status = chip->ops->status(chip); |
| 1120 | if ((status & mask) == mask) | 832 | if ((status & mask) == mask) |
| 1121 | return 0; | 833 | return 0; |
| 1122 | 834 | ||
| @@ -1143,7 +855,7 @@ again: | |||
| 1143 | } else { | 855 | } else { |
| 1144 | do { | 856 | do { |
| 1145 | msleep(TPM_TIMEOUT); | 857 | msleep(TPM_TIMEOUT); |
| 1146 | status = chip->vendor.status(chip); | 858 | status = chip->ops->status(chip); |
| 1147 | if ((status & mask) == mask) | 859 | if ((status & mask) == mask) |
| 1148 | return 0; | 860 | return 0; |
| 1149 | } while (time_before(jiffies, stop)); | 861 | } while (time_before(jiffies, stop)); |
| @@ -1151,127 +863,6 @@ again: | |||
| 1151 | return -ETIME; | 863 | return -ETIME; |
| 1152 | } | 864 | } |
| 1153 | EXPORT_SYMBOL_GPL(wait_for_tpm_stat); | 865 | EXPORT_SYMBOL_GPL(wait_for_tpm_stat); |
| 1154 | /* | ||
| 1155 | * Device file system interface to the TPM | ||
| 1156 | * | ||
| 1157 | * It's assured that the chip will be opened just once, | ||
| 1158 | * by the check of is_open variable, which is protected | ||
| 1159 | * by driver_lock. | ||
| 1160 | */ | ||
| 1161 | int tpm_open(struct inode *inode, struct file *file) | ||
| 1162 | { | ||
| 1163 | struct miscdevice *misc = file->private_data; | ||
| 1164 | struct tpm_chip *chip = container_of(misc, struct tpm_chip, | ||
| 1165 | vendor.miscdev); | ||
| 1166 | |||
| 1167 | if (test_and_set_bit(0, &chip->is_open)) { | ||
| 1168 | dev_dbg(chip->dev, "Another process owns this TPM\n"); | ||
| 1169 | return -EBUSY; | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL); | ||
| 1173 | if (chip->data_buffer == NULL) { | ||
| 1174 | clear_bit(0, &chip->is_open); | ||
| 1175 | return -ENOMEM; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | atomic_set(&chip->data_pending, 0); | ||
| 1179 | |||
| 1180 | file->private_data = chip; | ||
| 1181 | get_device(chip->dev); | ||
| 1182 | return 0; | ||
| 1183 | } | ||
| 1184 | EXPORT_SYMBOL_GPL(tpm_open); | ||
| 1185 | |||
| 1186 | /* | ||
| 1187 | * Called on file close | ||
| 1188 | */ | ||
| 1189 | int tpm_release(struct inode *inode, struct file *file) | ||
| 1190 | { | ||
| 1191 | struct tpm_chip *chip = file->private_data; | ||
| 1192 | |||
| 1193 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
| 1194 | flush_work(&chip->work); | ||
| 1195 | file->private_data = NULL; | ||
| 1196 | atomic_set(&chip->data_pending, 0); | ||
| 1197 | kzfree(chip->data_buffer); | ||
| 1198 | clear_bit(0, &chip->is_open); | ||
| 1199 | put_device(chip->dev); | ||
| 1200 | return 0; | ||
| 1201 | } | ||
| 1202 | EXPORT_SYMBOL_GPL(tpm_release); | ||
| 1203 | |||
| 1204 | ssize_t tpm_write(struct file *file, const char __user *buf, | ||
| 1205 | size_t size, loff_t *off) | ||
| 1206 | { | ||
| 1207 | struct tpm_chip *chip = file->private_data; | ||
| 1208 | size_t in_size = size; | ||
| 1209 | ssize_t out_size; | ||
| 1210 | |||
| 1211 | /* cannot perform a write until the read has cleared | ||
| 1212 | either via tpm_read or a user_read_timer timeout. | ||
| 1213 | This also prevents splitted buffered writes from blocking here. | ||
| 1214 | */ | ||
| 1215 | if (atomic_read(&chip->data_pending) != 0) | ||
| 1216 | return -EBUSY; | ||
| 1217 | |||
| 1218 | if (in_size > TPM_BUFSIZE) | ||
| 1219 | return -E2BIG; | ||
| 1220 | |||
| 1221 | mutex_lock(&chip->buffer_mutex); | ||
| 1222 | |||
| 1223 | if (copy_from_user | ||
| 1224 | (chip->data_buffer, (void __user *) buf, in_size)) { | ||
| 1225 | mutex_unlock(&chip->buffer_mutex); | ||
| 1226 | return -EFAULT; | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | /* atomic tpm command send and result receive */ | ||
| 1230 | out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); | ||
| 1231 | if (out_size < 0) { | ||
| 1232 | mutex_unlock(&chip->buffer_mutex); | ||
| 1233 | return out_size; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | atomic_set(&chip->data_pending, out_size); | ||
| 1237 | mutex_unlock(&chip->buffer_mutex); | ||
| 1238 | |||
| 1239 | /* Set a timeout by which the reader must come claim the result */ | ||
| 1240 | mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); | ||
| 1241 | |||
| 1242 | return in_size; | ||
| 1243 | } | ||
| 1244 | EXPORT_SYMBOL_GPL(tpm_write); | ||
| 1245 | |||
| 1246 | ssize_t tpm_read(struct file *file, char __user *buf, | ||
| 1247 | size_t size, loff_t *off) | ||
| 1248 | { | ||
| 1249 | struct tpm_chip *chip = file->private_data; | ||
| 1250 | ssize_t ret_size; | ||
| 1251 | int rc; | ||
| 1252 | |||
| 1253 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
| 1254 | flush_work(&chip->work); | ||
| 1255 | ret_size = atomic_read(&chip->data_pending); | ||
| 1256 | if (ret_size > 0) { /* relay data */ | ||
| 1257 | ssize_t orig_ret_size = ret_size; | ||
| 1258 | if (size < ret_size) | ||
| 1259 | ret_size = size; | ||
| 1260 | |||
| 1261 | mutex_lock(&chip->buffer_mutex); | ||
| 1262 | rc = copy_to_user(buf, chip->data_buffer, ret_size); | ||
| 1263 | memset(chip->data_buffer, 0, orig_ret_size); | ||
| 1264 | if (rc) | ||
| 1265 | ret_size = -EFAULT; | ||
| 1266 | |||
| 1267 | mutex_unlock(&chip->buffer_mutex); | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | atomic_set(&chip->data_pending, 0); | ||
| 1271 | |||
| 1272 | return ret_size; | ||
| 1273 | } | ||
| 1274 | EXPORT_SYMBOL_GPL(tpm_read); | ||
| 1275 | 866 | ||
| 1276 | void tpm_remove_hardware(struct device *dev) | 867 | void tpm_remove_hardware(struct device *dev) |
| 1277 | { | 868 | { |
| @@ -1287,8 +878,8 @@ void tpm_remove_hardware(struct device *dev) | |||
| 1287 | spin_unlock(&driver_lock); | 878 | spin_unlock(&driver_lock); |
| 1288 | synchronize_rcu(); | 879 | synchronize_rcu(); |
| 1289 | 880 | ||
| 1290 | misc_deregister(&chip->vendor.miscdev); | 881 | tpm_dev_del_device(chip); |
| 1291 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); | 882 | tpm_sysfs_del_device(chip); |
| 1292 | tpm_remove_ppi(&dev->kobj); | 883 | tpm_remove_ppi(&dev->kobj); |
| 1293 | tpm_bios_log_teardown(chip->bios_dir); | 884 | tpm_bios_log_teardown(chip->bios_dir); |
| 1294 | 885 | ||
| @@ -1436,9 +1027,6 @@ void tpm_dev_vendor_release(struct tpm_chip *chip) | |||
| 1436 | if (!chip) | 1027 | if (!chip) |
| 1437 | return; | 1028 | return; |
| 1438 | 1029 | ||
| 1439 | if (chip->vendor.release) | ||
| 1440 | chip->vendor.release(chip->dev); | ||
| 1441 | |||
| 1442 | clear_bit(chip->dev_num, dev_mask); | 1030 | clear_bit(chip->dev_num, dev_mask); |
| 1443 | } | 1031 | } |
| 1444 | EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); | 1032 | EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); |
| @@ -1448,7 +1036,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); | |||
| 1448 | * Once all references to platform device are down to 0, | 1036 | * Once all references to platform device are down to 0, |
| 1449 | * release all allocated structures. | 1037 | * release all allocated structures. |
| 1450 | */ | 1038 | */ |
| 1451 | void tpm_dev_release(struct device *dev) | 1039 | static void tpm_dev_release(struct device *dev) |
| 1452 | { | 1040 | { |
| 1453 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1041 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| 1454 | 1042 | ||
| @@ -1460,7 +1048,6 @@ void tpm_dev_release(struct device *dev) | |||
| 1460 | chip->release(dev); | 1048 | chip->release(dev); |
| 1461 | kfree(chip); | 1049 | kfree(chip); |
| 1462 | } | 1050 | } |
| 1463 | EXPORT_SYMBOL_GPL(tpm_dev_release); | ||
| 1464 | 1051 | ||
| 1465 | /* | 1052 | /* |
| 1466 | * Called from tpm_<specific>.c probe function only for devices | 1053 | * Called from tpm_<specific>.c probe function only for devices |
| @@ -1470,7 +1057,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_release); | |||
| 1470 | * pci_disable_device | 1057 | * pci_disable_device |
| 1471 | */ | 1058 | */ |
| 1472 | struct tpm_chip *tpm_register_hardware(struct device *dev, | 1059 | struct tpm_chip *tpm_register_hardware(struct device *dev, |
| 1473 | const struct tpm_vendor_specific *entry) | 1060 | const struct tpm_class_ops *ops) |
| 1474 | { | 1061 | { |
| 1475 | struct tpm_chip *chip; | 1062 | struct tpm_chip *chip; |
| 1476 | 1063 | ||
| @@ -1480,56 +1067,35 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
| 1480 | if (chip == NULL) | 1067 | if (chip == NULL) |
| 1481 | return NULL; | 1068 | return NULL; |
| 1482 | 1069 | ||
| 1483 | mutex_init(&chip->buffer_mutex); | ||
| 1484 | mutex_init(&chip->tpm_mutex); | 1070 | mutex_init(&chip->tpm_mutex); |
| 1485 | INIT_LIST_HEAD(&chip->list); | 1071 | INIT_LIST_HEAD(&chip->list); |
| 1486 | 1072 | ||
| 1487 | INIT_WORK(&chip->work, timeout_work); | 1073 | chip->ops = ops; |
| 1488 | |||
| 1489 | setup_timer(&chip->user_read_timer, user_reader_timeout, | ||
| 1490 | (unsigned long)chip); | ||
| 1491 | |||
| 1492 | memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); | ||
| 1493 | |||
| 1494 | chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); | 1074 | chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); |
| 1495 | 1075 | ||
| 1496 | if (chip->dev_num >= TPM_NUM_DEVICES) { | 1076 | if (chip->dev_num >= TPM_NUM_DEVICES) { |
| 1497 | dev_err(dev, "No available tpm device numbers\n"); | 1077 | dev_err(dev, "No available tpm device numbers\n"); |
| 1498 | goto out_free; | 1078 | goto out_free; |
| 1499 | } else if (chip->dev_num == 0) | 1079 | } |
| 1500 | chip->vendor.miscdev.minor = TPM_MINOR; | ||
| 1501 | else | ||
| 1502 | chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; | ||
| 1503 | 1080 | ||
| 1504 | set_bit(chip->dev_num, dev_mask); | 1081 | set_bit(chip->dev_num, dev_mask); |
| 1505 | 1082 | ||
| 1506 | scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", | 1083 | scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", |
| 1507 | chip->dev_num); | 1084 | chip->dev_num); |
| 1508 | chip->vendor.miscdev.name = chip->devname; | ||
| 1509 | 1085 | ||
| 1510 | chip->vendor.miscdev.parent = dev; | ||
| 1511 | chip->dev = get_device(dev); | 1086 | chip->dev = get_device(dev); |
| 1512 | chip->release = dev->release; | 1087 | chip->release = dev->release; |
| 1513 | dev->release = tpm_dev_release; | 1088 | dev->release = tpm_dev_release; |
| 1514 | dev_set_drvdata(dev, chip); | 1089 | dev_set_drvdata(dev, chip); |
| 1515 | 1090 | ||
| 1516 | if (misc_register(&chip->vendor.miscdev)) { | 1091 | if (tpm_dev_add_device(chip)) |
| 1517 | dev_err(chip->dev, | ||
| 1518 | "unable to misc_register %s, minor %d\n", | ||
| 1519 | chip->vendor.miscdev.name, | ||
| 1520 | chip->vendor.miscdev.minor); | ||
| 1521 | goto put_device; | 1092 | goto put_device; |
| 1522 | } | ||
| 1523 | 1093 | ||
| 1524 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { | 1094 | if (tpm_sysfs_add_device(chip)) |
| 1525 | misc_deregister(&chip->vendor.miscdev); | 1095 | goto del_misc; |
| 1526 | goto put_device; | ||
| 1527 | } | ||
| 1528 | 1096 | ||
| 1529 | if (tpm_add_ppi(&dev->kobj)) { | 1097 | if (tpm_add_ppi(&dev->kobj)) |
| 1530 | misc_deregister(&chip->vendor.miscdev); | 1098 | goto del_misc; |
| 1531 | goto put_device; | ||
| 1532 | } | ||
| 1533 | 1099 | ||
| 1534 | chip->bios_dir = tpm_bios_log_setup(chip->devname); | 1100 | chip->bios_dir = tpm_bios_log_setup(chip->devname); |
| 1535 | 1101 | ||
| @@ -1540,6 +1106,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
| 1540 | 1106 | ||
| 1541 | return chip; | 1107 | return chip; |
| 1542 | 1108 | ||
| 1109 | del_misc: | ||
| 1110 | tpm_dev_del_device(chip); | ||
| 1543 | put_device: | 1111 | put_device: |
| 1544 | put_device(chip->dev); | 1112 | put_device(chip->dev); |
| 1545 | out_free: | 1113 | out_free: |
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c new file mode 100644 index 000000000000..01730a27ae07 --- /dev/null +++ b/drivers/char/tpm/tpm-sysfs.c | |||
| @@ -0,0 +1,318 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2004 IBM Corporation | ||
| 3 | * Authors: | ||
| 4 | * Leendert van Doorn <leendert@watson.ibm.com> | ||
| 5 | * Dave Safford <safford@watson.ibm.com> | ||
| 6 | * Reiner Sailer <sailer@watson.ibm.com> | ||
| 7 | * Kylene Hall <kjhall@us.ibm.com> | ||
| 8 | * | ||
| 9 | * Copyright (C) 2013 Obsidian Research Corp | ||
| 10 | * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> | ||
| 11 | * | ||
| 12 | * sysfs filesystem inspection interface to the TPM | ||
| 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 as | ||
| 16 | * published by the Free Software Foundation, version 2 of the | ||
| 17 | * License. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | #include <linux/device.h> | ||
| 21 | #include "tpm.h" | ||
| 22 | |||
| 23 | /* XXX for now this helper is duplicated in tpm-interface.c */ | ||
| 24 | static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, | ||
| 25 | int len, const char *desc) | ||
| 26 | { | ||
| 27 | int err; | ||
| 28 | |||
| 29 | len = tpm_transmit(chip, (u8 *) cmd, len); | ||
| 30 | if (len < 0) | ||
| 31 | return len; | ||
| 32 | else if (len < TPM_HEADER_SIZE) | ||
| 33 | return -EFAULT; | ||
| 34 | |||
| 35 | err = be32_to_cpu(cmd->header.out.return_code); | ||
| 36 | if (err != 0 && desc) | ||
| 37 | dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); | ||
| 38 | |||
| 39 | return err; | ||
| 40 | } | ||
| 41 | |||
| 42 | #define READ_PUBEK_RESULT_SIZE 314 | ||
| 43 | #define TPM_ORD_READPUBEK cpu_to_be32(124) | ||
| 44 | static struct tpm_input_header tpm_readpubek_header = { | ||
| 45 | .tag = TPM_TAG_RQU_COMMAND, | ||
| 46 | .length = cpu_to_be32(30), | ||
| 47 | .ordinal = TPM_ORD_READPUBEK | ||
| 48 | }; | ||
| 49 | static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, | ||
| 50 | char *buf) | ||
| 51 | { | ||
| 52 | u8 *data; | ||
| 53 | struct tpm_cmd_t tpm_cmd; | ||
| 54 | ssize_t err; | ||
| 55 | int i, rc; | ||
| 56 | char *str = buf; | ||
| 57 | |||
| 58 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 59 | |||
| 60 | tpm_cmd.header.in = tpm_readpubek_header; | ||
| 61 | err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, | ||
| 62 | "attempting to read the PUBEK"); | ||
| 63 | if (err) | ||
| 64 | goto out; | ||
| 65 | |||
| 66 | /* | ||
| 67 | ignore header 10 bytes | ||
| 68 | algorithm 32 bits (1 == RSA ) | ||
| 69 | encscheme 16 bits | ||
| 70 | sigscheme 16 bits | ||
| 71 | parameters (RSA 12->bytes: keybit, #primes, expbit) | ||
| 72 | keylenbytes 32 bits | ||
| 73 | 256 byte modulus | ||
| 74 | ignore checksum 20 bytes | ||
| 75 | */ | ||
| 76 | data = tpm_cmd.params.readpubek_out_buffer; | ||
| 77 | str += | ||
| 78 | sprintf(str, | ||
| 79 | "Algorithm: %02X %02X %02X %02X\n" | ||
| 80 | "Encscheme: %02X %02X\n" | ||
| 81 | "Sigscheme: %02X %02X\n" | ||
| 82 | "Parameters: %02X %02X %02X %02X " | ||
| 83 | "%02X %02X %02X %02X " | ||
| 84 | "%02X %02X %02X %02X\n" | ||
| 85 | "Modulus length: %d\n" | ||
| 86 | "Modulus:\n", | ||
| 87 | data[0], data[1], data[2], data[3], | ||
| 88 | data[4], data[5], | ||
| 89 | data[6], data[7], | ||
| 90 | data[12], data[13], data[14], data[15], | ||
| 91 | data[16], data[17], data[18], data[19], | ||
| 92 | data[20], data[21], data[22], data[23], | ||
| 93 | be32_to_cpu(*((__be32 *) (data + 24)))); | ||
| 94 | |||
| 95 | for (i = 0; i < 256; i++) { | ||
| 96 | str += sprintf(str, "%02X ", data[i + 28]); | ||
| 97 | if ((i + 1) % 16 == 0) | ||
| 98 | str += sprintf(str, "\n"); | ||
| 99 | } | ||
| 100 | out: | ||
| 101 | rc = str - buf; | ||
| 102 | return rc; | ||
| 103 | } | ||
| 104 | static DEVICE_ATTR_RO(pubek); | ||
| 105 | |||
| 106 | static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, | ||
| 107 | char *buf) | ||
| 108 | { | ||
| 109 | cap_t cap; | ||
| 110 | u8 digest[TPM_DIGEST_SIZE]; | ||
| 111 | ssize_t rc; | ||
| 112 | int i, j, num_pcrs; | ||
| 113 | char *str = buf; | ||
| 114 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 115 | |||
| 116 | rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, | ||
| 117 | "attempting to determine the number of PCRS"); | ||
| 118 | if (rc) | ||
| 119 | return 0; | ||
| 120 | |||
| 121 | num_pcrs = be32_to_cpu(cap.num_pcrs); | ||
| 122 | for (i = 0; i < num_pcrs; i++) { | ||
| 123 | rc = tpm_pcr_read_dev(chip, i, digest); | ||
| 124 | if (rc) | ||
| 125 | break; | ||
| 126 | str += sprintf(str, "PCR-%02d: ", i); | ||
| 127 | for (j = 0; j < TPM_DIGEST_SIZE; j++) | ||
| 128 | str += sprintf(str, "%02X ", digest[j]); | ||
| 129 | str += sprintf(str, "\n"); | ||
| 130 | } | ||
| 131 | return str - buf; | ||
| 132 | } | ||
| 133 | static DEVICE_ATTR_RO(pcrs); | ||
| 134 | |||
| 135 | static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, | ||
| 136 | char *buf) | ||
| 137 | { | ||
| 138 | cap_t cap; | ||
| 139 | ssize_t rc; | ||
| 140 | |||
| 141 | rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, | ||
| 142 | "attempting to determine the permanent enabled state"); | ||
| 143 | if (rc) | ||
| 144 | return 0; | ||
| 145 | |||
| 146 | rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); | ||
| 147 | return rc; | ||
| 148 | } | ||
| 149 | static DEVICE_ATTR_RO(enabled); | ||
| 150 | |||
| 151 | static ssize_t active_show(struct device *dev, struct device_attribute *attr, | ||
| 152 | char *buf) | ||
| 153 | { | ||
| 154 | cap_t cap; | ||
| 155 | ssize_t rc; | ||
| 156 | |||
| 157 | rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, | ||
| 158 | "attempting to determine the permanent active state"); | ||
| 159 | if (rc) | ||
| 160 | return 0; | ||
| 161 | |||
| 162 | rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); | ||
| 163 | return rc; | ||
| 164 | } | ||
| 165 | static DEVICE_ATTR_RO(active); | ||
| 166 | |||
| 167 | static ssize_t owned_show(struct device *dev, struct device_attribute *attr, | ||
| 168 | char *buf) | ||
| 169 | { | ||
| 170 | cap_t cap; | ||
| 171 | ssize_t rc; | ||
| 172 | |||
| 173 | rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap, | ||
| 174 | "attempting to determine the owner state"); | ||
| 175 | if (rc) | ||
| 176 | return 0; | ||
| 177 | |||
| 178 | rc = sprintf(buf, "%d\n", cap.owned); | ||
| 179 | return rc; | ||
| 180 | } | ||
| 181 | static DEVICE_ATTR_RO(owned); | ||
| 182 | |||
| 183 | static ssize_t temp_deactivated_show(struct device *dev, | ||
| 184 | struct device_attribute *attr, char *buf) | ||
| 185 | { | ||
| 186 | cap_t cap; | ||
| 187 | ssize_t rc; | ||
| 188 | |||
| 189 | rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap, | ||
| 190 | "attempting to determine the temporary state"); | ||
| 191 | if (rc) | ||
| 192 | return 0; | ||
| 193 | |||
| 194 | rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); | ||
| 195 | return rc; | ||
| 196 | } | ||
| 197 | static DEVICE_ATTR_RO(temp_deactivated); | ||
| 198 | |||
| 199 | static ssize_t caps_show(struct device *dev, struct device_attribute *attr, | ||
| 200 | char *buf) | ||
| 201 | { | ||
| 202 | cap_t cap; | ||
| 203 | ssize_t rc; | ||
| 204 | char *str = buf; | ||
| 205 | |||
| 206 | rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, | ||
| 207 | "attempting to determine the manufacturer"); | ||
| 208 | if (rc) | ||
| 209 | return 0; | ||
| 210 | str += sprintf(str, "Manufacturer: 0x%x\n", | ||
| 211 | be32_to_cpu(cap.manufacturer_id)); | ||
| 212 | |||
| 213 | /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ | ||
| 214 | rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, | ||
| 215 | "attempting to determine the 1.2 version"); | ||
| 216 | if (!rc) { | ||
| 217 | str += sprintf(str, | ||
| 218 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | ||
| 219 | cap.tpm_version_1_2.Major, | ||
| 220 | cap.tpm_version_1_2.Minor, | ||
| 221 | cap.tpm_version_1_2.revMajor, | ||
| 222 | cap.tpm_version_1_2.revMinor); | ||
| 223 | } else { | ||
| 224 | /* Otherwise just use TPM_STRUCT_VER */ | ||
| 225 | rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, | ||
| 226 | "attempting to determine the 1.1 version"); | ||
| 227 | if (rc) | ||
| 228 | return 0; | ||
| 229 | str += sprintf(str, | ||
| 230 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | ||
| 231 | cap.tpm_version.Major, | ||
| 232 | cap.tpm_version.Minor, | ||
| 233 | cap.tpm_version.revMajor, | ||
| 234 | cap.tpm_version.revMinor); | ||
| 235 | } | ||
| 236 | |||
| 237 | return str - buf; | ||
| 238 | } | ||
| 239 | static DEVICE_ATTR_RO(caps); | ||
| 240 | |||
| 241 | static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, | ||
| 242 | const char *buf, size_t count) | ||
| 243 | { | ||
| 244 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 245 | if (chip == NULL) | ||
| 246 | return 0; | ||
| 247 | |||
| 248 | chip->ops->cancel(chip); | ||
| 249 | return count; | ||
| 250 | } | ||
| 251 | static DEVICE_ATTR_WO(cancel); | ||
| 252 | |||
| 253 | static ssize_t durations_show(struct device *dev, struct device_attribute *attr, | ||
| 254 | char *buf) | ||
| 255 | { | ||
| 256 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 257 | |||
| 258 | if (chip->vendor.duration[TPM_LONG] == 0) | ||
| 259 | return 0; | ||
| 260 | |||
| 261 | return sprintf(buf, "%d %d %d [%s]\n", | ||
| 262 | jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), | ||
| 263 | jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), | ||
| 264 | jiffies_to_usecs(chip->vendor.duration[TPM_LONG]), | ||
| 265 | chip->vendor.duration_adjusted | ||
| 266 | ? "adjusted" : "original"); | ||
| 267 | } | ||
| 268 | static DEVICE_ATTR_RO(durations); | ||
| 269 | |||
| 270 | static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr, | ||
| 271 | char *buf) | ||
| 272 | { | ||
| 273 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 274 | |||
| 275 | return sprintf(buf, "%d %d %d %d [%s]\n", | ||
| 276 | jiffies_to_usecs(chip->vendor.timeout_a), | ||
| 277 | jiffies_to_usecs(chip->vendor.timeout_b), | ||
| 278 | jiffies_to_usecs(chip->vendor.timeout_c), | ||
| 279 | jiffies_to_usecs(chip->vendor.timeout_d), | ||
| 280 | chip->vendor.timeout_adjusted | ||
| 281 | ? "adjusted" : "original"); | ||
| 282 | } | ||
| 283 | static DEVICE_ATTR_RO(timeouts); | ||
| 284 | |||
| 285 | static struct attribute *tpm_dev_attrs[] = { | ||
| 286 | &dev_attr_pubek.attr, | ||
| 287 | &dev_attr_pcrs.attr, | ||
| 288 | &dev_attr_enabled.attr, | ||
| 289 | &dev_attr_active.attr, | ||
| 290 | &dev_attr_owned.attr, | ||
| 291 | &dev_attr_temp_deactivated.attr, | ||
| 292 | &dev_attr_caps.attr, | ||
| 293 | &dev_attr_cancel.attr, | ||
| 294 | &dev_attr_durations.attr, | ||
| 295 | &dev_attr_timeouts.attr, | ||
| 296 | NULL, | ||
| 297 | }; | ||
| 298 | |||
| 299 | static const struct attribute_group tpm_dev_group = { | ||
| 300 | .attrs = tpm_dev_attrs, | ||
| 301 | }; | ||
| 302 | |||
| 303 | int tpm_sysfs_add_device(struct tpm_chip *chip) | ||
| 304 | { | ||
| 305 | int err; | ||
| 306 | err = sysfs_create_group(&chip->dev->kobj, | ||
| 307 | &tpm_dev_group); | ||
| 308 | |||
| 309 | if (err) | ||
| 310 | dev_err(chip->dev, | ||
| 311 | "failed to create sysfs attributes, %d\n", err); | ||
| 312 | return err; | ||
| 313 | } | ||
| 314 | |||
| 315 | void tpm_sysfs_del_device(struct tpm_chip *chip) | ||
| 316 | { | ||
| 317 | sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group); | ||
| 318 | } | ||
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index f32847872193..e4d0888d2eab 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
| @@ -46,6 +46,14 @@ enum tpm_addr { | |||
| 46 | TPM_ADDR = 0x4E, | 46 | TPM_ADDR = 0x4E, |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | /* Indexes the duration array */ | ||
| 50 | enum tpm_duration { | ||
| 51 | TPM_SHORT = 0, | ||
| 52 | TPM_MEDIUM = 1, | ||
| 53 | TPM_LONG = 2, | ||
| 54 | TPM_UNDEFINED, | ||
| 55 | }; | ||
| 56 | |||
| 49 | #define TPM_WARN_RETRY 0x800 | 57 | #define TPM_WARN_RETRY 0x800 |
| 50 | #define TPM_WARN_DOING_SELFTEST 0x802 | 58 | #define TPM_WARN_DOING_SELFTEST 0x802 |
| 51 | #define TPM_ERR_DEACTIVATED 0x6 | 59 | #define TPM_ERR_DEACTIVATED 0x6 |
| @@ -53,33 +61,9 @@ enum tpm_addr { | |||
| 53 | #define TPM_ERR_INVALID_POSTINIT 38 | 61 | #define TPM_ERR_INVALID_POSTINIT 38 |
| 54 | 62 | ||
| 55 | #define TPM_HEADER_SIZE 10 | 63 | #define TPM_HEADER_SIZE 10 |
| 56 | extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, | ||
| 57 | char *); | ||
| 58 | extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, | ||
| 59 | char *); | ||
| 60 | extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, | ||
| 61 | char *); | ||
| 62 | extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, | ||
| 63 | const char *, size_t); | ||
| 64 | extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr, | ||
| 65 | char *); | ||
| 66 | extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr, | ||
| 67 | char *); | ||
| 68 | extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, | ||
| 69 | char *); | ||
| 70 | extern ssize_t tpm_show_temp_deactivated(struct device *, | ||
| 71 | struct device_attribute *attr, char *); | ||
| 72 | extern ssize_t tpm_show_durations(struct device *, | ||
| 73 | struct device_attribute *attr, char *); | ||
| 74 | extern ssize_t tpm_show_timeouts(struct device *, | ||
| 75 | struct device_attribute *attr, char *); | ||
| 76 | |||
| 77 | struct tpm_chip; | 64 | struct tpm_chip; |
| 78 | 65 | ||
| 79 | struct tpm_vendor_specific { | 66 | struct tpm_vendor_specific { |
| 80 | const u8 req_complete_mask; | ||
| 81 | const u8 req_complete_val; | ||
| 82 | bool (*req_canceled)(struct tpm_chip *chip, u8 status); | ||
| 83 | void __iomem *iobase; /* ioremapped address */ | 67 | void __iomem *iobase; /* ioremapped address */ |
| 84 | unsigned long base; /* TPM base address */ | 68 | unsigned long base; /* TPM base address */ |
| 85 | 69 | ||
| @@ -89,13 +73,7 @@ struct tpm_vendor_specific { | |||
| 89 | int region_size; | 73 | int region_size; |
| 90 | int have_region; | 74 | int have_region; |
| 91 | 75 | ||
| 92 | int (*recv) (struct tpm_chip *, u8 *, size_t); | ||
| 93 | int (*send) (struct tpm_chip *, u8 *, size_t); | ||
| 94 | void (*cancel) (struct tpm_chip *); | ||
| 95 | u8 (*status) (struct tpm_chip *); | ||
| 96 | void (*release) (struct device *); | ||
| 97 | struct miscdevice miscdev; | 76 | struct miscdevice miscdev; |
| 98 | struct attribute_group *attr_group; | ||
| 99 | struct list_head list; | 77 | struct list_head list; |
| 100 | int locality; | 78 | int locality; |
| 101 | unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ | 79 | unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ |
| @@ -118,19 +96,13 @@ struct tpm_vendor_specific { | |||
| 118 | 96 | ||
| 119 | struct tpm_chip { | 97 | struct tpm_chip { |
| 120 | struct device *dev; /* Device stuff */ | 98 | struct device *dev; /* Device stuff */ |
| 99 | const struct tpm_class_ops *ops; | ||
| 121 | 100 | ||
| 122 | int dev_num; /* /dev/tpm# */ | 101 | int dev_num; /* /dev/tpm# */ |
| 123 | char devname[7]; | 102 | char devname[7]; |
| 124 | unsigned long is_open; /* only one allowed */ | 103 | unsigned long is_open; /* only one allowed */ |
| 125 | int time_expired; | 104 | int time_expired; |
| 126 | 105 | ||
| 127 | /* Data passed to and from the tpm via the read/write calls */ | ||
| 128 | u8 *data_buffer; | ||
| 129 | atomic_t data_pending; | ||
| 130 | struct mutex buffer_mutex; | ||
| 131 | |||
| 132 | struct timer_list user_read_timer; /* user needs to claim result */ | ||
| 133 | struct work_struct work; | ||
| 134 | struct mutex tpm_mutex; /* tpm is processing */ | 106 | struct mutex tpm_mutex; /* tpm is processing */ |
| 135 | 107 | ||
| 136 | struct tpm_vendor_specific vendor; | 108 | struct tpm_vendor_specific vendor; |
| @@ -171,6 +143,8 @@ struct tpm_output_header { | |||
| 171 | __be32 return_code; | 143 | __be32 return_code; |
| 172 | } __packed; | 144 | } __packed; |
| 173 | 145 | ||
| 146 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) | ||
| 147 | |||
| 174 | struct stclear_flags_t { | 148 | struct stclear_flags_t { |
| 175 | __be16 tag; | 149 | __be16 tag; |
| 176 | u8 deactivated; | 150 | u8 deactivated; |
| @@ -244,6 +218,24 @@ typedef union { | |||
| 244 | struct duration_t duration; | 218 | struct duration_t duration; |
| 245 | } cap_t; | 219 | } cap_t; |
| 246 | 220 | ||
| 221 | enum tpm_capabilities { | ||
| 222 | TPM_CAP_FLAG = cpu_to_be32(4), | ||
| 223 | TPM_CAP_PROP = cpu_to_be32(5), | ||
| 224 | CAP_VERSION_1_1 = cpu_to_be32(0x06), | ||
| 225 | CAP_VERSION_1_2 = cpu_to_be32(0x1A) | ||
| 226 | }; | ||
| 227 | |||
| 228 | enum tpm_sub_capabilities { | ||
| 229 | TPM_CAP_PROP_PCR = cpu_to_be32(0x101), | ||
| 230 | TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), | ||
| 231 | TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), | ||
| 232 | TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), | ||
| 233 | TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), | ||
| 234 | TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), | ||
| 235 | TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), | ||
| 236 | |||
| 237 | }; | ||
| 238 | |||
| 247 | struct tpm_getcap_params_in { | 239 | struct tpm_getcap_params_in { |
| 248 | __be32 cap; | 240 | __be32 cap; |
| 249 | __be32 subcap_size; | 241 | __be32 subcap_size; |
| @@ -323,25 +315,28 @@ struct tpm_cmd_t { | |||
| 323 | 315 | ||
| 324 | ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); | 316 | ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); |
| 325 | 317 | ||
| 318 | ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | ||
| 319 | size_t bufsiz); | ||
| 326 | extern int tpm_get_timeouts(struct tpm_chip *); | 320 | extern int tpm_get_timeouts(struct tpm_chip *); |
| 327 | extern void tpm_gen_interrupt(struct tpm_chip *); | 321 | extern void tpm_gen_interrupt(struct tpm_chip *); |
| 328 | extern int tpm_do_selftest(struct tpm_chip *); | 322 | extern int tpm_do_selftest(struct tpm_chip *); |
| 329 | extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); | 323 | extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); |
| 330 | extern struct tpm_chip* tpm_register_hardware(struct device *, | 324 | extern struct tpm_chip* tpm_register_hardware(struct device *, |
| 331 | const struct tpm_vendor_specific *); | 325 | const struct tpm_class_ops *ops); |
| 332 | extern int tpm_open(struct inode *, struct file *); | ||
| 333 | extern int tpm_release(struct inode *, struct file *); | ||
| 334 | extern void tpm_dev_release(struct device *dev); | ||
| 335 | extern void tpm_dev_vendor_release(struct tpm_chip *); | 326 | extern void tpm_dev_vendor_release(struct tpm_chip *); |
| 336 | extern ssize_t tpm_write(struct file *, const char __user *, size_t, | ||
| 337 | loff_t *); | ||
| 338 | extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); | ||
| 339 | extern void tpm_remove_hardware(struct device *); | 327 | extern void tpm_remove_hardware(struct device *); |
| 340 | extern int tpm_pm_suspend(struct device *); | 328 | extern int tpm_pm_suspend(struct device *); |
| 341 | extern int tpm_pm_resume(struct device *); | 329 | extern int tpm_pm_resume(struct device *); |
| 342 | extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, | 330 | extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, |
| 343 | wait_queue_head_t *, bool); | 331 | wait_queue_head_t *, bool); |
| 344 | 332 | ||
| 333 | int tpm_dev_add_device(struct tpm_chip *chip); | ||
| 334 | void tpm_dev_del_device(struct tpm_chip *chip); | ||
| 335 | int tpm_sysfs_add_device(struct tpm_chip *chip); | ||
| 336 | void tpm_sysfs_del_device(struct tpm_chip *chip); | ||
| 337 | |||
| 338 | int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); | ||
| 339 | |||
| 345 | #ifdef CONFIG_ACPI | 340 | #ifdef CONFIG_ACPI |
| 346 | extern int tpm_add_ppi(struct kobject *); | 341 | extern int tpm_add_ppi(struct kobject *); |
| 347 | extern void tpm_remove_ppi(struct kobject *); | 342 | extern void tpm_remove_ppi(struct kobject *); |
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index c9a528d25d22..6069d13ae4ac 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c | |||
| @@ -121,31 +121,7 @@ static bool tpm_atml_req_canceled(struct tpm_chip *chip, u8 status) | |||
| 121 | return (status == ATML_STATUS_READY); | 121 | return (status == ATML_STATUS_READY); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | static const struct file_operations atmel_ops = { | 124 | static const struct tpm_class_ops tpm_atmel = { |
| 125 | .owner = THIS_MODULE, | ||
| 126 | .llseek = no_llseek, | ||
| 127 | .open = tpm_open, | ||
| 128 | .read = tpm_read, | ||
| 129 | .write = tpm_write, | ||
| 130 | .release = tpm_release, | ||
| 131 | }; | ||
| 132 | |||
| 133 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 134 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 135 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 136 | static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); | ||
| 137 | |||
| 138 | static struct attribute* atmel_attrs[] = { | ||
| 139 | &dev_attr_pubek.attr, | ||
| 140 | &dev_attr_pcrs.attr, | ||
| 141 | &dev_attr_caps.attr, | ||
| 142 | &dev_attr_cancel.attr, | ||
| 143 | NULL, | ||
| 144 | }; | ||
| 145 | |||
| 146 | static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; | ||
| 147 | |||
| 148 | static const struct tpm_vendor_specific tpm_atmel = { | ||
| 149 | .recv = tpm_atml_recv, | 125 | .recv = tpm_atml_recv, |
| 150 | .send = tpm_atml_send, | 126 | .send = tpm_atml_send, |
| 151 | .cancel = tpm_atml_cancel, | 127 | .cancel = tpm_atml_cancel, |
| @@ -153,8 +129,6 @@ static const struct tpm_vendor_specific tpm_atmel = { | |||
| 153 | .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, | 129 | .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, |
| 154 | .req_complete_val = ATML_STATUS_DATA_AVAIL, | 130 | .req_complete_val = ATML_STATUS_DATA_AVAIL, |
| 155 | .req_canceled = tpm_atml_req_canceled, | 131 | .req_canceled = tpm_atml_req_canceled, |
| 156 | .attr_group = &atmel_attr_grp, | ||
| 157 | .miscdev = { .fops = &atmel_ops, }, | ||
| 158 | }; | 132 | }; |
| 159 | 133 | ||
| 160 | static struct platform_device *pdev; | 134 | static struct platform_device *pdev; |
diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index c3cd7fe481a1..77272925dee6 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c | |||
| @@ -135,50 +135,12 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip) | |||
| 135 | return ATMEL_STS_OK; | 135 | return ATMEL_STS_OK; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | static const struct file_operations i2c_atmel_ops = { | ||
| 139 | .owner = THIS_MODULE, | ||
| 140 | .llseek = no_llseek, | ||
| 141 | .open = tpm_open, | ||
| 142 | .read = tpm_read, | ||
| 143 | .write = tpm_write, | ||
| 144 | .release = tpm_release, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 148 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 149 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 150 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 151 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 152 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); | ||
| 153 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 154 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 155 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
| 156 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
| 157 | |||
| 158 | static struct attribute *i2c_atmel_attrs[] = { | ||
| 159 | &dev_attr_pubek.attr, | ||
| 160 | &dev_attr_pcrs.attr, | ||
| 161 | &dev_attr_enabled.attr, | ||
| 162 | &dev_attr_active.attr, | ||
| 163 | &dev_attr_owned.attr, | ||
| 164 | &dev_attr_temp_deactivated.attr, | ||
| 165 | &dev_attr_caps.attr, | ||
| 166 | &dev_attr_cancel.attr, | ||
| 167 | &dev_attr_durations.attr, | ||
| 168 | &dev_attr_timeouts.attr, | ||
| 169 | NULL, | ||
| 170 | }; | ||
| 171 | |||
| 172 | static struct attribute_group i2c_atmel_attr_grp = { | ||
| 173 | .attrs = i2c_atmel_attrs | ||
| 174 | }; | ||
| 175 | |||
| 176 | static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status) | 138 | static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status) |
| 177 | { | 139 | { |
| 178 | return 0; | 140 | return false; |
| 179 | } | 141 | } |
| 180 | 142 | ||
| 181 | static const struct tpm_vendor_specific i2c_atmel = { | 143 | static const struct tpm_class_ops i2c_atmel = { |
| 182 | .status = i2c_atmel_read_status, | 144 | .status = i2c_atmel_read_status, |
| 183 | .recv = i2c_atmel_recv, | 145 | .recv = i2c_atmel_recv, |
| 184 | .send = i2c_atmel_send, | 146 | .send = i2c_atmel_send, |
| @@ -186,8 +148,6 @@ static const struct tpm_vendor_specific i2c_atmel = { | |||
| 186 | .req_complete_mask = ATMEL_STS_OK, | 148 | .req_complete_mask = ATMEL_STS_OK, |
| 187 | .req_complete_val = ATMEL_STS_OK, | 149 | .req_complete_val = ATMEL_STS_OK, |
| 188 | .req_canceled = i2c_atmel_req_canceled, | 150 | .req_canceled = i2c_atmel_req_canceled, |
| 189 | .attr_group = &i2c_atmel_attr_grp, | ||
| 190 | .miscdev.fops = &i2c_atmel_ops, | ||
| 191 | }; | 151 | }; |
| 192 | 152 | ||
| 193 | static int i2c_atmel_probe(struct i2c_client *client, | 153 | static int i2c_atmel_probe(struct i2c_client *client, |
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index fefd2aa5c81e..52b9b2b2f300 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c | |||
| @@ -566,45 +566,7 @@ static bool tpm_tis_i2c_req_canceled(struct tpm_chip *chip, u8 status) | |||
| 566 | return (status == TPM_STS_COMMAND_READY); | 566 | return (status == TPM_STS_COMMAND_READY); |
| 567 | } | 567 | } |
| 568 | 568 | ||
| 569 | static const struct file_operations tis_ops = { | 569 | static const struct tpm_class_ops tpm_tis_i2c = { |
| 570 | .owner = THIS_MODULE, | ||
| 571 | .llseek = no_llseek, | ||
| 572 | .open = tpm_open, | ||
| 573 | .read = tpm_read, | ||
| 574 | .write = tpm_write, | ||
| 575 | .release = tpm_release, | ||
| 576 | }; | ||
| 577 | |||
| 578 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 579 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 580 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 581 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 582 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 583 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); | ||
| 584 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 585 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 586 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
| 587 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
| 588 | |||
| 589 | static struct attribute *tis_attrs[] = { | ||
| 590 | &dev_attr_pubek.attr, | ||
| 591 | &dev_attr_pcrs.attr, | ||
| 592 | &dev_attr_enabled.attr, | ||
| 593 | &dev_attr_active.attr, | ||
| 594 | &dev_attr_owned.attr, | ||
| 595 | &dev_attr_temp_deactivated.attr, | ||
| 596 | &dev_attr_caps.attr, | ||
| 597 | &dev_attr_cancel.attr, | ||
| 598 | &dev_attr_durations.attr, | ||
| 599 | &dev_attr_timeouts.attr, | ||
| 600 | NULL, | ||
| 601 | }; | ||
| 602 | |||
| 603 | static struct attribute_group tis_attr_grp = { | ||
| 604 | .attrs = tis_attrs | ||
| 605 | }; | ||
| 606 | |||
| 607 | static struct tpm_vendor_specific tpm_tis_i2c = { | ||
| 608 | .status = tpm_tis_i2c_status, | 570 | .status = tpm_tis_i2c_status, |
| 609 | .recv = tpm_tis_i2c_recv, | 571 | .recv = tpm_tis_i2c_recv, |
| 610 | .send = tpm_tis_i2c_send, | 572 | .send = tpm_tis_i2c_send, |
| @@ -612,8 +574,6 @@ static struct tpm_vendor_specific tpm_tis_i2c = { | |||
| 612 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 574 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 613 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 575 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 614 | .req_canceled = tpm_tis_i2c_req_canceled, | 576 | .req_canceled = tpm_tis_i2c_req_canceled, |
| 615 | .attr_group = &tis_attr_grp, | ||
| 616 | .miscdev.fops = &tis_ops, | ||
| 617 | }; | 577 | }; |
| 618 | 578 | ||
| 619 | static int tpm_tis_i2c_init(struct device *dev) | 579 | static int tpm_tis_i2c_init(struct device *dev) |
diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 6276fea01ff0..7b158efd49f7 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c | |||
| @@ -178,7 +178,6 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, | |||
| 178 | { | 178 | { |
| 179 | if (chip->vendor.irq && queue) { | 179 | if (chip->vendor.irq && queue) { |
| 180 | s32 rc; | 180 | s32 rc; |
| 181 | DEFINE_WAIT(wait); | ||
| 182 | struct priv_data *priv = chip->vendor.priv; | 181 | struct priv_data *priv = chip->vendor.priv; |
| 183 | unsigned int cur_intrs = priv->intrs; | 182 | unsigned int cur_intrs = priv->intrs; |
| 184 | 183 | ||
| @@ -456,45 +455,7 @@ static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status) | |||
| 456 | return (status == TPM_STS_COMMAND_READY); | 455 | return (status == TPM_STS_COMMAND_READY); |
| 457 | } | 456 | } |
| 458 | 457 | ||
| 459 | static const struct file_operations i2c_nuvoton_ops = { | 458 | static const struct tpm_class_ops tpm_i2c = { |
| 460 | .owner = THIS_MODULE, | ||
| 461 | .llseek = no_llseek, | ||
| 462 | .open = tpm_open, | ||
| 463 | .read = tpm_read, | ||
| 464 | .write = tpm_write, | ||
| 465 | .release = tpm_release, | ||
| 466 | }; | ||
| 467 | |||
| 468 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 469 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 470 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 471 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 472 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 473 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); | ||
| 474 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 475 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 476 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
| 477 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
| 478 | |||
| 479 | static struct attribute *i2c_nuvoton_attrs[] = { | ||
| 480 | &dev_attr_pubek.attr, | ||
| 481 | &dev_attr_pcrs.attr, | ||
| 482 | &dev_attr_enabled.attr, | ||
| 483 | &dev_attr_active.attr, | ||
| 484 | &dev_attr_owned.attr, | ||
| 485 | &dev_attr_temp_deactivated.attr, | ||
| 486 | &dev_attr_caps.attr, | ||
| 487 | &dev_attr_cancel.attr, | ||
| 488 | &dev_attr_durations.attr, | ||
| 489 | &dev_attr_timeouts.attr, | ||
| 490 | NULL, | ||
| 491 | }; | ||
| 492 | |||
| 493 | static struct attribute_group i2c_nuvoton_attr_grp = { | ||
| 494 | .attrs = i2c_nuvoton_attrs | ||
| 495 | }; | ||
| 496 | |||
| 497 | static const struct tpm_vendor_specific tpm_i2c = { | ||
| 498 | .status = i2c_nuvoton_read_status, | 459 | .status = i2c_nuvoton_read_status, |
| 499 | .recv = i2c_nuvoton_recv, | 460 | .recv = i2c_nuvoton_recv, |
| 500 | .send = i2c_nuvoton_send, | 461 | .send = i2c_nuvoton_send, |
| @@ -502,8 +463,6 @@ static const struct tpm_vendor_specific tpm_i2c = { | |||
| 502 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 463 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 503 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 464 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 504 | .req_canceled = i2c_nuvoton_req_canceled, | 465 | .req_canceled = i2c_nuvoton_req_canceled, |
| 505 | .attr_group = &i2c_nuvoton_attr_grp, | ||
| 506 | .miscdev.fops = &i2c_nuvoton_ops, | ||
| 507 | }; | 466 | }; |
| 508 | 467 | ||
| 509 | /* The only purpose for the handler is to signal to any waiting threads that | 468 | /* The only purpose for the handler is to signal to any waiting threads that |
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index a0d6ceb5d005..5b0dd8ef74c0 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c | |||
| @@ -410,6 +410,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | |||
| 410 | &chip->vendor.read_queue) | 410 | &chip->vendor.read_queue) |
| 411 | == 0) { | 411 | == 0) { |
| 412 | burstcnt = get_burstcount(chip); | 412 | burstcnt = get_burstcount(chip); |
| 413 | if (burstcnt < 0) | ||
| 414 | return burstcnt; | ||
| 413 | len = min_t(int, burstcnt, count - size); | 415 | len = min_t(int, burstcnt, count - size); |
| 414 | I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len); | 416 | I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len); |
| 415 | size += len; | 417 | size += len; |
| @@ -451,7 +453,8 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) | |||
| 451 | static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, | 453 | static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, |
| 452 | size_t len) | 454 | size_t len) |
| 453 | { | 455 | { |
| 454 | u32 status, burstcnt = 0, i, size; | 456 | u32 status, i, size; |
| 457 | int burstcnt = 0; | ||
| 455 | int ret; | 458 | int ret; |
| 456 | u8 data; | 459 | u8 data; |
| 457 | struct i2c_client *client; | 460 | struct i2c_client *client; |
| @@ -482,6 +485,8 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, | |||
| 482 | 485 | ||
| 483 | for (i = 0; i < len - 1;) { | 486 | for (i = 0; i < len - 1;) { |
| 484 | burstcnt = get_burstcount(chip); | 487 | burstcnt = get_burstcount(chip); |
| 488 | if (burstcnt < 0) | ||
| 489 | return burstcnt; | ||
| 485 | size = min_t(int, len - i - 1, burstcnt); | 490 | size = min_t(int, len - i - 1, burstcnt); |
| 486 | ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size); | 491 | ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size); |
| 487 | if (ret < 0) | 492 | if (ret < 0) |
| @@ -559,7 +564,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, | |||
| 559 | } | 564 | } |
| 560 | 565 | ||
| 561 | out: | 566 | out: |
| 562 | chip->vendor.cancel(chip); | 567 | chip->ops->cancel(chip); |
| 563 | release_locality(chip); | 568 | release_locality(chip); |
| 564 | return size; | 569 | return size; |
| 565 | } | 570 | } |
| @@ -569,40 +574,7 @@ static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status) | |||
| 569 | return (status == TPM_STS_COMMAND_READY); | 574 | return (status == TPM_STS_COMMAND_READY); |
| 570 | } | 575 | } |
| 571 | 576 | ||
| 572 | static const struct file_operations tpm_st33_i2c_fops = { | 577 | static const struct tpm_class_ops st_i2c_tpm = { |
| 573 | .owner = THIS_MODULE, | ||
| 574 | .llseek = no_llseek, | ||
| 575 | .read = tpm_read, | ||
| 576 | .write = tpm_write, | ||
| 577 | .open = tpm_open, | ||
| 578 | .release = tpm_release, | ||
| 579 | }; | ||
| 580 | |||
| 581 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 582 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 583 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 584 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 585 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 586 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); | ||
| 587 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 588 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 589 | |||
| 590 | static struct attribute *stm_tpm_attrs[] = { | ||
| 591 | &dev_attr_pubek.attr, | ||
| 592 | &dev_attr_pcrs.attr, | ||
| 593 | &dev_attr_enabled.attr, | ||
| 594 | &dev_attr_active.attr, | ||
| 595 | &dev_attr_owned.attr, | ||
| 596 | &dev_attr_temp_deactivated.attr, | ||
| 597 | &dev_attr_caps.attr, | ||
| 598 | &dev_attr_cancel.attr, NULL, | ||
| 599 | }; | ||
| 600 | |||
| 601 | static struct attribute_group stm_tpm_attr_grp = { | ||
| 602 | .attrs = stm_tpm_attrs | ||
| 603 | }; | ||
| 604 | |||
| 605 | static struct tpm_vendor_specific st_i2c_tpm = { | ||
| 606 | .send = tpm_stm_i2c_send, | 578 | .send = tpm_stm_i2c_send, |
| 607 | .recv = tpm_stm_i2c_recv, | 579 | .recv = tpm_stm_i2c_recv, |
| 608 | .cancel = tpm_stm_i2c_cancel, | 580 | .cancel = tpm_stm_i2c_cancel, |
| @@ -610,8 +582,6 @@ static struct tpm_vendor_specific st_i2c_tpm = { | |||
| 610 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 582 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 611 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 583 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 612 | .req_canceled = tpm_st33_i2c_req_canceled, | 584 | .req_canceled = tpm_st33_i2c_req_canceled, |
| 613 | .attr_group = &stm_tpm_attr_grp, | ||
| 614 | .miscdev = {.fops = &tpm_st33_i2c_fops,}, | ||
| 615 | }; | 585 | }; |
| 616 | 586 | ||
| 617 | static int interrupts; | 587 | static int interrupts; |
| @@ -837,7 +807,7 @@ static int tpm_st33_i2c_pm_resume(struct device *dev) | |||
| 837 | if (power_mgt) { | 807 | if (power_mgt) { |
| 838 | gpio_set_value(pin_infos->io_lpcpd, 1); | 808 | gpio_set_value(pin_infos->io_lpcpd, 1); |
| 839 | ret = wait_for_serirq_timeout(chip, | 809 | ret = wait_for_serirq_timeout(chip, |
| 840 | (chip->vendor.status(chip) & | 810 | (chip->ops->status(chip) & |
| 841 | TPM_STS_VALID) == TPM_STS_VALID, | 811 | TPM_STS_VALID) == TPM_STS_VALID, |
| 842 | chip->vendor.timeout_b); | 812 | chip->vendor.timeout_b); |
| 843 | } else { | 813 | } else { |
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 2783a42aa732..af74c57e5090 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c | |||
| @@ -403,43 +403,7 @@ static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status) | |||
| 403 | return (status == 0); | 403 | return (status == 0); |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | static const struct file_operations ibmvtpm_ops = { | 406 | static const struct tpm_class_ops tpm_ibmvtpm = { |
| 407 | .owner = THIS_MODULE, | ||
| 408 | .llseek = no_llseek, | ||
| 409 | .open = tpm_open, | ||
| 410 | .read = tpm_read, | ||
| 411 | .write = tpm_write, | ||
| 412 | .release = tpm_release, | ||
| 413 | }; | ||
| 414 | |||
| 415 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 416 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 417 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 418 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 419 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 420 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, | ||
| 421 | NULL); | ||
| 422 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 423 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 424 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
| 425 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
| 426 | |||
| 427 | static struct attribute *ibmvtpm_attrs[] = { | ||
| 428 | &dev_attr_pubek.attr, | ||
| 429 | &dev_attr_pcrs.attr, | ||
| 430 | &dev_attr_enabled.attr, | ||
| 431 | &dev_attr_active.attr, | ||
| 432 | &dev_attr_owned.attr, | ||
| 433 | &dev_attr_temp_deactivated.attr, | ||
| 434 | &dev_attr_caps.attr, | ||
| 435 | &dev_attr_cancel.attr, | ||
| 436 | &dev_attr_durations.attr, | ||
| 437 | &dev_attr_timeouts.attr, NULL, | ||
| 438 | }; | ||
| 439 | |||
| 440 | static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs }; | ||
| 441 | |||
| 442 | static const struct tpm_vendor_specific tpm_ibmvtpm = { | ||
| 443 | .recv = tpm_ibmvtpm_recv, | 407 | .recv = tpm_ibmvtpm_recv, |
| 444 | .send = tpm_ibmvtpm_send, | 408 | .send = tpm_ibmvtpm_send, |
| 445 | .cancel = tpm_ibmvtpm_cancel, | 409 | .cancel = tpm_ibmvtpm_cancel, |
| @@ -447,8 +411,6 @@ static const struct tpm_vendor_specific tpm_ibmvtpm = { | |||
| 447 | .req_complete_mask = 0, | 411 | .req_complete_mask = 0, |
| 448 | .req_complete_val = 0, | 412 | .req_complete_val = 0, |
| 449 | .req_canceled = tpm_ibmvtpm_req_canceled, | 413 | .req_canceled = tpm_ibmvtpm_req_canceled, |
| 450 | .attr_group = &ibmvtpm_attr_grp, | ||
| 451 | .miscdev = { .fops = &ibmvtpm_ops, }, | ||
| 452 | }; | 414 | }; |
| 453 | 415 | ||
| 454 | static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = { | 416 | static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = { |
| @@ -507,7 +469,6 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, | |||
| 507 | dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg); | 469 | dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg); |
| 508 | return; | 470 | return; |
| 509 | } | 471 | } |
| 510 | return; | ||
| 511 | case IBMVTPM_VALID_CMD: | 472 | case IBMVTPM_VALID_CMD: |
| 512 | switch (crq->msg) { | 473 | switch (crq->msg) { |
| 513 | case VTPM_GET_RTCE_BUFFER_SIZE_RES: | 474 | case VTPM_GET_RTCE_BUFFER_SIZE_RES: |
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 2b480c2960bb..dc0a2554034e 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c | |||
| @@ -371,39 +371,13 @@ static u8 tpm_inf_status(struct tpm_chip *chip) | |||
| 371 | return tpm_data_in(STAT); | 371 | return tpm_data_in(STAT); |
| 372 | } | 372 | } |
| 373 | 373 | ||
| 374 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | 374 | static const struct tpm_class_ops tpm_inf = { |
| 375 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 376 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 377 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 378 | |||
| 379 | static struct attribute *inf_attrs[] = { | ||
| 380 | &dev_attr_pubek.attr, | ||
| 381 | &dev_attr_pcrs.attr, | ||
| 382 | &dev_attr_caps.attr, | ||
| 383 | &dev_attr_cancel.attr, | ||
| 384 | NULL, | ||
| 385 | }; | ||
| 386 | |||
| 387 | static struct attribute_group inf_attr_grp = {.attrs = inf_attrs }; | ||
| 388 | |||
| 389 | static const struct file_operations inf_ops = { | ||
| 390 | .owner = THIS_MODULE, | ||
| 391 | .llseek = no_llseek, | ||
| 392 | .open = tpm_open, | ||
| 393 | .read = tpm_read, | ||
| 394 | .write = tpm_write, | ||
| 395 | .release = tpm_release, | ||
| 396 | }; | ||
| 397 | |||
| 398 | static const struct tpm_vendor_specific tpm_inf = { | ||
| 399 | .recv = tpm_inf_recv, | 375 | .recv = tpm_inf_recv, |
| 400 | .send = tpm_inf_send, | 376 | .send = tpm_inf_send, |
| 401 | .cancel = tpm_inf_cancel, | 377 | .cancel = tpm_inf_cancel, |
| 402 | .status = tpm_inf_status, | 378 | .status = tpm_inf_status, |
| 403 | .req_complete_mask = 0, | 379 | .req_complete_mask = 0, |
| 404 | .req_complete_val = 0, | 380 | .req_complete_val = 0, |
| 405 | .attr_group = &inf_attr_grp, | ||
| 406 | .miscdev = {.fops = &inf_ops,}, | ||
| 407 | }; | 381 | }; |
| 408 | 382 | ||
| 409 | static const struct pnp_device_id tpm_inf_pnp_tbl[] = { | 383 | static const struct pnp_device_id tpm_inf_pnp_tbl[] = { |
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 770c46f8eb30..3179ec9cffdc 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c | |||
| @@ -232,31 +232,7 @@ static bool tpm_nsc_req_canceled(struct tpm_chip *chip, u8 status) | |||
| 232 | return (status == NSC_STATUS_RDY); | 232 | return (status == NSC_STATUS_RDY); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | static const struct file_operations nsc_ops = { | 235 | static const struct tpm_class_ops tpm_nsc = { |
| 236 | .owner = THIS_MODULE, | ||
| 237 | .llseek = no_llseek, | ||
| 238 | .open = tpm_open, | ||
| 239 | .read = tpm_read, | ||
| 240 | .write = tpm_write, | ||
| 241 | .release = tpm_release, | ||
| 242 | }; | ||
| 243 | |||
| 244 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 245 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 246 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 247 | static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel); | ||
| 248 | |||
| 249 | static struct attribute * nsc_attrs[] = { | ||
| 250 | &dev_attr_pubek.attr, | ||
| 251 | &dev_attr_pcrs.attr, | ||
| 252 | &dev_attr_caps.attr, | ||
| 253 | &dev_attr_cancel.attr, | ||
| 254 | NULL, | ||
| 255 | }; | ||
| 256 | |||
| 257 | static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; | ||
| 258 | |||
| 259 | static const struct tpm_vendor_specific tpm_nsc = { | ||
| 260 | .recv = tpm_nsc_recv, | 236 | .recv = tpm_nsc_recv, |
| 261 | .send = tpm_nsc_send, | 237 | .send = tpm_nsc_send, |
| 262 | .cancel = tpm_nsc_cancel, | 238 | .cancel = tpm_nsc_cancel, |
| @@ -264,8 +240,6 @@ static const struct tpm_vendor_specific tpm_nsc = { | |||
| 264 | .req_complete_mask = NSC_STATUS_OBF, | 240 | .req_complete_mask = NSC_STATUS_OBF, |
| 265 | .req_complete_val = NSC_STATUS_OBF, | 241 | .req_complete_val = NSC_STATUS_OBF, |
| 266 | .req_canceled = tpm_nsc_req_canceled, | 242 | .req_canceled = tpm_nsc_req_canceled, |
| 267 | .attr_group = &nsc_attr_grp, | ||
| 268 | .miscdev = { .fops = &nsc_ops, }, | ||
| 269 | }; | 243 | }; |
| 270 | 244 | ||
| 271 | static struct platform_device *pdev = NULL; | 245 | static struct platform_device *pdev = NULL; |
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index e1f3337a0cf9..2db4419831be 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c | |||
| @@ -172,7 +172,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev, | |||
| 172 | * is updated with function index from SUBREQ to SUBREQ2 since PPI | 172 | * is updated with function index from SUBREQ to SUBREQ2 since PPI |
| 173 | * version 1.1 | 173 | * version 1.1 |
| 174 | */ | 174 | */ |
| 175 | if (strcmp(version, "1.1") == -1) | 175 | if (strcmp(version, "1.1") < 0) |
| 176 | params[2].integer.value = TPM_PPI_FN_SUBREQ; | 176 | params[2].integer.value = TPM_PPI_FN_SUBREQ; |
| 177 | else | 177 | else |
| 178 | params[2].integer.value = TPM_PPI_FN_SUBREQ2; | 178 | params[2].integer.value = TPM_PPI_FN_SUBREQ2; |
| @@ -182,7 +182,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev, | |||
| 182 | * string/package type. For PPI version 1.0 and 1.1, use buffer type | 182 | * string/package type. For PPI version 1.0 and 1.1, use buffer type |
| 183 | * for compatibility, and use package type since 1.2 according to spec. | 183 | * for compatibility, and use package type since 1.2 according to spec. |
| 184 | */ | 184 | */ |
| 185 | if (strcmp(version, "1.2") == -1) { | 185 | if (strcmp(version, "1.2") < 0) { |
| 186 | params[3].type = ACPI_TYPE_BUFFER; | 186 | params[3].type = ACPI_TYPE_BUFFER; |
| 187 | params[3].buffer.length = sizeof(req); | 187 | params[3].buffer.length = sizeof(req); |
| 188 | sscanf(buf, "%d", &req); | 188 | sscanf(buf, "%d", &req); |
| @@ -248,7 +248,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev, | |||
| 248 | * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for | 248 | * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for |
| 249 | * compatibility, define params[3].type as buffer, if PPI version < 1.2 | 249 | * compatibility, define params[3].type as buffer, if PPI version < 1.2 |
| 250 | */ | 250 | */ |
| 251 | if (strcmp(version, "1.2") == -1) { | 251 | if (strcmp(version, "1.2") < 0) { |
| 252 | params[3].type = ACPI_TYPE_BUFFER; | 252 | params[3].type = ACPI_TYPE_BUFFER; |
| 253 | params[3].buffer.length = 0; | 253 | params[3].buffer.length = 0; |
| 254 | params[3].buffer.pointer = NULL; | 254 | params[3].buffer.pointer = NULL; |
| @@ -390,7 +390,7 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) | |||
| 390 | kfree(output.pointer); | 390 | kfree(output.pointer); |
| 391 | output.length = ACPI_ALLOCATE_BUFFER; | 391 | output.length = ACPI_ALLOCATE_BUFFER; |
| 392 | output.pointer = NULL; | 392 | output.pointer = NULL; |
| 393 | if (strcmp(version, "1.2") == -1) | 393 | if (strcmp(version, "1.2") < 0) |
| 394 | return -EPERM; | 394 | return -EPERM; |
| 395 | 395 | ||
| 396 | params[2].integer.value = TPM_PPI_FN_GETOPR; | 396 | params[2].integer.value = TPM_PPI_FN_GETOPR; |
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 1b74459c0723..a9ed2270c25d 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
| @@ -432,45 +432,7 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status) | |||
| 432 | } | 432 | } |
| 433 | } | 433 | } |
| 434 | 434 | ||
| 435 | static const struct file_operations tis_ops = { | 435 | static const struct tpm_class_ops tpm_tis = { |
| 436 | .owner = THIS_MODULE, | ||
| 437 | .llseek = no_llseek, | ||
| 438 | .open = tpm_open, | ||
| 439 | .read = tpm_read, | ||
| 440 | .write = tpm_write, | ||
| 441 | .release = tpm_release, | ||
| 442 | }; | ||
| 443 | |||
| 444 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 445 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 446 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 447 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 448 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 449 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, | ||
| 450 | NULL); | ||
| 451 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 452 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 453 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
| 454 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
| 455 | |||
| 456 | static struct attribute *tis_attrs[] = { | ||
| 457 | &dev_attr_pubek.attr, | ||
| 458 | &dev_attr_pcrs.attr, | ||
| 459 | &dev_attr_enabled.attr, | ||
| 460 | &dev_attr_active.attr, | ||
| 461 | &dev_attr_owned.attr, | ||
| 462 | &dev_attr_temp_deactivated.attr, | ||
| 463 | &dev_attr_caps.attr, | ||
| 464 | &dev_attr_cancel.attr, | ||
| 465 | &dev_attr_durations.attr, | ||
| 466 | &dev_attr_timeouts.attr, NULL, | ||
| 467 | }; | ||
| 468 | |||
| 469 | static struct attribute_group tis_attr_grp = { | ||
| 470 | .attrs = tis_attrs | ||
| 471 | }; | ||
| 472 | |||
| 473 | static struct tpm_vendor_specific tpm_tis = { | ||
| 474 | .status = tpm_tis_status, | 436 | .status = tpm_tis_status, |
| 475 | .recv = tpm_tis_recv, | 437 | .recv = tpm_tis_recv, |
| 476 | .send = tpm_tis_send, | 438 | .send = tpm_tis_send, |
| @@ -478,9 +440,6 @@ static struct tpm_vendor_specific tpm_tis = { | |||
| 478 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 440 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 479 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 441 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 480 | .req_canceled = tpm_tis_req_canceled, | 442 | .req_canceled = tpm_tis_req_canceled, |
| 481 | .attr_group = &tis_attr_grp, | ||
| 482 | .miscdev = { | ||
| 483 | .fops = &tis_ops,}, | ||
| 484 | }; | 443 | }; |
| 485 | 444 | ||
| 486 | static irqreturn_t tis_int_probe(int irq, void *dev_id) | 445 | static irqreturn_t tis_int_probe(int irq, void *dev_id) |
| @@ -743,7 +702,7 @@ out_err: | |||
| 743 | return rc; | 702 | return rc; |
| 744 | } | 703 | } |
| 745 | 704 | ||
| 746 | #if defined(CONFIG_PNP) || defined(CONFIG_PM_SLEEP) | 705 | #ifdef CONFIG_PM_SLEEP |
| 747 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | 706 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) |
| 748 | { | 707 | { |
| 749 | u32 intmask; | 708 | u32 intmask; |
| @@ -764,9 +723,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | |||
| 764 | iowrite32(intmask, | 723 | iowrite32(intmask, |
| 765 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); | 724 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); |
| 766 | } | 725 | } |
| 767 | #endif | ||
| 768 | 726 | ||
| 769 | #ifdef CONFIG_PM_SLEEP | ||
| 770 | static int tpm_tis_resume(struct device *dev) | 727 | static int tpm_tis_resume(struct device *dev) |
| 771 | { | 728 | { |
| 772 | struct tpm_chip *chip = dev_get_drvdata(dev); | 729 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| @@ -835,11 +792,9 @@ static struct pnp_driver tis_pnp_driver = { | |||
| 835 | .id_table = tpm_pnp_tbl, | 792 | .id_table = tpm_pnp_tbl, |
| 836 | .probe = tpm_tis_pnp_init, | 793 | .probe = tpm_tis_pnp_init, |
| 837 | .remove = tpm_tis_pnp_remove, | 794 | .remove = tpm_tis_pnp_remove, |
| 838 | #ifdef CONFIG_PM_SLEEP | ||
| 839 | .driver = { | 795 | .driver = { |
| 840 | .pm = &tpm_tis_pm, | 796 | .pm = &tpm_tis_pm, |
| 841 | }, | 797 | }, |
| 842 | #endif | ||
| 843 | }; | 798 | }; |
| 844 | 799 | ||
| 845 | #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 | 800 | #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 |
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index c8ff4df81779..92b097064df5 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c | |||
| @@ -143,46 +143,7 @@ static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
| 143 | return length; | 143 | return length; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | static const struct file_operations vtpm_ops = { | 146 | static const struct tpm_class_ops tpm_vtpm = { |
| 147 | .owner = THIS_MODULE, | ||
| 148 | .llseek = no_llseek, | ||
| 149 | .open = tpm_open, | ||
| 150 | .read = tpm_read, | ||
| 151 | .write = tpm_write, | ||
| 152 | .release = tpm_release, | ||
| 153 | }; | ||
| 154 | |||
| 155 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
| 156 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
| 157 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
| 158 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
| 159 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
| 160 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, | ||
| 161 | NULL); | ||
| 162 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | ||
| 163 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
| 164 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
| 165 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
| 166 | |||
| 167 | static struct attribute *vtpm_attrs[] = { | ||
| 168 | &dev_attr_pubek.attr, | ||
| 169 | &dev_attr_pcrs.attr, | ||
| 170 | &dev_attr_enabled.attr, | ||
| 171 | &dev_attr_active.attr, | ||
| 172 | &dev_attr_owned.attr, | ||
| 173 | &dev_attr_temp_deactivated.attr, | ||
| 174 | &dev_attr_caps.attr, | ||
| 175 | &dev_attr_cancel.attr, | ||
| 176 | &dev_attr_durations.attr, | ||
| 177 | &dev_attr_timeouts.attr, | ||
| 178 | NULL, | ||
| 179 | }; | ||
| 180 | |||
| 181 | static struct attribute_group vtpm_attr_grp = { | ||
| 182 | .attrs = vtpm_attrs, | ||
| 183 | }; | ||
| 184 | |||
| 185 | static const struct tpm_vendor_specific tpm_vtpm = { | ||
| 186 | .status = vtpm_status, | 147 | .status = vtpm_status, |
| 187 | .recv = vtpm_recv, | 148 | .recv = vtpm_recv, |
| 188 | .send = vtpm_send, | 149 | .send = vtpm_send, |
| @@ -190,10 +151,6 @@ static const struct tpm_vendor_specific tpm_vtpm = { | |||
| 190 | .req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT, | 151 | .req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT, |
| 191 | .req_complete_val = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT, | 152 | .req_complete_val = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT, |
| 192 | .req_canceled = vtpm_req_canceled, | 153 | .req_canceled = vtpm_req_canceled, |
| 193 | .attr_group = &vtpm_attr_grp, | ||
| 194 | .miscdev = { | ||
| 195 | .fops = &vtpm_ops, | ||
| 196 | }, | ||
| 197 | }; | 154 | }; |
| 198 | 155 | ||
| 199 | static irqreturn_t tpmif_interrupt(int dummy, void *dev_id) | 156 | static irqreturn_t tpmif_interrupt(int dummy, void *dev_id) |
diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 9a9051bb1a03..fff1d0976f80 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h | |||
| @@ -29,6 +29,18 @@ | |||
| 29 | */ | 29 | */ |
| 30 | #define TPM_ANY_NUM 0xFFFF | 30 | #define TPM_ANY_NUM 0xFFFF |
| 31 | 31 | ||
| 32 | struct tpm_chip; | ||
| 33 | |||
| 34 | struct tpm_class_ops { | ||
| 35 | const u8 req_complete_mask; | ||
| 36 | const u8 req_complete_val; | ||
| 37 | bool (*req_canceled)(struct tpm_chip *chip, u8 status); | ||
| 38 | int (*recv) (struct tpm_chip *chip, u8 *buf, size_t len); | ||
| 39 | int (*send) (struct tpm_chip *chip, u8 *buf, size_t len); | ||
| 40 | void (*cancel) (struct tpm_chip *chip); | ||
| 41 | u8 (*status) (struct tpm_chip *chip); | ||
| 42 | }; | ||
| 43 | |||
| 32 | #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) | 44 | #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) |
| 33 | 45 | ||
| 34 | extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); | 46 | extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); |
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index c38adcc910fb..1683bbf289a4 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c | |||
| @@ -162,8 +162,7 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show, | |||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, | 164 | static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, |
| 165 | struct ima_field_data *field_data, | 165 | struct ima_field_data *field_data) |
| 166 | bool size_limit) | ||
| 167 | { | 166 | { |
| 168 | /* | 167 | /* |
| 169 | * digest formats: | 168 | * digest formats: |
| @@ -176,11 +175,10 @@ static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, | |||
| 176 | enum data_formats fmt = DATA_FMT_DIGEST; | 175 | enum data_formats fmt = DATA_FMT_DIGEST; |
| 177 | u32 offset = 0; | 176 | u32 offset = 0; |
| 178 | 177 | ||
| 179 | if (!size_limit) { | 178 | if (hash_algo < HASH_ALGO__LAST) { |
| 180 | fmt = DATA_FMT_DIGEST_WITH_ALGO; | 179 | fmt = DATA_FMT_DIGEST_WITH_ALGO; |
| 181 | if (hash_algo < HASH_ALGO__LAST) | 180 | offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s", |
| 182 | offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, | 181 | hash_algo_name[hash_algo]); |
| 183 | "%s", hash_algo_name[hash_algo]); | ||
| 184 | buffer[offset] = ':'; | 182 | buffer[offset] = ':'; |
| 185 | offset += 2; | 183 | offset += 2; |
| 186 | } | 184 | } |
| @@ -243,8 +241,8 @@ int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file, | |||
| 243 | cur_digest = hash.hdr.digest; | 241 | cur_digest = hash.hdr.digest; |
| 244 | cur_digestsize = hash.hdr.length; | 242 | cur_digestsize = hash.hdr.length; |
| 245 | out: | 243 | out: |
| 246 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, -1, | 244 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, |
| 247 | field_data, true); | 245 | HASH_ALGO__LAST, field_data); |
| 248 | } | 246 | } |
| 249 | 247 | ||
| 250 | /* | 248 | /* |
| @@ -255,7 +253,7 @@ int ima_eventdigest_ng_init(struct integrity_iint_cache *iint, | |||
| 255 | struct evm_ima_xattr_data *xattr_value, | 253 | struct evm_ima_xattr_data *xattr_value, |
| 256 | int xattr_len, struct ima_field_data *field_data) | 254 | int xattr_len, struct ima_field_data *field_data) |
| 257 | { | 255 | { |
| 258 | u8 *cur_digest = NULL, hash_algo = HASH_ALGO__LAST; | 256 | u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1; |
| 259 | u32 cur_digestsize = 0; | 257 | u32 cur_digestsize = 0; |
| 260 | 258 | ||
| 261 | /* If iint is NULL, we are recording a violation. */ | 259 | /* If iint is NULL, we are recording a violation. */ |
| @@ -268,7 +266,7 @@ int ima_eventdigest_ng_init(struct integrity_iint_cache *iint, | |||
| 268 | hash_algo = iint->ima_hash->algo; | 266 | hash_algo = iint->ima_hash->algo; |
| 269 | out: | 267 | out: |
| 270 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, | 268 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, |
| 271 | hash_algo, field_data, false); | 269 | hash_algo, field_data); |
| 272 | } | 270 | } |
| 273 | 271 | ||
| 274 | static int ima_eventname_init_common(struct integrity_iint_cache *iint, | 272 | static int ima_eventname_init_common(struct integrity_iint_cache *iint, |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 57b0b49f4e6e..4b34847208cc 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -82,7 +82,6 @@ | |||
| 82 | #include <linux/syslog.h> | 82 | #include <linux/syslog.h> |
| 83 | #include <linux/user_namespace.h> | 83 | #include <linux/user_namespace.h> |
| 84 | #include <linux/export.h> | 84 | #include <linux/export.h> |
| 85 | #include <linux/security.h> | ||
| 86 | #include <linux/msg.h> | 85 | #include <linux/msg.h> |
| 87 | #include <linux/shm.h> | 86 | #include <linux/shm.h> |
| 88 | 87 | ||
| @@ -4490,14 +4489,10 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4490 | { | 4489 | { |
| 4491 | struct sk_security_struct *sksec = sk->sk_security; | 4490 | struct sk_security_struct *sksec = sk->sk_security; |
| 4492 | int err; | 4491 | int err; |
| 4493 | u16 family = sk->sk_family; | 4492 | u16 family = req->rsk_ops->family; |
| 4494 | u32 connsid; | 4493 | u32 connsid; |
| 4495 | u32 peersid; | 4494 | u32 peersid; |
| 4496 | 4495 | ||
| 4497 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ | ||
| 4498 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
| 4499 | family = PF_INET; | ||
| 4500 | |||
| 4501 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | 4496 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); |
| 4502 | if (err) | 4497 | if (err) |
| 4503 | return err; | 4498 | return err; |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index fe341ae37004..8ed8daf7f1ee 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
| @@ -33,13 +33,14 @@ | |||
| 33 | #define POLICYDB_VERSION_ROLETRANS 26 | 33 | #define POLICYDB_VERSION_ROLETRANS 26 |
| 34 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 | 34 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 |
| 35 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 | 35 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 |
| 36 | #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 | ||
| 36 | 37 | ||
| 37 | /* Range of policy versions we understand*/ | 38 | /* Range of policy versions we understand*/ |
| 38 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 39 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
| 39 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 40 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
| 40 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 41 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
| 41 | #else | 42 | #else |
| 42 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE | 43 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES |
| 43 | #endif | 44 | #endif |
| 44 | 45 | ||
| 45 | /* Mask for just the mount related flags */ | 46 | /* Mask for just the mount related flags */ |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 6235d052338b..0364120d1ec8 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -101,6 +101,32 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) | |||
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /** | 103 | /** |
| 104 | * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr | ||
| 105 | * @sk: the socket | ||
| 106 | * @sid: the SID | ||
| 107 | * | ||
| 108 | * Query the socket's cached secattr and if the SID matches the cached value | ||
| 109 | * return the cache, otherwise return NULL. | ||
| 110 | * | ||
| 111 | */ | ||
| 112 | static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr( | ||
| 113 | const struct sock *sk, | ||
| 114 | u32 sid) | ||
| 115 | { | ||
| 116 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 117 | struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr; | ||
| 118 | |||
| 119 | if (secattr == NULL) | ||
| 120 | return NULL; | ||
| 121 | |||
| 122 | if ((secattr->flags & NETLBL_SECATTR_SECID) && | ||
| 123 | (secattr->attr.secid == sid)) | ||
| 124 | return secattr; | ||
| 125 | |||
| 126 | return NULL; | ||
| 127 | } | ||
| 128 | |||
| 129 | /** | ||
| 104 | * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache | 130 | * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache |
| 105 | * | 131 | * |
| 106 | * Description: | 132 | * Description: |
| @@ -224,7 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
| 224 | struct sk_security_struct *sksec = sk->sk_security; | 250 | struct sk_security_struct *sksec = sk->sk_security; |
| 225 | if (sksec->nlbl_state != NLBL_REQSKB) | 251 | if (sksec->nlbl_state != NLBL_REQSKB) |
| 226 | return 0; | 252 | return 0; |
| 227 | secattr = sksec->nlbl_secattr; | 253 | secattr = selinux_netlbl_sock_getattr(sk, sid); |
| 228 | } | 254 | } |
| 229 | if (secattr == NULL) { | 255 | if (secattr == NULL) { |
| 230 | secattr = &secattr_storage; | 256 | secattr = &secattr_storage; |
| @@ -410,6 +436,9 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 410 | sksec->nlbl_state == NLBL_CONNLABELED)) { | 436 | sksec->nlbl_state == NLBL_CONNLABELED)) { |
| 411 | netlbl_secattr_init(&secattr); | 437 | netlbl_secattr_init(&secattr); |
| 412 | lock_sock(sk); | 438 | lock_sock(sk); |
| 439 | /* call the netlabel function directly as we want to see the | ||
| 440 | * on-the-wire label that is assigned via the socket's options | ||
| 441 | * and not the cached netlabel/lsm attributes */ | ||
| 413 | rc = netlbl_sock_getattr(sk, &secattr); | 442 | rc = netlbl_sock_getattr(sk, &secattr); |
| 414 | release_sock(sk); | 443 | release_sock(sk); |
| 415 | if (rc == 0) | 444 | if (rc == 0) |
diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h index 149dda731fd3..96fd947c494b 100644 --- a/security/selinux/ss/constraint.h +++ b/security/selinux/ss/constraint.h | |||
| @@ -48,6 +48,7 @@ struct constraint_expr { | |||
| 48 | u32 op; /* operator */ | 48 | u32 op; /* operator */ |
| 49 | 49 | ||
| 50 | struct ebitmap names; /* names */ | 50 | struct ebitmap names; /* names */ |
| 51 | struct type_set *type_names; | ||
| 51 | 52 | ||
| 52 | struct constraint_expr *next; /* next expression */ | 53 | struct constraint_expr *next; /* next expression */ |
| 53 | }; | 54 | }; |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f6195ebde3c9..c0f498842129 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -143,6 +143,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
| 143 | .sym_num = SYM_NUM, | 143 | .sym_num = SYM_NUM, |
| 144 | .ocon_num = OCON_NUM, | 144 | .ocon_num = OCON_NUM, |
| 145 | }, | 145 | }, |
| 146 | { | ||
| 147 | .version = POLICYDB_VERSION_CONSTRAINT_NAMES, | ||
| 148 | .sym_num = SYM_NUM, | ||
| 149 | .ocon_num = OCON_NUM, | ||
| 150 | }, | ||
| 146 | }; | 151 | }; |
| 147 | 152 | ||
| 148 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 153 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
| @@ -613,6 +618,19 @@ static int common_destroy(void *key, void *datum, void *p) | |||
| 613 | return 0; | 618 | return 0; |
| 614 | } | 619 | } |
| 615 | 620 | ||
| 621 | static void constraint_expr_destroy(struct constraint_expr *expr) | ||
| 622 | { | ||
| 623 | if (expr) { | ||
| 624 | ebitmap_destroy(&expr->names); | ||
| 625 | if (expr->type_names) { | ||
| 626 | ebitmap_destroy(&expr->type_names->types); | ||
| 627 | ebitmap_destroy(&expr->type_names->negset); | ||
| 628 | kfree(expr->type_names); | ||
| 629 | } | ||
| 630 | kfree(expr); | ||
| 631 | } | ||
| 632 | } | ||
| 633 | |||
| 616 | static int cls_destroy(void *key, void *datum, void *p) | 634 | static int cls_destroy(void *key, void *datum, void *p) |
| 617 | { | 635 | { |
| 618 | struct class_datum *cladatum; | 636 | struct class_datum *cladatum; |
| @@ -628,10 +646,9 @@ static int cls_destroy(void *key, void *datum, void *p) | |||
| 628 | while (constraint) { | 646 | while (constraint) { |
| 629 | e = constraint->expr; | 647 | e = constraint->expr; |
| 630 | while (e) { | 648 | while (e) { |
| 631 | ebitmap_destroy(&e->names); | ||
| 632 | etmp = e; | 649 | etmp = e; |
| 633 | e = e->next; | 650 | e = e->next; |
| 634 | kfree(etmp); | 651 | constraint_expr_destroy(etmp); |
| 635 | } | 652 | } |
| 636 | ctemp = constraint; | 653 | ctemp = constraint; |
| 637 | constraint = constraint->next; | 654 | constraint = constraint->next; |
| @@ -642,16 +659,14 @@ static int cls_destroy(void *key, void *datum, void *p) | |||
| 642 | while (constraint) { | 659 | while (constraint) { |
| 643 | e = constraint->expr; | 660 | e = constraint->expr; |
| 644 | while (e) { | 661 | while (e) { |
| 645 | ebitmap_destroy(&e->names); | ||
| 646 | etmp = e; | 662 | etmp = e; |
| 647 | e = e->next; | 663 | e = e->next; |
| 648 | kfree(etmp); | 664 | constraint_expr_destroy(etmp); |
| 649 | } | 665 | } |
| 650 | ctemp = constraint; | 666 | ctemp = constraint; |
| 651 | constraint = constraint->next; | 667 | constraint = constraint->next; |
| 652 | kfree(ctemp); | 668 | kfree(ctemp); |
| 653 | } | 669 | } |
| 654 | |||
| 655 | kfree(cladatum->comkey); | 670 | kfree(cladatum->comkey); |
| 656 | } | 671 | } |
| 657 | kfree(datum); | 672 | kfree(datum); |
| @@ -1156,8 +1171,34 @@ bad: | |||
| 1156 | return rc; | 1171 | return rc; |
| 1157 | } | 1172 | } |
| 1158 | 1173 | ||
| 1159 | static int read_cons_helper(struct constraint_node **nodep, int ncons, | 1174 | static void type_set_init(struct type_set *t) |
| 1160 | int allowxtarget, void *fp) | 1175 | { |
| 1176 | ebitmap_init(&t->types); | ||
| 1177 | ebitmap_init(&t->negset); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | static int type_set_read(struct type_set *t, void *fp) | ||
| 1181 | { | ||
| 1182 | __le32 buf[1]; | ||
| 1183 | int rc; | ||
| 1184 | |||
| 1185 | if (ebitmap_read(&t->types, fp)) | ||
| 1186 | return -EINVAL; | ||
| 1187 | if (ebitmap_read(&t->negset, fp)) | ||
| 1188 | return -EINVAL; | ||
| 1189 | |||
| 1190 | rc = next_entry(buf, fp, sizeof(u32)); | ||
| 1191 | if (rc < 0) | ||
| 1192 | return -EINVAL; | ||
| 1193 | t->flags = le32_to_cpu(buf[0]); | ||
| 1194 | |||
| 1195 | return 0; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | |||
| 1199 | static int read_cons_helper(struct policydb *p, | ||
| 1200 | struct constraint_node **nodep, | ||
| 1201 | int ncons, int allowxtarget, void *fp) | ||
| 1161 | { | 1202 | { |
| 1162 | struct constraint_node *c, *lc; | 1203 | struct constraint_node *c, *lc; |
| 1163 | struct constraint_expr *e, *le; | 1204 | struct constraint_expr *e, *le; |
| @@ -1225,6 +1266,18 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, | |||
| 1225 | rc = ebitmap_read(&e->names, fp); | 1266 | rc = ebitmap_read(&e->names, fp); |
| 1226 | if (rc) | 1267 | if (rc) |
| 1227 | return rc; | 1268 | return rc; |
| 1269 | if (p->policyvers >= | ||
| 1270 | POLICYDB_VERSION_CONSTRAINT_NAMES) { | ||
| 1271 | e->type_names = kzalloc(sizeof | ||
| 1272 | (*e->type_names), | ||
| 1273 | GFP_KERNEL); | ||
| 1274 | if (!e->type_names) | ||
| 1275 | return -ENOMEM; | ||
| 1276 | type_set_init(e->type_names); | ||
| 1277 | rc = type_set_read(e->type_names, fp); | ||
| 1278 | if (rc) | ||
| 1279 | return rc; | ||
| 1280 | } | ||
| 1228 | break; | 1281 | break; |
| 1229 | default: | 1282 | default: |
| 1230 | return -EINVAL; | 1283 | return -EINVAL; |
| @@ -1301,7 +1354,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1301 | goto bad; | 1354 | goto bad; |
| 1302 | } | 1355 | } |
| 1303 | 1356 | ||
| 1304 | rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp); | 1357 | rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp); |
| 1305 | if (rc) | 1358 | if (rc) |
| 1306 | goto bad; | 1359 | goto bad; |
| 1307 | 1360 | ||
| @@ -1311,7 +1364,8 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1311 | if (rc) | 1364 | if (rc) |
| 1312 | goto bad; | 1365 | goto bad; |
| 1313 | ncons = le32_to_cpu(buf[0]); | 1366 | ncons = le32_to_cpu(buf[0]); |
| 1314 | rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); | 1367 | rc = read_cons_helper(p, &cladatum->validatetrans, |
| 1368 | ncons, 1, fp); | ||
| 1315 | if (rc) | 1369 | if (rc) |
| 1316 | goto bad; | 1370 | goto bad; |
| 1317 | } | 1371 | } |
| @@ -1941,7 +1995,19 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
| 1941 | if (rc) | 1995 | if (rc) |
| 1942 | goto out; | 1996 | goto out; |
| 1943 | 1997 | ||
| 1944 | hashtab_insert(p->filename_trans, ft, otype); | 1998 | rc = hashtab_insert(p->filename_trans, ft, otype); |
| 1999 | if (rc) { | ||
| 2000 | /* | ||
| 2001 | * Do not return -EEXIST to the caller, or the system | ||
| 2002 | * will not boot. | ||
| 2003 | */ | ||
| 2004 | if (rc != -EEXIST) | ||
| 2005 | goto out; | ||
| 2006 | /* But free memory to avoid memory leak. */ | ||
| 2007 | kfree(ft); | ||
| 2008 | kfree(name); | ||
| 2009 | kfree(otype); | ||
| 2010 | } | ||
| 1945 | } | 2011 | } |
| 1946 | hash_eval(p->filename_trans, "filenametr"); | 2012 | hash_eval(p->filename_trans, "filenametr"); |
| 1947 | return 0; | 2013 | return 0; |
| @@ -2753,6 +2819,24 @@ static int common_write(void *vkey, void *datum, void *ptr) | |||
| 2753 | return 0; | 2819 | return 0; |
| 2754 | } | 2820 | } |
| 2755 | 2821 | ||
| 2822 | static int type_set_write(struct type_set *t, void *fp) | ||
| 2823 | { | ||
| 2824 | int rc; | ||
| 2825 | __le32 buf[1]; | ||
| 2826 | |||
| 2827 | if (ebitmap_write(&t->types, fp)) | ||
| 2828 | return -EINVAL; | ||
| 2829 | if (ebitmap_write(&t->negset, fp)) | ||
| 2830 | return -EINVAL; | ||
| 2831 | |||
| 2832 | buf[0] = cpu_to_le32(t->flags); | ||
| 2833 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
| 2834 | if (rc) | ||
| 2835 | return -EINVAL; | ||
| 2836 | |||
| 2837 | return 0; | ||
| 2838 | } | ||
| 2839 | |||
| 2756 | static int write_cons_helper(struct policydb *p, struct constraint_node *node, | 2840 | static int write_cons_helper(struct policydb *p, struct constraint_node *node, |
| 2757 | void *fp) | 2841 | void *fp) |
| 2758 | { | 2842 | { |
| @@ -2784,6 +2868,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node, | |||
| 2784 | rc = ebitmap_write(&e->names, fp); | 2868 | rc = ebitmap_write(&e->names, fp); |
| 2785 | if (rc) | 2869 | if (rc) |
| 2786 | return rc; | 2870 | return rc; |
| 2871 | if (p->policyvers >= | ||
| 2872 | POLICYDB_VERSION_CONSTRAINT_NAMES) { | ||
| 2873 | rc = type_set_write(e->type_names, fp); | ||
| 2874 | if (rc) | ||
| 2875 | return rc; | ||
| 2876 | } | ||
| 2787 | break; | 2877 | break; |
| 2788 | default: | 2878 | default: |
| 2789 | break; | 2879 | break; |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index da637471d4ce..725d5945a97e 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
| @@ -154,6 +154,17 @@ struct cond_bool_datum { | |||
| 154 | struct cond_node; | 154 | struct cond_node; |
| 155 | 155 | ||
| 156 | /* | 156 | /* |
| 157 | * type set preserves data needed to determine constraint info from | ||
| 158 | * policy source. This is not used by the kernel policy but allows | ||
| 159 | * utilities such as audit2allow to determine constraint denials. | ||
| 160 | */ | ||
| 161 | struct type_set { | ||
| 162 | struct ebitmap types; | ||
| 163 | struct ebitmap negset; | ||
| 164 | u32 flags; | ||
| 165 | }; | ||
| 166 | |||
| 167 | /* | ||
| 157 | * The configuration data includes security contexts for | 168 | * The configuration data includes security contexts for |
| 158 | * initial SIDs, unlabeled file systems, TCP and UDP port numbers, | 169 | * initial SIDs, unlabeled file systems, TCP and UDP port numbers, |
| 159 | * network interfaces, and nodes. This structure stores the | 170 | * network interfaces, and nodes. This structure stores the |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d106733ad987..fc5a63a05a1c 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -1831,7 +1831,7 @@ static int security_preserve_bools(struct policydb *p); | |||
| 1831 | */ | 1831 | */ |
| 1832 | int security_load_policy(void *data, size_t len) | 1832 | int security_load_policy(void *data, size_t len) |
| 1833 | { | 1833 | { |
| 1834 | struct policydb oldpolicydb, newpolicydb; | 1834 | struct policydb *oldpolicydb, *newpolicydb; |
| 1835 | struct sidtab oldsidtab, newsidtab; | 1835 | struct sidtab oldsidtab, newsidtab; |
| 1836 | struct selinux_mapping *oldmap, *map = NULL; | 1836 | struct selinux_mapping *oldmap, *map = NULL; |
| 1837 | struct convert_context_args args; | 1837 | struct convert_context_args args; |
| @@ -1840,12 +1840,19 @@ int security_load_policy(void *data, size_t len) | |||
| 1840 | int rc = 0; | 1840 | int rc = 0; |
| 1841 | struct policy_file file = { data, len }, *fp = &file; | 1841 | struct policy_file file = { data, len }, *fp = &file; |
| 1842 | 1842 | ||
| 1843 | oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); | ||
| 1844 | if (!oldpolicydb) { | ||
| 1845 | rc = -ENOMEM; | ||
| 1846 | goto out; | ||
| 1847 | } | ||
| 1848 | newpolicydb = oldpolicydb + 1; | ||
| 1849 | |||
| 1843 | if (!ss_initialized) { | 1850 | if (!ss_initialized) { |
| 1844 | avtab_cache_init(); | 1851 | avtab_cache_init(); |
| 1845 | rc = policydb_read(&policydb, fp); | 1852 | rc = policydb_read(&policydb, fp); |
| 1846 | if (rc) { | 1853 | if (rc) { |
| 1847 | avtab_cache_destroy(); | 1854 | avtab_cache_destroy(); |
| 1848 | return rc; | 1855 | goto out; |
| 1849 | } | 1856 | } |
| 1850 | 1857 | ||
| 1851 | policydb.len = len; | 1858 | policydb.len = len; |
| @@ -1855,14 +1862,14 @@ int security_load_policy(void *data, size_t len) | |||
| 1855 | if (rc) { | 1862 | if (rc) { |
| 1856 | policydb_destroy(&policydb); | 1863 | policydb_destroy(&policydb); |
| 1857 | avtab_cache_destroy(); | 1864 | avtab_cache_destroy(); |
| 1858 | return rc; | 1865 | goto out; |
| 1859 | } | 1866 | } |
| 1860 | 1867 | ||
| 1861 | rc = policydb_load_isids(&policydb, &sidtab); | 1868 | rc = policydb_load_isids(&policydb, &sidtab); |
| 1862 | if (rc) { | 1869 | if (rc) { |
| 1863 | policydb_destroy(&policydb); | 1870 | policydb_destroy(&policydb); |
| 1864 | avtab_cache_destroy(); | 1871 | avtab_cache_destroy(); |
| 1865 | return rc; | 1872 | goto out; |
| 1866 | } | 1873 | } |
| 1867 | 1874 | ||
| 1868 | security_load_policycaps(); | 1875 | security_load_policycaps(); |
| @@ -1874,36 +1881,36 @@ int security_load_policy(void *data, size_t len) | |||
| 1874 | selinux_status_update_policyload(seqno); | 1881 | selinux_status_update_policyload(seqno); |
| 1875 | selinux_netlbl_cache_invalidate(); | 1882 | selinux_netlbl_cache_invalidate(); |
| 1876 | selinux_xfrm_notify_policyload(); | 1883 | selinux_xfrm_notify_policyload(); |
| 1877 | return 0; | 1884 | goto out; |
| 1878 | } | 1885 | } |
| 1879 | 1886 | ||
| 1880 | #if 0 | 1887 | #if 0 |
| 1881 | sidtab_hash_eval(&sidtab, "sids"); | 1888 | sidtab_hash_eval(&sidtab, "sids"); |
| 1882 | #endif | 1889 | #endif |
| 1883 | 1890 | ||
| 1884 | rc = policydb_read(&newpolicydb, fp); | 1891 | rc = policydb_read(newpolicydb, fp); |
| 1885 | if (rc) | 1892 | if (rc) |
| 1886 | return rc; | 1893 | goto out; |
| 1887 | 1894 | ||
| 1888 | newpolicydb.len = len; | 1895 | newpolicydb->len = len; |
| 1889 | /* If switching between different policy types, log MLS status */ | 1896 | /* If switching between different policy types, log MLS status */ |
| 1890 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | 1897 | if (policydb.mls_enabled && !newpolicydb->mls_enabled) |
| 1891 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); | 1898 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); |
| 1892 | else if (!policydb.mls_enabled && newpolicydb.mls_enabled) | 1899 | else if (!policydb.mls_enabled && newpolicydb->mls_enabled) |
| 1893 | printk(KERN_INFO "SELinux: Enabling MLS support...\n"); | 1900 | printk(KERN_INFO "SELinux: Enabling MLS support...\n"); |
| 1894 | 1901 | ||
| 1895 | rc = policydb_load_isids(&newpolicydb, &newsidtab); | 1902 | rc = policydb_load_isids(newpolicydb, &newsidtab); |
| 1896 | if (rc) { | 1903 | if (rc) { |
| 1897 | printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); | 1904 | printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); |
| 1898 | policydb_destroy(&newpolicydb); | 1905 | policydb_destroy(newpolicydb); |
| 1899 | return rc; | 1906 | goto out; |
| 1900 | } | 1907 | } |
| 1901 | 1908 | ||
| 1902 | rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); | 1909 | rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size); |
| 1903 | if (rc) | 1910 | if (rc) |
| 1904 | goto err; | 1911 | goto err; |
| 1905 | 1912 | ||
| 1906 | rc = security_preserve_bools(&newpolicydb); | 1913 | rc = security_preserve_bools(newpolicydb); |
| 1907 | if (rc) { | 1914 | if (rc) { |
| 1908 | printk(KERN_ERR "SELinux: unable to preserve booleans\n"); | 1915 | printk(KERN_ERR "SELinux: unable to preserve booleans\n"); |
| 1909 | goto err; | 1916 | goto err; |
| @@ -1921,7 +1928,7 @@ int security_load_policy(void *data, size_t len) | |||
| 1921 | * in the new SID table. | 1928 | * in the new SID table. |
| 1922 | */ | 1929 | */ |
| 1923 | args.oldp = &policydb; | 1930 | args.oldp = &policydb; |
| 1924 | args.newp = &newpolicydb; | 1931 | args.newp = newpolicydb; |
| 1925 | rc = sidtab_map(&newsidtab, convert_context, &args); | 1932 | rc = sidtab_map(&newsidtab, convert_context, &args); |
| 1926 | if (rc) { | 1933 | if (rc) { |
| 1927 | printk(KERN_ERR "SELinux: unable to convert the internal" | 1934 | printk(KERN_ERR "SELinux: unable to convert the internal" |
| @@ -1931,12 +1938,12 @@ int security_load_policy(void *data, size_t len) | |||
| 1931 | } | 1938 | } |
| 1932 | 1939 | ||
| 1933 | /* Save the old policydb and SID table to free later. */ | 1940 | /* Save the old policydb and SID table to free later. */ |
| 1934 | memcpy(&oldpolicydb, &policydb, sizeof policydb); | 1941 | memcpy(oldpolicydb, &policydb, sizeof(policydb)); |
| 1935 | sidtab_set(&oldsidtab, &sidtab); | 1942 | sidtab_set(&oldsidtab, &sidtab); |
| 1936 | 1943 | ||
| 1937 | /* Install the new policydb and SID table. */ | 1944 | /* Install the new policydb and SID table. */ |
| 1938 | write_lock_irq(&policy_rwlock); | 1945 | write_lock_irq(&policy_rwlock); |
| 1939 | memcpy(&policydb, &newpolicydb, sizeof policydb); | 1946 | memcpy(&policydb, newpolicydb, sizeof(policydb)); |
| 1940 | sidtab_set(&sidtab, &newsidtab); | 1947 | sidtab_set(&sidtab, &newsidtab); |
| 1941 | security_load_policycaps(); | 1948 | security_load_policycaps(); |
| 1942 | oldmap = current_mapping; | 1949 | oldmap = current_mapping; |
| @@ -1946,7 +1953,7 @@ int security_load_policy(void *data, size_t len) | |||
| 1946 | write_unlock_irq(&policy_rwlock); | 1953 | write_unlock_irq(&policy_rwlock); |
| 1947 | 1954 | ||
| 1948 | /* Free the old policydb and SID table. */ | 1955 | /* Free the old policydb and SID table. */ |
| 1949 | policydb_destroy(&oldpolicydb); | 1956 | policydb_destroy(oldpolicydb); |
| 1950 | sidtab_destroy(&oldsidtab); | 1957 | sidtab_destroy(&oldsidtab); |
| 1951 | kfree(oldmap); | 1958 | kfree(oldmap); |
| 1952 | 1959 | ||
| @@ -1956,14 +1963,17 @@ int security_load_policy(void *data, size_t len) | |||
| 1956 | selinux_netlbl_cache_invalidate(); | 1963 | selinux_netlbl_cache_invalidate(); |
| 1957 | selinux_xfrm_notify_policyload(); | 1964 | selinux_xfrm_notify_policyload(); |
| 1958 | 1965 | ||
| 1959 | return 0; | 1966 | rc = 0; |
| 1967 | goto out; | ||
| 1960 | 1968 | ||
| 1961 | err: | 1969 | err: |
| 1962 | kfree(map); | 1970 | kfree(map); |
| 1963 | sidtab_destroy(&newsidtab); | 1971 | sidtab_destroy(&newsidtab); |
| 1964 | policydb_destroy(&newpolicydb); | 1972 | policydb_destroy(newpolicydb); |
| 1965 | return rc; | ||
| 1966 | 1973 | ||
| 1974 | out: | ||
| 1975 | kfree(oldpolicydb); | ||
| 1976 | return rc; | ||
| 1967 | } | 1977 | } |
| 1968 | 1978 | ||
| 1969 | size_t security_policydb_len(void) | 1979 | size_t security_policydb_len(void) |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 364cc64fce71..d072fd32212d 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
| @@ -241,7 +241,8 @@ u32 smack_to_secid(const char *); | |||
| 241 | extern int smack_cipso_direct; | 241 | extern int smack_cipso_direct; |
| 242 | extern int smack_cipso_mapped; | 242 | extern int smack_cipso_mapped; |
| 243 | extern struct smack_known *smack_net_ambient; | 243 | extern struct smack_known *smack_net_ambient; |
| 244 | extern char *smack_onlycap; | 244 | extern struct smack_known *smack_onlycap; |
| 245 | extern struct smack_known *smack_syslog_label; | ||
| 245 | extern const char *smack_cipso_option; | 246 | extern const char *smack_cipso_option; |
| 246 | 247 | ||
| 247 | extern struct smack_known smack_known_floor; | 248 | extern struct smack_known smack_known_floor; |
| @@ -312,7 +313,7 @@ static inline int smack_privileged(int cap) | |||
| 312 | 313 | ||
| 313 | if (!capable(cap)) | 314 | if (!capable(cap)) |
| 314 | return 0; | 315 | return 0; |
| 315 | if (smack_onlycap == NULL || smack_onlycap == skp->smk_known) | 316 | if (smack_onlycap == NULL || smack_onlycap == skp) |
| 316 | return 1; | 317 | return 1; |
| 317 | return 0; | 318 | return 0; |
| 318 | } | 319 | } |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index b0be893ad44d..d814e35987be 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -219,8 +219,6 @@ static int smack_ptrace_traceme(struct task_struct *ptp) | |||
| 219 | * smack_syslog - Smack approval on syslog | 219 | * smack_syslog - Smack approval on syslog |
| 220 | * @type: message type | 220 | * @type: message type |
| 221 | * | 221 | * |
| 222 | * Require that the task has the floor label | ||
| 223 | * | ||
| 224 | * Returns 0 on success, error code otherwise. | 222 | * Returns 0 on success, error code otherwise. |
| 225 | */ | 223 | */ |
| 226 | static int smack_syslog(int typefrom_file) | 224 | static int smack_syslog(int typefrom_file) |
| @@ -231,7 +229,7 @@ static int smack_syslog(int typefrom_file) | |||
| 231 | if (smack_privileged(CAP_MAC_OVERRIDE)) | 229 | if (smack_privileged(CAP_MAC_OVERRIDE)) |
| 232 | return 0; | 230 | return 0; |
| 233 | 231 | ||
| 234 | if (skp != &smack_known_floor) | 232 | if (smack_syslog_label != NULL && smack_syslog_label != skp) |
| 235 | rc = -EACCES; | 233 | rc = -EACCES; |
| 236 | 234 | ||
| 237 | return rc; | 235 | return rc; |
| @@ -341,10 +339,12 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 341 | struct inode *inode = root->d_inode; | 339 | struct inode *inode = root->d_inode; |
| 342 | struct superblock_smack *sp = sb->s_security; | 340 | struct superblock_smack *sp = sb->s_security; |
| 343 | struct inode_smack *isp; | 341 | struct inode_smack *isp; |
| 342 | struct smack_known *skp; | ||
| 344 | char *op; | 343 | char *op; |
| 345 | char *commap; | 344 | char *commap; |
| 346 | char *nsp; | 345 | char *nsp; |
| 347 | int transmute = 0; | 346 | int transmute = 0; |
| 347 | int specified = 0; | ||
| 348 | 348 | ||
| 349 | if (sp->smk_initialized) | 349 | if (sp->smk_initialized) |
| 350 | return 0; | 350 | return 0; |
| @@ -359,34 +359,56 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 359 | if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { | 359 | if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { |
| 360 | op += strlen(SMK_FSHAT); | 360 | op += strlen(SMK_FSHAT); |
| 361 | nsp = smk_import(op, 0); | 361 | nsp = smk_import(op, 0); |
| 362 | if (nsp != NULL) | 362 | if (nsp != NULL) { |
| 363 | sp->smk_hat = nsp; | 363 | sp->smk_hat = nsp; |
| 364 | specified = 1; | ||
| 365 | } | ||
| 364 | } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { | 366 | } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { |
| 365 | op += strlen(SMK_FSFLOOR); | 367 | op += strlen(SMK_FSFLOOR); |
| 366 | nsp = smk_import(op, 0); | 368 | nsp = smk_import(op, 0); |
| 367 | if (nsp != NULL) | 369 | if (nsp != NULL) { |
| 368 | sp->smk_floor = nsp; | 370 | sp->smk_floor = nsp; |
| 371 | specified = 1; | ||
| 372 | } | ||
| 369 | } else if (strncmp(op, SMK_FSDEFAULT, | 373 | } else if (strncmp(op, SMK_FSDEFAULT, |
| 370 | strlen(SMK_FSDEFAULT)) == 0) { | 374 | strlen(SMK_FSDEFAULT)) == 0) { |
| 371 | op += strlen(SMK_FSDEFAULT); | 375 | op += strlen(SMK_FSDEFAULT); |
| 372 | nsp = smk_import(op, 0); | 376 | nsp = smk_import(op, 0); |
| 373 | if (nsp != NULL) | 377 | if (nsp != NULL) { |
| 374 | sp->smk_default = nsp; | 378 | sp->smk_default = nsp; |
| 379 | specified = 1; | ||
| 380 | } | ||
| 375 | } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { | 381 | } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { |
| 376 | op += strlen(SMK_FSROOT); | 382 | op += strlen(SMK_FSROOT); |
| 377 | nsp = smk_import(op, 0); | 383 | nsp = smk_import(op, 0); |
| 378 | if (nsp != NULL) | 384 | if (nsp != NULL) { |
| 379 | sp->smk_root = nsp; | 385 | sp->smk_root = nsp; |
| 386 | specified = 1; | ||
| 387 | } | ||
| 380 | } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { | 388 | } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { |
| 381 | op += strlen(SMK_FSTRANS); | 389 | op += strlen(SMK_FSTRANS); |
| 382 | nsp = smk_import(op, 0); | 390 | nsp = smk_import(op, 0); |
| 383 | if (nsp != NULL) { | 391 | if (nsp != NULL) { |
| 384 | sp->smk_root = nsp; | 392 | sp->smk_root = nsp; |
| 385 | transmute = 1; | 393 | transmute = 1; |
| 394 | specified = 1; | ||
| 386 | } | 395 | } |
| 387 | } | 396 | } |
| 388 | } | 397 | } |
| 389 | 398 | ||
| 399 | if (!smack_privileged(CAP_MAC_ADMIN)) { | ||
| 400 | /* | ||
| 401 | * Unprivileged mounts don't get to specify Smack values. | ||
| 402 | */ | ||
| 403 | if (specified) | ||
| 404 | return -EPERM; | ||
| 405 | /* | ||
| 406 | * Unprivileged mounts get root and default from the caller. | ||
| 407 | */ | ||
| 408 | skp = smk_of_current(); | ||
| 409 | sp->smk_root = skp->smk_known; | ||
| 410 | sp->smk_default = skp->smk_known; | ||
| 411 | } | ||
| 390 | /* | 412 | /* |
| 391 | * Initialize the root inode. | 413 | * Initialize the root inode. |
| 392 | */ | 414 | */ |
| @@ -423,53 +445,6 @@ static int smack_sb_statfs(struct dentry *dentry) | |||
| 423 | return rc; | 445 | return rc; |
| 424 | } | 446 | } |
| 425 | 447 | ||
| 426 | /** | ||
| 427 | * smack_sb_mount - Smack check for mounting | ||
| 428 | * @dev_name: unused | ||
| 429 | * @path: mount point | ||
| 430 | * @type: unused | ||
| 431 | * @flags: unused | ||
| 432 | * @data: unused | ||
| 433 | * | ||
| 434 | * Returns 0 if current can write the floor of the filesystem | ||
| 435 | * being mounted on, an error code otherwise. | ||
| 436 | */ | ||
| 437 | static int smack_sb_mount(const char *dev_name, struct path *path, | ||
| 438 | const char *type, unsigned long flags, void *data) | ||
| 439 | { | ||
| 440 | struct superblock_smack *sbp = path->dentry->d_sb->s_security; | ||
| 441 | struct smk_audit_info ad; | ||
| 442 | |||
| 443 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | ||
| 444 | smk_ad_setfield_u_fs_path(&ad, *path); | ||
| 445 | |||
| 446 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); | ||
| 447 | } | ||
| 448 | |||
| 449 | /** | ||
| 450 | * smack_sb_umount - Smack check for unmounting | ||
| 451 | * @mnt: file system to unmount | ||
| 452 | * @flags: unused | ||
| 453 | * | ||
| 454 | * Returns 0 if current can write the floor of the filesystem | ||
| 455 | * being unmounted, an error code otherwise. | ||
| 456 | */ | ||
| 457 | static int smack_sb_umount(struct vfsmount *mnt, int flags) | ||
| 458 | { | ||
| 459 | struct superblock_smack *sbp; | ||
| 460 | struct smk_audit_info ad; | ||
| 461 | struct path path; | ||
| 462 | |||
| 463 | path.dentry = mnt->mnt_root; | ||
| 464 | path.mnt = mnt; | ||
| 465 | |||
| 466 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | ||
| 467 | smk_ad_setfield_u_fs_path(&ad, path); | ||
| 468 | |||
| 469 | sbp = path.dentry->d_sb->s_security; | ||
| 470 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); | ||
| 471 | } | ||
| 472 | |||
| 473 | /* | 448 | /* |
| 474 | * BPRM hooks | 449 | * BPRM hooks |
| 475 | */ | 450 | */ |
| @@ -837,31 +812,43 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 837 | const void *value, size_t size, int flags) | 812 | const void *value, size_t size, int flags) |
| 838 | { | 813 | { |
| 839 | struct smk_audit_info ad; | 814 | struct smk_audit_info ad; |
| 815 | struct smack_known *skp; | ||
| 816 | int check_priv = 0; | ||
| 817 | int check_import = 0; | ||
| 818 | int check_star = 0; | ||
| 840 | int rc = 0; | 819 | int rc = 0; |
| 841 | 820 | ||
| 821 | /* | ||
| 822 | * Check label validity here so import won't fail in post_setxattr | ||
| 823 | */ | ||
| 842 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || | 824 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || |
| 843 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || | 825 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || |
| 844 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || | 826 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { |
| 845 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || | 827 | check_priv = 1; |
| 846 | strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { | 828 | check_import = 1; |
| 847 | if (!smack_privileged(CAP_MAC_ADMIN)) | 829 | } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || |
| 848 | rc = -EPERM; | 830 | strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { |
| 849 | /* | 831 | check_priv = 1; |
| 850 | * check label validity here so import wont fail on | 832 | check_import = 1; |
| 851 | * post_setxattr | 833 | check_star = 1; |
| 852 | */ | ||
| 853 | if (size == 0 || size >= SMK_LONGLABEL || | ||
| 854 | smk_import(value, size) == NULL) | ||
| 855 | rc = -EINVAL; | ||
| 856 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | 834 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { |
| 857 | if (!smack_privileged(CAP_MAC_ADMIN)) | 835 | check_priv = 1; |
| 858 | rc = -EPERM; | ||
| 859 | if (size != TRANS_TRUE_SIZE || | 836 | if (size != TRANS_TRUE_SIZE || |
| 860 | strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) | 837 | strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) |
| 861 | rc = -EINVAL; | 838 | rc = -EINVAL; |
| 862 | } else | 839 | } else |
| 863 | rc = cap_inode_setxattr(dentry, name, value, size, flags); | 840 | rc = cap_inode_setxattr(dentry, name, value, size, flags); |
| 864 | 841 | ||
| 842 | if (check_priv && !smack_privileged(CAP_MAC_ADMIN)) | ||
| 843 | rc = -EPERM; | ||
| 844 | |||
| 845 | if (rc == 0 && check_import) { | ||
| 846 | skp = smk_import_entry(value, size); | ||
| 847 | if (skp == NULL || (check_star && | ||
| 848 | (skp == &smack_known_star || skp == &smack_known_web))) | ||
| 849 | rc = -EINVAL; | ||
| 850 | } | ||
| 851 | |||
| 865 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | 852 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); |
| 866 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 853 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
| 867 | 854 | ||
| @@ -1364,7 +1351,7 @@ static int smack_file_receive(struct file *file) | |||
| 1364 | int may = 0; | 1351 | int may = 0; |
| 1365 | struct smk_audit_info ad; | 1352 | struct smk_audit_info ad; |
| 1366 | 1353 | ||
| 1367 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | 1354 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); |
| 1368 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | 1355 | smk_ad_setfield_u_fs_path(&ad, file->f_path); |
| 1369 | /* | 1356 | /* |
| 1370 | * This code relies on bitmasks. | 1357 | * This code relies on bitmasks. |
| @@ -2847,8 +2834,17 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
| 2847 | if (rc >= 0) | 2834 | if (rc >= 0) |
| 2848 | transflag = SMK_INODE_TRANSMUTE; | 2835 | transflag = SMK_INODE_TRANSMUTE; |
| 2849 | } | 2836 | } |
| 2850 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | 2837 | /* |
| 2851 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | 2838 | * Don't let the exec or mmap label be "*" or "@". |
| 2839 | */ | ||
| 2840 | skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | ||
| 2841 | if (skp == &smack_known_star || skp == &smack_known_web) | ||
| 2842 | skp = NULL; | ||
| 2843 | isp->smk_task = skp; | ||
| 2844 | skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | ||
| 2845 | if (skp == &smack_known_star || skp == &smack_known_web) | ||
| 2846 | skp = NULL; | ||
| 2847 | isp->smk_mmap = skp; | ||
| 2852 | 2848 | ||
| 2853 | dput(dp); | 2849 | dput(dp); |
| 2854 | break; | 2850 | break; |
| @@ -3743,8 +3739,6 @@ struct security_operations smack_ops = { | |||
| 3743 | .sb_copy_data = smack_sb_copy_data, | 3739 | .sb_copy_data = smack_sb_copy_data, |
| 3744 | .sb_kern_mount = smack_sb_kern_mount, | 3740 | .sb_kern_mount = smack_sb_kern_mount, |
| 3745 | .sb_statfs = smack_sb_statfs, | 3741 | .sb_statfs = smack_sb_statfs, |
| 3746 | .sb_mount = smack_sb_mount, | ||
| 3747 | .sb_umount = smack_sb_umount, | ||
| 3748 | 3742 | ||
| 3749 | .bprm_set_creds = smack_bprm_set_creds, | 3743 | .bprm_set_creds = smack_bprm_set_creds, |
| 3750 | .bprm_committing_creds = smack_bprm_committing_creds, | 3744 | .bprm_committing_creds = smack_bprm_committing_creds, |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 160aa08e3cd5..3198cfe1dcc6 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -52,6 +52,7 @@ enum smk_inos { | |||
| 52 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ | 52 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ |
| 53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ | 53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ |
| 54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ | 54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ |
| 55 | SMK_SYSLOG = 20, /* change syslog label) */ | ||
| 55 | }; | 56 | }; |
| 56 | 57 | ||
| 57 | /* | 58 | /* |
| @@ -59,6 +60,7 @@ enum smk_inos { | |||
| 59 | */ | 60 | */ |
| 60 | static DEFINE_MUTEX(smack_cipso_lock); | 61 | static DEFINE_MUTEX(smack_cipso_lock); |
| 61 | static DEFINE_MUTEX(smack_ambient_lock); | 62 | static DEFINE_MUTEX(smack_ambient_lock); |
| 63 | static DEFINE_MUTEX(smack_syslog_lock); | ||
| 62 | static DEFINE_MUTEX(smk_netlbladdr_lock); | 64 | static DEFINE_MUTEX(smk_netlbladdr_lock); |
| 63 | 65 | ||
| 64 | /* | 66 | /* |
| @@ -90,7 +92,13 @@ int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; | |||
| 90 | * everyone. It is expected that the hat (^) label | 92 | * everyone. It is expected that the hat (^) label |
| 91 | * will be used if any label is used. | 93 | * will be used if any label is used. |
| 92 | */ | 94 | */ |
| 93 | char *smack_onlycap; | 95 | struct smack_known *smack_onlycap; |
| 96 | |||
| 97 | /* | ||
| 98 | * If this value is set restrict syslog use to the label specified. | ||
| 99 | * It can be reset via smackfs/syslog | ||
| 100 | */ | ||
| 101 | struct smack_known *smack_syslog_label; | ||
| 94 | 102 | ||
| 95 | /* | 103 | /* |
| 96 | * Certain IP addresses may be designated as single label hosts. | 104 | * Certain IP addresses may be designated as single label hosts. |
| @@ -301,7 +309,8 @@ static int smk_perm_from_str(const char *string) | |||
| 301 | * @import: if non-zero, import labels | 309 | * @import: if non-zero, import labels |
| 302 | * @len: label length limit | 310 | * @len: label length limit |
| 303 | * | 311 | * |
| 304 | * Returns 0 on success, -1 on failure | 312 | * Returns 0 on success, -EINVAL on failure and -ENOENT when either subject |
| 313 | * or object is missing. | ||
| 305 | */ | 314 | */ |
| 306 | static int smk_fill_rule(const char *subject, const char *object, | 315 | static int smk_fill_rule(const char *subject, const char *object, |
| 307 | const char *access1, const char *access2, | 316 | const char *access1, const char *access2, |
| @@ -314,28 +323,28 @@ static int smk_fill_rule(const char *subject, const char *object, | |||
| 314 | if (import) { | 323 | if (import) { |
| 315 | rule->smk_subject = smk_import_entry(subject, len); | 324 | rule->smk_subject = smk_import_entry(subject, len); |
| 316 | if (rule->smk_subject == NULL) | 325 | if (rule->smk_subject == NULL) |
| 317 | return -1; | 326 | return -EINVAL; |
| 318 | 327 | ||
| 319 | rule->smk_object = smk_import(object, len); | 328 | rule->smk_object = smk_import(object, len); |
| 320 | if (rule->smk_object == NULL) | 329 | if (rule->smk_object == NULL) |
| 321 | return -1; | 330 | return -EINVAL; |
| 322 | } else { | 331 | } else { |
| 323 | cp = smk_parse_smack(subject, len); | 332 | cp = smk_parse_smack(subject, len); |
| 324 | if (cp == NULL) | 333 | if (cp == NULL) |
| 325 | return -1; | 334 | return -EINVAL; |
| 326 | skp = smk_find_entry(cp); | 335 | skp = smk_find_entry(cp); |
| 327 | kfree(cp); | 336 | kfree(cp); |
| 328 | if (skp == NULL) | 337 | if (skp == NULL) |
| 329 | return -1; | 338 | return -ENOENT; |
| 330 | rule->smk_subject = skp; | 339 | rule->smk_subject = skp; |
| 331 | 340 | ||
| 332 | cp = smk_parse_smack(object, len); | 341 | cp = smk_parse_smack(object, len); |
| 333 | if (cp == NULL) | 342 | if (cp == NULL) |
| 334 | return -1; | 343 | return -EINVAL; |
| 335 | skp = smk_find_entry(cp); | 344 | skp = smk_find_entry(cp); |
| 336 | kfree(cp); | 345 | kfree(cp); |
| 337 | if (skp == NULL) | 346 | if (skp == NULL) |
| 338 | return -1; | 347 | return -ENOENT; |
| 339 | rule->smk_object = skp->smk_known; | 348 | rule->smk_object = skp->smk_known; |
| 340 | } | 349 | } |
| 341 | 350 | ||
| @@ -381,6 +390,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, | |||
| 381 | { | 390 | { |
| 382 | ssize_t cnt = 0; | 391 | ssize_t cnt = 0; |
| 383 | char *tok[4]; | 392 | char *tok[4]; |
| 393 | int rc; | ||
| 384 | int i; | 394 | int i; |
| 385 | 395 | ||
| 386 | /* | 396 | /* |
| @@ -405,10 +415,8 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, | |||
| 405 | while (i < 4) | 415 | while (i < 4) |
| 406 | tok[i++] = NULL; | 416 | tok[i++] = NULL; |
| 407 | 417 | ||
| 408 | if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0)) | 418 | rc = smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0); |
| 409 | return -1; | 419 | return rc == 0 ? cnt : rc; |
| 410 | |||
| 411 | return cnt; | ||
| 412 | } | 420 | } |
| 413 | 421 | ||
| 414 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ | 422 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ |
| @@ -1603,7 +1611,7 @@ static const struct file_operations smk_ambient_ops = { | |||
| 1603 | }; | 1611 | }; |
| 1604 | 1612 | ||
| 1605 | /** | 1613 | /** |
| 1606 | * smk_read_onlycap - read() for /smack/onlycap | 1614 | * smk_read_onlycap - read() for smackfs/onlycap |
| 1607 | * @filp: file pointer, not actually used | 1615 | * @filp: file pointer, not actually used |
| 1608 | * @buf: where to put the result | 1616 | * @buf: where to put the result |
| 1609 | * @cn: maximum to send along | 1617 | * @cn: maximum to send along |
| @@ -1622,7 +1630,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
| 1622 | return 0; | 1630 | return 0; |
| 1623 | 1631 | ||
| 1624 | if (smack_onlycap != NULL) | 1632 | if (smack_onlycap != NULL) |
| 1625 | smack = smack_onlycap; | 1633 | smack = smack_onlycap->smk_known; |
| 1626 | 1634 | ||
| 1627 | asize = strlen(smack) + 1; | 1635 | asize = strlen(smack) + 1; |
| 1628 | 1636 | ||
| @@ -1633,7 +1641,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
| 1633 | } | 1641 | } |
| 1634 | 1642 | ||
| 1635 | /** | 1643 | /** |
| 1636 | * smk_write_onlycap - write() for /smack/onlycap | 1644 | * smk_write_onlycap - write() for smackfs/onlycap |
| 1637 | * @file: file pointer, not actually used | 1645 | * @file: file pointer, not actually used |
| 1638 | * @buf: where to get the data from | 1646 | * @buf: where to get the data from |
| 1639 | * @count: bytes sent | 1647 | * @count: bytes sent |
| @@ -1656,7 +1664,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
| 1656 | * explicitly for clarity. The smk_access() implementation | 1664 | * explicitly for clarity. The smk_access() implementation |
| 1657 | * would use smk_access(smack_onlycap, MAY_WRITE) | 1665 | * would use smk_access(smack_onlycap, MAY_WRITE) |
| 1658 | */ | 1666 | */ |
| 1659 | if (smack_onlycap != NULL && smack_onlycap != skp->smk_known) | 1667 | if (smack_onlycap != NULL && smack_onlycap != skp) |
| 1660 | return -EPERM; | 1668 | return -EPERM; |
| 1661 | 1669 | ||
| 1662 | data = kzalloc(count, GFP_KERNEL); | 1670 | data = kzalloc(count, GFP_KERNEL); |
| @@ -1676,7 +1684,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
| 1676 | if (copy_from_user(data, buf, count) != 0) | 1684 | if (copy_from_user(data, buf, count) != 0) |
| 1677 | rc = -EFAULT; | 1685 | rc = -EFAULT; |
| 1678 | else | 1686 | else |
| 1679 | smack_onlycap = smk_import(data, count); | 1687 | smack_onlycap = smk_import_entry(data, count); |
| 1680 | 1688 | ||
| 1681 | kfree(data); | 1689 | kfree(data); |
| 1682 | return rc; | 1690 | return rc; |
| @@ -1856,11 +1864,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
| 1856 | res = smk_parse_long_rule(data, &rule, 0, 3); | 1864 | res = smk_parse_long_rule(data, &rule, 0, 3); |
| 1857 | } | 1865 | } |
| 1858 | 1866 | ||
| 1859 | if (res < 0) | 1867 | if (res >= 0) |
| 1868 | res = smk_access(rule.smk_subject, rule.smk_object, | ||
| 1869 | rule.smk_access1, NULL); | ||
| 1870 | else if (res != -ENOENT) | ||
| 1860 | return -EINVAL; | 1871 | return -EINVAL; |
| 1861 | 1872 | ||
| 1862 | res = smk_access(rule.smk_subject, rule.smk_object, | ||
| 1863 | rule.smk_access1, NULL); | ||
| 1864 | data[0] = res == 0 ? '1' : '0'; | 1873 | data[0] = res == 0 ? '1' : '0'; |
| 1865 | data[1] = '\0'; | 1874 | data[1] = '\0'; |
| 1866 | 1875 | ||
| @@ -2143,7 +2152,7 @@ static ssize_t smk_write_change_rule(struct file *file, const char __user *buf, | |||
| 2143 | /* | 2152 | /* |
| 2144 | * Must have privilege. | 2153 | * Must have privilege. |
| 2145 | */ | 2154 | */ |
| 2146 | if (!capable(CAP_MAC_ADMIN)) | 2155 | if (!smack_privileged(CAP_MAC_ADMIN)) |
| 2147 | return -EPERM; | 2156 | return -EPERM; |
| 2148 | 2157 | ||
| 2149 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, | 2158 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, |
| @@ -2158,12 +2167,89 @@ static const struct file_operations smk_change_rule_ops = { | |||
| 2158 | }; | 2167 | }; |
| 2159 | 2168 | ||
| 2160 | /** | 2169 | /** |
| 2161 | * smk_fill_super - fill the /smackfs superblock | 2170 | * smk_read_syslog - read() for smackfs/syslog |
| 2171 | * @filp: file pointer, not actually used | ||
| 2172 | * @buf: where to put the result | ||
| 2173 | * @cn: maximum to send along | ||
| 2174 | * @ppos: where to start | ||
| 2175 | * | ||
| 2176 | * Returns number of bytes read or error code, as appropriate | ||
| 2177 | */ | ||
| 2178 | static ssize_t smk_read_syslog(struct file *filp, char __user *buf, | ||
| 2179 | size_t cn, loff_t *ppos) | ||
| 2180 | { | ||
| 2181 | struct smack_known *skp; | ||
| 2182 | ssize_t rc = -EINVAL; | ||
| 2183 | int asize; | ||
| 2184 | |||
| 2185 | if (*ppos != 0) | ||
| 2186 | return 0; | ||
| 2187 | |||
| 2188 | if (smack_syslog_label == NULL) | ||
| 2189 | skp = &smack_known_star; | ||
| 2190 | else | ||
| 2191 | skp = smack_syslog_label; | ||
| 2192 | |||
| 2193 | asize = strlen(skp->smk_known) + 1; | ||
| 2194 | |||
| 2195 | if (cn >= asize) | ||
| 2196 | rc = simple_read_from_buffer(buf, cn, ppos, skp->smk_known, | ||
| 2197 | asize); | ||
| 2198 | |||
| 2199 | return rc; | ||
| 2200 | } | ||
| 2201 | |||
| 2202 | /** | ||
| 2203 | * smk_write_syslog - write() for smackfs/syslog | ||
| 2204 | * @file: file pointer, not actually used | ||
| 2205 | * @buf: where to get the data from | ||
| 2206 | * @count: bytes sent | ||
| 2207 | * @ppos: where to start | ||
| 2208 | * | ||
| 2209 | * Returns number of bytes written or error code, as appropriate | ||
| 2210 | */ | ||
| 2211 | static ssize_t smk_write_syslog(struct file *file, const char __user *buf, | ||
| 2212 | size_t count, loff_t *ppos) | ||
| 2213 | { | ||
| 2214 | char *data; | ||
| 2215 | struct smack_known *skp; | ||
| 2216 | int rc = count; | ||
| 2217 | |||
| 2218 | if (!smack_privileged(CAP_MAC_ADMIN)) | ||
| 2219 | return -EPERM; | ||
| 2220 | |||
| 2221 | data = kzalloc(count, GFP_KERNEL); | ||
| 2222 | if (data == NULL) | ||
| 2223 | return -ENOMEM; | ||
| 2224 | |||
| 2225 | if (copy_from_user(data, buf, count) != 0) | ||
| 2226 | rc = -EFAULT; | ||
| 2227 | else { | ||
| 2228 | skp = smk_import_entry(data, count); | ||
| 2229 | if (skp == NULL) | ||
| 2230 | rc = -EINVAL; | ||
| 2231 | else | ||
| 2232 | smack_syslog_label = smk_import_entry(data, count); | ||
| 2233 | } | ||
| 2234 | |||
| 2235 | kfree(data); | ||
| 2236 | return rc; | ||
| 2237 | } | ||
| 2238 | |||
| 2239 | static const struct file_operations smk_syslog_ops = { | ||
| 2240 | .read = smk_read_syslog, | ||
| 2241 | .write = smk_write_syslog, | ||
| 2242 | .llseek = default_llseek, | ||
| 2243 | }; | ||
| 2244 | |||
| 2245 | |||
| 2246 | /** | ||
| 2247 | * smk_fill_super - fill the smackfs superblock | ||
| 2162 | * @sb: the empty superblock | 2248 | * @sb: the empty superblock |
| 2163 | * @data: unused | 2249 | * @data: unused |
| 2164 | * @silent: unused | 2250 | * @silent: unused |
| 2165 | * | 2251 | * |
| 2166 | * Fill in the well known entries for /smack | 2252 | * Fill in the well known entries for the smack filesystem |
| 2167 | * | 2253 | * |
| 2168 | * Returns 0 on success, an error code on failure | 2254 | * Returns 0 on success, an error code on failure |
| 2169 | */ | 2255 | */ |
| @@ -2208,6 +2294,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2208 | S_IRUGO|S_IWUSR}, | 2294 | S_IRUGO|S_IWUSR}, |
| 2209 | [SMK_CHANGE_RULE] = { | 2295 | [SMK_CHANGE_RULE] = { |
| 2210 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, | 2296 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, |
| 2297 | [SMK_SYSLOG] = { | ||
| 2298 | "syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR}, | ||
| 2211 | /* last one */ | 2299 | /* last one */ |
| 2212 | {""} | 2300 | {""} |
| 2213 | }; | 2301 | }; |
