Pull security subsystem updates from James Morris: "Highlights: IMA: - provide ">" and "<" operators for fowner/uid/euid rules KEYS: - add a system blacklist keyring - add KEYCTL_RESTRICT_KEYRING, exposes keyring link restriction functionality to userland via keyctl() LSM: - harden LSM API with __ro_after_init - add prlmit security hook, implement for SELinux - revive security_task_alloc hook TPM: - implement contextual TPM command 'spaces'" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (98 commits) tpm: Fix reference count to main device tpm_tis: convert to using locality callbacks tpm: fix handling of the TPM 2.0 event logs tpm_crb: remove a cruft constant keys: select CONFIG_CRYPTO when selecting DH / KDF apparmor: Make path_max parameter readonly apparmor: fix parameters so that the permission test is bypassed at boot apparmor: fix invalid reference to index variable of iterator line 836 apparmor: use SHASH_DESC_ON_STACK security/apparmor/lsm.c: set debug messages apparmor: fix boolreturn.cocci warnings Smack: Use GFP_KERNEL for smk_netlbl_mls(). smack: fix double free in smack_parse_opts_str() KEYS: add SP800-56A KDF support for DH KEYS: Keyring asymmetric key restrict method with chaining KEYS: Restrict asymmetric key linkage using a specific keychain KEYS: Add a lookup_restriction function for the asymmetric key type KEYS: Add KEYCTL_RESTRICT_KEYRING KEYS: Consistent ordering for __key_link_begin and restrict check KEYS: Add an optional lookup_restriction hook to key_type ...
Unified · Split
| @@ -311,3 +311,54 @@ Functions are provided to register and unregister parsers: · 310 unmodified lines | ||
| 311 | 311 | |
| 312 | 312 | Parsers may not have the same name. The names are otherwise only used for |
| 313 | 313 | displaying in debugging messages. |
| 314 | + | |
| 315 | + | |
| 316 | +========================= | |
| 317 | +KEYRING LINK RESTRICTIONS | |
| 318 | +========================= | |
| 319 | + | |
| 320 | +Keyrings created from userspace using add_key can be configured to check the | |
| 321 | +signature of the key being linked. | |
| 322 | + | |
| 323 | +Several restriction methods are available: | |
| 324 | + | |
| 325 | + (1) Restrict using the kernel builtin trusted keyring | |
| 326 | + | |
| 327 | + - Option string used with KEYCTL_RESTRICT_KEYRING: | |
| 328 | + - "builtin_trusted" | |
| 329 | + | |
| 330 | + The kernel builtin trusted keyring will be searched for the signing | |
| 331 | + key. The ca_keys kernel parameter also affects which keys are used for | |
| 332 | + signature verification. | |
| 333 | + | |
| 334 | + (2) Restrict using the kernel builtin and secondary trusted keyrings | |
| 335 | + | |
| 336 | + - Option string used with KEYCTL_RESTRICT_KEYRING: | |
| 337 | + - "builtin_and_secondary_trusted" | |
| 338 | + | |
| 339 | + The kernel builtin and secondary trusted keyrings will be searched for the | |
| 340 | + signing key. The ca_keys kernel parameter also affects which keys are used | |
| 341 | + for signature verification. | |
| 342 | + | |
| 343 | + (3) Restrict using a separate key or keyring | |
| 344 | + | |
| 345 | + - Option string used with KEYCTL_RESTRICT_KEYRING: | |
| 346 | + - "key_or_keyring:<key or keyring serial number>[:chain]" | |
| 347 | + | |
| 348 | + Whenever a key link is requested, the link will only succeed if the key | |
| 349 | + being linked is signed by one of the designated keys. This key may be | |
| 350 | + specified directly by providing a serial number for one asymmetric key, or | |
| 351 | + a group of keys may be searched for the signing key by providing the | |
| 352 | + serial number for a keyring. | |
| 353 | + | |
| 354 | + When the "chain" option is provided at the end of the string, the keys | |
| 355 | + within the destination keyring will also be searched for signing keys. | |
| 356 | + This allows for verification of certificate chains by adding each | |
| 357 | + cert in order (starting closest to the root) to one keyring. | |
| 358 | + | |
| 359 | +In all of these cases, if the signing key is found the signature of the key to | |
| 360 | +be linked will be verified using the signing key. The requested key is added | |
| 361 | +to the keyring only if the signature is successfully verified. -ENOKEY is | |
| 362 | +returned if the parent certificate could not be found, or -EKEYREJECTED is | |
| 363 | +returned if the signature check fails or the key is blacklisted. Other errors | |
| 364 | +may be returned if the signature check could not be performed. | |
| @@ -827,7 +827,7 @@ The keyctl syscall functions are: · 826 unmodified lines | ||
| 827 | 827 | |
| 828 | 828 | long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params, |
| 829 | 829 | char *buffer, size_t buflen, |
| 830 | − void *reserved); | |
| 830 | + struct keyctl_kdf_params *kdf); | |
| 831 | 831 | |
| 832 | 832 | The params struct contains serial numbers for three keys: |
| 833 | 833 | |
| @@ -844,18 +844,61 @@ The keyctl syscall functions are: · 10 unmodified lines | ||
| 844 | 844 | public key. If the base is the remote public key, the result is |
| 845 | 845 | the shared secret. |
| 846 | 846 | |
| 847 | − The reserved argument must be set to NULL. | |
| 847 | + If the parameter kdf is NULL, the following applies: | |
| 848 | 848 | |
| 849 | − The buffer length must be at least the length of the prime, or zero. | |
| 849 | + - The buffer length must be at least the length of the prime, or zero. | |
| 850 | 850 | |
| 851 | − If the buffer length is nonzero, the length of the result is | |
| 852 | − returned when it is successfully calculated and copied in to the | |
| 853 | − buffer. When the buffer length is zero, the minimum required | |
| 854 | − buffer length is returned. | |
| 851 | + - If the buffer length is nonzero, the length of the result is | |
| 852 | + returned when it is successfully calculated and copied in to the | |
| 853 | + buffer. When the buffer length is zero, the minimum required | |
| 854 | + buffer length is returned. | |
| 855 | + | |
| 856 | + The kdf parameter allows the caller to apply a key derivation function | |
| 857 | + (KDF) on the Diffie-Hellman computation where only the result | |
| 858 | + of the KDF is returned to the caller. The KDF is characterized with | |
| 859 | + struct keyctl_kdf_params as follows: | |
| 860 | + | |
| 861 | + - char *hashname specifies the NUL terminated string identifying | |
| 862 | + the hash used from the kernel crypto API and applied for the KDF | |
| 863 | + operation. The KDF implemenation complies with SP800-56A as well | |
| 864 | + as with SP800-108 (the counter KDF). | |
| 865 | + | |
| 866 | + - char *otherinfo specifies the OtherInfo data as documented in | |
| 867 | + SP800-56A section 5.8.1.2. The length of the buffer is given with | |
| 868 | + otherinfolen. The format of OtherInfo is defined by the caller. | |
| 869 | + The otherinfo pointer may be NULL if no OtherInfo shall be used. | |
| 855 | 870 | |
| 856 | 871 | This function will return error EOPNOTSUPP if the key type is not |
| 857 | 872 | supported, error ENOKEY if the key could not be found, or error |
| 858 | − EACCES if the key is not readable by the caller. | |
| 873 | + EACCES if the key is not readable by the caller. In addition, the | |
| 874 | + function will return EMSGSIZE when the parameter kdf is non-NULL | |
| 875 | + and either the buffer length or the OtherInfo length exceeds the | |
| 876 | + allowed length. | |
| 877 | + | |
| 878 | + (*) Restrict keyring linkage | |
| 879 | + | |
| 880 | + long keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring, | |
| 881 | + const char *type, const char *restriction); | |
| 882 | + | |
| 883 | + An existing keyring can restrict linkage of additional keys by evaluating | |
| 884 | + the contents of the key according to a restriction scheme. | |
| 885 | + | |
| 886 | + "keyring" is the key ID for an existing keyring to apply a restriction | |
| 887 | + to. It may be empty or may already have keys linked. Existing linked keys | |
| 888 | + will remain in the keyring even if the new restriction would reject them. | |
| 889 | + | |
| 890 | + "type" is a registered key type. | |
| 891 | + | |
| 892 | + "restriction" is a string describing how key linkage is to be restricted. | |
| 893 | + The format varies depending on the key type, and the string is passed to | |
| 894 | + the lookup_restriction() function for the requested type. It may specify | |
| 895 | + a method and relevant data for the restriction such as signature | |
| 896 | + verification or constraints on key payload. If the requested key type is | |
| 897 | + later unregistered, no keys may be added to the keyring after the key type | |
| 898 | + is removed. | |
| 899 | + | |
| 900 | + To apply a keyring restriction the process must have Set Attribute | |
| 901 | + permission and the keyring must not be previously restricted. | |
| 859 | 902 | |
| 860 | 903 | =============== |
| 861 | 904 | KERNEL SERVICES |
| @@ -1032,10 +1075,7 @@ payload contents" for more information. · 170 unmodified lines | ||
| 1032 | 1075 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, |
| 1033 | 1076 | const struct cred *cred, |
| 1034 | 1077 | key_perm_t perm, |
| 1035 | − int (*restrict_link)(struct key *, | |
| 1036 | − const struct key_type *, | |
| 1037 | − unsigned long, | |
| 1038 | − const union key_payload *), | |
| 1078 | + struct key_restriction *restrict_link, | |
| 1039 | 1079 | unsigned long flags, |
| 1040 | 1080 | struct key *dest); |
| 1041 | 1081 | |
| @@ -1047,20 +1087,23 @@ payload contents" for more information. · 5 unmodified lines | ||
| 1047 | 1087 | KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted |
| 1048 | 1088 | towards the user's quota). Error ENOMEM can also be returned. |
| 1049 | 1089 | |
| 1050 | − If restrict_link not NULL, it should point to a function that will be | |
| 1051 | − called each time an attempt is made to link a key into the new keyring. | |
| 1052 | − This function is called to check whether a key may be added into the keying | |
| 1053 | − or not. Callers of key_create_or_update() within the kernel can pass | |
| 1054 | − KEY_ALLOC_BYPASS_RESTRICTION to suppress the check. An example of using | |
| 1055 | − this is to manage rings of cryptographic keys that are set up when the | |
| 1056 | − kernel boots where userspace is also permitted to add keys - provided they | |
| 1057 | − can be verified by a key the kernel already has. | |
| 1090 | + If restrict_link is not NULL, it should point to a structure that contains | |
| 1091 | + the function that will be called each time an attempt is made to link a | |
| 1092 | + key into the new keyring. The structure may also contain a key pointer | |
| 1093 | + and an associated key type. The function is called to check whether a key | |
| 1094 | + may be added into the keyring or not. The key type is used by the garbage | |
| 1095 | + collector to clean up function or data pointers in this structure if the | |
| 1096 | + given key type is unregistered. Callers of key_create_or_update() within | |
| 1097 | + the kernel can pass KEY_ALLOC_BYPASS_RESTRICTION to suppress the check. | |
| 1098 | + An example of using this is to manage rings of cryptographic keys that are | |
| 1099 | + set up when the kernel boots where userspace is also permitted to add keys | |
| 1100 | + - provided they can be verified by a key the kernel already has. | |
| 1058 | 1101 | |
| 1059 | 1102 | When called, the restriction function will be passed the keyring being |
| 1060 | − added to, the key flags value and the type and payload of the key being | |
| 1061 | − added. Note that when a new key is being created, this is called between | |
| 1062 | − payload preparsing and actual key creation. The function should return 0 | |
| 1063 | − to allow the link or an error to reject it. | |
| 1103 | + added to, the key type, the payload of the key being added, and data to be | |
| 1104 | + used in the restriction check. Note that when a new key is being created, | |
| 1105 | + this is called between payload preparsing and actual key creation. The | |
| 1106 | + function should return 0 to allow the link or an error to reject it. | |
| 1064 | 1107 | |
| 1065 | 1108 | A convenience function, restrict_link_reject, exists to always return |
| 1066 | 1109 | -EPERM to in this case. |
| @@ -1445,6 +1488,15 @@ The structure has a number of fields, some of which are mandatory: · 378 unmodified lines | ||
| 1445 | 1488 | The authorisation key. |
| 1446 | 1489 | |
| 1447 | 1490 | |
| 1491 | + (*) struct key_restriction *(*lookup_restriction)(const char *params); | |
| 1492 | + | |
| 1493 | + This optional method is used to enable userspace configuration of keyring | |
| 1494 | + restrictions. The restriction parameter string (not including the key type | |
| 1495 | + name) is passed in, and this method returns a pointer to a key_restriction | |
| 1496 | + structure containing the relevant functions and data to evaluate each | |
| 1497 | + attempted key link operation. If there is no match, -EINVAL is returned. | |
| 1498 | + | |
| 1499 | + | |
| 1448 | 1500 | ============================ |
| 1449 | 1501 | REQUEST-KEY CALLBACK SERVICE |
| 1450 | 1502 | ============================ |
| @@ -64,4 +64,22 @@ config SECONDARY_TRUSTED_KEYRING · 63 unmodified lines | ||
| 64 | 64 | those keys are not blacklisted and are vouched for by a key built |
| 65 | 65 | into the kernel or already in the secondary trusted keyring. |
| 66 | 66 | |
| 67 | +config SYSTEM_BLACKLIST_KEYRING | |
| 68 | + bool "Provide system-wide ring of blacklisted keys" | |
| 69 | + depends on KEYS | |
| 70 | + help | |
| 71 | + Provide a system keyring to which blacklisted keys can be added. | |
| 72 | + Keys in the keyring are considered entirely untrusted. Keys in this | |
| 73 | + keyring are used by the module signature checking to reject loading | |
| 74 | + of modules signed with a blacklisted key. | |
| 75 | + | |
| 76 | +config SYSTEM_BLACKLIST_HASH_LIST | |
| 77 | + string "Hashes to be preloaded into the system blacklist keyring" | |
| 78 | + depends on SYSTEM_BLACKLIST_KEYRING | |
| 79 | + help | |
| 80 | + If set, this option should be the filename of a list of hashes in the | |
| 81 | + form "<hash>", "<hash>", ... . This will be included into a C | |
| 82 | + wrapper to incorporate the list into the kernel. Each <hash> should | |
| 83 | + be a string of hex digits. | |
| 84 | + | |
| 67 | 85 | endmenu |
| @@ -3,6 +3,12 @@ · 2 unmodified lines | ||
| 3 | 3 | # |
| 4 | 4 | |
| 5 | 5 | obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o |
| 6 | +obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o | |
| 7 | +ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),"") | |
| 8 | +obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o | |
| 9 | +else | |
| 10 | +obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_nohashes.o | |
| 11 | +endif | |
| 6 | 12 | |
| 7 | 13 | ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) |
| 8 | 14 | |
| @@ -0,0 +1,174 @@ | ||
| 1 | +/* System hash blacklist. | |
| 2 | + * | |
| 3 | + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#define pr_fmt(fmt) "blacklist: "fmt | |
| 13 | +#include <linux/module.h> | |
| 14 | +#include <linux/slab.h> | |
| 15 | +#include <linux/key.h> | |
| 16 | +#include <linux/key-type.h> | |
| 17 | +#include <linux/sched.h> | |
| 18 | +#include <linux/ctype.h> | |
| 19 | +#include <linux/err.h> | |
| 20 | +#include <linux/seq_file.h> | |
| 21 | +#include <keys/system_keyring.h> | |
| 22 | +#include "blacklist.h" | |
| 23 | + | |
| 24 | +static struct key *blacklist_keyring; | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * The description must be a type prefix, a colon and then an even number of | |
| 28 | + * hex digits. The hash is kept in the description. | |
| 29 | + */ | |
| 30 | +static int blacklist_vet_description(const char *desc) | |
| 31 | +{ | |
| 32 | + int n = 0; | |
| 33 | + | |
| 34 | + if (*desc == ':') | |
| 35 | + return -EINVAL; | |
| 36 | + for (; *desc; desc++) | |
| 37 | + if (*desc == ':') | |
| 38 | + goto found_colon; | |
| 39 | + return -EINVAL; | |
| 40 | + | |
| 41 | +found_colon: | |
| 42 | + desc++; | |
| 43 | + for (; *desc; desc++) { | |
| 44 | + if (!isxdigit(*desc)) | |
| 45 | + return -EINVAL; | |
| 46 | + n++; | |
| 47 | + } | |
| 48 | + | |
| 49 | + if (n == 0 || n & 1) | |
| 50 | + return -EINVAL; | |
| 51 | + return 0; | |
| 52 | +} | |
| 53 | + | |
| 54 | +/* | |
| 55 | + * The hash to be blacklisted is expected to be in the description. There will | |
| 56 | + * be no payload. | |
| 57 | + */ | |
| 58 | +static int blacklist_preparse(struct key_preparsed_payload *prep) | |
| 59 | +{ | |
| 60 | + if (prep->datalen > 0) | |
| 61 | + return -EINVAL; | |
| 62 | + return 0; | |
| 63 | +} | |
| 64 | + | |
| 65 | +static void blacklist_free_preparse(struct key_preparsed_payload *prep) | |
| 66 | +{ | |
| 67 | +} | |
| 68 | + | |
| 69 | +static void blacklist_describe(const struct key *key, struct seq_file *m) | |
| 70 | +{ | |
| 71 | + seq_puts(m, key->description); | |
| 72 | +} | |
| 73 | + | |
| 74 | +static struct key_type key_type_blacklist = { | |
| 75 | + .name = "blacklist", | |
| 76 | + .vet_description = blacklist_vet_description, | |
| 77 | + .preparse = blacklist_preparse, | |
| 78 | + .free_preparse = blacklist_free_preparse, | |
| 79 | + .instantiate = generic_key_instantiate, | |
| 80 | + .describe = blacklist_describe, | |
| 81 | +}; | |
| 82 | + | |
| 83 | +/** | |
| 84 | + * mark_hash_blacklisted - Add a hash to the system blacklist | |
| 85 | + * @hash - The hash as a hex string with a type prefix (eg. "tbs:23aa429783") | |
| 86 | + */ | |
| 87 | +int mark_hash_blacklisted(const char *hash) | |
| 88 | +{ | |
| 89 | + key_ref_t key; | |
| 90 | + | |
| 91 | + key = key_create_or_update(make_key_ref(blacklist_keyring, true), | |
| 92 | + "blacklist", | |
| 93 | + hash, | |
| 94 | + NULL, | |
| 95 | + 0, | |
| 96 | + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | |
| 97 | + KEY_USR_VIEW), | |
| 98 | + KEY_ALLOC_NOT_IN_QUOTA | | |
| 99 | + KEY_ALLOC_BUILT_IN); | |
| 100 | + if (IS_ERR(key)) { | |
| 101 | + pr_err("Problem blacklisting hash (%ld)\n", PTR_ERR(key)); | |
| 102 | + return PTR_ERR(key); | |
| 103 | + } | |
| 104 | + return 0; | |
| 105 | +} | |
| 106 | + | |
| 107 | +/** | |
| 108 | + * is_hash_blacklisted - Determine if a hash is blacklisted | |
| 109 | + * @hash: The hash to be checked as a binary blob | |
| 110 | + * @hash_len: The length of the binary hash | |
| 111 | + * @type: Type of hash | |
| 112 | + */ | |
| 113 | +int is_hash_blacklisted(const u8 *hash, size_t hash_len, const char *type) | |
| 114 | +{ | |
| 115 | + key_ref_t kref; | |
| 116 | + size_t type_len = strlen(type); | |
| 117 | + char *buffer, *p; | |
| 118 | + int ret = 0; | |
| 119 | + | |
| 120 | + buffer = kmalloc(type_len + 1 + hash_len * 2 + 1, GFP_KERNEL); | |
| 121 | + if (!buffer) | |
| 122 | + return -ENOMEM; | |
| 123 | + p = memcpy(buffer, type, type_len); | |
| 124 | + p += type_len; | |
| 125 | + *p++ = ':'; | |
| 126 | + bin2hex(p, hash, hash_len); | |
| 127 | + p += hash_len * 2; | |
| 128 | + *p = 0; | |
| 129 | + | |
| 130 | + kref = keyring_search(make_key_ref(blacklist_keyring, true), | |
| 131 | + &key_type_blacklist, buffer); | |
| 132 | + if (!IS_ERR(kref)) { | |
| 133 | + key_ref_put(kref); | |
| 134 | + ret = -EKEYREJECTED; | |
| 135 | + } | |
| 136 | + | |
| 137 | + kfree(buffer); | |
| 138 | + return ret; | |
| 139 | +} | |
| 140 | +EXPORT_SYMBOL_GPL(is_hash_blacklisted); | |
| 141 | + | |
| 142 | +/* | |
| 143 | + * Intialise the blacklist | |
| 144 | + */ | |
| 145 | +static int __init blacklist_init(void) | |
| 146 | +{ | |
| 147 | + const char *const *bl; | |
| 148 | + | |
| 149 | + if (register_key_type(&key_type_blacklist) < 0) | |
| 150 | + panic("Can't allocate system blacklist key type\n"); | |
| 151 | + | |
| 152 | + blacklist_keyring = | |
| 153 | + keyring_alloc(".blacklist", | |
| 154 | + KUIDT_INIT(0), KGIDT_INIT(0), | |
| 155 | + current_cred(), | |
| 156 | + (KEY_POS_ALL & ~KEY_POS_SETATTR) | | |
| 157 | + KEY_USR_VIEW | KEY_USR_READ | | |
| 158 | + KEY_USR_SEARCH, | |
| 159 | + KEY_ALLOC_NOT_IN_QUOTA | | |
| 160 | + KEY_FLAG_KEEP, | |
| 161 | + NULL, NULL); | |
| 162 | + if (IS_ERR(blacklist_keyring)) | |
| 163 | + panic("Can't allocate system blacklist keyring\n"); | |
| 164 | + | |
| 165 | + for (bl = blacklist_hashes; *bl; bl++) | |
| 166 | + if (mark_hash_blacklisted(*bl) < 0) | |
| 167 | + pr_err("- blacklisting failed\n"); | |
| 168 | + return 0; | |
| 169 | +} | |
| 170 | + | |
| 171 | +/* | |
| 172 | + * Must be initialised before we try and load the keys into the keyring. | |
| 173 | + */ | |
| 174 | +device_initcall(blacklist_init); | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +#include <linux/kernel.h> | |
| 2 | + | |
| 3 | +extern const char __initdata *const blacklist_hashes[]; | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +#include "blacklist.h" | |
| 2 | + | |
| 3 | +const char __initdata *const blacklist_hashes[] = { | |
| 4 | +#include CONFIG_SYSTEM_BLACKLIST_HASH_LIST | |
| 5 | + , NULL | |
| 6 | +}; | |
| @@ -0,0 +1,5 @@ | ||
| 1 | +#include "blacklist.h" | |
| 2 | + | |
| 3 | +const char __initdata *const blacklist_hashes[] = { | |
| 4 | + NULL | |
| 5 | +}; | |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/sched.h> |
| 15 | 15 | #include <linux/cred.h> |
| 16 | 16 | #include <linux/err.h> |
| 17 | +#include <linux/slab.h> | |
| 17 | 18 | #include <keys/asymmetric-type.h> |
| 18 | 19 | #include <keys/system_keyring.h> |
| 19 | 20 | #include <crypto/pkcs7.h> |
| @@ -32,11 +33,13 @@ extern __initconst const unsigned long system_certificate_list_size; · 12 unmodified lines | ||
| 32 | 33 | * Restrict the addition of keys into a keyring based on the key-to-be-added |
| 33 | 34 | * being vouched for by a key in the built in system keyring. |
| 34 | 35 | */ |
| 35 | −int restrict_link_by_builtin_trusted(struct key *keyring, | |
| 36 | +int restrict_link_by_builtin_trusted(struct key *dest_keyring, | |
| 36 | 37 | const struct key_type *type, |
| 37 | − const union key_payload *payload) | |
| 38 | + const union key_payload *payload, | |
| 39 | + struct key *restriction_key) | |
| 38 | 40 | { |
| 39 | − return restrict_link_by_signature(builtin_trusted_keys, type, payload); | |
| 41 | + return restrict_link_by_signature(dest_keyring, type, payload, | |
| 42 | + builtin_trusted_keys); | |
| 40 | 43 | } |
| 41 | 44 | |
| 42 | 45 | #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING |
| @@ -49,20 +52,40 @@ int restrict_link_by_builtin_trusted(struct key *keyring, · 6 unmodified lines | ||
| 49 | 52 | * keyrings. |
| 50 | 53 | */ |
| 51 | 54 | int restrict_link_by_builtin_and_secondary_trusted( |
| 52 | − struct key *keyring, | |
| 55 | + struct key *dest_keyring, | |
| 53 | 56 | const struct key_type *type, |
| 54 | − const union key_payload *payload) | |
| 57 | + const union key_payload *payload, | |
| 58 | + struct key *restrict_key) | |
| 55 | 59 | { |
| 56 | 60 | /* If we have a secondary trusted keyring, then that contains a link |
| 57 | 61 | * through to the builtin keyring and the search will follow that link. |
| 58 | 62 | */ |
| 59 | 63 | if (type == &key_type_keyring && |
| 60 | − keyring == secondary_trusted_keys && | |
| 64 | + dest_keyring == secondary_trusted_keys && | |
| 61 | 65 | payload == &builtin_trusted_keys->payload) |
| 62 | 66 | /* Allow the builtin keyring to be added to the secondary */ |
| 63 | 67 | return 0; |
| 64 | 68 | |
| 65 | − return restrict_link_by_signature(secondary_trusted_keys, type, payload); | |
| 69 | + return restrict_link_by_signature(dest_keyring, type, payload, | |
| 70 | + secondary_trusted_keys); | |
| 71 | +} | |
| 72 | + | |
| 73 | +/** | |
| 74 | + * Allocate a struct key_restriction for the "builtin and secondary trust" | |
| 75 | + * keyring. Only for use in system_trusted_keyring_init(). | |
| 76 | + */ | |
| 77 | +static __init struct key_restriction *get_builtin_and_secondary_restriction(void) | |
| 78 | +{ | |
| 79 | + struct key_restriction *restriction; | |
| 80 | + | |
| 81 | + restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL); | |
| 82 | + | |
| 83 | + if (!restriction) | |
| 84 | + panic("Can't allocate secondary trusted keyring restriction\n"); | |
| 85 | + | |
| 86 | + restriction->check = restrict_link_by_builtin_and_secondary_trusted; | |
| 87 | + | |
| 88 | + return restriction; | |
| 66 | 89 | } |
| 67 | 90 | #endif |
| 68 | 91 | |
| @@ -91,7 +114,7 @@ static __init int system_trusted_keyring_init(void) · 22 unmodified lines | ||
| 91 | 114 | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH | |
| 92 | 115 | KEY_USR_WRITE), |
| 93 | 116 | KEY_ALLOC_NOT_IN_QUOTA, |
| 94 | − restrict_link_by_builtin_and_secondary_trusted, | |
| 117 | + get_builtin_and_secondary_restriction(), | |
| 95 | 118 | NULL); |
| 96 | 119 | if (IS_ERR(secondary_trusted_keys)) |
| 97 | 120 | panic("Can't allocate secondary trusted keyring\n"); |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/module.h> |
| 18 | 18 | #include <linux/slab.h> |
| 19 | 19 | #include <linux/ctype.h> |
| 20 | +#include <keys/system_keyring.h> | |
| 20 | 21 | #include "asymmetric_keys.h" |
| 21 | 22 | |
| 22 | 23 | MODULE_LICENSE("GPL"); |
| @@ -451,15 +452,100 @@ static void asymmetric_key_destroy(struct key *key) · 428 unmodified lines | ||
| 451 | 452 | asymmetric_key_free_kids(kids); |
| 452 | 453 | } |
| 453 | 454 | |
| 455 | +static struct key_restriction *asymmetric_restriction_alloc( | |
| 456 | + key_restrict_link_func_t check, | |
| 457 | + struct key *key) | |
| 458 | +{ | |
| 459 | + struct key_restriction *keyres = | |
| 460 | + kzalloc(sizeof(struct key_restriction), GFP_KERNEL); | |
| 461 | + | |
| 462 | + if (!keyres) | |
| 463 | + return ERR_PTR(-ENOMEM); | |
| 464 | + | |
| 465 | + keyres->check = check; | |
| 466 | + keyres->key = key; | |
| 467 | + keyres->keytype = &key_type_asymmetric; | |
| 468 | + | |
| 469 | + return keyres; | |
| 470 | +} | |
| 471 | + | |
| 472 | +/* | |
| 473 | + * look up keyring restrict functions for asymmetric keys | |
| 474 | + */ | |
| 475 | +static struct key_restriction *asymmetric_lookup_restriction( | |
| 476 | + const char *restriction) | |
| 477 | +{ | |
| 478 | + char *restrict_method; | |
| 479 | + char *parse_buf; | |
| 480 | + char *next; | |
| 481 | + struct key_restriction *ret = ERR_PTR(-EINVAL); | |
| 482 | + | |
| 483 | + if (strcmp("builtin_trusted", restriction) == 0) | |
| 484 | + return asymmetric_restriction_alloc( | |
| 485 | + restrict_link_by_builtin_trusted, NULL); | |
| 486 | + | |
| 487 | + if (strcmp("builtin_and_secondary_trusted", restriction) == 0) | |
| 488 | + return asymmetric_restriction_alloc( | |
| 489 | + restrict_link_by_builtin_and_secondary_trusted, NULL); | |
| 490 | + | |
| 491 | + parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL); | |
| 492 | + if (!parse_buf) | |
| 493 | + return ERR_PTR(-ENOMEM); | |
| 494 | + | |
| 495 | + next = parse_buf; | |
| 496 | + restrict_method = strsep(&next, ":"); | |
| 497 | + | |
| 498 | + if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) { | |
| 499 | + char *key_text; | |
| 500 | + key_serial_t serial; | |
| 501 | + struct key *key; | |
| 502 | + key_restrict_link_func_t link_fn = | |
| 503 | + restrict_link_by_key_or_keyring; | |
| 504 | + bool allow_null_key = false; | |
| 505 | + | |
| 506 | + key_text = strsep(&next, ":"); | |
| 507 | + | |
| 508 | + if (next) { | |
| 509 | + if (strcmp(next, "chain") != 0) | |
| 510 | + goto out; | |
| 511 | + | |
| 512 | + link_fn = restrict_link_by_key_or_keyring_chain; | |
| 513 | + allow_null_key = true; | |
| 514 | + } | |
| 515 | + | |
| 516 | + if (kstrtos32(key_text, 0, &serial) < 0) | |
| 517 | + goto out; | |
| 518 | + | |
| 519 | + if ((serial == 0) && allow_null_key) { | |
| 520 | + key = NULL; | |
| 521 | + } else { | |
| 522 | + key = key_lookup(serial); | |
| 523 | + if (IS_ERR(key)) { | |
| 524 | + ret = ERR_CAST(key); | |
| 525 | + goto out; | |
| 526 | + } | |
| 527 | + } | |
| 528 | + | |
| 529 | + ret = asymmetric_restriction_alloc(link_fn, key); | |
| 530 | + if (IS_ERR(ret)) | |
| 531 | + key_put(key); | |
| 532 | + } | |
| 533 | + | |
| 534 | +out: | |
| 535 | + kfree(parse_buf); | |
| 536 | + return ret; | |
| 537 | +} | |
| 538 | + | |
| 454 | 539 | struct key_type key_type_asymmetric = { |
| 455 | − .name = "asymmetric", | |
| 456 | − .preparse = asymmetric_key_preparse, | |
| 457 | − .free_preparse = asymmetric_key_free_preparse, | |
| 458 | − .instantiate = generic_key_instantiate, | |
| 459 | − .match_preparse = asymmetric_key_match_preparse, | |
| 460 | − .match_free = asymmetric_key_match_free, | |
| 461 | − .destroy = asymmetric_key_destroy, | |
| 462 | − .describe = asymmetric_key_describe, | |
| 540 | + .name = "asymmetric", | |
| 541 | + .preparse = asymmetric_key_preparse, | |
| 542 | + .free_preparse = asymmetric_key_free_preparse, | |
| 543 | + .instantiate = generic_key_instantiate, | |
| 544 | + .match_preparse = asymmetric_key_match_preparse, | |
| 545 | + .match_free = asymmetric_key_match_free, | |
| 546 | + .destroy = asymmetric_key_destroy, | |
| 547 | + .describe = asymmetric_key_describe, | |
| 548 | + .lookup_restriction = asymmetric_lookup_restriction, | |
| 463 | 549 | }; |
| 464 | 550 | EXPORT_SYMBOL_GPL(key_type_asymmetric); |
| 465 | 551 | |
| @@ -23,6 +23,7 @@ struct pkcs7_signed_info { · 22 unmodified lines | ||
| 23 | 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ |
| 24 | 24 | unsigned index; |
| 25 | 25 | bool unsupported_crypto; /* T if not usable due to missing crypto */ |
| 26 | + bool blacklisted; | |
| 26 | 27 | |
| 27 | 28 | /* Message digest - the digest of the Content Data (or NULL) */ |
| 28 | 29 | const void *msgdigest; |
| @@ -190,6 +190,18 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, · 189 unmodified lines | ||
| 190 | 190 | x509->subject, |
| 191 | 191 | x509->raw_serial_size, x509->raw_serial); |
| 192 | 192 | x509->seen = true; |
| 193 | + | |
| 194 | + if (x509->blacklisted) { | |
| 195 | + /* If this cert is blacklisted, then mark everything | |
| 196 | + * that depends on this as blacklisted too. | |
| 197 | + */ | |
| 198 | + sinfo->blacklisted = true; | |
| 199 | + for (p = sinfo->signer; p != x509; p = p->signer) | |
| 200 | + p->blacklisted = true; | |
| 201 | + pr_debug("- blacklisted\n"); | |
| 202 | + return 0; | |
| 203 | + } | |
| 204 | + | |
| 193 | 205 | if (x509->unsupported_key) |
| 194 | 206 | goto unsupported_crypto_in_x509; |
| 195 | 207 | |
| @@ -357,17 +369,19 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, · 161 unmodified lines | ||
| 357 | 369 | * |
| 358 | 370 | * (*) -EBADMSG if some part of the message was invalid, or: |
| 359 | 371 | * |
| 360 | − * (*) -ENOPKG if none of the signature chains are verifiable because suitable | |
| 361 | − * crypto modules couldn't be found, or: | |
| 372 | + * (*) 0 if no signature chains were found to be blacklisted or to contain | |
| 373 | + * unsupported crypto, or: | |
| 362 | 374 | * |
| 363 | − * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified | |
| 364 | − * (note that a signature chain may be of zero length), or: | |
| 375 | + * (*) -EKEYREJECTED if a blacklisted key was encountered, or: | |
| 376 | + * | |
| 377 | + * (*) -ENOPKG if none of the signature chains are verifiable because suitable | |
| 378 | + * crypto modules couldn't be found. | |
| 365 | 379 | */ |
| 366 | 380 | int pkcs7_verify(struct pkcs7_message *pkcs7, |
| 367 | 381 | enum key_being_used_for usage) |
| 368 | 382 | { |
| 369 | 383 | struct pkcs7_signed_info *sinfo; |
| 370 | − int enopkg = -ENOPKG; | |
| 384 | + int actual_ret = -ENOPKG; | |
| 371 | 385 | int ret; |
| 372 | 386 | |
| 373 | 387 | kenter(""); |
| @@ -412,6 +426,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, · 38 unmodified lines | ||
| 412 | 426 | |
| 413 | 427 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
| 414 | 428 | ret = pkcs7_verify_one(pkcs7, sinfo); |
| 429 | + if (sinfo->blacklisted && actual_ret == -ENOPKG) | |
| 430 | + actual_ret = -EKEYREJECTED; | |
| 415 | 431 | if (ret < 0) { |
| 416 | 432 | if (ret == -ENOPKG) { |
| 417 | 433 | sinfo->unsupported_crypto = true; |
| @@ -420,11 +436,11 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, · 2 unmodified lines | ||
| 420 | 436 | kleave(" = %d", ret); |
| 421 | 437 | return ret; |
| 422 | 438 | } |
| 423 | − enopkg = 0; | |
| 439 | + actual_ret = 0; | |
| 424 | 440 | } |
| 425 | 441 | |
| 426 | − kleave(" = %d", enopkg); | |
| 427 | − return enopkg; | |
| 442 | + kleave(" = %d", actual_ret); | |
| 443 | + return actual_ret; | |
| 428 | 444 | } |
| 429 | 445 | EXPORT_SYMBOL_GPL(pkcs7_verify); |
| 430 | 446 | |
| @@ -56,9 +56,10 @@ __setup("ca_keys=", ca_keys_setup); · 55 unmodified lines | ||
| 56 | 56 | |
| 57 | 57 | /** |
| 58 | 58 | * restrict_link_by_signature - Restrict additions to a ring of public keys |
| 59 | − * @trust_keyring: A ring of keys that can be used to vouch for the new cert. | |
| 59 | + * @dest_keyring: Keyring being linked to. | |
| 60 | 60 | * @type: The type of key being added. |
| 61 | 61 | * @payload: The payload of the new key. |
| 62 | + * @trust_keyring: A ring of keys that can be used to vouch for the new cert. | |
| 62 | 63 | * |
| 63 | 64 | * Check the new certificate against the ones in the trust keyring. If one of |
| 64 | 65 | * those is the signing key and validates the new certificate, then mark the |
| @@ -69,9 +70,10 @@ __setup("ca_keys=", ca_keys_setup); · 4 unmodified lines | ||
| 69 | 70 | * signature check fails or the key is blacklisted and some other error if |
| 70 | 71 | * there is a matching certificate but the signature check cannot be performed. |
| 71 | 72 | */ |
| 72 | −int restrict_link_by_signature(struct key *trust_keyring, | |
| 73 | +int restrict_link_by_signature(struct key *dest_keyring, | |
| 73 | 74 | const struct key_type *type, |
| 74 | − const union key_payload *payload) | |
| 75 | + const union key_payload *payload, | |
| 76 | + struct key *trust_keyring) | |
| 75 | 77 | { |
| 76 | 78 | const struct public_key_signature *sig; |
| 77 | 79 | struct key *key; |
| @@ -106,3 +108,156 @@ int restrict_link_by_signature(struct key *trust_keyring, · 28 unmodified lines | ||
| 106 | 108 | key_put(key); |
| 107 | 109 | return ret; |
| 108 | 110 | } |
| 111 | + | |
| 112 | +static bool match_either_id(const struct asymmetric_key_ids *pair, | |
| 113 | + const struct asymmetric_key_id *single) | |
| 114 | +{ | |
| 115 | + return (asymmetric_key_id_same(pair->id[0], single) || | |
| 116 | + asymmetric_key_id_same(pair->id[1], single)); | |
| 117 | +} | |
| 118 | + | |
| 119 | +static int key_or_keyring_common(struct key *dest_keyring, | |
| 120 | + const struct key_type *type, | |
| 121 | + const union key_payload *payload, | |
| 122 | + struct key *trusted, bool check_dest) | |
| 123 | +{ | |
| 124 | + const struct public_key_signature *sig; | |
| 125 | + struct key *key = NULL; | |
| 126 | + int ret; | |
| 127 | + | |
| 128 | + pr_devel("==>%s()\n", __func__); | |
| 129 | + | |
| 130 | + if (!dest_keyring) | |
| 131 | + return -ENOKEY; | |
| 132 | + else if (dest_keyring->type != &key_type_keyring) | |
| 133 | + return -EOPNOTSUPP; | |
| 134 | + | |
| 135 | + if (!trusted && !check_dest) | |
| 136 | + return -ENOKEY; | |
| 137 | + | |
| 138 | + if (type != &key_type_asymmetric) | |
| 139 | + return -EOPNOTSUPP; | |
| 140 | + | |
| 141 | + sig = payload->data[asym_auth]; | |
| 142 | + if (!sig->auth_ids[0] && !sig->auth_ids[1]) | |
| 143 | + return -ENOKEY; | |
| 144 | + | |
| 145 | + if (trusted) { | |
| 146 | + if (trusted->type == &key_type_keyring) { | |
| 147 | + /* See if we have a key that signed this one. */ | |
| 148 | + key = find_asymmetric_key(trusted, sig->auth_ids[0], | |
| 149 | + sig->auth_ids[1], false); | |
| 150 | + if (IS_ERR(key)) | |
| 151 | + key = NULL; | |
| 152 | + } else if (trusted->type == &key_type_asymmetric) { | |
| 153 | + const struct asymmetric_key_ids *signer_ids; | |
| 154 | + | |
| 155 | + signer_ids = asymmetric_key_ids(trusted); | |
| 156 | + | |
| 157 | + /* | |
| 158 | + * The auth_ids come from the candidate key (the | |
| 159 | + * one that is being considered for addition to | |
| 160 | + * dest_keyring) and identify the key that was | |
| 161 | + * used to sign. | |
| 162 | + * | |
| 163 | + * The signer_ids are identifiers for the | |
| 164 | + * signing key specified for dest_keyring. | |
| 165 | + * | |
| 166 | + * The first auth_id is the preferred id, and | |
| 167 | + * the second is the fallback. If only one | |
| 168 | + * auth_id is present, it may match against | |
| 169 | + * either signer_id. If two auth_ids are | |
| 170 | + * present, the first auth_id must match one | |
| 171 | + * signer_id and the second auth_id must match | |
| 172 | + * the second signer_id. | |
| 173 | + */ | |
| 174 | + if (!sig->auth_ids[0] || !sig->auth_ids[1]) { | |
| 175 | + const struct asymmetric_key_id *auth_id; | |
| 176 | + | |
| 177 | + auth_id = sig->auth_ids[0] ?: sig->auth_ids[1]; | |
| 178 | + if (match_either_id(signer_ids, auth_id)) | |
| 179 | + key = __key_get(trusted); | |
| 180 | + | |
| 181 | + } else if (asymmetric_key_id_same(signer_ids->id[1], | |
| 182 | + sig->auth_ids[1]) && | |
| 183 | + match_either_id(signer_ids, | |
| 184 | + sig->auth_ids[0])) { | |
| 185 | + key = __key_get(trusted); | |
| 186 | + } | |
| 187 | + } else { | |
| 188 | + return -EOPNOTSUPP; | |
| 189 | + } | |
| 190 | + } | |
| 191 | + | |
| 192 | + if (check_dest && !key) { | |
| 193 | + /* See if the destination has a key that signed this one. */ | |
| 194 | + key = find_asymmetric_key(dest_keyring, sig->auth_ids[0], | |
| 195 | + sig->auth_ids[1], false); | |
| 196 | + if (IS_ERR(key)) | |
| 197 | + key = NULL; | |
| 198 | + } | |
| 199 | + | |
| 200 | + if (!key) | |
| 201 | + return -ENOKEY; | |
| 202 | + | |
| 203 | + ret = key_validate(key); | |
| 204 | + if (ret == 0) | |
| 205 | + ret = verify_signature(key, sig); | |
| 206 | + | |
| 207 | + key_put(key); | |
| 208 | + return ret; | |
| 209 | +} | |
| 210 | + | |
| 211 | +/** | |
| 212 | + * restrict_link_by_key_or_keyring - Restrict additions to a ring of public | |
| 213 | + * keys using the restrict_key information stored in the ring. | |
| 214 | + * @dest_keyring: Keyring being linked to. | |
| 215 | + * @type: The type of key being added. | |
| 216 | + * @payload: The payload of the new key. | |
| 217 | + * @trusted: A key or ring of keys that can be used to vouch for the new cert. | |
| 218 | + * | |
| 219 | + * Check the new certificate only against the key or keys passed in the data | |
| 220 | + * parameter. If one of those is the signing key and validates the new | |
| 221 | + * certificate, then mark the new certificate as being ok to link. | |
| 222 | + * | |
| 223 | + * Returns 0 if the new certificate was accepted, -ENOKEY if we | |
| 224 | + * couldn't find a matching parent certificate in the trusted list, | |
| 225 | + * -EKEYREJECTED if the signature check fails, and some other error if | |
| 226 | + * there is a matching certificate but the signature check cannot be | |
| 227 | + * performed. | |
| 228 | + */ | |
| 229 | +int restrict_link_by_key_or_keyring(struct key *dest_keyring, | |
| 230 | + const struct key_type *type, | |
| 231 | + const union key_payload *payload, | |
| 232 | + struct key *trusted) | |
| 233 | +{ | |
| 234 | + return key_or_keyring_common(dest_keyring, type, payload, trusted, | |
| 235 | + false); | |
| 236 | +} | |
| 237 | + | |
| 238 | +/** | |
| 239 | + * restrict_link_by_key_or_keyring_chain - Restrict additions to a ring of | |
| 240 | + * public keys using the restrict_key information stored in the ring. | |
| 241 | + * @dest_keyring: Keyring being linked to. | |
| 242 | + * @type: The type of key being added. | |
| 243 | + * @payload: The payload of the new key. | |
| 244 | + * @trusted: A key or ring of keys that can be used to vouch for the new cert. | |
| 245 | + * | |
| 246 | + * Check the new certificate only against the key or keys passed in the data | |
| 247 | + * parameter. If one of those is the signing key and validates the new | |
| 248 | + * certificate, then mark the new certificate as being ok to link. | |
| 249 | + * | |
| 250 | + * Returns 0 if the new certificate was accepted, -ENOKEY if we | |
| 251 | + * couldn't find a matching parent certificate in the trusted list, | |
| 252 | + * -EKEYREJECTED if the signature check fails, and some other error if | |
| 253 | + * there is a matching certificate but the signature check cannot be | |
| 254 | + * performed. | |
| 255 | + */ | |
| 256 | +int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring, | |
| 257 | + const struct key_type *type, | |
| 258 | + const union key_payload *payload, | |
| 259 | + struct key *trusted) | |
| 260 | +{ | |
| 261 | + return key_or_keyring_common(dest_keyring, type, payload, trusted, | |
| 262 | + true); | |
| 263 | +} | |
| @@ -42,6 +42,7 @@ struct x509_certificate { · 41 unmodified lines | ||
| 42 | 42 | bool self_signed; /* T if self-signed (check unsupported_sig too) */ |
| 43 | 43 | bool unsupported_key; /* T if key uses unsupported crypto */ |
| 44 | 44 | bool unsupported_sig; /* T if signature uses unsupported crypto */ |
| 45 | + bool blacklisted; | |
| 45 | 46 | }; |
| 46 | 47 | |
| 47 | 48 | /* |
| @@ -84,6 +84,16 @@ int x509_get_sig_params(struct x509_certificate *cert) · 83 unmodified lines | ||
| 84 | 84 | goto error_2; |
| 85 | 85 | might_sleep(); |
| 86 | 86 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); |
| 87 | + if (ret < 0) | |
| 88 | + goto error_2; | |
| 89 | + | |
| 90 | + ret = is_hash_blacklisted(sig->digest, sig->digest_size, "tbs"); | |
| 91 | + if (ret == -EKEYREJECTED) { | |
| 92 | + pr_err("Cert %*phN is blacklisted\n", | |
| 93 | + sig->digest_size, sig->digest); | |
| 94 | + cert->blacklisted = true; | |
| 95 | + ret = 0; | |
| 96 | + } | |
| 87 | 97 | |
| 88 | 98 | error_2: |
| 89 | 99 | kfree(desc); |
| @@ -186,6 +196,11 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) · 96 unmodified lines | ||
| 186 | 196 | cert->sig->pkey_algo, cert->sig->hash_algo); |
| 187 | 197 | } |
| 188 | 198 | |
| 199 | + /* Don't permit addition of blacklisted keys */ | |
| 200 | + ret = -EKEYREJECTED; | |
| 201 | + if (cert->blacklisted) | |
| 202 | + goto error_free_cert; | |
| 203 | + | |
| 189 | 204 | /* Propose a description */ |
| 190 | 205 | sulen = strlen(cert->subject); |
| 191 | 206 | if (cert->raw_skid) { |
| @@ -6,6 +6,7 @@ menuconfig TCG_TPM · 5 unmodified lines | ||
| 6 | 6 | tristate "TPM Hardware Support" |
| 7 | 7 | depends on HAS_IOMEM |
| 8 | 8 | select SECURITYFS |
| 9 | + select CRYPTO | |
| 9 | 10 | select CRYPTO_HASH_INFO |
| 10 | 11 | ---help--- |
| 11 | 12 | If you have a TPM security chip in your system, which |
| @@ -135,7 +136,7 @@ config TCG_XEN · 123 unmodified lines | ||
| 135 | 136 | |
| 136 | 137 | config TCG_CRB |
| 137 | 138 | tristate "TPM 2.0 CRB Interface" |
| 138 | − depends on X86 && ACPI | |
| 139 | + depends on ACPI | |
| 139 | 140 | ---help--- |
| 140 | 141 | If you have a TPM security chip that is compliant with the |
| 141 | 142 | TCG CRB 2.0 TPM specification say Yes and it will be accessible |
| @@ -3,7 +3,8 @@ · 2 unmodified lines | ||
| 3 | 3 | # |
| 4 | 4 | obj-$(CONFIG_TCG_TPM) += tpm.o |
| 5 | 5 | tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ |
| 6 | − tpm1_eventlog.o tpm2_eventlog.o | |
| 6 | + tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \ | |
| 7 | + tpm2-space.o | |
| 7 | 8 | tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o |
| 8 | 9 | tpm-$(CONFIG_OF) += tpm_of.o |
| 9 | 10 | obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o |
| @@ -111,6 +111,13 @@ static const struct st33zp24_phy_ops i2c_phy_ops = { · 110 unmodified lines | ||
| 111 | 111 | .recv = st33zp24_i2c_recv, |
| 112 | 112 | }; |
| 113 | 113 | |
| 114 | +static const struct acpi_gpio_params lpcpd_gpios = { 1, 0, false }; | |
| 115 | + | |
| 116 | +static const struct acpi_gpio_mapping acpi_st33zp24_gpios[] = { | |
| 117 | + { "lpcpd-gpios", &lpcpd_gpios, 1 }, | |
| 118 | + {}, | |
| 119 | +}; | |
| 120 | + | |
| 114 | 121 | static int st33zp24_i2c_acpi_request_resources(struct i2c_client *client) |
| 115 | 122 | { |
| 116 | 123 | struct tpm_chip *chip = i2c_get_clientdata(client); |
| @@ -118,10 +125,14 @@ static int st33zp24_i2c_acpi_request_resources(struct i2c_client *client) · 1 unmodified line | ||
| 118 | 125 | struct st33zp24_i2c_phy *phy = tpm_dev->phy_id; |
| 119 | 126 | struct gpio_desc *gpiod_lpcpd; |
| 120 | 127 | struct device *dev = &client->dev; |
| 128 | + int ret; | |
| 129 | + | |
| 130 | + ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_st33zp24_gpios); | |
| 131 | + if (ret) | |
| 132 | + return ret; | |
| 121 | 133 | |
| 122 | 134 | /* Get LPCPD GPIO from ACPI */ |
| 123 | − gpiod_lpcpd = devm_gpiod_get_index(dev, "TPM IO LPCPD", 1, | |
| 124 | − GPIOD_OUT_HIGH); | |
| 135 | + gpiod_lpcpd = devm_gpiod_get(dev, "lpcpd", GPIOD_OUT_HIGH); | |
| 125 | 136 | if (IS_ERR(gpiod_lpcpd)) { |
| 126 | 137 | dev_err(&client->dev, |
| 127 | 138 | "Failed to retrieve lpcpd-gpios from acpi.\n"); |
| @@ -268,8 +279,14 @@ static int st33zp24_i2c_probe(struct i2c_client *client, · 140 unmodified lines | ||
| 268 | 279 | static int st33zp24_i2c_remove(struct i2c_client *client) |
| 269 | 280 | { |
| 270 | 281 | struct tpm_chip *chip = i2c_get_clientdata(client); |
| 282 | + int ret; | |
| 271 | 283 | |
| 272 | − return st33zp24_remove(chip); | |
| 284 | + ret = st33zp24_remove(chip); | |
| 285 | + if (ret) | |
| 286 | + return ret; | |
| 287 | + | |
| 288 | + acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev)); | |
| 289 | + return 0; | |
| 273 | 290 | } |
| 274 | 291 | |
| 275 | 292 | static const struct i2c_device_id st33zp24_i2c_id[] = { |
| @@ -230,6 +230,13 @@ static const struct st33zp24_phy_ops spi_phy_ops = { · 229 unmodified lines | ||
| 230 | 230 | .recv = st33zp24_spi_recv, |
| 231 | 231 | }; |
| 232 | 232 | |
| 233 | +static const struct acpi_gpio_params lpcpd_gpios = { 1, 0, false }; | |
| 234 | + | |
| 235 | +static const struct acpi_gpio_mapping acpi_st33zp24_gpios[] = { | |
| 236 | + { "lpcpd-gpios", &lpcpd_gpios, 1 }, | |
| 237 | + {}, | |
| 238 | +}; | |
| 239 | + | |
| 233 | 240 | static int st33zp24_spi_acpi_request_resources(struct spi_device *spi_dev) |
| 234 | 241 | { |
| 235 | 242 | struct tpm_chip *chip = spi_get_drvdata(spi_dev); |
| @@ -237,10 +244,14 @@ static int st33zp24_spi_acpi_request_resources(struct spi_device *spi_dev) · 1 unmodified line | ||
| 237 | 244 | struct st33zp24_spi_phy *phy = tpm_dev->phy_id; |
| 238 | 245 | struct gpio_desc *gpiod_lpcpd; |
| 239 | 246 | struct device *dev = &spi_dev->dev; |
| 247 | + int ret; | |
| 248 | + | |
| 249 | + ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_st33zp24_gpios); | |
| 250 | + if (ret) | |
| 251 | + return ret; | |
| 240 | 252 | |
| 241 | 253 | /* Get LPCPD GPIO from ACPI */ |
| 242 | − gpiod_lpcpd = devm_gpiod_get_index(dev, "TPM IO LPCPD", 1, | |
| 243 | − GPIOD_OUT_HIGH); | |
| 254 | + gpiod_lpcpd = devm_gpiod_get(dev, "lpcpd", GPIOD_OUT_HIGH); | |
| 244 | 255 | if (IS_ERR(gpiod_lpcpd)) { |
| 245 | 256 | dev_err(dev, "Failed to retrieve lpcpd-gpios from acpi.\n"); |
| 246 | 257 | phy->io_lpcpd = -1; |
| @@ -385,8 +396,14 @@ static int st33zp24_spi_probe(struct spi_device *dev) · 138 unmodified lines | ||
| 385 | 396 | static int st33zp24_spi_remove(struct spi_device *dev) |
| 386 | 397 | { |
| 387 | 398 | struct tpm_chip *chip = spi_get_drvdata(dev); |
| 399 | + int ret; | |
| 388 | 400 | |
| 389 | − return st33zp24_remove(chip); | |
| 401 | + ret = st33zp24_remove(chip); | |
| 402 | + if (ret) | |
| 403 | + return ret; | |
| 404 | + | |
| 405 | + acpi_dev_remove_driver_gpios(ACPI_COMPANION(&dev->dev)); | |
| 406 | + return 0; | |
| 390 | 407 | } |
| 391 | 408 | |
| 392 | 409 | static const struct spi_device_id st33zp24_spi_id[] = { |
| @@ -117,9 +117,9 @@ static u8 st33zp24_status(struct tpm_chip *chip) · 116 unmodified lines | ||
| 117 | 117 | /* |
| 118 | 118 | * check_locality if the locality is active |
| 119 | 119 | * @param: chip, the tpm chip description |
| 120 | − * @return: the active locality or -EACCESS. | |
| 120 | + * @return: true if LOCALITY0 is active, otherwise false | |
| 121 | 121 | */ |
| 122 | −static int check_locality(struct tpm_chip *chip) | |
| 122 | +static bool check_locality(struct tpm_chip *chip) | |
| 123 | 123 | { |
| 124 | 124 | struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); |
| 125 | 125 | u8 data; |
| @@ -129,9 +129,9 @@ static int check_locality(struct tpm_chip *chip) · 3 unmodified lines | ||
| 129 | 129 | if (status && (data & |
| 130 | 130 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == |
| 131 | 131 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) |
| 132 | − return tpm_dev->locality; | |
| 132 | + return true; | |
| 133 | 133 | |
| 134 | − return -EACCES; | |
| 134 | + return false; | |
| 135 | 135 | } /* check_locality() */ |
| 136 | 136 | |
| 137 | 137 | /* |
| @@ -146,7 +146,7 @@ static int request_locality(struct tpm_chip *chip) · 8 unmodified lines | ||
| 146 | 146 | long ret; |
| 147 | 147 | u8 data; |
| 148 | 148 | |
| 149 | − if (check_locality(chip) == tpm_dev->locality) | |
| 149 | + if (check_locality(chip)) | |
| 150 | 150 | return tpm_dev->locality; |
| 151 | 151 | |
| 152 | 152 | data = TPM_ACCESS_REQUEST_USE; |
| @@ -158,7 +158,7 @@ static int request_locality(struct tpm_chip *chip) · 5 unmodified lines | ||
| 158 | 158 | |
| 159 | 159 | /* Request locality is usually effective after the request */ |
| 160 | 160 | do { |
| 161 | − if (check_locality(chip) >= 0) | |
| 161 | + if (check_locality(chip)) | |
| 162 | 162 | return tpm_dev->locality; |
| 163 | 163 | msleep(TPM_TIMEOUT); |
| 164 | 164 | } while (time_before(jiffies, stop)); |
| @@ -33,6 +33,7 @@ DEFINE_IDR(dev_nums_idr); · 32 unmodified lines | ||
| 33 | 33 | static DEFINE_MUTEX(idr_lock); |
| 34 | 34 | |
| 35 | 35 | struct class *tpm_class; |
| 36 | +struct class *tpmrm_class; | |
| 36 | 37 | dev_t tpm_devt; |
| 37 | 38 | |
| 38 | 39 | /** |
| @@ -128,9 +129,19 @@ static void tpm_dev_release(struct device *dev) · 89 unmodified lines | ||
| 128 | 129 | mutex_unlock(&idr_lock); |
| 129 | 130 | |
| 130 | 131 | kfree(chip->log.bios_event_log); |
| 132 | + kfree(chip->work_space.context_buf); | |
| 133 | + kfree(chip->work_space.session_buf); | |
| 131 | 134 | kfree(chip); |
| 132 | 135 | } |
| 133 | 136 | |
| 137 | +static void tpm_devs_release(struct device *dev) | |
| 138 | +{ | |
| 139 | + struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); | |
| 140 | + | |
| 141 | + /* release the master device reference */ | |
| 142 | + put_device(&chip->dev); | |
| 143 | +} | |
| 144 | + | |
| 134 | 145 | /** |
| 135 | 146 | * tpm_chip_alloc() - allocate a new struct tpm_chip instance |
| 136 | 147 | * @pdev: device to which the chip is associated |
| @@ -167,18 +178,36 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, · 30 unmodified lines | ||
| 167 | 178 | chip->dev_num = rc; |
| 168 | 179 | |
| 169 | 180 | device_initialize(&chip->dev); |
| 181 | + device_initialize(&chip->devs); | |
| 170 | 182 | |
| 171 | 183 | chip->dev.class = tpm_class; |
| 172 | 184 | chip->dev.release = tpm_dev_release; |
| 173 | 185 | chip->dev.parent = pdev; |
| 174 | 186 | chip->dev.groups = chip->groups; |
| 175 | 187 | |
| 188 | + chip->devs.parent = pdev; | |
| 189 | + chip->devs.class = tpmrm_class; | |
| 190 | + chip->devs.release = tpm_devs_release; | |
| 191 | + /* get extra reference on main device to hold on | |
| 192 | + * behalf of devs. This holds the chip structure | |
| 193 | + * while cdevs is in use. The corresponding put | |
| 194 | + * is in the tpm_devs_release (TPM2 only) | |
| 195 | + */ | |
| 196 | + if (chip->flags & TPM_CHIP_FLAG_TPM2) | |
| 197 | + get_device(&chip->dev); | |
| 198 | + | |
| 176 | 199 | if (chip->dev_num == 0) |
| 177 | 200 | chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); |
| 178 | 201 | else |
| 179 | 202 | chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); |
| 180 | 203 | |
| 204 | + chip->devs.devt = | |
| 205 | + MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); | |
| 206 | + | |
| 181 | 207 | rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num); |
| 208 | + if (rc) | |
| 209 | + goto out; | |
| 210 | + rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); | |
| 182 | 211 | if (rc) |
| 183 | 212 | goto out; |
| 184 | 213 | |
| @@ -186,12 +215,28 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, · 1 unmodified line | ||
| 186 | 215 | chip->flags |= TPM_CHIP_FLAG_VIRTUAL; |
| 187 | 216 | |
| 188 | 217 | cdev_init(&chip->cdev, &tpm_fops); |
| 218 | + cdev_init(&chip->cdevs, &tpmrm_fops); | |
| 189 | 219 | chip->cdev.owner = THIS_MODULE; |
| 220 | + chip->cdevs.owner = THIS_MODULE; | |
| 190 | 221 | chip->cdev.kobj.parent = &chip->dev.kobj; |
| 222 | + chip->cdevs.kobj.parent = &chip->devs.kobj; | |
| 223 | + | |
| 224 | + chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); | |
| 225 | + if (!chip->work_space.context_buf) { | |
| 226 | + rc = -ENOMEM; | |
| 227 | + goto out; | |
| 228 | + } | |
| 229 | + chip->work_space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); | |
| 230 | + if (!chip->work_space.session_buf) { | |
| 231 | + rc = -ENOMEM; | |
| 232 | + goto out; | |
| 233 | + } | |
| 191 | 234 | |
| 235 | + chip->locality = -1; | |
| 192 | 236 | return chip; |
| 193 | 237 | |
| 194 | 238 | out: |
| 239 | + put_device(&chip->devs); | |
| 195 | 240 | put_device(&chip->dev); |
| 196 | 241 | return ERR_PTR(rc); |
| 197 | 242 | } |
| @@ -236,7 +281,6 @@ static int tpm_add_char_device(struct tpm_chip *chip) · 38 unmodified lines | ||
| 236 | 281 | "unable to cdev_add() %s, major %d, minor %d, err=%d\n", |
| 237 | 282 | dev_name(&chip->dev), MAJOR(chip->dev.devt), |
| 238 | 283 | MINOR(chip->dev.devt), rc); |
| 239 | − | |
| 240 | 284 | return rc; |
| 241 | 285 | } |
| 242 | 286 | |
| @@ -251,6 +295,27 @@ static int tpm_add_char_device(struct tpm_chip *chip) · 8 unmodified lines | ||
| 251 | 295 | return rc; |
| 252 | 296 | } |
| 253 | 297 | |
| 298 | + if (chip->flags & TPM_CHIP_FLAG_TPM2) | |
| 299 | + rc = cdev_add(&chip->cdevs, chip->devs.devt, 1); | |
| 300 | + if (rc) { | |
| 301 | + dev_err(&chip->dev, | |
| 302 | + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", | |
| 303 | + dev_name(&chip->devs), MAJOR(chip->devs.devt), | |
| 304 | + MINOR(chip->devs.devt), rc); | |
| 305 | + return rc; | |
| 306 | + } | |
| 307 | + | |
| 308 | + if (chip->flags & TPM_CHIP_FLAG_TPM2) | |
| 309 | + rc = device_add(&chip->devs); | |
| 310 | + if (rc) { | |
| 311 | + dev_err(&chip->dev, | |
| 312 | + "unable to device_register() %s, major %d, minor %d, err=%d\n", | |
| 313 | + dev_name(&chip->devs), MAJOR(chip->devs.devt), | |
| 314 | + MINOR(chip->devs.devt), rc); | |
| 315 | + cdev_del(&chip->cdevs); | |
| 316 | + return rc; | |
| 317 | + } | |
| 318 | + | |
| 254 | 319 | /* Make the chip available. */ |
| 255 | 320 | mutex_lock(&idr_lock); |
| 256 | 321 | idr_replace(&dev_nums_idr, chip, chip->dev_num); |
| @@ -384,6 +449,10 @@ void tpm_chip_unregister(struct tpm_chip *chip) · 127 unmodified lines | ||
| 384 | 449 | { |
| 385 | 450 | tpm_del_legacy_sysfs(chip); |
| 386 | 451 | tpm_bios_log_teardown(chip); |
| 452 | + if (chip->flags & TPM_CHIP_FLAG_TPM2) { | |
| 453 | + cdev_del(&chip->cdevs); | |
| 454 | + device_del(&chip->devs); | |
| 455 | + } | |
| 387 | 456 | tpm_del_char_device(chip); |
| 388 | 457 | } |
| 389 | 458 | EXPORT_SYMBOL_GPL(tpm_chip_unregister); |
| @@ -0,0 +1,148 @@ | ||
| 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/slab.h> | |
| 21 | +#include <linux/uaccess.h> | |
| 22 | +#include "tpm.h" | |
| 23 | +#include "tpm-dev.h" | |
| 24 | + | |
| 25 | +static void user_reader_timeout(unsigned long ptr) | |
| 26 | +{ | |
| 27 | + struct file_priv *priv = (struct file_priv *)ptr; | |
| 28 | + | |
| 29 | + pr_warn("TPM user space timeout is deprecated (pid=%d)\n", | |
| 30 | + task_tgid_nr(current)); | |
| 31 | + | |
| 32 | + schedule_work(&priv->work); | |
| 33 | +} | |
| 34 | + | |
| 35 | +static void timeout_work(struct work_struct *work) | |
| 36 | +{ | |
| 37 | + struct file_priv *priv = container_of(work, struct file_priv, work); | |
| 38 | + | |
| 39 | + mutex_lock(&priv->buffer_mutex); | |
| 40 | + atomic_set(&priv->data_pending, 0); | |
| 41 | + memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); | |
| 42 | + mutex_unlock(&priv->buffer_mutex); | |
| 43 | +} | |
| 44 | + | |
| 45 | +void tpm_common_open(struct file *file, struct tpm_chip *chip, | |
| 46 | + struct file_priv *priv) | |
| 47 | +{ | |
| 48 | + priv->chip = chip; | |
| 49 | + atomic_set(&priv->data_pending, 0); | |
| 50 | + mutex_init(&priv->buffer_mutex); | |
| 51 | + setup_timer(&priv->user_read_timer, user_reader_timeout, | |
| 52 | + (unsigned long)priv); | |
| 53 | + INIT_WORK(&priv->work, timeout_work); | |
| 54 | + | |
| 55 | + file->private_data = priv; | |
| 56 | +} | |
| 57 | + | |
| 58 | +ssize_t tpm_common_read(struct file *file, char __user *buf, | |
| 59 | + size_t size, loff_t *off) | |
| 60 | +{ | |
| 61 | + struct file_priv *priv = file->private_data; | |
| 62 | + ssize_t ret_size; | |
| 63 | + ssize_t orig_ret_size; | |
| 64 | + int rc; | |
| 65 | + | |
| 66 | + del_singleshot_timer_sync(&priv->user_read_timer); | |
| 67 | + flush_work(&priv->work); | |
| 68 | + ret_size = atomic_read(&priv->data_pending); | |
| 69 | + if (ret_size > 0) { /* relay data */ | |
| 70 | + orig_ret_size = ret_size; | |
| 71 | + if (size < ret_size) | |
| 72 | + ret_size = size; | |
| 73 | + | |
| 74 | + mutex_lock(&priv->buffer_mutex); | |
| 75 | + rc = copy_to_user(buf, priv->data_buffer, ret_size); | |
| 76 | + memset(priv->data_buffer, 0, orig_ret_size); | |
| 77 | + if (rc) | |
| 78 | + ret_size = -EFAULT; | |
| 79 | + | |
| 80 | + mutex_unlock(&priv->buffer_mutex); | |
| 81 | + } | |
| 82 | + | |
| 83 | + atomic_set(&priv->data_pending, 0); | |
| 84 | + | |
| 85 | + return ret_size; | |
| 86 | +} | |
| 87 | + | |
| 88 | +ssize_t tpm_common_write(struct file *file, const char __user *buf, | |
| 89 | + size_t size, loff_t *off, struct tpm_space *space) | |
| 90 | +{ | |
| 91 | + struct file_priv *priv = file->private_data; | |
| 92 | + size_t in_size = size; | |
| 93 | + ssize_t out_size; | |
| 94 | + | |
| 95 | + /* Cannot perform a write until the read has cleared either via | |
| 96 | + * tpm_read or a user_read_timer timeout. This also prevents split | |
| 97 | + * buffered writes from blocking here. | |
| 98 | + */ | |
| 99 | + if (atomic_read(&priv->data_pending) != 0) | |
| 100 | + return -EBUSY; | |
| 101 | + | |
| 102 | + if (in_size > TPM_BUFSIZE) | |
| 103 | + return -E2BIG; | |
| 104 | + | |
| 105 | + mutex_lock(&priv->buffer_mutex); | |
| 106 | + | |
| 107 | + if (copy_from_user | |
| 108 | + (priv->data_buffer, (void __user *) buf, in_size)) { | |
| 109 | + mutex_unlock(&priv->buffer_mutex); | |
| 110 | + return -EFAULT; | |
| 111 | + } | |
| 112 | + | |
| 113 | + /* atomic tpm command send and result receive. We only hold the ops | |
| 114 | + * lock during this period so that the tpm can be unregistered even if | |
| 115 | + * the char dev is held open. | |
| 116 | + */ | |
| 117 | + if (tpm_try_get_ops(priv->chip)) { | |
| 118 | + mutex_unlock(&priv->buffer_mutex); | |
| 119 | + return -EPIPE; | |
| 120 | + } | |
| 121 | + out_size = tpm_transmit(priv->chip, space, priv->data_buffer, | |
| 122 | + sizeof(priv->data_buffer), 0); | |
| 123 | + | |
| 124 | + tpm_put_ops(priv->chip); | |
| 125 | + if (out_size < 0) { | |
| 126 | + mutex_unlock(&priv->buffer_mutex); | |
| 127 | + return out_size; | |
| 128 | + } | |
| 129 | + | |
| 130 | + atomic_set(&priv->data_pending, out_size); | |
| 131 | + mutex_unlock(&priv->buffer_mutex); | |
| 132 | + | |
| 133 | + /* Set a timeout by which the reader must come claim the result */ | |
| 134 | + mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); | |
| 135 | + | |
| 136 | + return in_size; | |
| 137 | +} | |
| 138 | + | |
| 139 | +/* | |
| 140 | + * Called on file close | |
| 141 | + */ | |
| 142 | +void tpm_common_release(struct file *file, struct file_priv *priv) | |
| 143 | +{ | |
| 144 | + del_singleshot_timer_sync(&priv->user_read_timer); | |
| 145 | + flush_work(&priv->work); | |
| 146 | + file->private_data = NULL; | |
| 147 | + atomic_set(&priv->data_pending, 0); | |
| 148 | +} | |
| @@ -18,48 +18,15 @@ · 17 unmodified lines | ||
| 18 | 18 | * |
| 19 | 19 | */ |
| 20 | 20 | #include <linux/slab.h> |
| 21 | −#include <linux/uaccess.h> | |
| 22 | −#include "tpm.h" | |
| 23 | − | |
| 24 | −struct file_priv { | |
| 25 | − struct tpm_chip *chip; | |
| 26 | − | |
| 27 | − /* Data passed to and from the tpm via the read/write calls */ | |
| 28 | − atomic_t data_pending; | |
| 29 | − struct mutex buffer_mutex; | |
| 30 | − | |
| 31 | − struct timer_list user_read_timer; /* user needs to claim result */ | |
| 32 | − struct work_struct work; | |
| 33 | − | |
| 34 | − u8 data_buffer[TPM_BUFSIZE]; | |
| 35 | −}; | |
| 36 | − | |
| 37 | −static void user_reader_timeout(unsigned long ptr) | |
| 38 | −{ | |
| 39 | − struct file_priv *priv = (struct file_priv *)ptr; | |
| 40 | − | |
| 41 | − pr_warn("TPM user space timeout is deprecated (pid=%d)\n", | |
| 42 | − task_tgid_nr(current)); | |
| 43 | − | |
| 44 | − schedule_work(&priv->work); | |
| 45 | −} | |
| 46 | − | |
| 47 | −static void timeout_work(struct work_struct *work) | |
| 48 | −{ | |
| 49 | − struct file_priv *priv = container_of(work, struct file_priv, work); | |
| 50 | − | |
| 51 | − mutex_lock(&priv->buffer_mutex); | |
| 52 | − atomic_set(&priv->data_pending, 0); | |
| 53 | − memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); | |
| 54 | − mutex_unlock(&priv->buffer_mutex); | |
| 55 | −} | |
| 21 | +#include "tpm-dev.h" | |
| 56 | 22 | |
| 57 | 23 | static int tpm_open(struct inode *inode, struct file *file) |
| 58 | 24 | { |
| 59 | − struct tpm_chip *chip = | |
| 60 | − container_of(inode->i_cdev, struct tpm_chip, cdev); | |
| 25 | + struct tpm_chip *chip; | |
| 61 | 26 | struct file_priv *priv; |
| 62 | 27 | |
| 28 | + chip = container_of(inode->i_cdev, struct tpm_chip, cdev); | |
| 29 | + | |
| 63 | 30 | /* It's assured that the chip will be opened just once, |
| 64 | 31 | * by the check of is_open variable, which is protected |
| 65 | 32 | * by driver_lock. */ |
| @@ -69,100 +36,22 @@ static int tpm_open(struct inode *inode, struct file *file) · 3 unmodified lines | ||
| 69 | 36 | } |
| 70 | 37 | |
| 71 | 38 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
| 72 | − if (priv == NULL) { | |
| 73 | − clear_bit(0, &chip->is_open); | |
| 74 | − return -ENOMEM; | |
| 75 | − } | |
| 39 | + if (priv == NULL) | |
| 40 | + goto out; | |
| 76 | 41 | |
| 77 | − priv->chip = chip; | |
| 78 | − atomic_set(&priv->data_pending, 0); | |
| 79 | − mutex_init(&priv->buffer_mutex); | |
| 80 | − setup_timer(&priv->user_read_timer, user_reader_timeout, | |
| 81 | − (unsigned long)priv); | |
| 82 | − INIT_WORK(&priv->work, timeout_work); | |
| 42 | + tpm_common_open(file, chip, priv); | |
| 83 | 43 | |
| 84 | − file->private_data = priv; | |
| 85 | 44 | 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 | 45 | |
| 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; | |
| 46 | + out: | |
| 47 | + clear_bit(0, &chip->is_open); | |
| 48 | + return -ENOMEM; | |
| 115 | 49 | } |
| 116 | 50 | |
| 117 | 51 | static ssize_t tpm_write(struct file *file, const char __user *buf, |
| 118 | 52 | size_t size, loff_t *off) |
| 119 | 53 | { |
| 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. We only hold the ops | |
| 143 | − * lock during this period so that the tpm can be unregistered even if | |
| 144 | − * the char dev is held open. | |
| 145 | − */ | |
| 146 | − if (tpm_try_get_ops(priv->chip)) { | |
| 147 | − mutex_unlock(&priv->buffer_mutex); | |
| 148 | − return -EPIPE; | |
| 149 | − } | |
| 150 | − out_size = tpm_transmit(priv->chip, priv->data_buffer, | |
| 151 | − sizeof(priv->data_buffer), 0); | |
| 152 | − | |
| 153 | − tpm_put_ops(priv->chip); | |
| 154 | − if (out_size < 0) { | |
| 155 | − mutex_unlock(&priv->buffer_mutex); | |
| 156 | − return out_size; | |
| 157 | − } | |
| 158 | − | |
| 159 | − atomic_set(&priv->data_pending, out_size); | |
| 160 | − mutex_unlock(&priv->buffer_mutex); | |
| 161 | − | |
| 162 | − /* Set a timeout by which the reader must come claim the result */ | |
| 163 | − mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); | |
| 164 | − | |
| 165 | − return in_size; | |
| 54 | + return tpm_common_write(file, buf, size, off, NULL); | |
| 166 | 55 | } |
| 167 | 56 | |
| 168 | 57 | /* |
| @@ -172,12 +61,10 @@ static int tpm_release(struct inode *inode, struct file *file) · 3 unmodified lines | ||
| 172 | 61 | { |
| 173 | 62 | struct file_priv *priv = file->private_data; |
| 174 | 63 | |
| 175 | − del_singleshot_timer_sync(&priv->user_read_timer); | |
| 176 | − flush_work(&priv->work); | |
| 177 | − file->private_data = NULL; | |
| 178 | − atomic_set(&priv->data_pending, 0); | |
| 64 | + tpm_common_release(file, priv); | |
| 179 | 65 | clear_bit(0, &priv->chip->is_open); |
| 180 | 66 | kfree(priv); |
| 67 | + | |
| 181 | 68 | return 0; |
| 182 | 69 | } |
| 183 | 70 | |
| @@ -185,9 +72,7 @@ const struct file_operations tpm_fops = { · 1 unmodified line | ||
| 185 | 72 | .owner = THIS_MODULE, |
| 186 | 73 | .llseek = no_llseek, |
| 187 | 74 | .open = tpm_open, |
| 188 | − .read = tpm_read, | |
| 75 | + .read = tpm_common_read, | |
| 189 | 76 | .write = tpm_write, |
| 190 | 77 | .release = tpm_release, |
| 191 | 78 | }; |
| 192 | − | |
| 193 | − | |
| @@ -0,0 +1,27 @@ | ||
| 1 | +#ifndef _TPM_DEV_H | |
| 2 | +#define _TPM_DEV_H | |
| 3 | + | |
| 4 | +#include "tpm.h" | |
| 5 | + | |
| 6 | +struct file_priv { | |
| 7 | + struct tpm_chip *chip; | |
| 8 | + | |
| 9 | + /* Data passed to and from the tpm via the read/write calls */ | |
| 10 | + atomic_t data_pending; | |
| 11 | + struct mutex buffer_mutex; | |
| 12 | + | |
| 13 | + struct timer_list user_read_timer; /* user needs to claim result */ | |
| 14 | + struct work_struct work; | |
| 15 | + | |
| 16 | + u8 data_buffer[TPM_BUFSIZE]; | |
| 17 | +}; | |
| 18 | + | |
| 19 | +void tpm_common_open(struct file *file, struct tpm_chip *chip, | |
| 20 | + struct file_priv *priv); | |
| 21 | +ssize_t tpm_common_read(struct file *file, char __user *buf, | |
| 22 | + size_t size, loff_t *off); | |
| 23 | +ssize_t tpm_common_write(struct file *file, const char __user *buf, | |
| 24 | + size_t size, loff_t *off, struct tpm_space *space); | |
| 25 | +void tpm_common_release(struct file *file, struct file_priv *priv); | |
| 26 | + | |
| 27 | +#endif | |
| @@ -328,6 +328,47 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, · 327 unmodified lines | ||
| 328 | 328 | } |
| 329 | 329 | EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); |
| 330 | 330 | |
| 331 | +static bool tpm_validate_command(struct tpm_chip *chip, | |
| 332 | + struct tpm_space *space, | |
| 333 | + const u8 *cmd, | |
| 334 | + size_t len) | |
| 335 | +{ | |
| 336 | + const struct tpm_input_header *header = (const void *)cmd; | |
| 337 | + int i; | |
| 338 | + u32 cc; | |
| 339 | + u32 attrs; | |
| 340 | + unsigned int nr_handles; | |
| 341 | + | |
| 342 | + if (len < TPM_HEADER_SIZE) | |
| 343 | + return false; | |
| 344 | + | |
| 345 | + if (!space) | |
| 346 | + return true; | |
| 347 | + | |
| 348 | + if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) { | |
| 349 | + cc = be32_to_cpu(header->ordinal); | |
| 350 | + | |
| 351 | + i = tpm2_find_cc(chip, cc); | |
| 352 | + if (i < 0) { | |
| 353 | + dev_dbg(&chip->dev, "0x%04X is an invalid command\n", | |
| 354 | + cc); | |
| 355 | + return false; | |
| 356 | + } | |
| 357 | + | |
| 358 | + attrs = chip->cc_attrs_tbl[i]; | |
| 359 | + nr_handles = | |
| 360 | + 4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0)); | |
| 361 | + if (len < TPM_HEADER_SIZE + 4 * nr_handles) | |
| 362 | + goto err_len; | |
| 363 | + } | |
| 364 | + | |
| 365 | + return true; | |
| 366 | +err_len: | |
| 367 | + dev_dbg(&chip->dev, | |
| 368 | + "%s: insufficient command length %zu", __func__, len); | |
| 369 | + return false; | |
| 370 | +} | |
| 371 | + | |
| 331 | 372 | /** |
| 332 | 373 | * tmp_transmit - Internal kernel interface to transmit TPM commands. |
| 333 | 374 | * |
| @@ -340,14 +381,17 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); · 6 unmodified lines | ||
| 340 | 381 | * 0 when the operation is successful. |
| 341 | 382 | * A negative number for system errors (errno). |
| 342 | 383 | */ |
| 343 | −ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, | |
| 344 | − unsigned int flags) | |
| 384 | +ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, | |
| 385 | + u8 *buf, size_t bufsiz, unsigned int flags) | |
| 345 | 386 | { |
| 346 | − ssize_t rc; | |
| 387 | + struct tpm_output_header *header = (void *)buf; | |
| 388 | + int rc; | |
| 389 | + ssize_t len = 0; | |
| 347 | 390 | u32 count, ordinal; |
| 348 | 391 | unsigned long stop; |
| 392 | + bool need_locality; | |
| 349 | 393 | |
| 350 | − if (bufsiz < TPM_HEADER_SIZE) | |
| 394 | + if (!tpm_validate_command(chip, space, buf, bufsiz)) | |
| 351 | 395 | return -EINVAL; |
| 352 | 396 | |
| 353 | 397 | if (bufsiz > TPM_BUFSIZE) |
| @@ -369,10 +413,24 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, · 15 unmodified lines | ||
| 369 | 413 | if (chip->dev.parent) |
| 370 | 414 | pm_runtime_get_sync(chip->dev.parent); |
| 371 | 415 | |
| 416 | + /* Store the decision as chip->locality will be changed. */ | |
| 417 | + need_locality = chip->locality == -1; | |
| 418 | + | |
| 419 | + if (need_locality && chip->ops->request_locality) { | |
| 420 | + rc = chip->ops->request_locality(chip, 0); | |
| 421 | + if (rc < 0) | |
| 422 | + goto out_no_locality; | |
| 423 | + chip->locality = rc; | |
| 424 | + } | |
| 425 | + | |
| 426 | + rc = tpm2_prepare_space(chip, space, ordinal, buf); | |
| 427 | + if (rc) | |
| 428 | + goto out; | |
| 429 | + | |
| 372 | 430 | rc = chip->ops->send(chip, (u8 *) buf, count); |
| 373 | 431 | if (rc < 0) { |
| 374 | 432 | dev_err(&chip->dev, |
| 375 | − "tpm_transmit: tpm_send: error %zd\n", rc); | |
| 433 | + "tpm_transmit: tpm_send: error %d\n", rc); | |
| 376 | 434 | goto out; |
| 377 | 435 | } |
| 378 | 436 | |
| @@ -405,17 +463,36 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, · 26 unmodified lines | ||
| 405 | 463 | goto out; |
| 406 | 464 | |
| 407 | 465 | out_recv: |
| 408 | − rc = chip->ops->recv(chip, (u8 *) buf, bufsiz); | |
| 409 | − if (rc < 0) | |
| 466 | + len = chip->ops->recv(chip, (u8 *) buf, bufsiz); | |
| 467 | + if (len < 0) { | |
| 468 | + rc = len; | |
| 410 | 469 | dev_err(&chip->dev, |
| 411 | − "tpm_transmit: tpm_recv: error %zd\n", rc); | |
| 470 | + "tpm_transmit: tpm_recv: error %d\n", rc); | |
| 471 | + goto out; | |
| 472 | + } else if (len < TPM_HEADER_SIZE) { | |
| 473 | + rc = -EFAULT; | |
| 474 | + goto out; | |
| 475 | + } | |
| 476 | + | |
| 477 | + if (len != be32_to_cpu(header->length)) { | |
| 478 | + rc = -EFAULT; | |
| 479 | + goto out; | |
| 480 | + } | |
| 481 | + | |
| 482 | + rc = tpm2_commit_space(chip, space, ordinal, buf, &len); | |
| 483 | + | |
| 412 | 484 | out: |
| 485 | + if (need_locality && chip->ops->relinquish_locality) { | |
| 486 | + chip->ops->relinquish_locality(chip, chip->locality); | |
| 487 | + chip->locality = -1; | |
| 488 | + } | |
| 489 | +out_no_locality: | |
| 413 | 490 | if (chip->dev.parent) |
| 414 | 491 | pm_runtime_put_sync(chip->dev.parent); |
| 415 | 492 | |
| 416 | 493 | if (!(flags & TPM_TRANSMIT_UNLOCKED)) |
| 417 | 494 | mutex_unlock(&chip->tpm_mutex); |
| 418 | − return rc; | |
| 495 | + return rc ? rc : len; | |
| 419 | 496 | } |
| 420 | 497 | |
| 421 | 498 | /** |
| @@ -434,23 +511,18 @@ out: · 12 unmodified lines | ||
| 434 | 511 | * A negative number for system errors (errno). |
| 435 | 512 | * A positive number for a TPM error. |
| 436 | 513 | */ |
| 437 | −ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, | |
| 438 | − size_t bufsiz, size_t min_rsp_body_length, | |
| 439 | − unsigned int flags, const char *desc) | |
| 514 | +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, | |
| 515 | + const void *buf, size_t bufsiz, | |
| 516 | + size_t min_rsp_body_length, unsigned int flags, | |
| 517 | + const char *desc) | |
| 440 | 518 | { |
| 441 | − const struct tpm_output_header *header; | |
| 519 | + const struct tpm_output_header *header = buf; | |
| 442 | 520 | int err; |
| 443 | 521 | ssize_t len; |
| 444 | 522 | |
| 445 | − len = tpm_transmit(chip, (const u8 *)buf, bufsiz, flags); | |
| 523 | + len = tpm_transmit(chip, space, (u8 *)buf, bufsiz, flags); | |
| 446 | 524 | if (len < 0) |
| 447 | 525 | return len; |
| 448 | − else if (len < TPM_HEADER_SIZE) | |
| 449 | − return -EFAULT; | |
| 450 | − | |
| 451 | − header = buf; | |
| 452 | − if (len != be32_to_cpu(header->length)) | |
| 453 | − return -EFAULT; | |
| 454 | 526 | |
| 455 | 527 | err = be32_to_cpu(header->return_code); |
| 456 | 528 | if (err != 0 && desc) |
| @@ -501,7 +573,7 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, · 44 unmodified lines | ||
| 501 | 573 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
| 502 | 574 | tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id); |
| 503 | 575 | } |
| 504 | − rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, | |
| 576 | + rc = tpm_transmit_cmd(chip, NULL, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, | |
| 505 | 577 | min_cap_length, 0, desc); |
| 506 | 578 | if (!rc) |
| 507 | 579 | *cap = tpm_cmd.params.getcap_out.cap; |
| @@ -525,7 +597,8 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) · 17 unmodified lines | ||
| 525 | 597 | start_cmd.header.in = tpm_startup_header; |
| 526 | 598 | |
| 527 | 599 | start_cmd.params.startup_in.startup_type = startup_type; |
| 528 | − return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0, | |
| 600 | + return tpm_transmit_cmd(chip, NULL, &start_cmd, | |
| 601 | + TPM_INTERNAL_RESULT_SIZE, 0, | |
| 529 | 602 | 0, "attempting to start the TPM"); |
| 530 | 603 | } |
| 531 | 604 | |
| @@ -682,8 +755,8 @@ static int tpm_continue_selftest(struct tpm_chip *chip) · 150 unmodified lines | ||
| 682 | 755 | struct tpm_cmd_t cmd; |
| 683 | 756 | |
| 684 | 757 | cmd.header.in = continue_selftest_header; |
| 685 | − rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, 0, | |
| 686 | − "continue selftest"); | |
| 758 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, | |
| 759 | + 0, 0, "continue selftest"); | |
| 687 | 760 | return rc; |
| 688 | 761 | } |
| 689 | 762 | |
| @@ -703,7 +776,7 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) · 13 unmodified lines | ||
| 703 | 776 | |
| 704 | 777 | cmd.header.in = pcrread_header; |
| 705 | 778 | cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); |
| 706 | − rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, | |
| 779 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, READ_PCR_RESULT_SIZE, | |
| 707 | 780 | READ_PCR_RESULT_BODY_SIZE, 0, |
| 708 | 781 | "attempting to read a pcr value"); |
| 709 | 782 | |
| @@ -815,7 +888,7 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) · 105 unmodified lines | ||
| 815 | 888 | cmd.header.in = pcrextend_header; |
| 816 | 889 | cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); |
| 817 | 890 | memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); |
| 818 | − rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, | |
| 891 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, EXTEND_PCR_RESULT_SIZE, | |
| 819 | 892 | EXTEND_PCR_RESULT_BODY_SIZE, 0, |
| 820 | 893 | "attempting extend a PCR value"); |
| 821 | 894 | |
| @@ -920,8 +993,8 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) · 98 unmodified lines | ||
| 920 | 993 | if (chip == NULL) |
| 921 | 994 | return -ENODEV; |
| 922 | 995 | |
| 923 | − rc = tpm_transmit_cmd(chip, cmd, buflen, 0, 0, "attempting tpm_cmd"); | |
| 924 | − | |
| 996 | + rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0, | |
| 997 | + "attempting tpm_cmd"); | |
| 925 | 998 | tpm_put_ops(chip); |
| 926 | 999 | return rc; |
| 927 | 1000 | } |
| @@ -1022,16 +1095,16 @@ int tpm_pm_suspend(struct device *dev) · 94 unmodified lines | ||
| 1022 | 1095 | cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); |
| 1023 | 1096 | memcpy(cmd.params.pcrextend_in.hash, dummy_hash, |
| 1024 | 1097 | TPM_DIGEST_SIZE); |
| 1025 | − rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, | |
| 1026 | − EXTEND_PCR_RESULT_BODY_SIZE, 0, | |
| 1098 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, EXTEND_PCR_RESULT_SIZE, | |
| 1099 | + EXTEND_PCR_RESULT_BODY_SIZE, 0, | |
| 1027 | 1100 | "extending dummy pcr before suspend"); |
| 1028 | 1101 | } |
| 1029 | 1102 | |
| 1030 | 1103 | /* now do the actual savestate */ |
| 1031 | 1104 | for (try = 0; try < TPM_RETRY; try++) { |
| 1032 | 1105 | cmd.header.in = savestate_header; |
| 1033 | − rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0, | |
| 1034 | − 0, NULL); | |
| 1106 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, SAVESTATE_RESULT_SIZE, | |
| 1107 | + 0, 0, NULL); | |
| 1035 | 1108 | |
| 1036 | 1109 | /* |
| 1037 | 1110 | * If the TPM indicates that it is too busy to respond to |
| @@ -1114,7 +1187,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) · 76 unmodified lines | ||
| 1114 | 1187 | tpm_cmd.header.in = tpm_getrandom_header; |
| 1115 | 1188 | tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); |
| 1116 | 1189 | |
| 1117 | − err = tpm_transmit_cmd(chip, &tpm_cmd, | |
| 1190 | + err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, | |
| 1118 | 1191 | TPM_GETRANDOM_RESULT_SIZE + num_bytes, |
| 1119 | 1192 | offsetof(struct tpm_getrandom_out, |
| 1120 | 1193 | rng_data), |
| @@ -1205,9 +1278,17 @@ static int __init tpm_init(void) · 84 unmodified lines | ||
| 1205 | 1278 | return PTR_ERR(tpm_class); |
| 1206 | 1279 | } |
| 1207 | 1280 | |
| 1208 | − rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm"); | |
| 1281 | + tpmrm_class = class_create(THIS_MODULE, "tpmrm"); | |
| 1282 | + if (IS_ERR(tpmrm_class)) { | |
| 1283 | + pr_err("couldn't create tpmrm class\n"); | |
| 1284 | + class_destroy(tpm_class); | |
| 1285 | + return PTR_ERR(tpmrm_class); | |
| 1286 | + } | |
| 1287 | + | |
| 1288 | + rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm"); | |
| 1209 | 1289 | if (rc < 0) { |
| 1210 | 1290 | pr_err("tpm: failed to allocate char dev region\n"); |
| 1291 | + class_destroy(tpmrm_class); | |
| 1211 | 1292 | class_destroy(tpm_class); |
| 1212 | 1293 | return rc; |
| 1213 | 1294 | } |
| @@ -1219,7 +1300,8 @@ static void __exit tpm_exit(void) · 5 unmodified lines | ||
| 1219 | 1300 | { |
| 1220 | 1301 | idr_destroy(&dev_nums_idr); |
| 1221 | 1302 | class_destroy(tpm_class); |
| 1222 | − unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES); | |
| 1303 | + class_destroy(tpmrm_class); | |
| 1304 | + unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES); | |
| 1223 | 1305 | } |
| 1224 | 1306 | |
| 1225 | 1307 | subsys_initcall(tpm_init); |
| @@ -40,7 +40,7 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, · 39 unmodified lines | ||
| 40 | 40 | struct tpm_chip *chip = to_tpm_chip(dev); |
| 41 | 41 | |
| 42 | 42 | tpm_cmd.header.in = tpm_readpubek_header; |
| 43 | − err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, | |
| 43 | + err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE, | |
| 44 | 44 | READ_PUBEK_RESULT_MIN_BODY_SIZE, 0, |
| 45 | 45 | "attempting to read the PUBEK"); |
| 46 | 46 | if (err) |
| @@ -89,10 +89,13 @@ enum tpm2_structures { · 88 unmodified lines | ||
| 89 | 89 | }; |
| 90 | 90 | |
| 91 | 91 | enum tpm2_return_codes { |
| 92 | + TPM2_RC_SUCCESS = 0x0000, | |
| 92 | 93 | TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ |
| 94 | + TPM2_RC_HANDLE = 0x008B, | |
| 93 | 95 | TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ |
| 94 | 96 | TPM2_RC_DISABLED = 0x0120, |
| 95 | 97 | TPM2_RC_TESTING = 0x090A, /* RC_WARN */ |
| 98 | + TPM2_RC_REFERENCE_H0 = 0x0910, | |
| 96 | 99 | }; |
| 97 | 100 | |
| 98 | 101 | enum tpm2_algorithms { |
| @@ -114,6 +117,8 @@ enum tpm2_command_codes { · 15 unmodified lines | ||
| 114 | 117 | TPM2_CC_CREATE = 0x0153, |
| 115 | 118 | TPM2_CC_LOAD = 0x0157, |
| 116 | 119 | TPM2_CC_UNSEAL = 0x015E, |
| 120 | + TPM2_CC_CONTEXT_LOAD = 0x0161, | |
| 121 | + TPM2_CC_CONTEXT_SAVE = 0x0162, | |
| 117 | 122 | TPM2_CC_FLUSH_CONTEXT = 0x0165, |
| 118 | 123 | TPM2_CC_GET_CAPABILITY = 0x017A, |
| 119 | 124 | TPM2_CC_GET_RANDOM = 0x017B, |
| @@ -127,21 +132,39 @@ enum tpm2_permanent_handles { · 7 unmodified lines | ||
| 127 | 132 | }; |
| 128 | 133 | |
| 129 | 134 | enum tpm2_capabilities { |
| 135 | + TPM2_CAP_HANDLES = 1, | |
| 136 | + TPM2_CAP_COMMANDS = 2, | |
| 130 | 137 | TPM2_CAP_PCRS = 5, |
| 131 | 138 | TPM2_CAP_TPM_PROPERTIES = 6, |
| 132 | 139 | }; |
| 133 | 140 | |
| 141 | +enum tpm2_properties { | |
| 142 | + TPM_PT_TOTAL_COMMANDS = 0x0129, | |
| 143 | +}; | |
| 144 | + | |
| 134 | 145 | enum tpm2_startup_types { |
| 135 | 146 | TPM2_SU_CLEAR = 0x0000, |
| 136 | 147 | TPM2_SU_STATE = 0x0001, |
| 137 | 148 | }; |
| 138 | 149 | |
| 150 | +enum tpm2_cc_attrs { | |
| 151 | + TPM2_CC_ATTR_CHANDLES = 25, | |
| 152 | + TPM2_CC_ATTR_RHANDLE = 28, | |
| 153 | +}; | |
| 154 | + | |
| 139 | 155 | #define TPM_VID_INTEL 0x8086 |
| 140 | 156 | #define TPM_VID_WINBOND 0x1050 |
| 141 | 157 | #define TPM_VID_STM 0x104A |
| 142 | 158 | |
| 143 | 159 | #define TPM_PPI_VERSION_LEN 3 |
| 144 | 160 | |
| 161 | +struct tpm_space { | |
| 162 | + u32 context_tbl[3]; | |
| 163 | + u8 *context_buf; | |
| 164 | + u32 session_tbl[3]; | |
| 165 | + u8 *session_buf; | |
| 166 | +}; | |
| 167 | + | |
| 145 | 168 | enum tpm_chip_flags { |
| 146 | 169 | TPM_CHIP_FLAG_TPM2 = BIT(1), |
| 147 | 170 | TPM_CHIP_FLAG_IRQ = BIT(2), |
| @@ -161,7 +184,9 @@ struct tpm_chip_seqops { · 13 unmodified lines | ||
| 161 | 184 | |
| 162 | 185 | struct tpm_chip { |
| 163 | 186 | struct device dev; |
| 187 | + struct device devs; | |
| 164 | 188 | struct cdev cdev; |
| 189 | + struct cdev cdevs; | |
| 165 | 190 | |
| 166 | 191 | /* A driver callback under ops cannot be run unless ops_sem is held |
| 167 | 192 | * (sometimes implicitly, eg for the sysfs code). ops becomes null |
| @@ -199,6 +224,13 @@ struct tpm_chip { · 31 unmodified lines | ||
| 199 | 224 | acpi_handle acpi_dev_handle; |
| 200 | 225 | char ppi_version[TPM_PPI_VERSION_LEN + 1]; |
| 201 | 226 | #endif /* CONFIG_ACPI */ |
| 227 | + | |
| 228 | + struct tpm_space work_space; | |
| 229 | + u32 nr_commands; | |
| 230 | + u32 *cc_attrs_tbl; | |
| 231 | + | |
| 232 | + /* active locality */ | |
| 233 | + int locality; | |
| 202 | 234 | }; |
| 203 | 235 | |
| 204 | 236 | #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) |
| @@ -485,18 +517,21 @@ static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value) · 280 unmodified lines | ||
| 485 | 517 | } |
| 486 | 518 | |
| 487 | 519 | extern struct class *tpm_class; |
| 520 | +extern struct class *tpmrm_class; | |
| 488 | 521 | extern dev_t tpm_devt; |
| 489 | 522 | extern const struct file_operations tpm_fops; |
| 523 | +extern const struct file_operations tpmrm_fops; | |
| 490 | 524 | extern struct idr dev_nums_idr; |
| 491 | 525 | |
| 492 | 526 | enum tpm_transmit_flags { |
| 493 | 527 | TPM_TRANSMIT_UNLOCKED = BIT(0), |
| 494 | 528 | }; |
| 495 | 529 | |
| 496 | −ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, | |
| 497 | − unsigned int flags); | |
| 498 | −ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, size_t bufsiz, | |
| 499 | − size_t min_rsp_body_len, unsigned int flags, | |
| 530 | +ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, | |
| 531 | + u8 *buf, size_t bufsiz, unsigned int flags); | |
| 532 | +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, | |
| 533 | + const void *buf, size_t bufsiz, | |
| 534 | + size_t min_rsp_body_length, unsigned int flags, | |
| 500 | 535 | const char *desc); |
| 501 | 536 | ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, |
| 502 | 537 | const char *desc, size_t min_cap_length); |
| @@ -541,6 +576,8 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); · 38 unmodified lines | ||
| 541 | 576 | int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, |
| 542 | 577 | struct tpm2_digest *digests); |
| 543 | 578 | int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); |
| 579 | +void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, | |
| 580 | + unsigned int flags); | |
| 544 | 581 | int tpm2_seal_trusted(struct tpm_chip *chip, |
| 545 | 582 | struct trusted_key_payload *payload, |
| 546 | 583 | struct trusted_key_options *options); |
| @@ -554,4 +591,11 @@ int tpm2_auto_startup(struct tpm_chip *chip); · 7 unmodified lines | ||
| 554 | 591 | void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); |
| 555 | 592 | unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); |
| 556 | 593 | int tpm2_probe(struct tpm_chip *chip); |
| 594 | +int tpm2_find_cc(struct tpm_chip *chip, u32 cc); | |
| 595 | +int tpm2_init_space(struct tpm_space *space); | |
| 596 | +void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space); | |
| 597 | +int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, | |
| 598 | + u8 *cmd); | |
| 599 | +int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, | |
| 600 | + u32 cc, u8 *buf, size_t *bufsiz); | |
| 557 | 601 | #endif |
| @@ -266,7 +266,7 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) · 265 unmodified lines | ||
| 266 | 266 | sizeof(cmd.params.pcrread_in.pcr_select)); |
| 267 | 267 | cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); |
| 268 | 268 | |
| 269 | − rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), | |
| 269 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), | |
| 270 | 270 | TPM2_PCR_READ_RESP_BODY_SIZE, |
| 271 | 271 | 0, "attempting to read a pcr value"); |
| 272 | 272 | if (rc == 0) { |
| @@ -333,7 +333,7 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, · 60 unmodified lines | ||
| 333 | 333 | } |
| 334 | 334 | } |
| 335 | 335 | |
| 336 | − rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, 0, | |
| 336 | + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, | |
| 337 | 337 | "attempting extend a PCR value"); |
| 338 | 338 | |
| 339 | 339 | tpm_buf_destroy(&buf); |
| @@ -382,7 +382,7 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) · 42 unmodified lines | ||
| 382 | 382 | cmd.header.in = tpm2_getrandom_header; |
| 383 | 383 | cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); |
| 384 | 384 | |
| 385 | − err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), | |
| 385 | + err = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), | |
| 386 | 386 | offsetof(struct tpm2_get_random_out, |
| 387 | 387 | buffer), |
| 388 | 388 | 0, "attempting get random"); |
| @@ -418,6 +418,35 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = { · 29 unmodified lines | ||
| 418 | 418 | .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY) |
| 419 | 419 | }; |
| 420 | 420 | |
| 421 | +/** | |
| 422 | + * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command | |
| 423 | + * @chip: TPM chip to use | |
| 424 | + * @payload: the key data in clear and encrypted form | |
| 425 | + * @options: authentication values and other options | |
| 426 | + * | |
| 427 | + * Return: same as with tpm_transmit_cmd | |
| 428 | + */ | |
| 429 | +void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, | |
| 430 | + unsigned int flags) | |
| 431 | +{ | |
| 432 | + struct tpm_buf buf; | |
| 433 | + int rc; | |
| 434 | + | |
| 435 | + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT); | |
| 436 | + if (rc) { | |
| 437 | + dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n", | |
| 438 | + handle); | |
| 439 | + return; | |
| 440 | + } | |
| 441 | + | |
| 442 | + tpm_buf_append_u32(&buf, handle); | |
| 443 | + | |
| 444 | + (void) tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, flags, | |
| 445 | + "flushing context"); | |
| 446 | + | |
| 447 | + tpm_buf_destroy(&buf); | |
| 448 | +} | |
| 449 | + | |
| 421 | 450 | /** |
| 422 | 451 | * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. |
| 423 | 452 | * |
| @@ -528,7 +557,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, · 104 unmodified lines | ||
| 528 | 557 | goto out; |
| 529 | 558 | } |
| 530 | 559 | |
| 531 | − rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, 0, | |
| 560 | + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, 0, | |
| 532 | 561 | "sealing data"); |
| 533 | 562 | if (rc) |
| 534 | 563 | goto out; |
| @@ -612,7 +641,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip, · 77 unmodified lines | ||
| 612 | 641 | goto out; |
| 613 | 642 | } |
| 614 | 643 | |
| 615 | − rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, flags, | |
| 644 | + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, flags, | |
| 616 | 645 | "loading blob"); |
| 617 | 646 | if (!rc) |
| 618 | 647 | *blob_handle = be32_to_cpup( |
| @@ -627,39 +656,6 @@ out: · 8 unmodified lines | ||
| 627 | 656 | return rc; |
| 628 | 657 | } |
| 629 | 658 | |
| 630 | −/** | |
| 631 | − * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command | |
| 632 | − * | |
| 633 | − * @chip: TPM chip to use | |
| 634 | − * @handle: the key data in clear and encrypted form | |
| 635 | − * @flags: tpm transmit flags | |
| 636 | − * | |
| 637 | − * Return: Same as with tpm_transmit_cmd. | |
| 638 | − */ | |
| 639 | −static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, | |
| 640 | − unsigned int flags) | |
| 641 | −{ | |
| 642 | − struct tpm_buf buf; | |
| 643 | − int rc; | |
| 644 | − | |
| 645 | − rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT); | |
| 646 | − if (rc) { | |
| 647 | − dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n", | |
| 648 | − handle); | |
| 649 | − return; | |
| 650 | − } | |
| 651 | − | |
| 652 | − tpm_buf_append_u32(&buf, handle); | |
| 653 | − | |
| 654 | − rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags, | |
| 655 | − "flushing context"); | |
| 656 | − if (rc) | |
| 657 | − dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle, | |
| 658 | − rc); | |
| 659 | − | |
| 660 | − tpm_buf_destroy(&buf); | |
| 661 | −} | |
| 662 | − | |
| 663 | 659 | /** |
| 664 | 660 | * tpm2_unseal_cmd() - execute a TPM2_Unload command |
| 665 | 661 | * |
| @@ -697,7 +693,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, · 31 unmodified lines | ||
| 697 | 693 | options->blobauth /* hmac */, |
| 698 | 694 | TPM_DIGEST_SIZE); |
| 699 | 695 | |
| 700 | − rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 6, flags, | |
| 696 | + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 6, flags, | |
| 701 | 697 | "unsealing"); |
| 702 | 698 | if (rc > 0) |
| 703 | 699 | rc = -EPERM; |
| @@ -774,7 +770,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, · 70 unmodified lines | ||
| 774 | 770 | cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); |
| 775 | 771 | cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); |
| 776 | 772 | |
| 777 | − rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), | |
| 773 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), | |
| 778 | 774 | TPM2_GET_TPM_PT_OUT_BODY_SIZE, 0, desc); |
| 779 | 775 | if (!rc) |
| 780 | 776 | *value = be32_to_cpu(cmd.params.get_tpm_pt_out.value); |
| @@ -809,7 +805,7 @@ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) · 28 unmodified lines | ||
| 809 | 805 | cmd.header.in = tpm2_startup_header; |
| 810 | 806 | |
| 811 | 807 | cmd.params.startup_in.startup_type = cpu_to_be16(startup_type); |
| 812 | − return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, | |
| 808 | + return tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, | |
| 813 | 809 | "attempting to start the TPM"); |
| 814 | 810 | } |
| 815 | 811 | |
| @@ -838,7 +834,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) · 22 unmodified lines | ||
| 838 | 834 | cmd.header.in = tpm2_shutdown_header; |
| 839 | 835 | cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); |
| 840 | 836 | |
| 841 | − rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, | |
| 837 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, | |
| 842 | 838 | "stopping the TPM"); |
| 843 | 839 | |
| 844 | 840 | /* In places where shutdown command is sent there's no much we can do |
| @@ -902,7 +898,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) · 57 unmodified lines | ||
| 902 | 898 | cmd.header.in = tpm2_selftest_header; |
| 903 | 899 | cmd.params.selftest_in.full_test = full; |
| 904 | 900 | |
| 905 | − rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0, | |
| 901 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0, | |
| 906 | 902 | "continue selftest"); |
| 907 | 903 | |
| 908 | 904 | /* At least some prototype chips seem to give RC_TESTING error |
| @@ -953,7 +949,8 @@ static int tpm2_do_selftest(struct tpm_chip *chip) · 44 unmodified lines | ||
| 953 | 949 | cmd.params.pcrread_in.pcr_select[1] = 0x00; |
| 954 | 950 | cmd.params.pcrread_in.pcr_select[2] = 0x00; |
| 955 | 951 | |
| 956 | − rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL); | |
| 952 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, | |
| 953 | + NULL); | |
| 957 | 954 | if (rc < 0) |
| 958 | 955 | break; |
| 959 | 956 | |
| @@ -986,7 +983,7 @@ int tpm2_probe(struct tpm_chip *chip) · 26 unmodified lines | ||
| 986 | 983 | cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100); |
| 987 | 984 | cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); |
| 988 | 985 | |
| 989 | − rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL); | |
| 986 | + rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, NULL); | |
| 990 | 987 | if (rc < 0) |
| 991 | 988 | return rc; |
| 992 | 989 | |
| @@ -1024,7 +1021,7 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) · 31 unmodified lines | ||
| 1024 | 1021 | tpm_buf_append_u32(&buf, 0); |
| 1025 | 1022 | tpm_buf_append_u32(&buf, 1); |
| 1026 | 1023 | |
| 1027 | − rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 9, 0, | |
| 1024 | + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 9, 0, | |
| 1028 | 1025 | "get tpm pcr allocation"); |
| 1029 | 1026 | if (rc) |
| 1030 | 1027 | goto out; |
| @@ -1067,15 +1064,76 @@ out: · 36 unmodified lines | ||
| 1067 | 1064 | return rc; |
| 1068 | 1065 | } |
| 1069 | 1066 | |
| 1067 | +static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) | |
| 1068 | +{ | |
| 1069 | + struct tpm_buf buf; | |
| 1070 | + u32 nr_commands; | |
| 1071 | + u32 *attrs; | |
| 1072 | + u32 cc; | |
| 1073 | + int i; | |
| 1074 | + int rc; | |
| 1075 | + | |
| 1076 | + rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL); | |
| 1077 | + if (rc) | |
| 1078 | + goto out; | |
| 1079 | + | |
| 1080 | + if (nr_commands > 0xFFFFF) { | |
| 1081 | + rc = -EFAULT; | |
| 1082 | + goto out; | |
| 1083 | + } | |
| 1084 | + | |
| 1085 | + chip->cc_attrs_tbl = devm_kzalloc(&chip->dev, 4 * nr_commands, | |
| 1086 | + GFP_KERNEL); | |
| 1087 | + | |
| 1088 | + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); | |
| 1089 | + if (rc) | |
| 1090 | + goto out; | |
| 1091 | + | |
| 1092 | + tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS); | |
| 1093 | + tpm_buf_append_u32(&buf, TPM2_CC_FIRST); | |
| 1094 | + tpm_buf_append_u32(&buf, nr_commands); | |
| 1095 | + | |
| 1096 | + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, | |
| 1097 | + 9 + 4 * nr_commands, 0, NULL); | |
| 1098 | + if (rc) { | |
| 1099 | + tpm_buf_destroy(&buf); | |
| 1100 | + goto out; | |
| 1101 | + } | |
| 1102 | + | |
| 1103 | + if (nr_commands != | |
| 1104 | + be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) { | |
| 1105 | + tpm_buf_destroy(&buf); | |
| 1106 | + goto out; | |
| 1107 | + } | |
| 1108 | + | |
| 1109 | + chip->nr_commands = nr_commands; | |
| 1110 | + | |
| 1111 | + attrs = (u32 *)&buf.data[TPM_HEADER_SIZE + 9]; | |
| 1112 | + for (i = 0; i < nr_commands; i++, attrs++) { | |
| 1113 | + chip->cc_attrs_tbl[i] = be32_to_cpup(attrs); | |
| 1114 | + cc = chip->cc_attrs_tbl[i] & 0xFFFF; | |
| 1115 | + | |
| 1116 | + if (cc == TPM2_CC_CONTEXT_SAVE || cc == TPM2_CC_FLUSH_CONTEXT) { | |
| 1117 | + chip->cc_attrs_tbl[i] &= | |
| 1118 | + ~(GENMASK(2, 0) << TPM2_CC_ATTR_CHANDLES); | |
| 1119 | + chip->cc_attrs_tbl[i] |= 1 << TPM2_CC_ATTR_CHANDLES; | |
| 1120 | + } | |
| 1121 | + } | |
| 1122 | + | |
| 1123 | + tpm_buf_destroy(&buf); | |
| 1124 | + | |
| 1125 | +out: | |
| 1126 | + if (rc > 0) | |
| 1127 | + rc = -ENODEV; | |
| 1128 | + return rc; | |
| 1129 | +} | |
| 1130 | + | |
| 1070 | 1131 | /** |
| 1071 | 1132 | * tpm2_auto_startup - Perform the standard automatic TPM initialization |
| 1072 | 1133 | * sequence |
| 1073 | 1134 | * @chip: TPM chip to use |
| 1074 | 1135 | * |
| 1075 | − * Initializes timeout values for operation and command durations, conducts | |
| 1076 | − * a self-test and reads the list of active PCR banks. | |
| 1077 | − * | |
| 1078 | − * Return: 0 on success. Otherwise, a system error code is returned. | |
| 1136 | + * Returns 0 on success, < 0 in case of fatal error. | |
| 1079 | 1137 | */ |
| 1080 | 1138 | int tpm2_auto_startup(struct tpm_chip *chip) |
| 1081 | 1139 | { |
| @@ -1104,9 +1162,24 @@ int tpm2_auto_startup(struct tpm_chip *chip) · 22 unmodified lines | ||
| 1104 | 1162 | } |
| 1105 | 1163 | |
| 1106 | 1164 | rc = tpm2_get_pcr_allocation(chip); |
| 1165 | + if (rc) | |
| 1166 | + goto out; | |
| 1167 | + | |
| 1168 | + rc = tpm2_get_cc_attrs_tbl(chip); | |
| 1107 | 1169 | |
| 1108 | 1170 | out: |
| 1109 | 1171 | if (rc > 0) |
| 1110 | 1172 | rc = -ENODEV; |
| 1111 | 1173 | return rc; |
| 1112 | 1174 | } |
| 1175 | + | |
| 1176 | +int tpm2_find_cc(struct tpm_chip *chip, u32 cc) | |
| 1177 | +{ | |
| 1178 | + int i; | |
| 1179 | + | |
| 1180 | + for (i = 0; i < chip->nr_commands; i++) | |
| 1181 | + if (cc == (chip->cc_attrs_tbl[i] & GENMASK(15, 0))) | |
| 1182 | + return i; | |
| 1183 | + | |
| 1184 | + return -1; | |
| 1185 | +} | |
| @@ -0,0 +1,528 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2016 Intel Corporation | |
| 3 | + * | |
| 4 | + * Authors: | |
| 5 | + * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | |
| 6 | + * | |
| 7 | + * Maintained by: <tpmdd-devel@lists.sourceforge.net> | |
| 8 | + * | |
| 9 | + * This file contains TPM2 protocol implementations of the commands | |
| 10 | + * used by the kernel internally. | |
| 11 | + * | |
| 12 | + * This program is free software; you can redistribute it and/or | |
| 13 | + * modify it under the terms of the GNU General Public License | |
| 14 | + * as published by the Free Software Foundation; version 2 | |
| 15 | + * of the License. | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#include <linux/gfp.h> | |
| 19 | +#include <asm/unaligned.h> | |
| 20 | +#include "tpm.h" | |
| 21 | + | |
| 22 | +enum tpm2_handle_types { | |
| 23 | + TPM2_HT_HMAC_SESSION = 0x02000000, | |
| 24 | + TPM2_HT_POLICY_SESSION = 0x03000000, | |
| 25 | + TPM2_HT_TRANSIENT = 0x80000000, | |
| 26 | +}; | |
| 27 | + | |
| 28 | +struct tpm2_context { | |
| 29 | + __be64 sequence; | |
| 30 | + __be32 saved_handle; | |
| 31 | + __be32 hierarchy; | |
| 32 | + __be16 blob_size; | |
| 33 | +} __packed; | |
| 34 | + | |
| 35 | +static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space) | |
| 36 | +{ | |
| 37 | + int i; | |
| 38 | + | |
| 39 | + for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) { | |
| 40 | + if (space->session_tbl[i]) | |
| 41 | + tpm2_flush_context_cmd(chip, space->session_tbl[i], | |
| 42 | + TPM_TRANSMIT_UNLOCKED); | |
| 43 | + } | |
| 44 | +} | |
| 45 | + | |
| 46 | +int tpm2_init_space(struct tpm_space *space) | |
| 47 | +{ | |
| 48 | + space->context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); | |
| 49 | + if (!space->context_buf) | |
| 50 | + return -ENOMEM; | |
| 51 | + | |
| 52 | + space->session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); | |
| 53 | + if (space->session_buf == NULL) { | |
| 54 | + kfree(space->context_buf); | |
| 55 | + return -ENOMEM; | |
| 56 | + } | |
| 57 | + | |
| 58 | + return 0; | |
| 59 | +} | |
| 60 | + | |
| 61 | +void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space) | |
| 62 | +{ | |
| 63 | + mutex_lock(&chip->tpm_mutex); | |
| 64 | + tpm2_flush_sessions(chip, space); | |
| 65 | + mutex_unlock(&chip->tpm_mutex); | |
| 66 | + kfree(space->context_buf); | |
| 67 | + kfree(space->session_buf); | |
| 68 | +} | |
| 69 | + | |
| 70 | +static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, | |
| 71 | + unsigned int *offset, u32 *handle) | |
| 72 | +{ | |
| 73 | + struct tpm_buf tbuf; | |
| 74 | + struct tpm2_context *ctx; | |
| 75 | + unsigned int body_size; | |
| 76 | + int rc; | |
| 77 | + | |
| 78 | + rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD); | |
| 79 | + if (rc) | |
| 80 | + return rc; | |
| 81 | + | |
| 82 | + ctx = (struct tpm2_context *)&buf[*offset]; | |
| 83 | + body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size); | |
| 84 | + tpm_buf_append(&tbuf, &buf[*offset], body_size); | |
| 85 | + | |
| 86 | + rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4, | |
| 87 | + TPM_TRANSMIT_UNLOCKED, NULL); | |
| 88 | + if (rc < 0) { | |
| 89 | + dev_warn(&chip->dev, "%s: failed with a system error %d\n", | |
| 90 | + __func__, rc); | |
| 91 | + tpm_buf_destroy(&tbuf); | |
| 92 | + return -EFAULT; | |
| 93 | + } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE || | |
| 94 | + rc == TPM2_RC_REFERENCE_H0) { | |
| 95 | + /* | |
| 96 | + * TPM_RC_HANDLE means that the session context can't | |
| 97 | + * be loaded because of an internal counter mismatch | |
| 98 | + * that makes the TPM think there might have been a | |
| 99 | + * replay. This might happen if the context was saved | |
| 100 | + * and loaded outside the space. | |
| 101 | + * | |
| 102 | + * TPM_RC_REFERENCE_H0 means the session has been | |
| 103 | + * flushed outside the space | |
| 104 | + */ | |
| 105 | + rc = -ENOENT; | |
| 106 | + tpm_buf_destroy(&tbuf); | |
| 107 | + } else if (rc > 0) { | |
| 108 | + dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", | |
| 109 | + __func__, rc); | |
| 110 | + tpm_buf_destroy(&tbuf); | |
| 111 | + return -EFAULT; | |
| 112 | + } | |
| 113 | + | |
| 114 | + *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]); | |
| 115 | + *offset += body_size; | |
| 116 | + | |
| 117 | + tpm_buf_destroy(&tbuf); | |
| 118 | + return 0; | |
| 119 | +} | |
| 120 | + | |
| 121 | +static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, | |
| 122 | + unsigned int buf_size, unsigned int *offset) | |
| 123 | +{ | |
| 124 | + struct tpm_buf tbuf; | |
| 125 | + unsigned int body_size; | |
| 126 | + int rc; | |
| 127 | + | |
| 128 | + rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE); | |
| 129 | + if (rc) | |
| 130 | + return rc; | |
| 131 | + | |
| 132 | + tpm_buf_append_u32(&tbuf, handle); | |
| 133 | + | |
| 134 | + rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0, | |
| 135 | + TPM_TRANSMIT_UNLOCKED, NULL); | |
| 136 | + if (rc < 0) { | |
| 137 | + dev_warn(&chip->dev, "%s: failed with a system error %d\n", | |
| 138 | + __func__, rc); | |
| 139 | + tpm_buf_destroy(&tbuf); | |
| 140 | + return -EFAULT; | |
| 141 | + } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) { | |
| 142 | + tpm_buf_destroy(&tbuf); | |
| 143 | + return -ENOENT; | |
| 144 | + } else if (rc) { | |
| 145 | + dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", | |
| 146 | + __func__, rc); | |
| 147 | + tpm_buf_destroy(&tbuf); | |
| 148 | + return -EFAULT; | |
| 149 | + } | |
| 150 | + | |
| 151 | + body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE; | |
| 152 | + if ((*offset + body_size) > buf_size) { | |
| 153 | + dev_warn(&chip->dev, "%s: out of backing storage\n", __func__); | |
| 154 | + tpm_buf_destroy(&tbuf); | |
| 155 | + return -ENOMEM; | |
| 156 | + } | |
| 157 | + | |
| 158 | + memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size); | |
| 159 | + *offset += body_size; | |
| 160 | + tpm_buf_destroy(&tbuf); | |
| 161 | + return 0; | |
| 162 | +} | |
| 163 | + | |
| 164 | +static void tpm2_flush_space(struct tpm_chip *chip) | |
| 165 | +{ | |
| 166 | + struct tpm_space *space = &chip->work_space; | |
| 167 | + int i; | |
| 168 | + | |
| 169 | + for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) | |
| 170 | + if (space->context_tbl[i] && ~space->context_tbl[i]) | |
| 171 | + tpm2_flush_context_cmd(chip, space->context_tbl[i], | |
| 172 | + TPM_TRANSMIT_UNLOCKED); | |
| 173 | + | |
| 174 | + tpm2_flush_sessions(chip, space); | |
| 175 | +} | |
| 176 | + | |
| 177 | +static int tpm2_load_space(struct tpm_chip *chip) | |
| 178 | +{ | |
| 179 | + struct tpm_space *space = &chip->work_space; | |
| 180 | + unsigned int offset; | |
| 181 | + int i; | |
| 182 | + int rc; | |
| 183 | + | |
| 184 | + for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) { | |
| 185 | + if (!space->context_tbl[i]) | |
| 186 | + continue; | |
| 187 | + | |
| 188 | + /* sanity check, should never happen */ | |
| 189 | + if (~space->context_tbl[i]) { | |
| 190 | + dev_err(&chip->dev, "context table is inconsistent"); | |
| 191 | + return -EFAULT; | |
| 192 | + } | |
| 193 | + | |
| 194 | + rc = tpm2_load_context(chip, space->context_buf, &offset, | |
| 195 | + &space->context_tbl[i]); | |
| 196 | + if (rc) | |
| 197 | + return rc; | |
| 198 | + } | |
| 199 | + | |
| 200 | + for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) { | |
| 201 | + u32 handle; | |
| 202 | + | |
| 203 | + if (!space->session_tbl[i]) | |
| 204 | + continue; | |
| 205 | + | |
| 206 | + rc = tpm2_load_context(chip, space->session_buf, | |
| 207 | + &offset, &handle); | |
| 208 | + if (rc == -ENOENT) { | |
| 209 | + /* load failed, just forget session */ | |
| 210 | + space->session_tbl[i] = 0; | |
| 211 | + } else if (rc) { | |
| 212 | + tpm2_flush_space(chip); | |
| 213 | + return rc; | |
| 214 | + } | |
| 215 | + if (handle != space->session_tbl[i]) { | |
| 216 | + dev_warn(&chip->dev, "session restored to wrong handle\n"); | |
| 217 | + tpm2_flush_space(chip); | |
| 218 | + return -EFAULT; | |
| 219 | + } | |
| 220 | + } | |
| 221 | + | |
| 222 | + return 0; | |
| 223 | +} | |
| 224 | + | |
| 225 | +static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle) | |
| 226 | +{ | |
| 227 | + u32 vhandle = be32_to_cpup((__be32 *)handle); | |
| 228 | + u32 phandle; | |
| 229 | + int i; | |
| 230 | + | |
| 231 | + i = 0xFFFFFF - (vhandle & 0xFFFFFF); | |
| 232 | + if (i >= ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i]) | |
| 233 | + return false; | |
| 234 | + | |
| 235 | + phandle = space->context_tbl[i]; | |
| 236 | + *((__be32 *)handle) = cpu_to_be32(phandle); | |
| 237 | + return true; | |
| 238 | +} | |
| 239 | + | |
| 240 | +static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd) | |
| 241 | +{ | |
| 242 | + struct tpm_space *space = &chip->work_space; | |
| 243 | + unsigned int nr_handles; | |
| 244 | + u32 attrs; | |
| 245 | + u32 *handle; | |
| 246 | + int i; | |
| 247 | + | |
| 248 | + i = tpm2_find_cc(chip, cc); | |
| 249 | + if (i < 0) | |
| 250 | + return -EINVAL; | |
| 251 | + | |
| 252 | + attrs = chip->cc_attrs_tbl[i]; | |
| 253 | + nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0); | |
| 254 | + | |
| 255 | + handle = (u32 *)&cmd[TPM_HEADER_SIZE]; | |
| 256 | + for (i = 0; i < nr_handles; i++, handle++) { | |
| 257 | + if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) { | |
| 258 | + if (!tpm2_map_to_phandle(space, handle)) | |
| 259 | + return -EINVAL; | |
| 260 | + } | |
| 261 | + } | |
| 262 | + | |
| 263 | + return 0; | |
| 264 | +} | |
| 265 | + | |
| 266 | +int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, | |
| 267 | + u8 *cmd) | |
| 268 | +{ | |
| 269 | + int rc; | |
| 270 | + | |
| 271 | + if (!space) | |
| 272 | + return 0; | |
| 273 | + | |
| 274 | + memcpy(&chip->work_space.context_tbl, &space->context_tbl, | |
| 275 | + sizeof(space->context_tbl)); | |
| 276 | + memcpy(&chip->work_space.session_tbl, &space->session_tbl, | |
| 277 | + sizeof(space->session_tbl)); | |
| 278 | + memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE); | |
| 279 | + memcpy(chip->work_space.session_buf, space->session_buf, PAGE_SIZE); | |
| 280 | + | |
| 281 | + rc = tpm2_load_space(chip); | |
| 282 | + if (rc) { | |
| 283 | + tpm2_flush_space(chip); | |
| 284 | + return rc; | |
| 285 | + } | |
| 286 | + | |
| 287 | + rc = tpm2_map_command(chip, cc, cmd); | |
| 288 | + if (rc) { | |
| 289 | + tpm2_flush_space(chip); | |
| 290 | + return rc; | |
| 291 | + } | |
| 292 | + | |
| 293 | + return 0; | |
| 294 | +} | |
| 295 | + | |
| 296 | +static bool tpm2_add_session(struct tpm_chip *chip, u32 handle) | |
| 297 | +{ | |
| 298 | + struct tpm_space *space = &chip->work_space; | |
| 299 | + int i; | |
| 300 | + | |
| 301 | + for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) | |
| 302 | + if (space->session_tbl[i] == 0) | |
| 303 | + break; | |
| 304 | + | |
| 305 | + if (i == ARRAY_SIZE(space->session_tbl)) | |
| 306 | + return false; | |
| 307 | + | |
| 308 | + space->session_tbl[i] = handle; | |
| 309 | + return true; | |
| 310 | +} | |
| 311 | + | |
| 312 | +static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc) | |
| 313 | +{ | |
| 314 | + int i; | |
| 315 | + | |
| 316 | + for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) { | |
| 317 | + if (alloc) { | |
| 318 | + if (!space->context_tbl[i]) { | |
| 319 | + space->context_tbl[i] = phandle; | |
| 320 | + break; | |
| 321 | + } | |
| 322 | + } else if (space->context_tbl[i] == phandle) | |
| 323 | + break; | |
| 324 | + } | |
| 325 | + | |
| 326 | + if (i == ARRAY_SIZE(space->context_tbl)) | |
| 327 | + return 0; | |
| 328 | + | |
| 329 | + return TPM2_HT_TRANSIENT | (0xFFFFFF - i); | |
| 330 | +} | |
| 331 | + | |
| 332 | +static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, | |
| 333 | + size_t len) | |
| 334 | +{ | |
| 335 | + struct tpm_space *space = &chip->work_space; | |
| 336 | + struct tpm_output_header *header = (void *)rsp; | |
| 337 | + u32 phandle; | |
| 338 | + u32 phandle_type; | |
| 339 | + u32 vhandle; | |
| 340 | + u32 attrs; | |
| 341 | + int i; | |
| 342 | + | |
| 343 | + if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) | |
| 344 | + return 0; | |
| 345 | + | |
| 346 | + i = tpm2_find_cc(chip, cc); | |
| 347 | + /* sanity check, should never happen */ | |
| 348 | + if (i < 0) | |
| 349 | + return -EFAULT; | |
| 350 | + | |
| 351 | + attrs = chip->cc_attrs_tbl[i]; | |
| 352 | + if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1)) | |
| 353 | + return 0; | |
| 354 | + | |
| 355 | + phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]); | |
| 356 | + phandle_type = phandle & 0xFF000000; | |
| 357 | + | |
| 358 | + switch (phandle_type) { | |
| 359 | + case TPM2_HT_TRANSIENT: | |
| 360 | + vhandle = tpm2_map_to_vhandle(space, phandle, true); | |
| 361 | + if (!vhandle) | |
| 362 | + goto out_no_slots; | |
| 363 | + | |
| 364 | + *(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle); | |
| 365 | + break; | |
| 366 | + case TPM2_HT_HMAC_SESSION: | |
| 367 | + case TPM2_HT_POLICY_SESSION: | |
| 368 | + if (!tpm2_add_session(chip, phandle)) | |
| 369 | + goto out_no_slots; | |
| 370 | + break; | |
| 371 | + default: | |
| 372 | + dev_err(&chip->dev, "%s: unknown handle 0x%08X\n", | |
| 373 | + __func__, phandle); | |
| 374 | + break; | |
| 375 | + }; | |
| 376 | + | |
| 377 | + return 0; | |
| 378 | +out_no_slots: | |
| 379 | + tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_UNLOCKED); | |
| 380 | + dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, | |
| 381 | + phandle); | |
| 382 | + return -ENOMEM; | |
| 383 | +} | |
| 384 | + | |
| 385 | +struct tpm2_cap_handles { | |
| 386 | + u8 more_data; | |
| 387 | + __be32 capability; | |
| 388 | + __be32 count; | |
| 389 | + __be32 handles[]; | |
| 390 | +} __packed; | |
| 391 | + | |
| 392 | +static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp, | |
| 393 | + size_t len) | |
| 394 | +{ | |
| 395 | + struct tpm_space *space = &chip->work_space; | |
| 396 | + struct tpm_output_header *header = (void *)rsp; | |
| 397 | + struct tpm2_cap_handles *data; | |
| 398 | + u32 phandle; | |
| 399 | + u32 phandle_type; | |
| 400 | + u32 vhandle; | |
| 401 | + int i; | |
| 402 | + int j; | |
| 403 | + | |
| 404 | + if (cc != TPM2_CC_GET_CAPABILITY || | |
| 405 | + be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) { | |
| 406 | + return 0; | |
| 407 | + } | |
| 408 | + | |
| 409 | + if (len < TPM_HEADER_SIZE + 9) | |
| 410 | + return -EFAULT; | |
| 411 | + | |
| 412 | + data = (void *)&rsp[TPM_HEADER_SIZE]; | |
| 413 | + if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES) | |
| 414 | + return 0; | |
| 415 | + | |
| 416 | + if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count)) | |
| 417 | + return -EFAULT; | |
| 418 | + | |
| 419 | + for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) { | |
| 420 | + phandle = be32_to_cpup((__be32 *)&data->handles[i]); | |
| 421 | + phandle_type = phandle & 0xFF000000; | |
| 422 | + | |
| 423 | + switch (phandle_type) { | |
| 424 | + case TPM2_HT_TRANSIENT: | |
| 425 | + vhandle = tpm2_map_to_vhandle(space, phandle, false); | |
| 426 | + if (!vhandle) | |
| 427 | + break; | |
| 428 | + | |
| 429 | + data->handles[j] = cpu_to_be32(vhandle); | |
| 430 | + j++; | |
| 431 | + break; | |
| 432 | + | |
| 433 | + default: | |
| 434 | + data->handles[j] = cpu_to_be32(phandle); | |
| 435 | + j++; | |
| 436 | + break; | |
| 437 | + } | |
| 438 | + | |
| 439 | + } | |
| 440 | + | |
| 441 | + header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j); | |
| 442 | + data->count = cpu_to_be32(j); | |
| 443 | + return 0; | |
| 444 | +} | |
| 445 | + | |
| 446 | +static int tpm2_save_space(struct tpm_chip *chip) | |
| 447 | +{ | |
| 448 | + struct tpm_space *space = &chip->work_space; | |
| 449 | + unsigned int offset; | |
| 450 | + int i; | |
| 451 | + int rc; | |
| 452 | + | |
| 453 | + for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) { | |
| 454 | + if (!(space->context_tbl[i] && ~space->context_tbl[i])) | |
| 455 | + continue; | |
| 456 | + | |
| 457 | + rc = tpm2_save_context(chip, space->context_tbl[i], | |
| 458 | + space->context_buf, PAGE_SIZE, | |
| 459 | + &offset); | |
| 460 | + if (rc == -ENOENT) { | |
| 461 | + space->context_tbl[i] = 0; | |
| 462 | + continue; | |
| 463 | + } else if (rc) | |
| 464 | + return rc; | |
| 465 | + | |
| 466 | + tpm2_flush_context_cmd(chip, space->context_tbl[i], | |
| 467 | + TPM_TRANSMIT_UNLOCKED); | |
| 468 | + space->context_tbl[i] = ~0; | |
| 469 | + } | |
| 470 | + | |
| 471 | + for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) { | |
| 472 | + if (!space->session_tbl[i]) | |
| 473 | + continue; | |
| 474 | + | |
| 475 | + rc = tpm2_save_context(chip, space->session_tbl[i], | |
| 476 | + space->session_buf, PAGE_SIZE, | |
| 477 | + &offset); | |
| 478 | + | |
| 479 | + if (rc == -ENOENT) { | |
| 480 | + /* handle error saving session, just forget it */ | |
| 481 | + space->session_tbl[i] = 0; | |
| 482 | + } else if (rc < 0) { | |
| 483 | + tpm2_flush_space(chip); | |
| 484 | + return rc; | |
| 485 | + } | |
| 486 | + } | |
| 487 | + | |
| 488 | + return 0; | |
| 489 | +} | |
| 490 | + | |
| 491 | +int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, | |
| 492 | + u32 cc, u8 *buf, size_t *bufsiz) | |
| 493 | +{ | |
| 494 | + struct tpm_output_header *header = (void *)buf; | |
| 495 | + int rc; | |
| 496 | + | |
| 497 | + if (!space) | |
| 498 | + return 0; | |
| 499 | + | |
| 500 | + rc = tpm2_map_response_header(chip, cc, buf, *bufsiz); | |
| 501 | + if (rc) { | |
| 502 | + tpm2_flush_space(chip); | |
| 503 | + return rc; | |
| 504 | + } | |
| 505 | + | |
| 506 | + rc = tpm2_map_response_body(chip, cc, buf, *bufsiz); | |
| 507 | + if (rc) { | |
| 508 | + tpm2_flush_space(chip); | |
| 509 | + return rc; | |
| 510 | + } | |
| 511 | + | |
| 512 | + rc = tpm2_save_space(chip); | |
| 513 | + if (rc) { | |
| 514 | + tpm2_flush_space(chip); | |
| 515 | + return rc; | |
| 516 | + } | |
| 517 | + | |
| 518 | + *bufsiz = be32_to_cpu(header->length); | |
| 519 | + | |
| 520 | + memcpy(&space->context_tbl, &chip->work_space.context_tbl, | |
| 521 | + sizeof(space->context_tbl)); | |
| 522 | + memcpy(&space->session_tbl, &chip->work_space.session_tbl, | |
| 523 | + sizeof(space->session_tbl)); | |
| 524 | + memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE); | |
| 525 | + memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE); | |
| 526 | + | |
| 527 | + return 0; | |
| 528 | +} | |
| @@ -56,18 +56,24 @@ static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, · 55 unmodified lines | ||
| 56 | 56 | |
| 57 | 57 | efispecid = (struct tcg_efi_specid_event *)event_header->event; |
| 58 | 58 | |
| 59 | − for (i = 0; (i < event->count) && (i < TPM2_ACTIVE_PCR_BANKS); | |
| 60 | − i++) { | |
| 59 | + /* Check if event is malformed. */ | |
| 60 | + if (event->count > efispecid->num_algs) | |
| 61 | + return 0; | |
| 62 | + | |
| 63 | + for (i = 0; i < event->count; i++) { | |
| 61 | 64 | halg_size = sizeof(event->digests[i].alg_id); |
| 62 | 65 | memcpy(&halg, marker, halg_size); |
| 63 | 66 | marker = marker + halg_size; |
| 64 | − for (j = 0; (j < efispecid->num_algs); j++) { | |
| 67 | + for (j = 0; j < efispecid->num_algs; j++) { | |
| 65 | 68 | if (halg == efispecid->digest_sizes[j].alg_id) { |
| 66 | − marker = marker + | |
| 69 | + marker += | |
| 67 | 70 | efispecid->digest_sizes[j].digest_size; |
| 68 | 71 | break; |
| 69 | 72 | } |
| 70 | 73 | } |
| 74 | + /* Algorithm without known length. Such event is unparseable. */ | |
| 75 | + if (j == efispecid->num_algs) | |
| 76 | + return 0; | |
| 71 | 77 | } |
| 72 | 78 | |
| 73 | 79 | event_field = (struct tcg_event_field *)marker; |
| @@ -20,6 +20,9 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/rculist.h> |
| 21 | 21 | #include <linux/module.h> |
| 22 | 22 | #include <linux/pm_runtime.h> |
| 23 | +#ifdef CONFIG_ARM64 | |
| 24 | +#include <linux/arm-smccc.h> | |
| 25 | +#endif | |
| 23 | 26 | #include "tpm.h" |
| 24 | 27 | |
| 25 | 28 | #define ACPI_SIG_TPM2 "TPM2" |
| @@ -34,6 +37,16 @@ enum crb_defaults { · 8 unmodified lines | ||
| 34 | 37 | CRB_ACPI_START_INDEX = 1, |
| 35 | 38 | }; |
| 36 | 39 | |
| 40 | +enum crb_loc_ctrl { | |
| 41 | + CRB_LOC_CTRL_REQUEST_ACCESS = BIT(0), | |
| 42 | + CRB_LOC_CTRL_RELINQUISH = BIT(1), | |
| 43 | +}; | |
| 44 | + | |
| 45 | +enum crb_loc_state { | |
| 46 | + CRB_LOC_STATE_LOC_ASSIGNED = BIT(1), | |
| 47 | + CRB_LOC_STATE_TPM_REG_VALID_STS = BIT(7), | |
| 48 | +}; | |
| 49 | + | |
| 37 | 50 | enum crb_ctrl_req { |
| 38 | 51 | CRB_CTRL_REQ_CMD_READY = BIT(0), |
| 39 | 52 | CRB_CTRL_REQ_GO_IDLE = BIT(1), |
| @@ -52,18 +65,28 @@ enum crb_cancel { · 12 unmodified lines | ||
| 52 | 65 | CRB_CANCEL_INVOKE = BIT(0), |
| 53 | 66 | }; |
| 54 | 67 | |
| 55 | −struct crb_control_area { | |
| 56 | − u32 req; | |
| 57 | − u32 sts; | |
| 58 | − u32 cancel; | |
| 59 | − u32 start; | |
| 60 | − u32 int_enable; | |
| 61 | − u32 int_sts; | |
| 62 | − u32 cmd_size; | |
| 63 | − u32 cmd_pa_low; | |
| 64 | − u32 cmd_pa_high; | |
| 65 | − u32 rsp_size; | |
| 66 | − u64 rsp_pa; | |
| 68 | +struct crb_regs_head { | |
| 69 | + u32 loc_state; | |
| 70 | + u32 reserved1; | |
| 71 | + u32 loc_ctrl; | |
| 72 | + u32 loc_sts; | |
| 73 | + u8 reserved2[32]; | |
| 74 | + u64 intf_id; | |
| 75 | + u64 ctrl_ext; | |
| 76 | +} __packed; | |
| 77 | + | |
| 78 | +struct crb_regs_tail { | |
| 79 | + u32 ctrl_req; | |
| 80 | + u32 ctrl_sts; | |
| 81 | + u32 ctrl_cancel; | |
| 82 | + u32 ctrl_start; | |
| 83 | + u32 ctrl_int_enable; | |
| 84 | + u32 ctrl_int_sts; | |
| 85 | + u32 ctrl_cmd_size; | |
| 86 | + u32 ctrl_cmd_pa_low; | |
| 87 | + u32 ctrl_cmd_pa_high; | |
| 88 | + u32 ctrl_rsp_size; | |
| 89 | + u64 ctrl_rsp_pa; | |
| 67 | 90 | } __packed; |
| 68 | 91 | |
| 69 | 92 | enum crb_status { |
| @@ -73,15 +96,26 @@ enum crb_status { · 3 unmodified lines | ||
| 73 | 96 | enum crb_flags { |
| 74 | 97 | CRB_FL_ACPI_START = BIT(0), |
| 75 | 98 | CRB_FL_CRB_START = BIT(1), |
| 99 | + CRB_FL_CRB_SMC_START = BIT(2), | |
| 76 | 100 | }; |
| 77 | 101 | |
| 78 | 102 | struct crb_priv { |
| 79 | 103 | unsigned int flags; |
| 80 | 104 | void __iomem *iobase; |
| 81 | − struct crb_control_area __iomem *cca; | |
| 105 | + struct crb_regs_head __iomem *regs_h; | |
| 106 | + struct crb_regs_tail __iomem *regs_t; | |
| 82 | 107 | u8 __iomem *cmd; |
| 83 | 108 | u8 __iomem *rsp; |
| 84 | 109 | u32 cmd_size; |
| 110 | + u32 smc_func_id; | |
| 111 | +}; | |
| 112 | + | |
| 113 | +struct tpm2_crb_smc { | |
| 114 | + u32 interrupt; | |
| 115 | + u8 interrupt_flags; | |
| 116 | + u8 op_flags; | |
| 117 | + u16 reserved2; | |
| 118 | + u32 smc_func_id; | |
| 85 | 119 | }; |
| 86 | 120 | |
| 87 | 121 | /** |
| @@ -101,15 +135,35 @@ struct crb_priv { · 13 unmodified lines | ||
| 101 | 135 | */ |
| 102 | 136 | static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) |
| 103 | 137 | { |
| 104 | − if (priv->flags & CRB_FL_ACPI_START) | |
| 138 | + if ((priv->flags & CRB_FL_ACPI_START) || | |
| 139 | + (priv->flags & CRB_FL_CRB_SMC_START)) | |
| 105 | 140 | return 0; |
| 106 | 141 | |
| 107 | − iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->cca->req); | |
| 142 | + iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req); | |
| 108 | 143 | /* we don't really care when this settles */ |
| 109 | 144 | |
| 110 | 145 | return 0; |
| 111 | 146 | } |
| 112 | 147 | |
| 148 | +static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, | |
| 149 | + unsigned long timeout) | |
| 150 | +{ | |
| 151 | + ktime_t start; | |
| 152 | + ktime_t stop; | |
| 153 | + | |
| 154 | + start = ktime_get(); | |
| 155 | + stop = ktime_add(start, ms_to_ktime(timeout)); | |
| 156 | + | |
| 157 | + do { | |
| 158 | + if ((ioread32(reg) & mask) == value) | |
| 159 | + return true; | |
| 160 | + | |
| 161 | + usleep_range(50, 100); | |
| 162 | + } while (ktime_before(ktime_get(), stop)); | |
| 163 | + | |
| 164 | + return false; | |
| 165 | +} | |
| 166 | + | |
| 113 | 167 | /** |
| 114 | 168 | * crb_cmd_ready - request tpm crb device to enter ready state |
| 115 | 169 | * |
| @@ -127,35 +181,57 @@ static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) · 11 unmodified lines | ||
| 127 | 181 | static int __maybe_unused crb_cmd_ready(struct device *dev, |
| 128 | 182 | struct crb_priv *priv) |
| 129 | 183 | { |
| 130 | − ktime_t stop, start; | |
| 131 | − | |
| 132 | − if (priv->flags & CRB_FL_ACPI_START) | |
| 184 | + if ((priv->flags & CRB_FL_ACPI_START) || | |
| 185 | + (priv->flags & CRB_FL_CRB_SMC_START)) | |
| 133 | 186 | return 0; |
| 134 | 187 | |
| 135 | − iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->cca->req); | |
| 188 | + iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req); | |
| 189 | + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req, | |
| 190 | + CRB_CTRL_REQ_CMD_READY /* mask */, | |
| 191 | + 0, /* value */ | |
| 192 | + TPM2_TIMEOUT_C)) { | |
| 193 | + dev_warn(dev, "cmdReady timed out\n"); | |
| 194 | + return -ETIME; | |
| 195 | + } | |
| 136 | 196 | |
| 137 | − start = ktime_get(); | |
| 138 | − stop = ktime_add(start, ms_to_ktime(TPM2_TIMEOUT_C)); | |
| 139 | − do { | |
| 140 | − if (!(ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY)) | |
| 141 | − return 0; | |
| 142 | − usleep_range(50, 100); | |
| 143 | − } while (ktime_before(ktime_get(), stop)); | |
| 197 | + return 0; | |
| 198 | +} | |
| 144 | 199 | |
| 145 | − if (ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY) { | |
| 146 | − dev_warn(dev, "cmdReady timed out\n"); | |
| 200 | +static int crb_request_locality(struct tpm_chip *chip, int loc) | |
| 201 | +{ | |
| 202 | + struct crb_priv *priv = dev_get_drvdata(&chip->dev); | |
| 203 | + u32 value = CRB_LOC_STATE_LOC_ASSIGNED | | |
| 204 | + CRB_LOC_STATE_TPM_REG_VALID_STS; | |
| 205 | + | |
| 206 | + if (!priv->regs_h) | |
| 207 | + return 0; | |
| 208 | + | |
| 209 | + iowrite32(CRB_LOC_CTRL_REQUEST_ACCESS, &priv->regs_h->loc_ctrl); | |
| 210 | + if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, value, value, | |
| 211 | + TPM2_TIMEOUT_C)) { | |
| 212 | + dev_warn(&chip->dev, "TPM_LOC_STATE_x.requestAccess timed out\n"); | |
| 147 | 213 | return -ETIME; |
| 148 | 214 | } |
| 149 | 215 | |
| 150 | 216 | return 0; |
| 151 | 217 | } |
| 152 | 218 | |
| 219 | +static void crb_relinquish_locality(struct tpm_chip *chip, int loc) | |
| 220 | +{ | |
| 221 | + struct crb_priv *priv = dev_get_drvdata(&chip->dev); | |
| 222 | + | |
| 223 | + if (!priv->regs_h) | |
| 224 | + return; | |
| 225 | + | |
| 226 | + iowrite32(CRB_LOC_CTRL_RELINQUISH, &priv->regs_h->loc_ctrl); | |
| 227 | +} | |
| 228 | + | |
| 153 | 229 | static u8 crb_status(struct tpm_chip *chip) |
| 154 | 230 | { |
| 155 | 231 | struct crb_priv *priv = dev_get_drvdata(&chip->dev); |
| 156 | 232 | u8 sts = 0; |
| 157 | 233 | |
| 158 | − if ((ioread32(&priv->cca->start) & CRB_START_INVOKE) != | |
| 234 | + if ((ioread32(&priv->regs_t->ctrl_start) & CRB_START_INVOKE) != | |
| 159 | 235 | CRB_START_INVOKE) |
| 160 | 236 | sts |= CRB_DRV_STS_COMPLETE; |
| 161 | 237 | |
| @@ -171,13 +247,12 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) · 9 unmodified lines | ||
| 171 | 247 | if (count < 6) |
| 172 | 248 | return -EIO; |
| 173 | 249 | |
| 174 | − if (ioread32(&priv->cca->sts) & CRB_CTRL_STS_ERROR) | |
| 250 | + if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) | |
| 175 | 251 | return -EIO; |
| 176 | 252 | |
| 177 | 253 | memcpy_fromio(buf, priv->rsp, 6); |
| 178 | 254 | expected = be32_to_cpup((__be32 *) &buf[2]); |
| 179 | − | |
| 180 | − if (expected > count) | |
| 255 | + if (expected > count || expected < 6) | |
| 181 | 256 | return -EIO; |
| 182 | 257 | |
| 183 | 258 | memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6); |
| @@ -202,6 +277,34 @@ static int crb_do_acpi_start(struct tpm_chip *chip) · 18 unmodified lines | ||
| 202 | 277 | return rc; |
| 203 | 278 | } |
| 204 | 279 | |
| 280 | +#ifdef CONFIG_ARM64 | |
| 281 | +/* | |
| 282 | + * This is a TPM Command Response Buffer start method that invokes a | |
| 283 | + * Secure Monitor Call to requrest the firmware to execute or cancel | |
| 284 | + * a TPM 2.0 command. | |
| 285 | + */ | |
| 286 | +static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) | |
| 287 | +{ | |
| 288 | + struct arm_smccc_res res; | |
| 289 | + | |
| 290 | + arm_smccc_smc(func_id, 0, 0, 0, 0, 0, 0, 0, &res); | |
| 291 | + if (res.a0 != 0) { | |
| 292 | + dev_err(dev, | |
| 293 | + FW_BUG "tpm_crb_smc_start() returns res.a0 = 0x%lx\n", | |
| 294 | + res.a0); | |
| 295 | + return -EIO; | |
| 296 | + } | |
| 297 | + | |
| 298 | + return 0; | |
| 299 | +} | |
| 300 | +#else | |
| 301 | +static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) | |
| 302 | +{ | |
| 303 | + dev_err(dev, FW_BUG "tpm_crb: incorrect start method\n"); | |
| 304 | + return -EINVAL; | |
| 305 | +} | |
| 306 | +#endif | |
| 307 | + | |
| 205 | 308 | static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) |
| 206 | 309 | { |
| 207 | 310 | struct crb_priv *priv = dev_get_drvdata(&chip->dev); |
| @@ -210,7 +313,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) · 2 unmodified lines | ||
| 210 | 313 | /* Zero the cancel register so that the next command will not get |
| 211 | 314 | * canceled. |
| 212 | 315 | */ |
| 213 | − iowrite32(0, &priv->cca->cancel); | |
| 316 | + iowrite32(0, &priv->regs_t->ctrl_cancel); | |
| 214 | 317 | |
| 215 | 318 | if (len > priv->cmd_size) { |
| 216 | 319 | dev_err(&chip->dev, "invalid command count value %zd %d\n", |
| @@ -224,11 +327,16 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) · 7 unmodified lines | ||
| 224 | 327 | wmb(); |
| 225 | 328 | |
| 226 | 329 | if (priv->flags & CRB_FL_CRB_START) |
| 227 | − iowrite32(CRB_START_INVOKE, &priv->cca->start); | |
| 330 | + iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); | |
| 228 | 331 | |
| 229 | 332 | if (priv->flags & CRB_FL_ACPI_START) |
| 230 | 333 | rc = crb_do_acpi_start(chip); |
| 231 | 334 | |
| 335 | + if (priv->flags & CRB_FL_CRB_SMC_START) { | |
| 336 | + iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); | |
| 337 | + rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); | |
| 338 | + } | |
| 339 | + | |
| 232 | 340 | return rc; |
| 233 | 341 | } |
| 234 | 342 | |
| @@ -236,7 +344,7 @@ static void crb_cancel(struct tpm_chip *chip) · 1 unmodified line | ||
| 236 | 344 | { |
| 237 | 345 | struct crb_priv *priv = dev_get_drvdata(&chip->dev); |
| 238 | 346 | |
| 239 | − iowrite32(CRB_CANCEL_INVOKE, &priv->cca->cancel); | |
| 347 | + iowrite32(CRB_CANCEL_INVOKE, &priv->regs_t->ctrl_cancel); | |
| 240 | 348 | |
| 241 | 349 | if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip)) |
| 242 | 350 | dev_err(&chip->dev, "ACPI Start failed\n"); |
| @@ -245,7 +353,7 @@ static void crb_cancel(struct tpm_chip *chip) · 2 unmodified lines | ||
| 245 | 353 | static bool crb_req_canceled(struct tpm_chip *chip, u8 status) |
| 246 | 354 | { |
| 247 | 355 | struct crb_priv *priv = dev_get_drvdata(&chip->dev); |
| 248 | − u32 cancel = ioread32(&priv->cca->cancel); | |
| 356 | + u32 cancel = ioread32(&priv->regs_t->ctrl_cancel); | |
| 249 | 357 | |
| 250 | 358 | return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE; |
| 251 | 359 | } |
| @@ -257,6 +365,8 @@ static const struct tpm_class_ops tpm_crb = { · 5 unmodified lines | ||
| 257 | 365 | .send = crb_send, |
| 258 | 366 | .cancel = crb_cancel, |
| 259 | 367 | .req_canceled = crb_req_canceled, |
| 368 | + .request_locality = crb_request_locality, | |
| 369 | + .relinquish_locality = crb_relinquish_locality, | |
| 260 | 370 | .req_complete_mask = CRB_DRV_STS_COMPLETE, |
| 261 | 371 | .req_complete_val = CRB_DRV_STS_COMPLETE, |
| 262 | 372 | }; |
| @@ -295,6 +405,27 @@ static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv, · 32 unmodified lines | ||
| 295 | 405 | return priv->iobase + (new_res.start - io_res->start); |
| 296 | 406 | } |
| 297 | 407 | |
| 408 | +/* | |
| 409 | + * Work around broken BIOSs that return inconsistent values from the ACPI | |
| 410 | + * region vs the registers. Trust the ACPI region. Such broken systems | |
| 411 | + * probably cannot send large TPM commands since the buffer will be truncated. | |
| 412 | + */ | |
| 413 | +static u64 crb_fixup_cmd_size(struct device *dev, struct resource *io_res, | |
| 414 | + u64 start, u64 size) | |
| 415 | +{ | |
| 416 | + if (io_res->start > start || io_res->end < start) | |
| 417 | + return size; | |
| 418 | + | |
| 419 | + if (start + size - 1 <= io_res->end) | |
| 420 | + return size; | |
| 421 | + | |
| 422 | + dev_err(dev, | |
| 423 | + FW_BUG "ACPI region does not cover the entire command/response buffer. %pr vs %llx %llx\n", | |
| 424 | + io_res, start, size); | |
| 425 | + | |
| 426 | + return io_res->end - start + 1; | |
| 427 | +} | |
| 428 | + | |
| 298 | 429 | static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, |
| 299 | 430 | struct acpi_table_tpm2 *buf) |
| 300 | 431 | { |
| @@ -324,10 +455,22 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, · 23 unmodified lines | ||
| 324 | 455 | if (IS_ERR(priv->iobase)) |
| 325 | 456 | return PTR_ERR(priv->iobase); |
| 326 | 457 | |
| 327 | − priv->cca = crb_map_res(dev, priv, &io_res, buf->control_address, | |
| 328 | − sizeof(struct crb_control_area)); | |
| 329 | − if (IS_ERR(priv->cca)) | |
| 330 | − return PTR_ERR(priv->cca); | |
| 458 | + /* The ACPI IO region starts at the head area and continues to include | |
| 459 | + * the control area, as one nice sane region except for some older | |
| 460 | + * stuff that puts the control area outside the ACPI IO region. | |
| 461 | + */ | |
| 462 | + if (!(priv->flags & CRB_FL_ACPI_START)) { | |
| 463 | + if (buf->control_address == io_res.start + | |
| 464 | + sizeof(*priv->regs_h)) | |
| 465 | + priv->regs_h = priv->iobase; | |
| 466 | + else | |
| 467 | + dev_warn(dev, FW_BUG "Bad ACPI memory layout"); | |
| 468 | + } | |
| 469 | + | |
| 470 | + priv->regs_t = crb_map_res(dev, priv, &io_res, buf->control_address, | |
| 471 | + sizeof(struct crb_regs_tail)); | |
| 472 | + if (IS_ERR(priv->regs_t)) | |
| 473 | + return PTR_ERR(priv->regs_t); | |
| 331 | 474 | |
| 332 | 475 | /* |
| 333 | 476 | * PTT HW bug w/a: wake up the device to access |
| @@ -337,10 +480,11 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, · 3 unmodified lines | ||
| 337 | 480 | if (ret) |
| 338 | 481 | return ret; |
| 339 | 482 | |
| 340 | − pa_high = ioread32(&priv->cca->cmd_pa_high); | |
| 341 | − pa_low = ioread32(&priv->cca->cmd_pa_low); | |
| 483 | + pa_high = ioread32(&priv->regs_t->ctrl_cmd_pa_high); | |
| 484 | + pa_low = ioread32(&priv->regs_t->ctrl_cmd_pa_low); | |
| 342 | 485 | cmd_pa = ((u64)pa_high << 32) | pa_low; |
| 343 | − cmd_size = ioread32(&priv->cca->cmd_size); | |
| 486 | + cmd_size = crb_fixup_cmd_size(dev, &io_res, cmd_pa, | |
| 487 | + ioread32(&priv->regs_t->ctrl_cmd_size)); | |
| 344 | 488 | |
| 345 | 489 | dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n", |
| 346 | 490 | pa_high, pa_low, cmd_size); |
| @@ -351,9 +495,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, · 4 unmodified lines | ||
| 351 | 495 | goto out; |
| 352 | 496 | } |
| 353 | 497 | |
| 354 | − memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8); | |
| 498 | + memcpy_fromio(&rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8); | |
| 355 | 499 | rsp_pa = le64_to_cpu(rsp_pa); |
| 356 | − rsp_size = ioread32(&priv->cca->rsp_size); | |
| 500 | + rsp_size = crb_fixup_cmd_size(dev, &io_res, rsp_pa, | |
| 501 | + ioread32(&priv->regs_t->ctrl_rsp_size)); | |
| 357 | 502 | |
| 358 | 503 | if (cmd_pa != rsp_pa) { |
| 359 | 504 | priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size); |
| @@ -386,6 +531,7 @@ static int crb_acpi_add(struct acpi_device *device) · 26 unmodified lines | ||
| 386 | 531 | struct crb_priv *priv; |
| 387 | 532 | struct tpm_chip *chip; |
| 388 | 533 | struct device *dev = &device->dev; |
| 534 | + struct tpm2_crb_smc *crb_smc; | |
| 389 | 535 | acpi_status status; |
| 390 | 536 | u32 sm; |
| 391 | 537 | int rc; |
| @@ -418,6 +564,19 @@ static int crb_acpi_add(struct acpi_device *device) · 26 unmodified lines | ||
| 418 | 564 | sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) |
| 419 | 565 | priv->flags |= CRB_FL_ACPI_START; |
| 420 | 566 | |
| 567 | + if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_SMC) { | |
| 568 | + if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) { | |
| 569 | + dev_err(dev, | |
| 570 | + FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n", | |
| 571 | + buf->header.length, | |
| 572 | + ACPI_TPM2_COMMAND_BUFFER_WITH_SMC); | |
| 573 | + return -EINVAL; | |
| 574 | + } | |
| 575 | + crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf, sizeof(*buf)); | |
| 576 | + priv->smc_func_id = crb_smc->smc_func_id; | |
| 577 | + priv->flags |= CRB_FL_CRB_SMC_START; | |
| 578 | + } | |
| 579 | + | |
| 421 | 580 | rc = crb_map_io(device, priv, buf); |
| 422 | 581 | if (rc) |
| 423 | 582 | return rc; |
| @@ -463,8 +622,7 @@ static int crb_acpi_remove(struct acpi_device *device) · 39 unmodified lines | ||
| 463 | 622 | return 0; |
| 464 | 623 | } |
| 465 | 624 | |
| 466 | −#ifdef CONFIG_PM | |
| 467 | −static int crb_pm_runtime_suspend(struct device *dev) | |
| 625 | +static int __maybe_unused crb_pm_runtime_suspend(struct device *dev) | |
| 468 | 626 | { |
| 469 | 627 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| 470 | 628 | struct crb_priv *priv = dev_get_drvdata(&chip->dev); |
| @@ -472,17 +630,38 @@ static int crb_pm_runtime_suspend(struct device *dev) · 1 unmodified line | ||
| 472 | 630 | return crb_go_idle(dev, priv); |
| 473 | 631 | } |
| 474 | 632 | |
| 475 | −static int crb_pm_runtime_resume(struct device *dev) | |
| 633 | +static int __maybe_unused crb_pm_runtime_resume(struct device *dev) | |
| 476 | 634 | { |
| 477 | 635 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| 478 | 636 | struct crb_priv *priv = dev_get_drvdata(&chip->dev); |
| 479 | 637 | |
| 480 | 638 | return crb_cmd_ready(dev, priv); |
| 481 | 639 | } |
| 482 | −#endif /* CONFIG_PM */ | |
| 640 | + | |
| 641 | +static int __maybe_unused crb_pm_suspend(struct device *dev) | |
| 642 | +{ | |
| 643 | + int ret; | |
| 644 | + | |
| 645 | + ret = tpm_pm_suspend(dev); | |
| 646 | + if (ret) | |
| 647 | + return ret; | |
| 648 | + | |
| 649 | + return crb_pm_runtime_suspend(dev); | |
| 650 | +} | |
| 651 | + | |
| 652 | +static int __maybe_unused crb_pm_resume(struct device *dev) | |
| 653 | +{ | |
| 654 | + int ret; | |
| 655 | + | |
| 656 | + ret = crb_pm_runtime_resume(dev); | |
| 657 | + if (ret) | |
| 658 | + return ret; | |
| 659 | + | |
| 660 | + return tpm_pm_resume(dev); | |
| 661 | +} | |
| 483 | 662 | |
| 484 | 663 | static const struct dev_pm_ops crb_pm = { |
| 485 | − SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume) | |
| 664 | + SET_SYSTEM_SLEEP_PM_OPS(crb_pm_suspend, crb_pm_resume) | |
| 486 | 665 | SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL) |
| 487 | 666 | }; |
| 488 | 667 | |
| @@ -278,22 +278,22 @@ enum tis_defaults { · 277 unmodified lines | ||
| 278 | 278 | #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) |
| 279 | 279 | #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) |
| 280 | 280 | |
| 281 | −static int check_locality(struct tpm_chip *chip, int loc) | |
| 281 | +static bool check_locality(struct tpm_chip *chip, int loc) | |
| 282 | 282 | { |
| 283 | 283 | u8 buf; |
| 284 | 284 | int rc; |
| 285 | 285 | |
| 286 | 286 | rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1); |
| 287 | 287 | if (rc < 0) |
| 288 | − return rc; | |
| 288 | + return false; | |
| 289 | 289 | |
| 290 | 290 | if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == |
| 291 | 291 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { |
| 292 | 292 | tpm_dev.locality = loc; |
| 293 | − return loc; | |
| 293 | + return true; | |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | − return -EIO; | |
| 296 | + return false; | |
| 297 | 297 | } |
| 298 | 298 | |
| 299 | 299 | /* implementation similar to tpm_tis */ |
| @@ -315,7 +315,7 @@ static int request_locality(struct tpm_chip *chip, int loc) · 15 unmodified lines | ||
| 315 | 315 | unsigned long stop; |
| 316 | 316 | u8 buf = TPM_ACCESS_REQUEST_USE; |
| 317 | 317 | |
| 318 | − if (check_locality(chip, loc) >= 0) | |
| 318 | + if (check_locality(chip, loc)) | |
| 319 | 319 | return loc; |
| 320 | 320 | |
| 321 | 321 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); |
| @@ -323,7 +323,7 @@ static int request_locality(struct tpm_chip *chip, int loc) · 1 unmodified line | ||
| 323 | 323 | /* wait for burstcount */ |
| 324 | 324 | stop = jiffies + chip->timeout_a; |
| 325 | 325 | do { |
| 326 | − if (check_locality(chip, loc) >= 0) | |
| 326 | + if (check_locality(chip, loc)) | |
| 327 | 327 | return loc; |
| 328 | 328 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); |
| 329 | 329 | } while (time_before(jiffies, stop)); |
| @@ -49,9 +49,10 @@ · 48 unmodified lines | ||
| 49 | 49 | */ |
| 50 | 50 | #define TPM_I2C_MAX_BUF_SIZE 32 |
| 51 | 51 | #define TPM_I2C_RETRY_COUNT 32 |
| 52 | −#define TPM_I2C_BUS_DELAY 1 /* msec */ | |
| 53 | −#define TPM_I2C_RETRY_DELAY_SHORT 2 /* msec */ | |
| 54 | −#define TPM_I2C_RETRY_DELAY_LONG 10 /* msec */ | |
| 52 | +#define TPM_I2C_BUS_DELAY 1000 /* usec */ | |
| 53 | +#define TPM_I2C_RETRY_DELAY_SHORT (2 * 1000) /* usec */ | |
| 54 | +#define TPM_I2C_RETRY_DELAY_LONG (10 * 1000) /* usec */ | |
| 55 | +#define TPM_I2C_DELAY_RANGE 300 /* usec */ | |
| 55 | 56 | |
| 56 | 57 | #define OF_IS_TPM2 ((void *)1) |
| 57 | 58 | #define I2C_IS_TPM2 1 |
| @@ -123,7 +124,9 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data) · 65 unmodified lines | ||
| 123 | 124 | /* this causes the current command to be aborted */ |
| 124 | 125 | for (i = 0, status = -1; i < TPM_I2C_RETRY_COUNT && status < 0; i++) { |
| 125 | 126 | status = i2c_nuvoton_write_buf(client, TPM_STS, 1, &data); |
| 126 | − msleep(TPM_I2C_BUS_DELAY); | |
| 127 | + if (status < 0) | |
| 128 | + usleep_range(TPM_I2C_BUS_DELAY, TPM_I2C_BUS_DELAY | |
| 129 | + + TPM_I2C_DELAY_RANGE); | |
| 127 | 130 | } |
| 128 | 131 | return status; |
| 129 | 132 | } |
| @@ -160,7 +163,8 @@ static int i2c_nuvoton_get_burstcount(struct i2c_client *client, · 30 unmodified lines | ||
| 160 | 163 | burst_count = min_t(u8, TPM_I2C_MAX_BUF_SIZE, data); |
| 161 | 164 | break; |
| 162 | 165 | } |
| 163 | − msleep(TPM_I2C_BUS_DELAY); | |
| 166 | + usleep_range(TPM_I2C_BUS_DELAY, TPM_I2C_BUS_DELAY | |
| 167 | + + TPM_I2C_DELAY_RANGE); | |
| 164 | 168 | } while (time_before(jiffies, stop)); |
| 165 | 169 | |
| 166 | 170 | return burst_count; |
| @@ -203,13 +207,17 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, · 36 unmodified lines | ||
| 203 | 207 | return 0; |
| 204 | 208 | |
| 205 | 209 | /* use polling to wait for the event */ |
| 206 | − ten_msec = jiffies + msecs_to_jiffies(TPM_I2C_RETRY_DELAY_LONG); | |
| 210 | + ten_msec = jiffies + usecs_to_jiffies(TPM_I2C_RETRY_DELAY_LONG); | |
| 207 | 211 | stop = jiffies + timeout; |
| 208 | 212 | do { |
| 209 | 213 | if (time_before(jiffies, ten_msec)) |
| 210 | − msleep(TPM_I2C_RETRY_DELAY_SHORT); | |
| 214 | + usleep_range(TPM_I2C_RETRY_DELAY_SHORT, | |
| 215 | + TPM_I2C_RETRY_DELAY_SHORT | |
| 216 | + + TPM_I2C_DELAY_RANGE); | |
| 211 | 217 | else |
| 212 | − msleep(TPM_I2C_RETRY_DELAY_LONG); | |
| 218 | + usleep_range(TPM_I2C_RETRY_DELAY_LONG, | |
| 219 | + TPM_I2C_RETRY_DELAY_LONG | |
| 220 | + + TPM_I2C_DELAY_RANGE); | |
| 213 | 221 | status_valid = i2c_nuvoton_check_status(chip, mask, |
| 214 | 222 | value); |
| 215 | 223 | if (status_valid) |
| @@ -299,6 +299,8 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) · 298 unmodified lines | ||
| 299 | 299 | } |
| 300 | 300 | |
| 301 | 301 | kfree(ibmvtpm); |
| 302 | + /* For tpm_ibmvtpm_get_desired_dma */ | |
| 303 | + dev_set_drvdata(&vdev->dev, NULL); | |
| 302 | 304 | |
| 303 | 305 | return 0; |
| 304 | 306 | } |
| @@ -313,14 +315,16 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) · 8 unmodified lines | ||
| 313 | 315 | static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) |
| 314 | 316 | { |
| 315 | 317 | struct tpm_chip *chip = dev_get_drvdata(&vdev->dev); |
| 316 | − struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); | |
| 318 | + struct ibmvtpm_dev *ibmvtpm; | |
| 317 | 319 | |
| 318 | 320 | /* |
| 319 | 321 | * ibmvtpm initializes at probe time, so the data we are |
| 320 | 322 | * asking for may not be set yet. Estimate that 4K required |
| 321 | 323 | * for TCE-mapped buffer in addition to CRQ. |
| 322 | 324 | */ |
| 323 | − if (!ibmvtpm) | |
| 325 | + if (chip) | |
| 326 | + ibmvtpm = dev_get_drvdata(&chip->dev); | |
| 327 | + else | |
| 324 | 328 | return CRQ_RES_BUF_SIZE + PAGE_SIZE; |
| 325 | 329 | |
| 326 | 330 | return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size; |
| @@ -56,7 +56,7 @@ static int wait_startup(struct tpm_chip *chip, int l) · 55 unmodified lines | ||
| 56 | 56 | return -1; |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | −static int check_locality(struct tpm_chip *chip, int l) | |
| 59 | +static bool check_locality(struct tpm_chip *chip, int l) | |
| 60 | 60 | { |
| 61 | 61 | struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); |
| 62 | 62 | int rc; |
| @@ -64,30 +64,22 @@ static int check_locality(struct tpm_chip *chip, int l) · 1 unmodified line | ||
| 64 | 64 | |
| 65 | 65 | rc = tpm_tis_read8(priv, TPM_ACCESS(l), &access); |
| 66 | 66 | if (rc < 0) |
| 67 | − return rc; | |
| 67 | + return false; | |
| 68 | 68 | |
| 69 | 69 | if ((access & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == |
| 70 | − (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) | |
| 71 | − return priv->locality = l; | |
| 70 | + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { | |
| 71 | + priv->locality = l; | |
| 72 | + return true; | |
| 73 | + } | |
| 72 | 74 | |
| 73 | − return -1; | |
| 75 | + return false; | |
| 74 | 76 | } |
| 75 | 77 | |
| 76 | −static void release_locality(struct tpm_chip *chip, int l, int force) | |
| 78 | +static void release_locality(struct tpm_chip *chip, int l) | |
| 77 | 79 | { |
| 78 | 80 | struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); |
| 79 | − int rc; | |
| 80 | − u8 access; | |
| 81 | − | |
| 82 | − rc = tpm_tis_read8(priv, TPM_ACCESS(l), &access); | |
| 83 | − if (rc < 0) | |
| 84 | − return; | |
| 85 | − | |
| 86 | − if (force || (access & | |
| 87 | − (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == | |
| 88 | − (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) | |
| 89 | − tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY); | |
| 90 | 81 | |
| 82 | + tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY); | |
| 91 | 83 | } |
| 92 | 84 | |
| 93 | 85 | static int request_locality(struct tpm_chip *chip, int l) |
| @@ -96,7 +88,7 @@ static int request_locality(struct tpm_chip *chip, int l) · 2 unmodified lines | ||
| 96 | 88 | unsigned long stop, timeout; |
| 97 | 89 | long rc; |
| 98 | 90 | |
| 99 | − if (check_locality(chip, l) >= 0) | |
| 91 | + if (check_locality(chip, l)) | |
| 100 | 92 | return l; |
| 101 | 93 | |
| 102 | 94 | rc = tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_REQUEST_USE); |
| @@ -112,7 +104,7 @@ again: · 9 unmodified lines | ||
| 112 | 104 | return -1; |
| 113 | 105 | rc = wait_event_interruptible_timeout(priv->int_queue, |
| 114 | 106 | (check_locality |
| 115 | − (chip, l) >= 0), | |
| 107 | + (chip, l)), | |
| 116 | 108 | timeout); |
| 117 | 109 | if (rc > 0) |
| 118 | 110 | return l; |
| @@ -123,7 +115,7 @@ again: · 4 unmodified lines | ||
| 123 | 115 | } else { |
| 124 | 116 | /* wait for burstcount */ |
| 125 | 117 | do { |
| 126 | − if (check_locality(chip, l) >= 0) | |
| 118 | + if (check_locality(chip, l)) | |
| 127 | 119 | return l; |
| 128 | 120 | msleep(TPM_TIMEOUT); |
| 129 | 121 | } while (time_before(jiffies, stop)); |
| @@ -160,8 +152,10 @@ static int get_burstcount(struct tpm_chip *chip) · 30 unmodified lines | ||
| 160 | 152 | u32 value; |
| 161 | 153 | |
| 162 | 154 | /* wait for burstcount */ |
| 163 | − /* which timeout value, spec has 2 answers (c & d) */ | |
| 164 | − stop = jiffies + chip->timeout_d; | |
| 155 | + if (chip->flags & TPM_CHIP_FLAG_TPM2) | |
| 156 | + stop = jiffies + chip->timeout_a; | |
| 157 | + else | |
| 158 | + stop = jiffies + chip->timeout_d; | |
| 165 | 159 | do { |
| 166 | 160 | rc = tpm_tis_read32(priv, TPM_STS(priv->locality), &value); |
| 167 | 161 | if (rc < 0) |
| @@ -250,7 +244,6 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) · 82 unmodified lines | ||
| 250 | 244 | |
| 251 | 245 | out: |
| 252 | 246 | tpm_tis_ready(chip); |
| 253 | − release_locality(chip, priv->locality, 0); | |
| 254 | 247 | return size; |
| 255 | 248 | } |
| 256 | 249 | |
| @@ -266,9 +259,6 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) · 9 unmodified lines | ||
| 266 | 259 | size_t count = 0; |
| 267 | 260 | bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND; |
| 268 | 261 | |
| 269 | − if (request_locality(chip, 0) < 0) | |
| 270 | − return -EBUSY; | |
| 271 | − | |
| 272 | 262 | status = tpm_tis_status(chip); |
| 273 | 263 | if ((status & TPM_STS_COMMAND_READY) == 0) { |
| 274 | 264 | tpm_tis_ready(chip); |
| @@ -327,7 +317,6 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) · 52 unmodified lines | ||
| 327 | 317 | |
| 328 | 318 | out_err: |
| 329 | 319 | tpm_tis_ready(chip); |
| 330 | − release_locality(chip, priv->locality, 0); | |
| 331 | 320 | return rc; |
| 332 | 321 | } |
| 333 | 322 | |
| @@ -388,7 +377,6 @@ static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len) · 54 unmodified lines | ||
| 388 | 377 | return len; |
| 389 | 378 | out_err: |
| 390 | 379 | tpm_tis_ready(chip); |
| 391 | − release_locality(chip, priv->locality, 0); | |
| 392 | 380 | return rc; |
| 393 | 381 | } |
| 394 | 382 | |
| @@ -475,12 +463,14 @@ static int probe_itpm(struct tpm_chip *chip) · 80 unmodified lines | ||
| 475 | 463 | if (vendor != TPM_VID_INTEL) |
| 476 | 464 | return 0; |
| 477 | 465 | |
| 466 | + if (request_locality(chip, 0) != 0) | |
| 467 | + return -EBUSY; | |
| 468 | + | |
| 478 | 469 | rc = tpm_tis_send_data(chip, cmd_getticks, len); |
| 479 | 470 | if (rc == 0) |
| 480 | 471 | goto out; |
| 481 | 472 | |
| 482 | 473 | tpm_tis_ready(chip); |
| 483 | − release_locality(chip, priv->locality, 0); | |
| 484 | 474 | |
| 485 | 475 | priv->flags |= TPM_TIS_ITPM_WORKAROUND; |
| 486 | 476 | |
| @@ -494,7 +484,7 @@ static int probe_itpm(struct tpm_chip *chip) · 7 unmodified lines | ||
| 494 | 484 | |
| 495 | 485 | out: |
| 496 | 486 | tpm_tis_ready(chip); |
| 497 | − release_locality(chip, priv->locality, 0); | |
| 487 | + release_locality(chip, priv->locality); | |
| 498 | 488 | |
| 499 | 489 | return rc; |
| 500 | 490 | } |
| @@ -533,7 +523,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) · 32 unmodified lines | ||
| 533 | 523 | wake_up_interruptible(&priv->read_queue); |
| 534 | 524 | if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) |
| 535 | 525 | for (i = 0; i < 5; i++) |
| 536 | − if (check_locality(chip, i) >= 0) | |
| 526 | + if (check_locality(chip, i)) | |
| 537 | 527 | break; |
| 538 | 528 | if (interrupt & |
| 539 | 529 | (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | |
| @@ -668,7 +658,6 @@ void tpm_tis_remove(struct tpm_chip *chip) · 128 unmodified lines | ||
| 668 | 658 | interrupt = 0; |
| 669 | 659 | |
| 670 | 660 | tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt); |
| 671 | − release_locality(chip, priv->locality, 1); | |
| 672 | 661 | } |
| 673 | 662 | EXPORT_SYMBOL_GPL(tpm_tis_remove); |
| 674 | 663 | |
| @@ -682,6 +671,8 @@ static const struct tpm_class_ops tpm_tis = { · 7 unmodified lines | ||
| 682 | 671 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 683 | 672 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 684 | 673 | .req_canceled = tpm_tis_req_canceled, |
| 674 | + .request_locality = request_locality, | |
| 675 | + .relinquish_locality = release_locality, | |
| 685 | 676 | }; |
| 686 | 677 | |
| 687 | 678 | int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, |
| @@ -724,11 +715,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, · 36 unmodified lines | ||
| 724 | 715 | intmask &= ~TPM_GLOBAL_INT_ENABLE; |
| 725 | 716 | tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); |
| 726 | 717 | |
| 727 | − if (request_locality(chip, 0) != 0) { | |
| 728 | − rc = -ENODEV; | |
| 729 | − goto out_err; | |
| 730 | − } | |
| 731 | − | |
| 732 | 718 | rc = tpm2_probe(chip); |
| 733 | 719 | if (rc) |
| 734 | 720 | goto out_err; |
| @@ -47,8 +47,8 @@ struct tpm_tis_spi_phy { · 46 unmodified lines | ||
| 47 | 47 | struct tpm_tis_data priv; |
| 48 | 48 | struct spi_device *spi_device; |
| 49 | 49 | |
| 50 | − u8 tx_buf[MAX_SPI_FRAMESIZE + 4]; | |
| 51 | − u8 rx_buf[MAX_SPI_FRAMESIZE + 4]; | |
| 50 | + u8 tx_buf[4]; | |
| 51 | + u8 rx_buf[4]; | |
| 52 | 52 | }; |
| 53 | 53 | |
| 54 | 54 | static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *data) |
| @@ -56,122 +56,98 @@ static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *da · 1 unmodified line | ||
| 56 | 56 | return container_of(data, struct tpm_tis_spi_phy, priv); |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | −static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr, | |
| 60 | − u16 len, u8 *result) | |
| 59 | +static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, | |
| 60 | + u8 *buffer, u8 direction) | |
| 61 | 61 | { |
| 62 | 62 | struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data); |
| 63 | − int ret, i; | |
| 63 | + int ret = 0; | |
| 64 | + int i; | |
| 64 | 65 | struct spi_message m; |
| 65 | − struct spi_transfer spi_xfer = { | |
| 66 | − .tx_buf = phy->tx_buf, | |
| 67 | − .rx_buf = phy->rx_buf, | |
| 68 | − .len = 4, | |
| 69 | − }; | |
| 66 | + struct spi_transfer spi_xfer; | |
| 67 | + u8 transfer_len; | |
| 70 | 68 | |
| 71 | − if (len > MAX_SPI_FRAMESIZE) | |
| 72 | − return -ENOMEM; | |
| 69 | + spi_bus_lock(phy->spi_device->master); | |
| 73 | 70 | |
| 74 | − phy->tx_buf[0] = 0x80 | (len - 1); | |
| 75 | − phy->tx_buf[1] = 0xd4; | |
| 76 | − phy->tx_buf[2] = (addr >> 8) & 0xFF; | |
| 77 | − phy->tx_buf[3] = addr & 0xFF; | |
| 71 | + while (len) { | |
| 72 | + transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE); | |
| 78 | 73 | |
| 79 | − spi_xfer.cs_change = 1; | |
| 80 | − spi_message_init(&m); | |
| 81 | − spi_message_add_tail(&spi_xfer, &m); | |
| 74 | + phy->tx_buf[0] = direction | (transfer_len - 1); | |
| 75 | + phy->tx_buf[1] = 0xd4; | |
| 76 | + phy->tx_buf[2] = addr >> 8; | |
| 77 | + phy->tx_buf[3] = addr; | |
| 78 | + | |
| 79 | + memset(&spi_xfer, 0, sizeof(spi_xfer)); | |
| 80 | + spi_xfer.tx_buf = phy->tx_buf; | |
| 81 | + spi_xfer.rx_buf = phy->rx_buf; | |
| 82 | + spi_xfer.len = 4; | |
| 83 | + spi_xfer.cs_change = 1; | |
| 82 | 84 | |
| 83 | − spi_bus_lock(phy->spi_device->master); | |
| 84 | − ret = spi_sync_locked(phy->spi_device, &m); | |
| 85 | − if (ret < 0) | |
| 86 | − goto exit; | |
| 87 | − | |
| 88 | − memset(phy->tx_buf, 0, len); | |
| 89 | − | |
| 90 | − /* According to TCG PTP specification, if there is no TPM present at | |
| 91 | − * all, then the design has a weak pull-up on MISO. If a TPM is not | |
| 92 | − * present, a pull-up on MISO means that the SB controller sees a 1, | |
| 93 | − * and will latch in 0xFF on the read. | |
| 94 | − */ | |
| 95 | − for (i = 0; (phy->rx_buf[0] & 0x01) == 0 && i < TPM_RETRY; i++) { | |
| 96 | − spi_xfer.len = 1; | |
| 97 | 85 | spi_message_init(&m); |
| 98 | 86 | spi_message_add_tail(&spi_xfer, &m); |
| 99 | 87 | ret = spi_sync_locked(phy->spi_device, &m); |
| 100 | 88 | if (ret < 0) |
| 101 | 89 | goto exit; |
| 102 | − } | |
| 103 | − | |
| 104 | − spi_xfer.cs_change = 0; | |
| 105 | − spi_xfer.len = len; | |
| 106 | − spi_xfer.rx_buf = result; | |
| 107 | − | |
| 108 | − spi_message_init(&m); | |
| 109 | − spi_message_add_tail(&spi_xfer, &m); | |
| 110 | − ret = spi_sync_locked(phy->spi_device, &m); | |
| 111 | − | |
| 112 | −exit: | |
| 113 | − spi_bus_unlock(phy->spi_device->master); | |
| 114 | − return ret; | |
| 115 | −} | |
| 116 | − | |
| 117 | −static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr, | |
| 118 | − u16 len, u8 *value) | |
| 119 | −{ | |
| 120 | − struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data); | |
| 121 | − int ret, i; | |
| 122 | − struct spi_message m; | |
| 123 | − struct spi_transfer spi_xfer = { | |
| 124 | − .tx_buf = phy->tx_buf, | |
| 125 | − .rx_buf = phy->rx_buf, | |
| 126 | − .len = 4, | |
| 127 | − }; | |
| 128 | − | |
| 129 | − if (len > MAX_SPI_FRAMESIZE) | |
| 130 | − return -ENOMEM; | |
| 131 | − | |
| 132 | − phy->tx_buf[0] = len - 1; | |
| 133 | − phy->tx_buf[1] = 0xd4; | |
| 134 | − phy->tx_buf[2] = (addr >> 8) & 0xFF; | |
| 135 | − phy->tx_buf[3] = addr & 0xFF; | |
| 136 | 90 | |
| 137 | − spi_xfer.cs_change = 1; | |
| 138 | − spi_message_init(&m); | |
| 139 | − spi_message_add_tail(&spi_xfer, &m); | |
| 91 | + if ((phy->rx_buf[3] & 0x01) == 0) { | |
| 92 | + // handle SPI wait states | |
| 93 | + phy->tx_buf[0] = 0; | |
| 94 | + | |
| 95 | + for (i = 0; i < TPM_RETRY; i++) { | |
| 96 | + spi_xfer.len = 1; | |
| 97 | + spi_message_init(&m); | |
| 98 | + spi_message_add_tail(&spi_xfer, &m); | |
| 99 | + ret = spi_sync_locked(phy->spi_device, &m); | |
| 100 | + if (ret < 0) | |
| 101 | + goto exit; | |
| 102 | + if (phy->rx_buf[0] & 0x01) | |
| 103 | + break; | |
| 104 | + } | |
| 105 | + | |
| 106 | + if (i == TPM_RETRY) { | |
| 107 | + ret = -ETIMEDOUT; | |
| 108 | + goto exit; | |
| 109 | + } | |
| 110 | + } | |
| 111 | + | |
| 112 | + spi_xfer.cs_change = 0; | |
| 113 | + spi_xfer.len = transfer_len; | |
| 114 | + spi_xfer.delay_usecs = 5; | |
| 115 | + | |
| 116 | + if (direction) { | |
| 117 | + spi_xfer.tx_buf = NULL; | |
| 118 | + spi_xfer.rx_buf = buffer; | |
| 119 | + } else { | |
| 120 | + spi_xfer.tx_buf = buffer; | |
| 121 | + spi_xfer.rx_buf = NULL; | |
| 122 | + } | |
| 140 | 123 | |
| 141 | − spi_bus_lock(phy->spi_device->master); | |
| 142 | − ret = spi_sync_locked(phy->spi_device, &m); | |
| 143 | − if (ret < 0) | |
| 144 | − goto exit; | |
| 145 | − | |
| 146 | − memset(phy->tx_buf, 0, len); | |
| 147 | − | |
| 148 | − /* According to TCG PTP specification, if there is no TPM present at | |
| 149 | − * all, then the design has a weak pull-up on MISO. If a TPM is not | |
| 150 | − * present, a pull-up on MISO means that the SB controller sees a 1, | |
| 151 | − * and will latch in 0xFF on the read. | |
| 152 | − */ | |
| 153 | − for (i = 0; (phy->rx_buf[0] & 0x01) == 0 && i < TPM_RETRY; i++) { | |
| 154 | − spi_xfer.len = 1; | |
| 155 | 124 | spi_message_init(&m); |
| 156 | 125 | spi_message_add_tail(&spi_xfer, &m); |
| 157 | 126 | ret = spi_sync_locked(phy->spi_device, &m); |
| 158 | 127 | if (ret < 0) |
| 159 | 128 | goto exit; |
| 160 | − } | |
| 161 | 129 | |
| 162 | − spi_xfer.len = len; | |
| 163 | − spi_xfer.tx_buf = value; | |
| 164 | − spi_xfer.cs_change = 0; | |
| 165 | − spi_xfer.tx_buf = value; | |
| 166 | − spi_message_init(&m); | |
| 167 | − spi_message_add_tail(&spi_xfer, &m); | |
| 168 | − ret = spi_sync_locked(phy->spi_device, &m); | |
| 130 | + len -= transfer_len; | |
| 131 | + buffer += transfer_len; | |
| 132 | + } | |
| 169 | 133 | |
| 170 | 134 | exit: |
| 171 | 135 | spi_bus_unlock(phy->spi_device->master); |
| 172 | 136 | return ret; |
| 173 | 137 | } |
| 174 | 138 | |
| 139 | +static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr, | |
| 140 | + u16 len, u8 *result) | |
| 141 | +{ | |
| 142 | + return tpm_tis_spi_transfer(data, addr, len, result, 0x80); | |
| 143 | +} | |
| 144 | + | |
| 145 | +static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr, | |
| 146 | + u16 len, u8 *value) | |
| 147 | +{ | |
| 148 | + return tpm_tis_spi_transfer(data, addr, len, value, 0); | |
| 149 | +} | |
| 150 | + | |
| 175 | 151 | static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result) |
| 176 | 152 | { |
| 177 | 153 | int rc; |
| @@ -0,0 +1,65 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2017 James.Bottomley@HansenPartnership.com | |
| 3 | + * | |
| 4 | + * GPLv2 | |
| 5 | + */ | |
| 6 | +#include <linux/slab.h> | |
| 7 | +#include "tpm-dev.h" | |
| 8 | + | |
| 9 | +struct tpmrm_priv { | |
| 10 | + struct file_priv priv; | |
| 11 | + struct tpm_space space; | |
| 12 | +}; | |
| 13 | + | |
| 14 | +static int tpmrm_open(struct inode *inode, struct file *file) | |
| 15 | +{ | |
| 16 | + struct tpm_chip *chip; | |
| 17 | + struct tpmrm_priv *priv; | |
| 18 | + int rc; | |
| 19 | + | |
| 20 | + chip = container_of(inode->i_cdev, struct tpm_chip, cdevs); | |
| 21 | + priv = kzalloc(sizeof(*priv), GFP_KERNEL); | |
| 22 | + if (priv == NULL) | |
| 23 | + return -ENOMEM; | |
| 24 | + | |
| 25 | + rc = tpm2_init_space(&priv->space); | |
| 26 | + if (rc) { | |
| 27 | + kfree(priv); | |
| 28 | + return -ENOMEM; | |
| 29 | + } | |
| 30 | + | |
| 31 | + tpm_common_open(file, chip, &priv->priv); | |
| 32 | + | |
| 33 | + return 0; | |
| 34 | +} | |
| 35 | + | |
| 36 | +static int tpmrm_release(struct inode *inode, struct file *file) | |
| 37 | +{ | |
| 38 | + struct file_priv *fpriv = file->private_data; | |
| 39 | + struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv); | |
| 40 | + | |
| 41 | + tpm_common_release(file, fpriv); | |
| 42 | + tpm2_del_space(fpriv->chip, &priv->space); | |
| 43 | + kfree(priv); | |
| 44 | + | |
| 45 | + return 0; | |
| 46 | +} | |
| 47 | + | |
| 48 | +ssize_t tpmrm_write(struct file *file, const char __user *buf, | |
| 49 | + size_t size, loff_t *off) | |
| 50 | +{ | |
| 51 | + struct file_priv *fpriv = file->private_data; | |
| 52 | + struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv); | |
| 53 | + | |
| 54 | + return tpm_common_write(file, buf, size, off, &priv->space); | |
| 55 | +} | |
| 56 | + | |
| 57 | +const struct file_operations tpmrm_fops = { | |
| 58 | + .owner = THIS_MODULE, | |
| 59 | + .llseek = no_llseek, | |
| 60 | + .open = tpmrm_open, | |
| 61 | + .read = tpm_common_read, | |
| 62 | + .write = tpmrm_write, | |
| 63 | + .release = tpmrm_release, | |
| 64 | +}; | |
| 65 | + | |
| @@ -340,22 +340,14 @@ int generic_permission(struct inode *inode, int mask) · 339 unmodified lines | ||
| 340 | 340 | |
| 341 | 341 | if (S_ISDIR(inode->i_mode)) { |
| 342 | 342 | /* DACs are overridable for directories */ |
| 343 | − if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE)) | |
| 344 | − return 0; | |
| 345 | 343 | if (!(mask & MAY_WRITE)) |
| 346 | 344 | if (capable_wrt_inode_uidgid(inode, |
| 347 | 345 | CAP_DAC_READ_SEARCH)) |
| 348 | 346 | return 0; |
| 349 | − return -EACCES; | |
| 350 | − } | |
| 351 | − /* | |
| 352 | − * Read/write DACs are always overridable. | |
| 353 | − * Executable DACs are overridable when there is | |
| 354 | − * at least one exec bit set. | |
| 355 | − */ | |
| 356 | − if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) | |
| 357 | 347 | if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE)) |
| 358 | 348 | return 0; |
| 349 | + return -EACCES; | |
| 350 | + } | |
| 359 | 351 | |
| 360 | 352 | /* |
| 361 | 353 | * Searching includes executable on directories, else just read. |
| @@ -364,6 +356,14 @@ int generic_permission(struct inode *inode, int mask) · 2 unmodified lines | ||
| 364 | 356 | if (mask == MAY_READ) |
| 365 | 357 | if (capable_wrt_inode_uidgid(inode, CAP_DAC_READ_SEARCH)) |
| 366 | 358 | return 0; |
| 359 | + /* | |
| 360 | + * Read/write DACs are always overridable. | |
| 361 | + * Executable DACs are overridable when there is | |
| 362 | + * at least one exec bit set. | |
| 363 | + */ | |
| 364 | + if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) | |
| 365 | + if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE)) | |
| 366 | + return 0; | |
| 367 | 367 | |
| 368 | 368 | return -EACCES; |
| 369 | 369 | } |
| @@ -1294,6 +1294,7 @@ struct acpi_table_tpm2 { · 1293 unmodified lines | ||
| 1294 | 1294 | #define ACPI_TPM2_MEMORY_MAPPED 6 |
| 1295 | 1295 | #define ACPI_TPM2_COMMAND_BUFFER 7 |
| 1296 | 1296 | #define ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD 8 |
| 1297 | +#define ACPI_TPM2_COMMAND_BUFFER_WITH_SMC 11 | |
| 1297 | 1298 | |
| 1298 | 1299 | /******************************************************************************* |
| 1299 | 1300 | * |
| @@ -50,9 +50,20 @@ struct key; · 49 unmodified lines | ||
| 50 | 50 | struct key_type; |
| 51 | 51 | union key_payload; |
| 52 | 52 | |
| 53 | −extern int restrict_link_by_signature(struct key *trust_keyring, | |
| 53 | +extern int restrict_link_by_signature(struct key *dest_keyring, | |
| 54 | 54 | const struct key_type *type, |
| 55 | − const union key_payload *payload); | |
| 55 | + const union key_payload *payload, | |
| 56 | + struct key *trust_keyring); | |
| 57 | + | |
| 58 | +extern int restrict_link_by_key_or_keyring(struct key *dest_keyring, | |
| 59 | + const struct key_type *type, | |
| 60 | + const union key_payload *payload, | |
| 61 | + struct key *trusted); | |
| 62 | + | |
| 63 | +extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring, | |
| 64 | + const struct key_type *type, | |
| 65 | + const union key_payload *payload, | |
| 66 | + struct key *trusted); | |
| 56 | 67 | |
| 57 | 68 | extern int verify_signature(const struct key *key, |
| 58 | 69 | const struct public_key_signature *sig); |
| @@ -18,7 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | extern int restrict_link_by_builtin_trusted(struct key *keyring, |
| 20 | 20 | const struct key_type *type, |
| 21 | − const union key_payload *payload); | |
| 21 | + const union key_payload *payload, | |
| 22 | + struct key *restriction_key); | |
| 22 | 23 | |
| 23 | 24 | #else |
| 24 | 25 | #define restrict_link_by_builtin_trusted restrict_link_reject |
| @@ -28,11 +29,24 @@ extern int restrict_link_by_builtin_trusted(struct key *keyring, · 3 unmodified lines | ||
| 28 | 29 | extern int restrict_link_by_builtin_and_secondary_trusted( |
| 29 | 30 | struct key *keyring, |
| 30 | 31 | const struct key_type *type, |
| 31 | − const union key_payload *payload); | |
| 32 | + const union key_payload *payload, | |
| 33 | + struct key *restriction_key); | |
| 32 | 34 | #else |
| 33 | 35 | #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted |
| 34 | 36 | #endif |
| 35 | 37 | |
| 38 | +#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING | |
| 39 | +extern int mark_hash_blacklisted(const char *hash); | |
| 40 | +extern int is_hash_blacklisted(const u8 *hash, size_t hash_len, | |
| 41 | + const char *type); | |
| 42 | +#else | |
| 43 | +static inline int is_hash_blacklisted(const u8 *hash, size_t hash_len, | |
| 44 | + const char *type) | |
| 45 | +{ | |
| 46 | + return 0; | |
| 47 | +} | |
| 48 | +#endif | |
| 49 | + | |
| 36 | 50 | #ifdef CONFIG_IMA_BLACKLIST_KEYRING |
| 37 | 51 | extern struct key *ima_blacklist_keyring; |
| 38 | 52 | |
| @@ -295,6 +295,13 @@ struct compat_old_sigaction { · 294 unmodified lines | ||
| 295 | 295 | }; |
| 296 | 296 | #endif |
| 297 | 297 | |
| 298 | +struct compat_keyctl_kdf_params { | |
| 299 | + compat_uptr_t hashname; | |
| 300 | + compat_uptr_t otherinfo; | |
| 301 | + __u32 otherinfolen; | |
| 302 | + __u32 __spare[8]; | |
| 303 | +}; | |
| 304 | + | |
| 298 | 305 | struct compat_statfs; |
| 299 | 306 | struct compat_statfs64; |
| 300 | 307 | struct compat_old_linux_dirent; |
| @@ -219,6 +219,12 @@ extern struct cred init_cred; · 218 unmodified lines | ||
| 219 | 219 | # define INIT_TASK_TI(tsk) |
| 220 | 220 | #endif |
| 221 | 221 | |
| 222 | +#ifdef CONFIG_SECURITY | |
| 223 | +#define INIT_TASK_SECURITY .security = NULL, | |
| 224 | +#else | |
| 225 | +#define INIT_TASK_SECURITY | |
| 226 | +#endif | |
| 227 | + | |
| 222 | 228 | /* |
| 223 | 229 | * INIT_TASK is used to set up the first task table, touch at |
| 224 | 230 | * your own risk!. Base=0, limit=0x1fffff (=2MB) |
| @@ -298,6 +304,7 @@ extern struct cred init_cred; · 73 unmodified lines | ||
| 298 | 304 | INIT_NUMA_BALANCING(tsk) \ |
| 299 | 305 | INIT_KASAN(tsk) \ |
| 300 | 306 | INIT_LIVEPATCH(tsk) \ |
| 307 | + INIT_TASK_SECURITY \ | |
| 301 | 308 | } |
| 302 | 309 | |
| 303 | 310 | |
| @@ -147,6 +147,14 @@ struct key_type { · 146 unmodified lines | ||
| 147 | 147 | */ |
| 148 | 148 | request_key_actor_t request_key; |
| 149 | 149 | |
| 150 | + /* Look up a keyring access restriction (optional) | |
| 151 | + * | |
| 152 | + * - NULL is a valid return value (meaning the requested restriction | |
| 153 | + * is known but will never block addition of a key) | |
| 154 | + * - should return -EINVAL if the restriction is unknown | |
| 155 | + */ | |
| 156 | + struct key_restriction *(*lookup_restriction)(const char *params); | |
| 157 | + | |
| 150 | 158 | /* internal fields */ |
| 151 | 159 | struct list_head link; /* link in types list */ |
| 152 | 160 | struct lock_class_key lock_class; /* key->sem lock class */ |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <linux/rwsem.h> |
| 24 | 24 | #include <linux/atomic.h> |
| 25 | 25 | #include <linux/assoc_array.h> |
| 26 | +#include <linux/refcount.h> | |
| 26 | 27 | |
| 27 | 28 | #ifdef __KERNEL__ |
| 28 | 29 | #include <linux/uidgid.h> |
| @@ -126,6 +127,17 @@ static inline bool is_key_possessed(const key_ref_t key_ref) · 97 unmodified lines | ||
| 126 | 127 | return (unsigned long) key_ref & 1UL; |
| 127 | 128 | } |
| 128 | 129 | |
| 130 | +typedef int (*key_restrict_link_func_t)(struct key *dest_keyring, | |
| 131 | + const struct key_type *type, | |
| 132 | + const union key_payload *payload, | |
| 133 | + struct key *restriction_key); | |
| 134 | + | |
| 135 | +struct key_restriction { | |
| 136 | + key_restrict_link_func_t check; | |
| 137 | + struct key *key; | |
| 138 | + struct key_type *keytype; | |
| 139 | +}; | |
| 140 | + | |
| 129 | 141 | /*****************************************************************************/ |
| 130 | 142 | /* |
| 131 | 143 | * authentication token / access credential / keyring |
| @@ -135,7 +147,7 @@ static inline bool is_key_possessed(const key_ref_t key_ref) · 3 unmodified lines | ||
| 135 | 147 | * - Kerberos TGTs and tickets |
| 136 | 148 | */ |
| 137 | 149 | struct key { |
| 138 | − atomic_t usage; /* number of references */ | |
| 150 | + refcount_t usage; /* number of references */ | |
| 139 | 151 | key_serial_t serial; /* key serial number */ |
| 140 | 152 | union { |
| 141 | 153 | struct list_head graveyard_link; |
| @@ -205,18 +217,17 @@ struct key { · 63 unmodified lines | ||
| 205 | 217 | }; |
| 206 | 218 | |
| 207 | 219 | /* This is set on a keyring to restrict the addition of a link to a key |
| 208 | − * to it. If this method isn't provided then it is assumed that the | |
| 220 | + * to it. If this structure isn't provided then it is assumed that the | |
| 209 | 221 | * keyring is open to any addition. It is ignored for non-keyring |
| 210 | − * keys. | |
| 222 | + * keys. Only set this value using keyring_restrict(), keyring_alloc(), | |
| 223 | + * or key_alloc(). | |
| 211 | 224 | * |
| 212 | 225 | * This is intended for use with rings of trusted keys whereby addition |
| 213 | 226 | * to the keyring needs to be controlled. KEY_ALLOC_BYPASS_RESTRICTION |
| 214 | 227 | * overrides this, allowing the kernel to add extra keys without |
| 215 | 228 | * restriction. |
| 216 | 229 | */ |
| 217 | − int (*restrict_link)(struct key *keyring, | |
| 218 | − const struct key_type *type, | |
| 219 | − const union key_payload *payload); | |
| 230 | + struct key_restriction *restrict_link; | |
| 220 | 231 | }; |
| 221 | 232 | |
| 222 | 233 | extern struct key *key_alloc(struct key_type *type, |
| @@ -225,9 +236,7 @@ extern struct key *key_alloc(struct key_type *type, · 2 unmodified lines | ||
| 225 | 236 | const struct cred *cred, |
| 226 | 237 | key_perm_t perm, |
| 227 | 238 | unsigned long flags, |
| 228 | − int (*restrict_link)(struct key *, | |
| 229 | − const struct key_type *, | |
| 230 | − const union key_payload *)); | |
| 239 | + struct key_restriction *restrict_link); | |
| 231 | 240 | |
| 232 | 241 | |
| 233 | 242 | #define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */ |
| @@ -242,7 +251,7 @@ extern void key_put(struct key *key); · 8 unmodified lines | ||
| 242 | 251 | |
| 243 | 252 | static inline struct key *__key_get(struct key *key) |
| 244 | 253 | { |
| 245 | − atomic_inc(&key->usage); | |
| 254 | + refcount_inc(&key->usage); | |
| 246 | 255 | return key; |
| 247 | 256 | } |
| 248 | 257 | |
| @@ -303,14 +312,13 @@ extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid · 54 unmodified lines | ||
| 303 | 312 | const struct cred *cred, |
| 304 | 313 | key_perm_t perm, |
| 305 | 314 | unsigned long flags, |
| 306 | − int (*restrict_link)(struct key *, | |
| 307 | − const struct key_type *, | |
| 308 | − const union key_payload *), | |
| 315 | + struct key_restriction *restrict_link, | |
| 309 | 316 | struct key *dest); |
| 310 | 317 | |
| 311 | 318 | extern int restrict_link_reject(struct key *keyring, |
| 312 | 319 | const struct key_type *type, |
| 313 | − const union key_payload *payload); | |
| 320 | + const union key_payload *payload, | |
| 321 | + struct key *restriction_key); | |
| 314 | 322 | |
| 315 | 323 | extern int keyring_clear(struct key *keyring); |
| 316 | 324 | |
| @@ -321,6 +329,9 @@ extern key_ref_t keyring_search(key_ref_t keyring, · 4 unmodified lines | ||
| 321 | 329 | extern int keyring_add_key(struct key *keyring, |
| 322 | 330 | struct key *key); |
| 323 | 331 | |
| 332 | +extern int keyring_restrict(key_ref_t keyring, const char *type, | |
| 333 | + const char *restriction); | |
| 334 | + | |
| 324 | 335 | extern struct key *key_lookup(key_serial_t id); |
| 325 | 336 | |
| 326 | 337 | static inline key_serial_t key_serial(const struct key *key) |
| @@ -533,8 +533,13 @@ · 532 unmodified lines | ||
| 533 | 533 | * manual page for definitions of the @clone_flags. |
| 534 | 534 | * @clone_flags contains the flags indicating what should be shared. |
| 535 | 535 | * Return 0 if permission is granted. |
| 536 | + * @task_alloc: | |
| 537 | + * @task task being allocated. | |
| 538 | + * @clone_flags contains the flags indicating what should be shared. | |
| 539 | + * Handle allocation of task-related resources. | |
| 540 | + * Returns a zero on success, negative values on failure. | |
| 536 | 541 | * @task_free: |
| 537 | − * @task task being freed | |
| 542 | + * @task task about to be freed. | |
| 538 | 543 | * Handle release of task-related resources. (Note that this can be called |
| 539 | 544 | * from interrupt context.) |
| 540 | 545 | * @cred_alloc_blank: |
| @@ -630,10 +635,19 @@ · 89 unmodified lines | ||
| 630 | 635 | * Check permission before getting the ioprio value of @p. |
| 631 | 636 | * @p contains the task_struct of process. |
| 632 | 637 | * Return 0 if permission is granted. |
| 638 | + * @task_prlimit: | |
| 639 | + * Check permission before getting and/or setting the resource limits of | |
| 640 | + * another task. | |
| 641 | + * @cred points to the cred structure for the current task. | |
| 642 | + * @tcred points to the cred structure for the target task. | |
| 643 | + * @flags contains the LSM_PRLIMIT_* flag bits indicating whether the | |
| 644 | + * resource limits are being read, modified, or both. | |
| 645 | + * Return 0 if permission is granted. | |
| 633 | 646 | * @task_setrlimit: |
| 634 | − * Check permission before setting the resource limits of the current | |
| 635 | − * process for @resource to @new_rlim. The old resource limit values can | |
| 636 | − * be examined by dereferencing (current->signal->rlim + resource). | |
| 647 | + * Check permission before setting the resource limits of process @p | |
| 648 | + * for @resource to @new_rlim. The old resource limit values can | |
| 649 | + * be examined by dereferencing (p->signal->rlim + resource). | |
| 650 | + * @p points to the task_struct for the target task's group leader. | |
| 637 | 651 | * @resource contains the resource whose limit is being set. |
| 638 | 652 | * @new_rlim contains the new limits for @resource. |
| 639 | 653 | * Return 0 if permission is granted. |
| @@ -1473,6 +1487,7 @@ union security_list_options { · 833 unmodified lines | ||
| 1473 | 1487 | int (*file_open)(struct file *file, const struct cred *cred); |
| 1474 | 1488 | |
| 1475 | 1489 | int (*task_create)(unsigned long clone_flags); |
| 1490 | + int (*task_alloc)(struct task_struct *task, unsigned long clone_flags); | |
| 1476 | 1491 | void (*task_free)(struct task_struct *task); |
| 1477 | 1492 | int (*cred_alloc_blank)(struct cred *cred, gfp_t gfp); |
| 1478 | 1493 | void (*cred_free)(struct cred *cred); |
| @@ -1494,6 +1509,8 @@ union security_list_options { · 15 unmodified lines | ||
| 1494 | 1509 | int (*task_setnice)(struct task_struct *p, int nice); |
| 1495 | 1510 | int (*task_setioprio)(struct task_struct *p, int ioprio); |
| 1496 | 1511 | int (*task_getioprio)(struct task_struct *p); |
| 1512 | + int (*task_prlimit)(const struct cred *cred, const struct cred *tcred, | |
| 1513 | + unsigned int flags); | |
| 1497 | 1514 | int (*task_setrlimit)(struct task_struct *p, unsigned int resource, |
| 1498 | 1515 | struct rlimit *new_rlim); |
| 1499 | 1516 | int (*task_setscheduler)(struct task_struct *p); |
| @@ -1737,6 +1754,7 @@ struct security_hook_heads { · 237 unmodified lines | ||
| 1737 | 1754 | struct list_head file_receive; |
| 1738 | 1755 | struct list_head file_open; |
| 1739 | 1756 | struct list_head task_create; |
| 1757 | + struct list_head task_alloc; | |
| 1740 | 1758 | struct list_head task_free; |
| 1741 | 1759 | struct list_head cred_alloc_blank; |
| 1742 | 1760 | struct list_head cred_free; |
| @@ -1755,6 +1773,7 @@ struct security_hook_heads { · 12 unmodified lines | ||
| 1755 | 1773 | struct list_head task_setnice; |
| 1756 | 1774 | struct list_head task_setioprio; |
| 1757 | 1775 | struct list_head task_getioprio; |
| 1776 | + struct list_head task_prlimit; | |
| 1758 | 1777 | struct list_head task_setrlimit; |
| 1759 | 1778 | struct list_head task_setscheduler; |
| 1760 | 1779 | struct list_head task_getscheduler; |
| @@ -1908,6 +1927,13 @@ static inline void security_delete_hooks(struct security_hook_list *hooks, · 147 unmodified lines | ||
| 1908 | 1927 | } |
| 1909 | 1928 | #endif /* CONFIG_SECURITY_SELINUX_DISABLE */ |
| 1910 | 1929 | |
| 1930 | +/* Currently required to handle SELinux runtime hook disable. */ | |
| 1931 | +#ifdef CONFIG_SECURITY_WRITABLE_HOOKS | |
| 1932 | +#define __lsm_ro_after_init | |
| 1933 | +#else | |
| 1934 | +#define __lsm_ro_after_init __ro_after_init | |
| 1935 | +#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */ | |
| 1936 | + | |
| 1911 | 1937 | extern int __init security_module_enable(const char *module); |
| 1912 | 1938 | extern void __init capability_add_hooks(void); |
| 1913 | 1939 | #ifdef CONFIG_SECURITY_YAMA |
| @@ -1046,6 +1046,10 @@ struct task_struct { · 1045 unmodified lines | ||
| 1046 | 1046 | #endif |
| 1047 | 1047 | #ifdef CONFIG_LIVEPATCH |
| 1048 | 1048 | int patch_state; |
| 1049 | +#endif | |
| 1050 | +#ifdef CONFIG_SECURITY | |
| 1051 | + /* Used by LSM modules for access restriction: */ | |
| 1052 | + void *security; | |
| 1049 | 1053 | #endif |
| 1050 | 1054 | /* CPU-specific state of this task: */ |
| 1051 | 1055 | struct thread_struct thread; |
| @@ -133,6 +133,10 @@ extern unsigned long dac_mmap_min_addr; · 132 unmodified lines | ||
| 133 | 133 | /* setfsuid or setfsgid, id0 == fsuid or fsgid */ |
| 134 | 134 | #define LSM_SETID_FS 8 |
| 135 | 135 | |
| 136 | +/* Flags for security_task_prlimit(). */ | |
| 137 | +#define LSM_PRLIMIT_READ 1 | |
| 138 | +#define LSM_PRLIMIT_WRITE 2 | |
| 139 | + | |
| 136 | 140 | /* forward declares to avoid warnings */ |
| 137 | 141 | struct sched_param; |
| 138 | 142 | struct request_sock; |
| @@ -304,6 +308,7 @@ int security_file_send_sigiotask(struct task_struct *tsk, · 165 unmodified lines | ||
| 304 | 308 | int security_file_receive(struct file *file); |
| 305 | 309 | int security_file_open(struct file *file, const struct cred *cred); |
| 306 | 310 | int security_task_create(unsigned long clone_flags); |
| 311 | +int security_task_alloc(struct task_struct *task, unsigned long clone_flags); | |
| 307 | 312 | void security_task_free(struct task_struct *task); |
| 308 | 313 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); |
| 309 | 314 | void security_cred_free(struct cred *cred); |
| @@ -324,6 +329,8 @@ void security_task_getsecid(struct task_struct *p, u32 *secid); · 14 unmodified lines | ||
| 324 | 329 | int security_task_setnice(struct task_struct *p, int nice); |
| 325 | 330 | int security_task_setioprio(struct task_struct *p, int ioprio); |
| 326 | 331 | int security_task_getioprio(struct task_struct *p); |
| 332 | +int security_task_prlimit(const struct cred *cred, const struct cred *tcred, | |
| 333 | + unsigned int flags); | |
| 327 | 334 | int security_task_setrlimit(struct task_struct *p, unsigned int resource, |
| 328 | 335 | struct rlimit *new_rlim); |
| 329 | 336 | int security_task_setscheduler(struct task_struct *p); |
| @@ -855,6 +862,12 @@ static inline int security_task_create(unsigned long clone_flags) · 525 unmodified lines | ||
| 855 | 862 | return 0; |
| 856 | 863 | } |
| 857 | 864 | |
| 865 | +static inline int security_task_alloc(struct task_struct *task, | |
| 866 | + unsigned long clone_flags) | |
| 867 | +{ | |
| 868 | + return 0; | |
| 869 | +} | |
| 870 | + | |
| 858 | 871 | static inline void security_task_free(struct task_struct *task) |
| 859 | 872 | { } |
| 860 | 873 | |
| @@ -949,6 +962,13 @@ static inline int security_task_getioprio(struct task_struct *p) · 88 unmodified lines | ||
| 949 | 962 | return 0; |
| 950 | 963 | } |
| 951 | 964 | |
| 965 | +static inline int security_task_prlimit(const struct cred *cred, | |
| 966 | + const struct cred *tcred, | |
| 967 | + unsigned int flags) | |
| 968 | +{ | |
| 969 | + return 0; | |
| 970 | +} | |
| 971 | + | |
| 952 | 972 | static inline int security_task_setrlimit(struct task_struct *p, |
| 953 | 973 | unsigned int resource, |
| 954 | 974 | struct rlimit *new_rlim) |
| @@ -48,7 +48,8 @@ struct tpm_class_ops { · 47 unmodified lines | ||
| 48 | 48 | u8 (*status) (struct tpm_chip *chip); |
| 49 | 49 | bool (*update_timeouts)(struct tpm_chip *chip, |
| 50 | 50 | unsigned long *timeout_cap); |
| 51 | − | |
| 51 | + int (*request_locality)(struct tpm_chip *chip, int loc); | |
| 52 | + void (*relinquish_locality)(struct tpm_chip *chip, int loc); | |
| 52 | 53 | }; |
| 53 | 54 | |
| 54 | 55 | #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) |
| @@ -60,6 +60,7 @@ · 59 unmodified lines | ||
| 60 | 60 | #define KEYCTL_INVALIDATE 21 /* invalidate a key */ |
| 61 | 61 | #define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ |
| 62 | 62 | #define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */ |
| 63 | +#define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */ | |
| 63 | 64 | |
| 64 | 65 | /* keyctl structures */ |
| 65 | 66 | struct keyctl_dh_params { |
| @@ -68,4 +69,11 @@ struct keyctl_dh_params { · 2 unmodified lines | ||
| 68 | 69 | __s32 base; |
| 69 | 70 | }; |
| 70 | 71 | |
| 72 | +struct keyctl_kdf_params { | |
| 73 | + char *hashname; | |
| 74 | + char *otherinfo; | |
| 75 | + __u32 otherinfolen; | |
| 76 | + __u32 __spare[8]; | |
| 77 | +}; | |
| 78 | + | |
| 71 | 79 | #endif /* _LINUX_KEYCTL_H */ |
| @@ -1681,9 +1681,12 @@ static __latent_entropy struct task_struct *copy_process( · 1680 unmodified lines | ||
| 1681 | 1681 | goto bad_fork_cleanup_perf; |
| 1682 | 1682 | /* copy all the process information */ |
| 1683 | 1683 | shm_init_task(p); |
| 1684 | − retval = copy_semundo(clone_flags, p); | |
| 1684 | + retval = security_task_alloc(p, clone_flags); | |
| 1685 | 1685 | if (retval) |
| 1686 | 1686 | goto bad_fork_cleanup_audit; |
| 1687 | + retval = copy_semundo(clone_flags, p); | |
| 1688 | + if (retval) | |
| 1689 | + goto bad_fork_cleanup_security; | |
| 1687 | 1690 | retval = copy_files(clone_flags, p); |
| 1688 | 1691 | if (retval) |
| 1689 | 1692 | goto bad_fork_cleanup_semundo; |
| @@ -1907,6 +1910,8 @@ bad_fork_cleanup_files: · 217 unmodified lines | ||
| 1907 | 1910 | exit_files(p); /* blocking */ |
| 1908 | 1911 | bad_fork_cleanup_semundo: |
| 1909 | 1912 | exit_sem(p); |
| 1913 | +bad_fork_cleanup_security: | |
| 1914 | + security_task_free(p); | |
| 1910 | 1915 | bad_fork_cleanup_audit: |
| 1911 | 1916 | audit_free(p); |
| 1912 | 1917 | bad_fork_cleanup_perf: |
| @@ -1432,25 +1432,26 @@ out: · 1431 unmodified lines | ||
| 1432 | 1432 | } |
| 1433 | 1433 | |
| 1434 | 1434 | /* rcu lock must be held */ |
| 1435 | −static int check_prlimit_permission(struct task_struct *task) | |
| 1435 | +static int check_prlimit_permission(struct task_struct *task, | |
| 1436 | + unsigned int flags) | |
| 1436 | 1437 | { |
| 1437 | 1438 | const struct cred *cred = current_cred(), *tcred; |
| 1439 | + bool id_match; | |
| 1438 | 1440 | |
| 1439 | 1441 | if (current == task) |
| 1440 | 1442 | return 0; |
| 1441 | 1443 | |
| 1442 | 1444 | tcred = __task_cred(task); |
| 1443 | − if (uid_eq(cred->uid, tcred->euid) && | |
| 1444 | − uid_eq(cred->uid, tcred->suid) && | |
| 1445 | − uid_eq(cred->uid, tcred->uid) && | |
| 1446 | − gid_eq(cred->gid, tcred->egid) && | |
| 1447 | − gid_eq(cred->gid, tcred->sgid) && | |
| 1448 | − gid_eq(cred->gid, tcred->gid)) | |
| 1449 | − return 0; | |
| 1450 | − if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) | |
| 1451 | − return 0; | |
| 1445 | + id_match = (uid_eq(cred->uid, tcred->euid) && | |
| 1446 | + uid_eq(cred->uid, tcred->suid) && | |
| 1447 | + uid_eq(cred->uid, tcred->uid) && | |
| 1448 | + gid_eq(cred->gid, tcred->egid) && | |
| 1449 | + gid_eq(cred->gid, tcred->sgid) && | |
| 1450 | + gid_eq(cred->gid, tcred->gid)); | |
| 1451 | + if (!id_match && !ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) | |
| 1452 | + return -EPERM; | |
| 1452 | 1453 | |
| 1453 | − return -EPERM; | |
| 1454 | + return security_task_prlimit(cred, tcred, flags); | |
| 1454 | 1455 | } |
| 1455 | 1456 | |
| 1456 | 1457 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, |
| @@ -1460,12 +1461,17 @@ SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, · 3 unmodified lines | ||
| 1460 | 1461 | struct rlimit64 old64, new64; |
| 1461 | 1462 | struct rlimit old, new; |
| 1462 | 1463 | struct task_struct *tsk; |
| 1464 | + unsigned int checkflags = 0; | |
| 1463 | 1465 | int ret; |
| 1464 | 1466 | |
| 1467 | + if (old_rlim) | |
| 1468 | + checkflags |= LSM_PRLIMIT_READ; | |
| 1469 | + | |
| 1465 | 1470 | if (new_rlim) { |
| 1466 | 1471 | if (copy_from_user(&new64, new_rlim, sizeof(new64))) |
| 1467 | 1472 | return -EFAULT; |
| 1468 | 1473 | rlim64_to_rlim(&new64, &new); |
| 1474 | + checkflags |= LSM_PRLIMIT_WRITE; | |
| 1469 | 1475 | } |
| 1470 | 1476 | |
| 1471 | 1477 | rcu_read_lock(); |
| @@ -1474,7 +1480,7 @@ SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, · 2 unmodified lines | ||
| 1474 | 1480 | rcu_read_unlock(); |
| 1475 | 1481 | return -ESRCH; |
| 1476 | 1482 | } |
| 1477 | − ret = check_prlimit_permission(tsk); | |
| 1483 | + ret = check_prlimit_permission(tsk, checkflags); | |
| 1478 | 1484 | if (ret) { |
| 1479 | 1485 | rcu_read_unlock(); |
| 1480 | 1486 | return ret; |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <string.h> |
| 9 | 9 | #include <errno.h> |
| 10 | 10 | #include <ctype.h> |
| 11 | +#include <sys/socket.h> | |
| 11 | 12 | |
| 12 | 13 | struct security_class_mapping { |
| 13 | 14 | const char *name; |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include <stdlib.h> |
| 33 | 33 | #include <unistd.h> |
| 34 | 34 | #include <string.h> |
| 35 | +#include <sys/socket.h> | |
| 35 | 36 | |
| 36 | 37 | static void usage(char *name) |
| 37 | 38 | { |
| @@ -31,6 +31,11 @@ config SECURITY · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | If you are unsure how to answer this question, answer N. |
| 33 | 33 | |
| 34 | +config SECURITY_WRITABLE_HOOKS | |
| 35 | + depends on SECURITY | |
| 36 | + bool | |
| 37 | + default n | |
| 38 | + | |
| 34 | 39 | config SECURITYFS |
| 35 | 40 | bool "Enable the securityfs filesystem" |
| 36 | 41 | help |
| @@ -31,10 +31,7 @@ unsigned int aa_hash_size(void) · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | char *aa_calc_hash(void *data, size_t len) |
| 33 | 33 | { |
| 34 | − struct { | |
| 35 | − struct shash_desc shash; | |
| 36 | − char ctx[crypto_shash_descsize(apparmor_tfm)]; | |
| 37 | − } desc; | |
| 34 | + SHASH_DESC_ON_STACK(desc, apparmor_tfm); | |
| 38 | 35 | char *hash = NULL; |
| 39 | 36 | int error = -ENOMEM; |
| 40 | 37 | |
| @@ -45,16 +42,16 @@ char *aa_calc_hash(void *data, size_t len) · 4 unmodified lines | ||
| 45 | 42 | if (!hash) |
| 46 | 43 | goto fail; |
| 47 | 44 | |
| 48 | − desc.shash.tfm = apparmor_tfm; | |
| 49 | − desc.shash.flags = 0; | |
| 45 | + desc->tfm = apparmor_tfm; | |
| 46 | + desc->flags = 0; | |
| 50 | 47 | |
| 51 | − error = crypto_shash_init(&desc.shash); | |
| 48 | + error = crypto_shash_init(desc); | |
| 52 | 49 | if (error) |
| 53 | 50 | goto fail; |
| 54 | − error = crypto_shash_update(&desc.shash, (u8 *) data, len); | |
| 51 | + error = crypto_shash_update(desc, (u8 *) data, len); | |
| 55 | 52 | if (error) |
| 56 | 53 | goto fail; |
| 57 | − error = crypto_shash_final(&desc.shash, hash); | |
| 54 | + error = crypto_shash_final(desc, hash); | |
| 58 | 55 | if (error) |
| 59 | 56 | goto fail; |
| 60 | 57 | |
| @@ -69,10 +66,7 @@ fail: · 8 unmodified lines | ||
| 69 | 66 | int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, |
| 70 | 67 | size_t len) |
| 71 | 68 | { |
| 72 | − struct { | |
| 73 | − struct shash_desc shash; | |
| 74 | − char ctx[crypto_shash_descsize(apparmor_tfm)]; | |
| 75 | − } desc; | |
| 69 | + SHASH_DESC_ON_STACK(desc, apparmor_tfm); | |
| 76 | 70 | int error = -ENOMEM; |
| 77 | 71 | __le32 le32_version = cpu_to_le32(version); |
| 78 | 72 | |
| @@ -86,19 +80,19 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, · 7 unmodified lines | ||
| 86 | 80 | if (!profile->hash) |
| 87 | 81 | goto fail; |
| 88 | 82 | |
| 89 | − desc.shash.tfm = apparmor_tfm; | |
| 90 | − desc.shash.flags = 0; | |
| 83 | + desc->tfm = apparmor_tfm; | |
| 84 | + desc->flags = 0; | |
| 91 | 85 | |
| 92 | − error = crypto_shash_init(&desc.shash); | |
| 86 | + error = crypto_shash_init(desc); | |
| 93 | 87 | if (error) |
| 94 | 88 | goto fail; |
| 95 | − error = crypto_shash_update(&desc.shash, (u8 *) &le32_version, 4); | |
| 89 | + error = crypto_shash_update(desc, (u8 *) &le32_version, 4); | |
| 96 | 90 | if (error) |
| 97 | 91 | goto fail; |
| 98 | − error = crypto_shash_update(&desc.shash, (u8 *) start, len); | |
| 92 | + error = crypto_shash_update(desc, (u8 *) start, len); | |
| 99 | 93 | if (error) |
| 100 | 94 | goto fail; |
| 101 | − error = crypto_shash_final(&desc.shash, profile->hash); | |
| 95 | + error = crypto_shash_final(desc, profile->hash); | |
| 102 | 96 | if (error) |
| 103 | 97 | goto fail; |
| 104 | 98 | |
| @@ -57,7 +57,7 @@ · 56 unmodified lines | ||
| 57 | 57 | pr_err_ratelimited("AppArmor: " fmt, ##args) |
| 58 | 58 | |
| 59 | 59 | /* Flag indicating whether initialization completed */ |
| 60 | −extern int apparmor_initialized __initdata; | |
| 60 | +extern int apparmor_initialized; | |
| 61 | 61 | |
| 62 | 62 | /* fn's in lib */ |
| 63 | 63 | char *aa_split_fqname(char *args, char **ns_name); |
| @@ -180,13 +180,13 @@ bool aa_policy_init(struct aa_policy *policy, const char *prefix, · 179 unmodified lines | ||
| 180 | 180 | } else |
| 181 | 181 | policy->hname = kstrdup(name, gfp); |
| 182 | 182 | if (!policy->hname) |
| 183 | − return 0; | |
| 183 | + return false; | |
| 184 | 184 | /* base.name is a substring of fqname */ |
| 185 | 185 | policy->name = basename(policy->hname); |
| 186 | 186 | INIT_LIST_HEAD(&policy->list); |
| 187 | 187 | INIT_LIST_HEAD(&policy->profiles); |
| 188 | 188 | |
| 189 | − return 1; | |
| 189 | + return true; | |
| 190 | 190 | } |
| 191 | 191 | |
| 192 | 192 | /** |
| @@ -39,7 +39,7 @@ · 38 unmodified lines | ||
| 39 | 39 | #include "include/procattr.h" |
| 40 | 40 | |
| 41 | 41 | /* Flag indicating whether initialization completed */ |
| 42 | −int apparmor_initialized __initdata; | |
| 42 | +int apparmor_initialized; | |
| 43 | 43 | |
| 44 | 44 | DEFINE_PER_CPU(struct aa_buffers, aa_buffers); |
| 45 | 45 | |
| @@ -587,7 +587,7 @@ static int apparmor_task_setrlimit(struct task_struct *task, · 541 unmodified lines | ||
| 587 | 587 | return error; |
| 588 | 588 | } |
| 589 | 589 | |
| 590 | −static struct security_hook_list apparmor_hooks[] = { | |
| 590 | +static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |
| 591 | 591 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), |
| 592 | 592 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), |
| 593 | 593 | LSM_HOOK_INIT(capget, apparmor_capget), |
| @@ -681,7 +681,7 @@ module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); · 87 unmodified lines | ||
| 681 | 681 | #endif |
| 682 | 682 | |
| 683 | 683 | /* Debug mode */ |
| 684 | −bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_DEBUG_MESSAGES); | |
| 684 | +bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES); | |
| 685 | 685 | module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR); |
| 686 | 686 | |
| 687 | 687 | /* Audit mode */ |
| @@ -710,7 +710,7 @@ module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR); · 22 unmodified lines | ||
| 710 | 710 | |
| 711 | 711 | /* Maximum pathname length before accesses will start getting rejected */ |
| 712 | 712 | unsigned int aa_g_path_max = 2 * PATH_MAX; |
| 713 | −module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR); | |
| 713 | +module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); | |
| 714 | 714 | |
| 715 | 715 | /* Determines how paranoid loading of policy is and how much verification |
| 716 | 716 | * on the loaded policy is done. |
| @@ -738,78 +738,77 @@ __setup("apparmor=", apparmor_enabled_setup); · 21 unmodified lines | ||
| 738 | 738 | /* set global flag turning off the ability to load policy */ |
| 739 | 739 | static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp) |
| 740 | 740 | { |
| 741 | − if (!policy_admin_capable(NULL)) | |
| 741 | + if (!apparmor_enabled) | |
| 742 | + return -EINVAL; | |
| 743 | + if (apparmor_initialized && !policy_admin_capable(NULL)) | |
| 742 | 744 | return -EPERM; |
| 743 | 745 | return param_set_bool(val, kp); |
| 744 | 746 | } |
| 745 | 747 | |
| 746 | 748 | static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp) |
| 747 | 749 | { |
| 748 | − if (!policy_view_capable(NULL)) | |
| 749 | − return -EPERM; | |
| 750 | 750 | if (!apparmor_enabled) |
| 751 | 751 | return -EINVAL; |
| 752 | + if (apparmor_initialized && !policy_view_capable(NULL)) | |
| 753 | + return -EPERM; | |
| 752 | 754 | return param_get_bool(buffer, kp); |
| 753 | 755 | } |
| 754 | 756 | |
| 755 | 757 | static int param_set_aabool(const char *val, const struct kernel_param *kp) |
| 756 | 758 | { |
| 757 | − if (!policy_admin_capable(NULL)) | |
| 758 | − return -EPERM; | |
| 759 | 759 | if (!apparmor_enabled) |
| 760 | 760 | return -EINVAL; |
| 761 | + if (apparmor_initialized && !policy_admin_capable(NULL)) | |
| 762 | + return -EPERM; | |
| 761 | 763 | return param_set_bool(val, kp); |
| 762 | 764 | } |
| 763 | 765 | |
| 764 | 766 | static int param_get_aabool(char *buffer, const struct kernel_param *kp) |
| 765 | 767 | { |
| 766 | − if (!policy_view_capable(NULL)) | |
| 767 | − return -EPERM; | |
| 768 | 768 | if (!apparmor_enabled) |
| 769 | 769 | return -EINVAL; |
| 770 | + if (apparmor_initialized && !policy_view_capable(NULL)) | |
| 771 | + return -EPERM; | |
| 770 | 772 | return param_get_bool(buffer, kp); |
| 771 | 773 | } |
| 772 | 774 | |
| 773 | 775 | static int param_set_aauint(const char *val, const struct kernel_param *kp) |
| 774 | 776 | { |
| 775 | − if (!policy_admin_capable(NULL)) | |
| 776 | − return -EPERM; | |
| 777 | 777 | if (!apparmor_enabled) |
| 778 | 778 | return -EINVAL; |
| 779 | + if (apparmor_initialized && !policy_admin_capable(NULL)) | |
| 780 | + return -EPERM; | |
| 779 | 781 | return param_set_uint(val, kp); |
| 780 | 782 | } |
| 781 | 783 | |
| 782 | 784 | static int param_get_aauint(char *buffer, const struct kernel_param *kp) |
| 783 | 785 | { |
| 784 | − if (!policy_view_capable(NULL)) | |
| 785 | − return -EPERM; | |
| 786 | 786 | if (!apparmor_enabled) |
| 787 | 787 | return -EINVAL; |
| 788 | + if (apparmor_initialized && !policy_view_capable(NULL)) | |
| 789 | + return -EPERM; | |
| 788 | 790 | return param_get_uint(buffer, kp); |
| 789 | 791 | } |
| 790 | 792 | |
| 791 | 793 | static int param_get_audit(char *buffer, struct kernel_param *kp) |
| 792 | 794 | { |
| 793 | − if (!policy_view_capable(NULL)) | |
| 794 | − return -EPERM; | |
| 795 | − | |
| 796 | 795 | if (!apparmor_enabled) |
| 797 | 796 | return -EINVAL; |
| 798 | − | |
| 797 | + if (apparmor_initialized && !policy_view_capable(NULL)) | |
| 798 | + return -EPERM; | |
| 799 | 799 | return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); |
| 800 | 800 | } |
| 801 | 801 | |
| 802 | 802 | static int param_set_audit(const char *val, struct kernel_param *kp) |
| 803 | 803 | { |
| 804 | 804 | int i; |
| 805 | − if (!policy_admin_capable(NULL)) | |
| 806 | − return -EPERM; | |
| 807 | 805 | |
| 808 | 806 | if (!apparmor_enabled) |
| 809 | 807 | return -EINVAL; |
| 810 | − | |
| 811 | 808 | if (!val) |
| 812 | 809 | return -EINVAL; |
| 810 | + if (apparmor_initialized && !policy_admin_capable(NULL)) | |
| 811 | + return -EPERM; | |
| 813 | 812 | |
| 814 | 813 | for (i = 0; i < AUDIT_MAX_INDEX; i++) { |
| 815 | 814 | if (strcmp(val, audit_mode_names[i]) == 0) { |
| @@ -823,11 +822,10 @@ static int param_set_audit(const char *val, struct kernel_param *kp) · 7 unmodified lines | ||
| 823 | 822 | |
| 824 | 823 | static int param_get_mode(char *buffer, struct kernel_param *kp) |
| 825 | 824 | { |
| 826 | − if (!policy_view_capable(NULL)) | |
| 827 | − return -EPERM; | |
| 828 | − | |
| 829 | 825 | if (!apparmor_enabled) |
| 830 | 826 | return -EINVAL; |
| 827 | + if (apparmor_initialized && !policy_view_capable(NULL)) | |
| 828 | + return -EPERM; | |
| 831 | 829 | |
| 832 | 830 | return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); |
| 833 | 831 | } |
| @@ -835,14 +833,13 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) · 1 unmodified line | ||
| 835 | 833 | static int param_set_mode(const char *val, struct kernel_param *kp) |
| 836 | 834 | { |
| 837 | 835 | int i; |
| 838 | − if (!policy_admin_capable(NULL)) | |
| 839 | − return -EPERM; | |
| 840 | 836 | |
| 841 | 837 | if (!apparmor_enabled) |
| 842 | 838 | return -EINVAL; |
| 843 | − | |
| 844 | 839 | if (!val) |
| 845 | 840 | return -EINVAL; |
| 841 | + if (apparmor_initialized && !policy_admin_capable(NULL)) | |
| 842 | + return -EPERM; | |
| 846 | 843 | |
| 847 | 844 | for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) { |
| 848 | 845 | if (strcmp(val, aa_profile_mode_names[i]) == 0) { |
| @@ -876,9 +876,11 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, · 875 unmodified lines | ||
| 876 | 876 | if (ns_name) { |
| 877 | 877 | ns = aa_prepare_ns(view, ns_name); |
| 878 | 878 | if (IS_ERR(ns)) { |
| 879 | + op = OP_PROF_LOAD; | |
| 879 | 880 | info = "failed to prepare namespace"; |
| 880 | 881 | error = PTR_ERR(ns); |
| 881 | 882 | ns = NULL; |
| 883 | + ent = NULL; | |
| 882 | 884 | goto fail; |
| 883 | 885 | } |
| 884 | 886 | } else |
| @@ -1013,7 +1015,7 @@ fail_lock: · 128 unmodified lines | ||
| 1013 | 1015 | /* audit cause of failure */ |
| 1014 | 1016 | op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; |
| 1015 | 1017 | fail: |
| 1016 | − audit_policy(profile, op, ns_name, ent->new->base.hname, | |
| 1018 | + audit_policy(profile, op, ns_name, ent ? ent->new->base.hname : NULL, | |
| 1017 | 1019 | info, error); |
| 1018 | 1020 | /* audit status that rest of profiles in the atomic set failed too */ |
| 1019 | 1021 | info = "valid profile in failed atomic policy load"; |
| @@ -1023,7 +1025,7 @@ fail: · 3 unmodified lines | ||
| 1023 | 1025 | /* skip entry that caused failure */ |
| 1024 | 1026 | continue; |
| 1025 | 1027 | } |
| 1026 | − op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; | |
| 1028 | + op = (!tmp->old) ? OP_PROF_LOAD : OP_PROF_REPL; | |
| 1027 | 1029 | audit_policy(profile, op, ns_name, |
| 1028 | 1030 | tmp->new->base.hname, info, error); |
| 1029 | 1031 | } |
| @@ -1071,7 +1071,7 @@ int cap_mmap_file(struct file *file, unsigned long reqprot, · 1070 unmodified lines | ||
| 1071 | 1071 | |
| 1072 | 1072 | #ifdef CONFIG_SECURITY |
| 1073 | 1073 | |
| 1074 | −struct security_hook_list capability_hooks[] = { | |
| 1074 | +struct security_hook_list capability_hooks[] __lsm_ro_after_init = { | |
| 1075 | 1075 | LSM_HOOK_INIT(capable, cap_capable), |
| 1076 | 1076 | LSM_HOOK_INIT(settime, cap_settime), |
| 1077 | 1077 | LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check), |
| @@ -81,18 +81,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, · 80 unmodified lines | ||
| 81 | 81 | int __init integrity_init_keyring(const unsigned int id) |
| 82 | 82 | { |
| 83 | 83 | const struct cred *cred = current_cred(); |
| 84 | + struct key_restriction *restriction; | |
| 84 | 85 | int err = 0; |
| 85 | 86 | |
| 86 | 87 | if (!init_keyring) |
| 87 | 88 | return 0; |
| 88 | 89 | |
| 90 | + restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL); | |
| 91 | + if (!restriction) | |
| 92 | + return -ENOMEM; | |
| 93 | + | |
| 94 | + restriction->check = restrict_link_to_ima; | |
| 95 | + | |
| 89 | 96 | keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), |
| 90 | 97 | KGIDT_INIT(0), cred, |
| 91 | 98 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 92 | 99 | KEY_USR_VIEW | KEY_USR_READ | |
| 93 | 100 | KEY_USR_WRITE | KEY_USR_SEARCH), |
| 94 | 101 | KEY_ALLOC_NOT_IN_QUOTA, |
| 95 | − restrict_link_to_ima, NULL); | |
| 102 | + restriction, NULL); | |
| 96 | 103 | if (IS_ERR(keyring[id])) { |
| 97 | 104 | err = PTR_ERR(keyring[id]); |
| 98 | 105 | pr_info("Can't allocate %s keyring (%d)\n", |
| @@ -207,10 +207,11 @@ int ima_appraise_measurement(enum ima_hooks func, · 206 unmodified lines | ||
| 207 | 207 | |
| 208 | 208 | cause = "missing-hash"; |
| 209 | 209 | status = INTEGRITY_NOLABEL; |
| 210 | − if (opened & FILE_CREATED) { | |
| 210 | + if (opened & FILE_CREATED) | |
| 211 | 211 | iint->flags |= IMA_NEW_FILE; |
| 212 | + if ((iint->flags & IMA_NEW_FILE) && | |
| 213 | + !(iint->flags & IMA_DIGSIG_REQUIRED)) | |
| 212 | 214 | status = INTEGRITY_PASS; |
| 213 | − } | |
| 214 | 215 | goto out; |
| 215 | 216 | } |
| 216 | 217 | |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/cred.h> |
| 18 | 18 | #include <linux/err.h> |
| 19 | 19 | #include <linux/init.h> |
| 20 | +#include <linux/slab.h> | |
| 20 | 21 | #include <keys/system_keyring.h> |
| 21 | 22 | |
| 22 | 23 | |
| @@ -27,15 +28,23 @@ struct key *ima_blacklist_keyring; · 4 unmodified lines | ||
| 27 | 28 | */ |
| 28 | 29 | __init int ima_mok_init(void) |
| 29 | 30 | { |
| 31 | + struct key_restriction *restriction; | |
| 32 | + | |
| 30 | 33 | pr_notice("Allocating IMA blacklist keyring.\n"); |
| 31 | 34 | |
| 35 | + restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL); | |
| 36 | + if (!restriction) | |
| 37 | + panic("Can't allocate IMA blacklist restriction."); | |
| 38 | + | |
| 39 | + restriction->check = restrict_link_by_builtin_trusted; | |
| 40 | + | |
| 32 | 41 | ima_blacklist_keyring = keyring_alloc(".ima_blacklist", |
| 33 | 42 | KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), |
| 34 | 43 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 35 | 44 | KEY_USR_VIEW | KEY_USR_READ | |
| 36 | 45 | KEY_USR_WRITE | KEY_USR_SEARCH, |
| 37 | 46 | KEY_ALLOC_NOT_IN_QUOTA, |
| 38 | − restrict_link_by_builtin_trusted, NULL); | |
| 47 | + restriction, NULL); | |
| 39 | 48 | |
| 40 | 49 | if (IS_ERR(ima_blacklist_keyring)) |
| 41 | 50 | panic("Can't allocate IMA blacklist keyring."); |
| @@ -64,6 +64,8 @@ struct ima_rule_entry { · 63 unmodified lines | ||
| 64 | 64 | u8 fsuuid[16]; |
| 65 | 65 | kuid_t uid; |
| 66 | 66 | kuid_t fowner; |
| 67 | + bool (*uid_op)(kuid_t, kuid_t); /* Handlers for operators */ | |
| 68 | + bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */ | |
| 67 | 69 | int pcr; |
| 68 | 70 | struct { |
| 69 | 71 | void *rule; /* LSM file metadata specific */ |
| @@ -83,7 +85,7 @@ struct ima_rule_entry { · 13 unmodified lines | ||
| 83 | 85 | * normal users can easily run the machine out of memory simply building |
| 84 | 86 | * and running executables. |
| 85 | 87 | */ |
| 86 | −static struct ima_rule_entry dont_measure_rules[] = { | |
| 88 | +static struct ima_rule_entry dont_measure_rules[] __ro_after_init = { | |
| 87 | 89 | {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
| 88 | 90 | {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, |
| 89 | 91 | {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, |
| @@ -97,32 +99,35 @@ static struct ima_rule_entry dont_measure_rules[] = { · 7 unmodified lines | ||
| 97 | 99 | {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC} |
| 98 | 100 | }; |
| 99 | 101 | |
| 100 | −static struct ima_rule_entry original_measurement_rules[] = { | |
| 102 | +static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { | |
| 101 | 103 | {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, |
| 102 | 104 | .flags = IMA_FUNC | IMA_MASK}, |
| 103 | 105 | {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, |
| 104 | 106 | .flags = IMA_FUNC | IMA_MASK}, |
| 105 | 107 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, |
| 106 | − .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | |
| 108 | + .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, | |
| 109 | + .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | |
| 107 | 110 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, |
| 108 | 111 | {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, |
| 109 | 112 | }; |
| 110 | 113 | |
| 111 | −static struct ima_rule_entry default_measurement_rules[] = { | |
| 114 | +static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { | |
| 112 | 115 | {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, |
| 113 | 116 | .flags = IMA_FUNC | IMA_MASK}, |
| 114 | 117 | {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, |
| 115 | 118 | .flags = IMA_FUNC | IMA_MASK}, |
| 116 | 119 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, |
| 117 | − .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, | |
| 120 | + .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, | |
| 121 | + .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, | |
| 118 | 122 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, |
| 119 | − .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, | |
| 123 | + .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, | |
| 124 | + .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, | |
| 120 | 125 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, |
| 121 | 126 | {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, |
| 122 | 127 | {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, |
| 123 | 128 | }; |
| 124 | 129 | |
| 125 | −static struct ima_rule_entry default_appraise_rules[] = { | |
| 130 | +static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { | |
| 126 | 131 | {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
| 127 | 132 | {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, |
| 128 | 133 | {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, |
| @@ -139,10 +144,11 @@ static struct ima_rule_entry default_appraise_rules[] = { · 10 unmodified lines | ||
| 139 | 144 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, |
| 140 | 145 | #endif |
| 141 | 146 | #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT |
| 142 | − {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, | |
| 147 | + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, | |
| 148 | + .flags = IMA_FOWNER}, | |
| 143 | 149 | #else |
| 144 | 150 | /* force signature */ |
| 145 | − {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, | |
| 151 | + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, | |
| 146 | 152 | .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, |
| 147 | 153 | #endif |
| 148 | 154 | }; |
| @@ -240,19 +246,20 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, · 91 unmodified lines | ||
| 240 | 246 | if ((rule->flags & IMA_FSUUID) && |
| 241 | 247 | memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid))) |
| 242 | 248 | return false; |
| 243 | − if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) | |
| 249 | + if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) | |
| 244 | 250 | return false; |
| 245 | 251 | if (rule->flags & IMA_EUID) { |
| 246 | 252 | if (has_capability_noaudit(current, CAP_SETUID)) { |
| 247 | − if (!uid_eq(rule->uid, cred->euid) | |
| 248 | − && !uid_eq(rule->uid, cred->suid) | |
| 249 | − && !uid_eq(rule->uid, cred->uid)) | |
| 253 | + if (!rule->uid_op(cred->euid, rule->uid) | |
| 254 | + && !rule->uid_op(cred->suid, rule->uid) | |
| 255 | + && !rule->uid_op(cred->uid, rule->uid)) | |
| 250 | 256 | return false; |
| 251 | − } else if (!uid_eq(rule->uid, cred->euid)) | |
| 257 | + } else if (!rule->uid_op(cred->euid, rule->uid)) | |
| 252 | 258 | return false; |
| 253 | 259 | } |
| 254 | 260 | |
| 255 | − if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid)) | |
| 261 | + if ((rule->flags & IMA_FOWNER) && | |
| 262 | + !rule->fowner_op(inode->i_uid, rule->fowner)) | |
| 256 | 263 | return false; |
| 257 | 264 | for (i = 0; i < MAX_LSM_RULES; i++) { |
| 258 | 265 | int rc = 0; |
| @@ -486,7 +493,9 @@ enum { · 227 unmodified lines | ||
| 486 | 493 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
| 487 | 494 | Opt_subj_user, Opt_subj_role, Opt_subj_type, |
| 488 | 495 | Opt_func, Opt_mask, Opt_fsmagic, |
| 489 | − Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner, | |
| 496 | + Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq, | |
| 497 | + Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, | |
| 498 | + Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, | |
| 490 | 499 | Opt_appraise_type, Opt_permit_directio, |
| 491 | 500 | Opt_pcr |
| 492 | 501 | }; |
| @@ -507,9 +516,15 @@ static match_table_t policy_tokens = { · 14 unmodified lines | ||
| 507 | 516 | {Opt_mask, "mask=%s"}, |
| 508 | 517 | {Opt_fsmagic, "fsmagic=%s"}, |
| 509 | 518 | {Opt_fsuuid, "fsuuid=%s"}, |
| 510 | − {Opt_uid, "uid=%s"}, | |
| 511 | − {Opt_euid, "euid=%s"}, | |
| 512 | − {Opt_fowner, "fowner=%s"}, | |
| 519 | + {Opt_uid_eq, "uid=%s"}, | |
| 520 | + {Opt_euid_eq, "euid=%s"}, | |
| 521 | + {Opt_fowner_eq, "fowner=%s"}, | |
| 522 | + {Opt_uid_gt, "uid>%s"}, | |
| 523 | + {Opt_euid_gt, "euid>%s"}, | |
| 524 | + {Opt_fowner_gt, "fowner>%s"}, | |
| 525 | + {Opt_uid_lt, "uid<%s"}, | |
| 526 | + {Opt_euid_lt, "euid<%s"}, | |
| 527 | + {Opt_fowner_lt, "fowner<%s"}, | |
| 513 | 528 | {Opt_appraise_type, "appraise_type=%s"}, |
| 514 | 529 | {Opt_permit_directio, "permit_directio"}, |
| 515 | 530 | {Opt_pcr, "pcr=%s"}, |
| @@ -541,24 +556,37 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry, · 25 unmodified lines | ||
| 541 | 556 | return result; |
| 542 | 557 | } |
| 543 | 558 | |
| 544 | −static void ima_log_string(struct audit_buffer *ab, char *key, char *value) | |
| 559 | +static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value, | |
| 560 | + bool (*rule_operator)(kuid_t, kuid_t)) | |
| 545 | 561 | { |
| 546 | − audit_log_format(ab, "%s=", key); | |
| 562 | + if (rule_operator == &uid_gt) | |
| 563 | + audit_log_format(ab, "%s>", key); | |
| 564 | + else if (rule_operator == &uid_lt) | |
| 565 | + audit_log_format(ab, "%s<", key); | |
| 566 | + else | |
| 567 | + audit_log_format(ab, "%s=", key); | |
| 547 | 568 | audit_log_untrustedstring(ab, value); |
| 548 | 569 | audit_log_format(ab, " "); |
| 549 | 570 | } |
| 571 | +static void ima_log_string(struct audit_buffer *ab, char *key, char *value) | |
| 572 | +{ | |
| 573 | + ima_log_string_op(ab, key, value, NULL); | |
| 574 | +} | |
| 550 | 575 | |
| 551 | 576 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) |
| 552 | 577 | { |
| 553 | 578 | struct audit_buffer *ab; |
| 554 | 579 | char *from; |
| 555 | 580 | char *p; |
| 581 | + bool uid_token; | |
| 556 | 582 | int result = 0; |
| 557 | 583 | |
| 558 | 584 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); |
| 559 | 585 | |
| 560 | 586 | entry->uid = INVALID_UID; |
| 561 | 587 | entry->fowner = INVALID_UID; |
| 588 | + entry->uid_op = &uid_eq; | |
| 589 | + entry->fowner_op = &uid_eq; | |
| 562 | 590 | entry->action = UNKNOWN; |
| 563 | 591 | while ((p = strsep(&rule, " \t")) != NULL) { |
| 564 | 592 | substring_t args[MAX_OPT_ARGS]; |
| @@ -694,11 +722,21 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) · 129 unmodified lines | ||
| 694 | 722 | if (!result) |
| 695 | 723 | entry->flags |= IMA_FSUUID; |
| 696 | 724 | break; |
| 697 | − case Opt_uid: | |
| 698 | − ima_log_string(ab, "uid", args[0].from); | |
| 699 | − case Opt_euid: | |
| 700 | − if (token == Opt_euid) | |
| 701 | − ima_log_string(ab, "euid", args[0].from); | |
| 725 | + case Opt_uid_gt: | |
| 726 | + case Opt_euid_gt: | |
| 727 | + entry->uid_op = &uid_gt; | |
| 728 | + case Opt_uid_lt: | |
| 729 | + case Opt_euid_lt: | |
| 730 | + if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) | |
| 731 | + entry->uid_op = &uid_lt; | |
| 732 | + case Opt_uid_eq: | |
| 733 | + case Opt_euid_eq: | |
| 734 | + uid_token = (token == Opt_uid_eq) || | |
| 735 | + (token == Opt_uid_gt) || | |
| 736 | + (token == Opt_uid_lt); | |
| 737 | + | |
| 738 | + ima_log_string_op(ab, uid_token ? "uid" : "euid", | |
| 739 | + args[0].from, entry->uid_op); | |
| 702 | 740 | |
| 703 | 741 | if (uid_valid(entry->uid)) { |
| 704 | 742 | result = -EINVAL; |
| @@ -713,12 +751,18 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) · 8 unmodified lines | ||
| 713 | 751 | (uid_t)lnum != lnum) |
| 714 | 752 | result = -EINVAL; |
| 715 | 753 | else |
| 716 | − entry->flags |= (token == Opt_uid) | |
| 754 | + entry->flags |= uid_token | |
| 717 | 755 | ? IMA_UID : IMA_EUID; |
| 718 | 756 | } |
| 719 | 757 | break; |
| 720 | − case Opt_fowner: | |
| 721 | − ima_log_string(ab, "fowner", args[0].from); | |
| 758 | + case Opt_fowner_gt: | |
| 759 | + entry->fowner_op = &uid_gt; | |
| 760 | + case Opt_fowner_lt: | |
| 761 | + if (token == Opt_fowner_lt) | |
| 762 | + entry->fowner_op = &uid_lt; | |
| 763 | + case Opt_fowner_eq: | |
| 764 | + ima_log_string_op(ab, "fowner", args[0].from, | |
| 765 | + entry->fowner_op); | |
| 722 | 766 | |
| 723 | 767 | if (uid_valid(entry->fowner)) { |
| 724 | 768 | result = -EINVAL; |
| @@ -1049,19 +1093,34 @@ int ima_policy_show(struct seq_file *m, void *v) · 324 unmodified lines | ||
| 1049 | 1093 | |
| 1050 | 1094 | if (entry->flags & IMA_UID) { |
| 1051 | 1095 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); |
| 1052 | − seq_printf(m, pt(Opt_uid), tbuf); | |
| 1096 | + if (entry->uid_op == &uid_gt) | |
| 1097 | + seq_printf(m, pt(Opt_uid_gt), tbuf); | |
| 1098 | + else if (entry->uid_op == &uid_lt) | |
| 1099 | + seq_printf(m, pt(Opt_uid_lt), tbuf); | |
| 1100 | + else | |
| 1101 | + seq_printf(m, pt(Opt_uid_eq), tbuf); | |
| 1053 | 1102 | seq_puts(m, " "); |
| 1054 | 1103 | } |
| 1055 | 1104 | |
| 1056 | 1105 | if (entry->flags & IMA_EUID) { |
| 1057 | 1106 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); |
| 1058 | − seq_printf(m, pt(Opt_euid), tbuf); | |
| 1107 | + if (entry->uid_op == &uid_gt) | |
| 1108 | + seq_printf(m, pt(Opt_euid_gt), tbuf); | |
| 1109 | + else if (entry->uid_op == &uid_lt) | |
| 1110 | + seq_printf(m, pt(Opt_euid_lt), tbuf); | |
| 1111 | + else | |
| 1112 | + seq_printf(m, pt(Opt_euid_eq), tbuf); | |
| 1059 | 1113 | seq_puts(m, " "); |
| 1060 | 1114 | } |
| 1061 | 1115 | |
| 1062 | 1116 | if (entry->flags & IMA_FOWNER) { |
| 1063 | 1117 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); |
| 1064 | − seq_printf(m, pt(Opt_fowner), tbuf); | |
| 1118 | + if (entry->fowner_op == &uid_gt) | |
| 1119 | + seq_printf(m, pt(Opt_fowner_gt), tbuf); | |
| 1120 | + else if (entry->fowner_op == &uid_lt) | |
| 1121 | + seq_printf(m, pt(Opt_fowner_lt), tbuf); | |
| 1122 | + else | |
| 1123 | + seq_printf(m, pt(Opt_fowner_eq), tbuf); | |
| 1065 | 1124 | seq_puts(m, " "); |
| 1066 | 1125 | } |
| 1067 | 1126 | |
| @@ -90,6 +90,8 @@ config KEY_DH_OPERATIONS · 89 unmodified lines | ||
| 90 | 90 | bool "Diffie-Hellman operations on retained keys" |
| 91 | 91 | depends on KEYS |
| 92 | 92 | select MPILIB |
| 93 | + select CRYPTO | |
| 94 | + select CRYPTO_HASH | |
| 93 | 95 | help |
| 94 | 96 | This option provides support for calculating Diffie-Hellman |
| 95 | 97 | public keys and shared secrets using values stored as keys |
| @@ -15,7 +15,8 @@ obj-y := \ · 14 unmodified lines | ||
| 15 | 15 | request_key.o \ |
| 16 | 16 | request_key_auth.o \ |
| 17 | 17 | user_defined.o |
| 18 | −obj-$(CONFIG_KEYS_COMPAT) += compat.o | |
| 18 | +compat-obj-$(CONFIG_KEY_DH_OPERATIONS) += compat_dh.o | |
| 19 | +obj-$(CONFIG_KEYS_COMPAT) += compat.o $(compat-obj-y) | |
| 19 | 20 | obj-$(CONFIG_PROC_FS) += proc.o |
| 20 | 21 | obj-$(CONFIG_SYSCTL) += sysctl.o |
| 21 | 22 | obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o |
| @@ -133,8 +133,13 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, · 132 unmodified lines | ||
| 133 | 133 | return keyctl_get_persistent(arg2, arg3); |
| 134 | 134 | |
| 135 | 135 | case KEYCTL_DH_COMPUTE: |
| 136 | − return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3), | |
| 137 | − arg4, compat_ptr(arg5)); | |
| 136 | + return compat_keyctl_dh_compute(compat_ptr(arg2), | |
| 137 | + compat_ptr(arg3), | |
| 138 | + arg4, compat_ptr(arg5)); | |
| 139 | + | |
| 140 | + case KEYCTL_RESTRICT_KEYRING: | |
| 141 | + return keyctl_restrict_keyring(arg2, compat_ptr(arg3), | |
| 142 | + compat_ptr(arg4)); | |
| 138 | 143 | |
| 139 | 144 | default: |
| 140 | 145 | return -EOPNOTSUPP; |
| @@ -0,0 +1,38 @@ | ||
| 1 | +/* 32-bit compatibility syscall for 64-bit systems for DH operations | |
| 2 | + * | |
| 3 | + * Copyright (C) 2016 Stephan Mueller <smueller@chronox.de> | |
| 4 | + * | |
| 5 | + * This program is free software; you can redistribute it and/or | |
| 6 | + * modify it under the terms of the GNU General Public License | |
| 7 | + * as published by the Free Software Foundation; either version | |
| 8 | + * 2 of the License, or (at your option) any later version. | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#include <linux/uaccess.h> | |
| 12 | + | |
| 13 | +#include "internal.h" | |
| 14 | + | |
| 15 | +/* | |
| 16 | + * Perform the DH computation or DH based key derivation. | |
| 17 | + * | |
| 18 | + * If successful, 0 will be returned. | |
| 19 | + */ | |
| 20 | +long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params, | |
| 21 | + char __user *buffer, size_t buflen, | |
| 22 | + struct compat_keyctl_kdf_params __user *kdf) | |
| 23 | +{ | |
| 24 | + struct keyctl_kdf_params kdfcopy; | |
| 25 | + struct compat_keyctl_kdf_params compat_kdfcopy; | |
| 26 | + | |
| 27 | + if (!kdf) | |
| 28 | + return __keyctl_dh_compute(params, buffer, buflen, NULL); | |
| 29 | + | |
| 30 | + if (copy_from_user(&compat_kdfcopy, kdf, sizeof(compat_kdfcopy)) != 0) | |
| 31 | + return -EFAULT; | |
| 32 | + | |
| 33 | + kdfcopy.hashname = compat_ptr(compat_kdfcopy.hashname); | |
| 34 | + kdfcopy.otherinfo = compat_ptr(compat_kdfcopy.otherinfo); | |
| 35 | + kdfcopy.otherinfolen = compat_kdfcopy.otherinfolen; | |
| 36 | + | |
| 37 | + return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy); | |
| 38 | +} | |
| @@ -11,6 +11,8 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <linux/mpi.h> |
| 12 | 12 | #include <linux/slab.h> |
| 13 | 13 | #include <linux/uaccess.h> |
| 14 | +#include <linux/crypto.h> | |
| 15 | +#include <crypto/hash.h> | |
| 14 | 16 | #include <keys/user-type.h> |
| 15 | 17 | #include "internal.h" |
| 16 | 18 | |
| @@ -77,9 +79,146 @@ error: · 60 unmodified lines | ||
| 77 | 79 | return ret; |
| 78 | 80 | } |
| 79 | 81 | |
| 80 | −long keyctl_dh_compute(struct keyctl_dh_params __user *params, | |
| 81 | − char __user *buffer, size_t buflen, | |
| 82 | − void __user *reserved) | |
| 82 | +struct kdf_sdesc { | |
| 83 | + struct shash_desc shash; | |
| 84 | + char ctx[]; | |
| 85 | +}; | |
| 86 | + | |
| 87 | +static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname) | |
| 88 | +{ | |
| 89 | + struct crypto_shash *tfm; | |
| 90 | + struct kdf_sdesc *sdesc; | |
| 91 | + int size; | |
| 92 | + | |
| 93 | + /* allocate synchronous hash */ | |
| 94 | + tfm = crypto_alloc_shash(hashname, 0, 0); | |
| 95 | + if (IS_ERR(tfm)) { | |
| 96 | + pr_info("could not allocate digest TFM handle %s\n", hashname); | |
| 97 | + return PTR_ERR(tfm); | |
| 98 | + } | |
| 99 | + | |
| 100 | + size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm); | |
| 101 | + sdesc = kmalloc(size, GFP_KERNEL); | |
| 102 | + if (!sdesc) | |
| 103 | + return -ENOMEM; | |
| 104 | + sdesc->shash.tfm = tfm; | |
| 105 | + sdesc->shash.flags = 0x0; | |
| 106 | + | |
| 107 | + *sdesc_ret = sdesc; | |
| 108 | + | |
| 109 | + return 0; | |
| 110 | +} | |
| 111 | + | |
| 112 | +static void kdf_dealloc(struct kdf_sdesc *sdesc) | |
| 113 | +{ | |
| 114 | + if (!sdesc) | |
| 115 | + return; | |
| 116 | + | |
| 117 | + if (sdesc->shash.tfm) | |
| 118 | + crypto_free_shash(sdesc->shash.tfm); | |
| 119 | + | |
| 120 | + kzfree(sdesc); | |
| 121 | +} | |
| 122 | + | |
| 123 | +/* convert 32 bit integer into its string representation */ | |
| 124 | +static inline void crypto_kw_cpu_to_be32(u32 val, u8 *buf) | |
| 125 | +{ | |
| 126 | + __be32 *a = (__be32 *)buf; | |
| 127 | + | |
| 128 | + *a = cpu_to_be32(val); | |
| 129 | +} | |
| 130 | + | |
| 131 | +/* | |
| 132 | + * Implementation of the KDF in counter mode according to SP800-108 section 5.1 | |
| 133 | + * as well as SP800-56A section 5.8.1 (Single-step KDF). | |
| 134 | + * | |
| 135 | + * SP800-56A: | |
| 136 | + * The src pointer is defined as Z || other info where Z is the shared secret | |
| 137 | + * from DH and other info is an arbitrary string (see SP800-56A section | |
| 138 | + * 5.8.1.2). | |
| 139 | + */ | |
| 140 | +static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, | |
| 141 | + u8 *dst, unsigned int dlen) | |
| 142 | +{ | |
| 143 | + struct shash_desc *desc = &sdesc->shash; | |
| 144 | + unsigned int h = crypto_shash_digestsize(desc->tfm); | |
| 145 | + int err = 0; | |
| 146 | + u8 *dst_orig = dst; | |
| 147 | + u32 i = 1; | |
| 148 | + u8 iteration[sizeof(u32)]; | |
| 149 | + | |
| 150 | + while (dlen) { | |
| 151 | + err = crypto_shash_init(desc); | |
| 152 | + if (err) | |
| 153 | + goto err; | |
| 154 | + | |
| 155 | + crypto_kw_cpu_to_be32(i, iteration); | |
| 156 | + err = crypto_shash_update(desc, iteration, sizeof(u32)); | |
| 157 | + if (err) | |
| 158 | + goto err; | |
| 159 | + | |
| 160 | + if (src && slen) { | |
| 161 | + err = crypto_shash_update(desc, src, slen); | |
| 162 | + if (err) | |
| 163 | + goto err; | |
| 164 | + } | |
| 165 | + | |
| 166 | + if (dlen < h) { | |
| 167 | + u8 tmpbuffer[h]; | |
| 168 | + | |
| 169 | + err = crypto_shash_final(desc, tmpbuffer); | |
| 170 | + if (err) | |
| 171 | + goto err; | |
| 172 | + memcpy(dst, tmpbuffer, dlen); | |
| 173 | + memzero_explicit(tmpbuffer, h); | |
| 174 | + return 0; | |
| 175 | + } else { | |
| 176 | + err = crypto_shash_final(desc, dst); | |
| 177 | + if (err) | |
| 178 | + goto err; | |
| 179 | + | |
| 180 | + dlen -= h; | |
| 181 | + dst += h; | |
| 182 | + i++; | |
| 183 | + } | |
| 184 | + } | |
| 185 | + | |
| 186 | + return 0; | |
| 187 | + | |
| 188 | +err: | |
| 189 | + memzero_explicit(dst_orig, dlen); | |
| 190 | + return err; | |
| 191 | +} | |
| 192 | + | |
| 193 | +static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, | |
| 194 | + char __user *buffer, size_t buflen, | |
| 195 | + uint8_t *kbuf, size_t kbuflen) | |
| 196 | +{ | |
| 197 | + uint8_t *outbuf = NULL; | |
| 198 | + int ret; | |
| 199 | + | |
| 200 | + outbuf = kmalloc(buflen, GFP_KERNEL); | |
| 201 | + if (!outbuf) { | |
| 202 | + ret = -ENOMEM; | |
| 203 | + goto err; | |
| 204 | + } | |
| 205 | + | |
| 206 | + ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen); | |
| 207 | + if (ret) | |
| 208 | + goto err; | |
| 209 | + | |
| 210 | + ret = buflen; | |
| 211 | + if (copy_to_user(buffer, outbuf, buflen) != 0) | |
| 212 | + ret = -EFAULT; | |
| 213 | + | |
| 214 | +err: | |
| 215 | + kzfree(outbuf); | |
| 216 | + return ret; | |
| 217 | +} | |
| 218 | + | |
| 219 | +long __keyctl_dh_compute(struct keyctl_dh_params __user *params, | |
| 220 | + char __user *buffer, size_t buflen, | |
| 221 | + struct keyctl_kdf_params *kdfcopy) | |
| 83 | 222 | { |
| 84 | 223 | long ret; |
| 85 | 224 | MPI base, private, prime, result; |
| @@ -88,6 +227,7 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params, · 2 unmodified lines | ||
| 88 | 227 | uint8_t *kbuf; |
| 89 | 228 | ssize_t keylen; |
| 90 | 229 | size_t resultlen; |
| 230 | + struct kdf_sdesc *sdesc = NULL; | |
| 91 | 231 | |
| 92 | 232 | if (!params || (!buffer && buflen)) { |
| 93 | 233 | ret = -EINVAL; |
| @@ -98,12 +238,34 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params, · 4 unmodified lines | ||
| 98 | 238 | goto out; |
| 99 | 239 | } |
| 100 | 240 | |
| 101 | − if (reserved) { | |
| 102 | − ret = -EINVAL; | |
| 103 | − goto out; | |
| 241 | + if (kdfcopy) { | |
| 242 | + char *hashname; | |
| 243 | + | |
| 244 | + if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN || | |
| 245 | + kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) { | |
| 246 | + ret = -EMSGSIZE; | |
| 247 | + goto out; | |
| 248 | + } | |
| 249 | + | |
| 250 | + /* get KDF name string */ | |
| 251 | + hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME); | |
| 252 | + if (IS_ERR(hashname)) { | |
| 253 | + ret = PTR_ERR(hashname); | |
| 254 | + goto out; | |
| 255 | + } | |
| 256 | + | |
| 257 | + /* allocate KDF from the kernel crypto API */ | |
| 258 | + ret = kdf_alloc(&sdesc, hashname); | |
| 259 | + kfree(hashname); | |
| 260 | + if (ret) | |
| 261 | + goto out; | |
| 104 | 262 | } |
| 105 | 263 | |
| 106 | − keylen = mpi_from_key(pcopy.prime, buflen, &prime); | |
| 264 | + /* | |
| 265 | + * If the caller requests postprocessing with a KDF, allow an | |
| 266 | + * arbitrary output buffer size since the KDF ensures proper truncation. | |
| 267 | + */ | |
| 268 | + keylen = mpi_from_key(pcopy.prime, kdfcopy ? SIZE_MAX : buflen, &prime); | |
| 107 | 269 | if (keylen < 0 || !prime) { |
| 108 | 270 | /* buflen == 0 may be used to query the required buffer size, |
| 109 | 271 | * which is the prime key length. |
| @@ -133,12 +295,25 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params, · 23 unmodified lines | ||
| 133 | 295 | goto error3; |
| 134 | 296 | } |
| 135 | 297 | |
| 136 | − kbuf = kmalloc(resultlen, GFP_KERNEL); | |
| 298 | + /* allocate space for DH shared secret and SP800-56A otherinfo */ | |
| 299 | + kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen, | |
| 300 | + GFP_KERNEL); | |
| 137 | 301 | if (!kbuf) { |
| 138 | 302 | ret = -ENOMEM; |
| 139 | 303 | goto error4; |
| 140 | 304 | } |
| 141 | 305 | |
| 306 | + /* | |
| 307 | + * Concatenate SP800-56A otherinfo past DH shared secret -- the | |
| 308 | + * input to the KDF is (DH shared secret || otherinfo) | |
| 309 | + */ | |
| 310 | + if (kdfcopy && kdfcopy->otherinfo && | |
| 311 | + copy_from_user(kbuf + resultlen, kdfcopy->otherinfo, | |
| 312 | + kdfcopy->otherinfolen) != 0) { | |
| 313 | + ret = -EFAULT; | |
| 314 | + goto error5; | |
| 315 | + } | |
| 316 | + | |
| 142 | 317 | ret = do_dh(result, base, private, prime); |
| 143 | 318 | if (ret) |
| 144 | 319 | goto error5; |
| @@ -147,12 +322,17 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params, · 2 unmodified lines | ||
| 147 | 322 | if (ret != 0) |
| 148 | 323 | goto error5; |
| 149 | 324 | |
| 150 | − ret = nbytes; | |
| 151 | − if (copy_to_user(buffer, kbuf, nbytes) != 0) | |
| 152 | − ret = -EFAULT; | |
| 325 | + if (kdfcopy) { | |
| 326 | + ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, kbuf, | |
| 327 | + resultlen + kdfcopy->otherinfolen); | |
| 328 | + } else { | |
| 329 | + ret = nbytes; | |
| 330 | + if (copy_to_user(buffer, kbuf, nbytes) != 0) | |
| 331 | + ret = -EFAULT; | |
| 332 | + } | |
| 153 | 333 | |
| 154 | 334 | error5: |
| 155 | − kfree(kbuf); | |
| 335 | + kzfree(kbuf); | |
| 156 | 336 | error4: |
| 157 | 337 | mpi_free(result); |
| 158 | 338 | error3: |
| @@ -162,5 +342,21 @@ error2: · 3 unmodified lines | ||
| 162 | 342 | error1: |
| 163 | 343 | mpi_free(prime); |
| 164 | 344 | out: |
| 345 | + kdf_dealloc(sdesc); | |
| 165 | 346 | return ret; |
| 166 | 347 | } |
| 348 | + | |
| 349 | +long keyctl_dh_compute(struct keyctl_dh_params __user *params, | |
| 350 | + char __user *buffer, size_t buflen, | |
| 351 | + struct keyctl_kdf_params __user *kdf) | |
| 352 | +{ | |
| 353 | + struct keyctl_kdf_params kdfcopy; | |
| 354 | + | |
| 355 | + if (!kdf) | |
| 356 | + return __keyctl_dh_compute(params, buffer, buflen, NULL); | |
| 357 | + | |
| 358 | + if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0) | |
| 359 | + return -EFAULT; | |
| 360 | + | |
| 361 | + return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy); | |
| 362 | +} | |
| @@ -220,7 +220,7 @@ continue_scanning: · 219 unmodified lines | ||
| 220 | 220 | key = rb_entry(cursor, struct key, serial_node); |
| 221 | 221 | cursor = rb_next(cursor); |
| 222 | 222 | |
| 223 | − if (atomic_read(&key->usage) == 0) | |
| 223 | + if (refcount_read(&key->usage) == 0) | |
| 224 | 224 | goto found_unreferenced_key; |
| 225 | 225 | |
| 226 | 226 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { |
| @@ -229,6 +229,9 @@ continue_scanning: · 2 unmodified lines | ||
| 229 | 229 | set_bit(KEY_FLAG_DEAD, &key->flags); |
| 230 | 230 | key->perm = 0; |
| 231 | 231 | goto skip_dead_key; |
| 232 | + } else if (key->type == &key_type_keyring && | |
| 233 | + key->restrict_link) { | |
| 234 | + goto found_restricted_keyring; | |
| 232 | 235 | } |
| 233 | 236 | } |
| 234 | 237 | |
| @@ -334,6 +337,14 @@ found_unreferenced_key: · 99 unmodified lines | ||
| 334 | 337 | gc_state |= KEY_GC_REAP_AGAIN; |
| 335 | 338 | goto maybe_resched; |
| 336 | 339 | |
| 340 | + /* We found a restricted keyring and need to update the restriction if | |
| 341 | + * it is associated with the dead key type. | |
| 342 | + */ | |
| 343 | +found_restricted_keyring: | |
| 344 | + spin_unlock(&key_serial_lock); | |
| 345 | + keyring_restriction_gc(key, key_gc_dead_keytype); | |
| 346 | + goto maybe_resched; | |
| 347 | + | |
| 337 | 348 | /* We found a keyring and we need to check the payload for links to |
| 338 | 349 | * dead or expired keys. We don't flag another reap immediately as we |
| 339 | 350 | * have to wait for the old payload to be destroyed by RCU before we |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/key-type.h> |
| 18 | 18 | #include <linux/task_work.h> |
| 19 | 19 | #include <linux/keyctl.h> |
| 20 | +#include <linux/refcount.h> | |
| 21 | +#include <linux/compat.h> | |
| 20 | 22 | |
| 21 | 23 | struct iovec; |
| 22 | 24 | |
| @@ -53,7 +55,7 @@ struct key_user { · 30 unmodified lines | ||
| 53 | 55 | struct rb_node node; |
| 54 | 56 | struct mutex cons_lock; /* construction initiation lock */ |
| 55 | 57 | spinlock_t lock; |
| 56 | − atomic_t usage; /* for accessing qnkeys & qnbytes */ | |
| 58 | + refcount_t usage; /* for accessing qnkeys & qnbytes */ | |
| 57 | 59 | atomic_t nkeys; /* number of keys */ |
| 58 | 60 | atomic_t nikeys; /* number of instantiated keys */ |
| 59 | 61 | kuid_t uid; |
| @@ -167,6 +169,8 @@ extern void key_change_session_keyring(struct callback_head *twork); · 107 unmodified lines | ||
| 167 | 169 | extern struct work_struct key_gc_work; |
| 168 | 170 | extern unsigned key_gc_delay; |
| 169 | 171 | extern void keyring_gc(struct key *keyring, time_t limit); |
| 172 | +extern void keyring_restriction_gc(struct key *keyring, | |
| 173 | + struct key_type *dead_type); | |
| 170 | 174 | extern void key_schedule_gc(time_t gc_at); |
| 171 | 175 | extern void key_schedule_gc_links(void); |
| 172 | 176 | extern void key_gc_keytype(struct key_type *ktype); |
| @@ -249,6 +253,9 @@ struct iov_iter; · 76 unmodified lines | ||
| 249 | 253 | extern long keyctl_instantiate_key_common(key_serial_t, |
| 250 | 254 | struct iov_iter *, |
| 251 | 255 | key_serial_t); |
| 256 | +extern long keyctl_restrict_keyring(key_serial_t id, | |
| 257 | + const char __user *_type, | |
| 258 | + const char __user *_restriction); | |
| 252 | 259 | #ifdef CONFIG_PERSISTENT_KEYRINGS |
| 253 | 260 | extern long keyctl_get_persistent(uid_t, key_serial_t); |
| 254 | 261 | extern unsigned persistent_keyring_expiry; |
| @@ -261,15 +268,34 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring) · 6 unmodified lines | ||
| 261 | 268 | |
| 262 | 269 | #ifdef CONFIG_KEY_DH_OPERATIONS |
| 263 | 270 | extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *, |
| 264 | − size_t, void __user *); | |
| 271 | + size_t, struct keyctl_kdf_params __user *); | |
| 272 | +extern long __keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *, | |
| 273 | + size_t, struct keyctl_kdf_params *); | |
| 274 | +#ifdef CONFIG_KEYS_COMPAT | |
| 275 | +extern long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params, | |
| 276 | + char __user *buffer, size_t buflen, | |
| 277 | + struct compat_keyctl_kdf_params __user *kdf); | |
| 278 | +#endif | |
| 279 | +#define KEYCTL_KDF_MAX_OUTPUT_LEN 1024 /* max length of KDF output */ | |
| 280 | +#define KEYCTL_KDF_MAX_OI_LEN 64 /* max length of otherinfo */ | |
| 265 | 281 | #else |
| 266 | 282 | static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params, |
| 267 | 283 | char __user *buffer, size_t buflen, |
| 268 | − void __user *reserved) | |
| 284 | + struct keyctl_kdf_params __user *kdf) | |
| 285 | +{ | |
| 286 | + return -EOPNOTSUPP; | |
| 287 | +} | |
| 288 | + | |
| 289 | +#ifdef CONFIG_KEYS_COMPAT | |
| 290 | +static inline long compat_keyctl_dh_compute( | |
| 291 | + struct keyctl_dh_params __user *params, | |
| 292 | + char __user *buffer, size_t buflen, | |
| 293 | + struct keyctl_kdf_params __user *kdf) | |
| 269 | 294 | { |
| 270 | 295 | return -EOPNOTSUPP; |
| 271 | 296 | } |
| 272 | 297 | #endif |
| 298 | +#endif | |
| 273 | 299 | |
| 274 | 300 | /* |
| 275 | 301 | * Debugging key validation |
| @@ -93,7 +93,7 @@ try_again: · 92 unmodified lines | ||
| 93 | 93 | |
| 94 | 94 | /* if we get here, then the user record still hadn't appeared on the |
| 95 | 95 | * second pass - so we use the candidate record */ |
| 96 | − atomic_set(&candidate->usage, 1); | |
| 96 | + refcount_set(&candidate->usage, 1); | |
| 97 | 97 | atomic_set(&candidate->nkeys, 0); |
| 98 | 98 | atomic_set(&candidate->nikeys, 0); |
| 99 | 99 | candidate->uid = uid; |
| @@ -110,7 +110,7 @@ try_again: · 10 unmodified lines | ||
| 110 | 110 | |
| 111 | 111 | /* okay - we found a user record for this UID */ |
| 112 | 112 | found: |
| 113 | − atomic_inc(&user->usage); | |
| 113 | + refcount_inc(&user->usage); | |
| 114 | 114 | spin_unlock(&key_user_lock); |
| 115 | 115 | kfree(candidate); |
| 116 | 116 | out: |
| @@ -122,7 +122,7 @@ out: · 5 unmodified lines | ||
| 122 | 122 | */ |
| 123 | 123 | void key_user_put(struct key_user *user) |
| 124 | 124 | { |
| 125 | − if (atomic_dec_and_lock(&user->usage, &key_user_lock)) { | |
| 125 | + if (refcount_dec_and_lock(&user->usage, &key_user_lock)) { | |
| 126 | 126 | rb_erase(&user->node, &key_user_tree); |
| 127 | 127 | spin_unlock(&key_user_lock); |
| 128 | 128 | |
| @@ -201,12 +201,15 @@ serial_exists: · 72 unmodified lines | ||
| 201 | 201 | * @cred: The credentials specifying UID namespace. |
| 202 | 202 | * @perm: The permissions mask of the new key. |
| 203 | 203 | * @flags: Flags specifying quota properties. |
| 204 | − * @restrict_link: Optional link restriction method for new keyrings. | |
| 204 | + * @restrict_link: Optional link restriction for new keyrings. | |
| 205 | 205 | * |
| 206 | 206 | * Allocate a key of the specified type with the attributes given. The key is |
| 207 | 207 | * returned in an uninstantiated state and the caller needs to instantiate the |
| 208 | 208 | * key before returning. |
| 209 | 209 | * |
| 210 | + * The restrict_link structure (if not NULL) will be freed when the | |
| 211 | + * keyring is destroyed, so it must be dynamically allocated. | |
| 212 | + * | |
| 210 | 213 | * The user's key count quota is updated to reflect the creation of the key and |
| 211 | 214 | * the user's key data quota has the default for the key type reserved. The |
| 212 | 215 | * instantiation function should amend this as necessary. If insufficient |
| @@ -225,9 +228,7 @@ serial_exists: · 12 unmodified lines | ||
| 225 | 228 | struct key *key_alloc(struct key_type *type, const char *desc, |
| 226 | 229 | kuid_t uid, kgid_t gid, const struct cred *cred, |
| 227 | 230 | key_perm_t perm, unsigned long flags, |
| 228 | − int (*restrict_link)(struct key *, | |
| 229 | − const struct key_type *, | |
| 230 | − const union key_payload *)) | |
| 231 | + struct key_restriction *restrict_link) | |
| 231 | 232 | { |
| 232 | 233 | struct key_user *user = NULL; |
| 233 | 234 | struct key *key; |
| @@ -285,7 +286,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, · 51 unmodified lines | ||
| 285 | 286 | if (!key->index_key.description) |
| 286 | 287 | goto no_memory_3; |
| 287 | 288 | |
| 288 | − atomic_set(&key->usage, 1); | |
| 289 | + refcount_set(&key->usage, 1); | |
| 289 | 290 | init_rwsem(&key->sem); |
| 290 | 291 | lockdep_set_class(&key->sem, &type->lock_class); |
| 291 | 292 | key->index_key.type = type; |
| @@ -499,19 +500,23 @@ int key_instantiate_and_link(struct key *key, · 207 unmodified lines | ||
| 499 | 500 | } |
| 500 | 501 | |
| 501 | 502 | if (keyring) { |
| 502 | − if (keyring->restrict_link) { | |
| 503 | − ret = keyring->restrict_link(keyring, key->type, | |
| 504 | − &prep.payload); | |
| 505 | − if (ret < 0) | |
| 506 | − goto error; | |
| 507 | − } | |
| 508 | 503 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
| 509 | 504 | if (ret < 0) |
| 510 | 505 | goto error; |
| 506 | + | |
| 507 | + if (keyring->restrict_link && keyring->restrict_link->check) { | |
| 508 | + struct key_restriction *keyres = keyring->restrict_link; | |
| 509 | + | |
| 510 | + ret = keyres->check(keyring, key->type, &prep.payload, | |
| 511 | + keyres->key); | |
| 512 | + if (ret < 0) | |
| 513 | + goto error_link_end; | |
| 514 | + } | |
| 511 | 515 | } |
| 512 | 516 | |
| 513 | 517 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); |
| 514 | 518 | |
| 519 | +error_link_end: | |
| 515 | 520 | if (keyring) |
| 516 | 521 | __key_link_end(keyring, &key->index_key, edit); |
| 517 | 522 | |
| @@ -621,7 +626,7 @@ void key_put(struct key *key) · 103 unmodified lines | ||
| 621 | 626 | if (key) { |
| 622 | 627 | key_check(key); |
| 623 | 628 | |
| 624 | − if (atomic_dec_and_test(&key->usage)) | |
| 629 | + if (refcount_dec_and_test(&key->usage)) | |
| 625 | 630 | schedule_work(&key_gc_work); |
| 626 | 631 | } |
| 627 | 632 | } |
| @@ -656,7 +661,7 @@ not_found: · 28 unmodified lines | ||
| 656 | 661 | |
| 657 | 662 | found: |
| 658 | 663 | /* pretend it doesn't exist if it is awaiting deletion */ |
| 659 | − if (atomic_read(&key->usage) == 0) | |
| 664 | + if (refcount_read(&key->usage) == 0) | |
| 660 | 665 | goto not_found; |
| 661 | 666 | |
| 662 | 667 | /* this races with key_put(), but that doesn't matter since key_put() |
| @@ -806,9 +811,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, · 143 unmodified lines | ||
| 806 | 811 | struct key *keyring, *key = NULL; |
| 807 | 812 | key_ref_t key_ref; |
| 808 | 813 | int ret; |
| 809 | − int (*restrict_link)(struct key *, | |
| 810 | − const struct key_type *, | |
| 811 | − const union key_payload *) = NULL; | |
| 814 | + struct key_restriction *restrict_link = NULL; | |
| 812 | 815 | |
| 813 | 816 | /* look up the key type to see if it's one of the registered kernel |
| 814 | 817 | * types */ |
| @@ -854,20 +857,21 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, · 39 unmodified lines | ||
| 854 | 857 | } |
| 855 | 858 | index_key.desc_len = strlen(index_key.description); |
| 856 | 859 | |
| 857 | − if (restrict_link) { | |
| 858 | − ret = restrict_link(keyring, index_key.type, &prep.payload); | |
| 859 | − if (ret < 0) { | |
| 860 | − key_ref = ERR_PTR(ret); | |
| 861 | − goto error_free_prep; | |
| 862 | − } | |
| 863 | − } | |
| 864 | − | |
| 865 | 860 | ret = __key_link_begin(keyring, &index_key, &edit); |
| 866 | 861 | if (ret < 0) { |
| 867 | 862 | key_ref = ERR_PTR(ret); |
| 868 | 863 | goto error_free_prep; |
| 869 | 864 | } |
| 870 | 865 | |
| 866 | + if (restrict_link && restrict_link->check) { | |
| 867 | + ret = restrict_link->check(keyring, index_key.type, | |
| 868 | + &prep.payload, restrict_link->key); | |
| 869 | + if (ret < 0) { | |
| 870 | + key_ref = ERR_PTR(ret); | |
| 871 | + goto error_link_end; | |
| 872 | + } | |
| 873 | + } | |
| 874 | + | |
| 871 | 875 | /* if we're going to allocate a new key, we're going to have |
| 872 | 876 | * to modify the keyring */ |
| 873 | 877 | ret = key_permission(keyring_ref, KEY_NEED_WRITE); |
| @@ -1584,6 +1584,59 @@ error_keyring: · 1583 unmodified lines | ||
| 1584 | 1584 | return ret; |
| 1585 | 1585 | } |
| 1586 | 1586 | |
| 1587 | +/* | |
| 1588 | + * Apply a restriction to a given keyring. | |
| 1589 | + * | |
| 1590 | + * The caller must have Setattr permission to change keyring restrictions. | |
| 1591 | + * | |
| 1592 | + * The requested type name may be a NULL pointer to reject all attempts | |
| 1593 | + * to link to the keyring. If _type is non-NULL, _restriction can be | |
| 1594 | + * NULL or a pointer to a string describing the restriction. If _type is | |
| 1595 | + * NULL, _restriction must also be NULL. | |
| 1596 | + * | |
| 1597 | + * Returns 0 if successful. | |
| 1598 | + */ | |
| 1599 | +long keyctl_restrict_keyring(key_serial_t id, const char __user *_type, | |
| 1600 | + const char __user *_restriction) | |
| 1601 | +{ | |
| 1602 | + key_ref_t key_ref; | |
| 1603 | + bool link_reject = !_type; | |
| 1604 | + char type[32]; | |
| 1605 | + char *restriction = NULL; | |
| 1606 | + long ret; | |
| 1607 | + | |
| 1608 | + key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR); | |
| 1609 | + if (IS_ERR(key_ref)) | |
| 1610 | + return PTR_ERR(key_ref); | |
| 1611 | + | |
| 1612 | + if (_type) { | |
| 1613 | + ret = key_get_type_from_user(type, _type, sizeof(type)); | |
| 1614 | + if (ret < 0) | |
| 1615 | + goto error; | |
| 1616 | + } | |
| 1617 | + | |
| 1618 | + if (_restriction) { | |
| 1619 | + if (!_type) { | |
| 1620 | + ret = -EINVAL; | |
| 1621 | + goto error; | |
| 1622 | + } | |
| 1623 | + | |
| 1624 | + restriction = strndup_user(_restriction, PAGE_SIZE); | |
| 1625 | + if (IS_ERR(restriction)) { | |
| 1626 | + ret = PTR_ERR(restriction); | |
| 1627 | + goto error; | |
| 1628 | + } | |
| 1629 | + } | |
| 1630 | + | |
| 1631 | + ret = keyring_restrict(key_ref, link_reject ? NULL : type, restriction); | |
| 1632 | + kfree(restriction); | |
| 1633 | + | |
| 1634 | +error: | |
| 1635 | + key_ref_put(key_ref); | |
| 1636 | + | |
| 1637 | + return ret; | |
| 1638 | +} | |
| 1639 | + | |
| 1587 | 1640 | /* |
| 1588 | 1641 | * The key control system call |
| 1589 | 1642 | */ |
| @@ -1693,7 +1746,12 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, · 103 unmodified lines | ||
| 1693 | 1746 | case KEYCTL_DH_COMPUTE: |
| 1694 | 1747 | return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2, |
| 1695 | 1748 | (char __user *) arg3, (size_t) arg4, |
| 1696 | − (void __user *) arg5); | |
| 1749 | + (struct keyctl_kdf_params __user *) arg5); | |
| 1750 | + | |
| 1751 | + case KEYCTL_RESTRICT_KEYRING: | |
| 1752 | + return keyctl_restrict_keyring((key_serial_t) arg2, | |
| 1753 | + (const char __user *) arg3, | |
| 1754 | + (const char __user *) arg4); | |
| 1697 | 1755 | |
| 1698 | 1756 | default: |
| 1699 | 1757 | return -EOPNOTSUPP; |
| @@ -394,6 +394,13 @@ static void keyring_destroy(struct key *keyring) · 393 unmodified lines | ||
| 394 | 394 | write_unlock(&keyring_name_lock); |
| 395 | 395 | } |
| 396 | 396 | |
| 397 | + if (keyring->restrict_link) { | |
| 398 | + struct key_restriction *keyres = keyring->restrict_link; | |
| 399 | + | |
| 400 | + key_put(keyres->key); | |
| 401 | + kfree(keyres); | |
| 402 | + } | |
| 403 | + | |
| 397 | 404 | assoc_array_destroy(&keyring->keys, &keyring_assoc_array_ops); |
| 398 | 405 | } |
| 399 | 406 | |
| @@ -492,9 +499,7 @@ static long keyring_read(const struct key *keyring, · 92 unmodified lines | ||
| 492 | 499 | struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, |
| 493 | 500 | const struct cred *cred, key_perm_t perm, |
| 494 | 501 | unsigned long flags, |
| 495 | − int (*restrict_link)(struct key *, | |
| 496 | − const struct key_type *, | |
| 497 | − const union key_payload *), | |
| 502 | + struct key_restriction *restrict_link, | |
| 498 | 503 | struct key *dest) |
| 499 | 504 | { |
| 500 | 505 | struct key *keyring; |
| @@ -519,17 +524,19 @@ EXPORT_SYMBOL(keyring_alloc); · 18 unmodified lines | ||
| 519 | 524 | * @keyring: The keyring being added to. |
| 520 | 525 | * @type: The type of key being added. |
| 521 | 526 | * @payload: The payload of the key intended to be added. |
| 527 | + * @data: Additional data for evaluating restriction. | |
| 522 | 528 | * |
| 523 | 529 | * Reject the addition of any links to a keyring. It can be overridden by |
| 524 | 530 | * passing KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when |
| 525 | 531 | * adding a key to a keyring. |
| 526 | 532 | * |
| 527 | − * This is meant to be passed as the restrict_link parameter to | |
| 528 | − * keyring_alloc(). | |
| 533 | + * This is meant to be stored in a key_restriction structure which is passed | |
| 534 | + * in the restrict_link parameter to keyring_alloc(). | |
| 529 | 535 | */ |
| 530 | 536 | int restrict_link_reject(struct key *keyring, |
| 531 | 537 | const struct key_type *type, |
| 532 | − const union key_payload *payload) | |
| 538 | + const union key_payload *payload, | |
| 539 | + struct key *restriction_key) | |
| 533 | 540 | { |
| 534 | 541 | return -EPERM; |
| 535 | 542 | } |
| @@ -940,6 +947,111 @@ key_ref_t keyring_search(key_ref_t keyring, · 404 unmodified lines | ||
| 940 | 947 | } |
| 941 | 948 | EXPORT_SYMBOL(keyring_search); |
| 942 | 949 | |
| 950 | +static struct key_restriction *keyring_restriction_alloc( | |
| 951 | + key_restrict_link_func_t check) | |
| 952 | +{ | |
| 953 | + struct key_restriction *keyres = | |
| 954 | + kzalloc(sizeof(struct key_restriction), GFP_KERNEL); | |
| 955 | + | |
| 956 | + if (!keyres) | |
| 957 | + return ERR_PTR(-ENOMEM); | |
| 958 | + | |
| 959 | + keyres->check = check; | |
| 960 | + | |
| 961 | + return keyres; | |
| 962 | +} | |
| 963 | + | |
| 964 | +/* | |
| 965 | + * Semaphore to serialise restriction setup to prevent reference count | |
| 966 | + * cycles through restriction key pointers. | |
| 967 | + */ | |
| 968 | +static DECLARE_RWSEM(keyring_serialise_restrict_sem); | |
| 969 | + | |
| 970 | +/* | |
| 971 | + * Check for restriction cycles that would prevent keyring garbage collection. | |
| 972 | + * keyring_serialise_restrict_sem must be held. | |
| 973 | + */ | |
| 974 | +static bool keyring_detect_restriction_cycle(const struct key *dest_keyring, | |
| 975 | + struct key_restriction *keyres) | |
| 976 | +{ | |
| 977 | + while (keyres && keyres->key && | |
| 978 | + keyres->key->type == &key_type_keyring) { | |
| 979 | + if (keyres->key == dest_keyring) | |
| 980 | + return true; | |
| 981 | + | |
| 982 | + keyres = keyres->key->restrict_link; | |
| 983 | + } | |
| 984 | + | |
| 985 | + return false; | |
| 986 | +} | |
| 987 | + | |
| 988 | +/** | |
| 989 | + * keyring_restrict - Look up and apply a restriction to a keyring | |
| 990 | + * | |
| 991 | + * @keyring: The keyring to be restricted | |
| 992 | + * @restriction: The restriction options to apply to the keyring | |
| 993 | + */ | |
| 994 | +int keyring_restrict(key_ref_t keyring_ref, const char *type, | |
| 995 | + const char *restriction) | |
| 996 | +{ | |
| 997 | + struct key *keyring; | |
| 998 | + struct key_type *restrict_type = NULL; | |
| 999 | + struct key_restriction *restrict_link; | |
| 1000 | + int ret = 0; | |
| 1001 | + | |
| 1002 | + keyring = key_ref_to_ptr(keyring_ref); | |
| 1003 | + key_check(keyring); | |
| 1004 | + | |
| 1005 | + if (keyring->type != &key_type_keyring) | |
| 1006 | + return -ENOTDIR; | |
| 1007 | + | |
| 1008 | + if (!type) { | |
| 1009 | + restrict_link = keyring_restriction_alloc(restrict_link_reject); | |
| 1010 | + } else { | |
| 1011 | + restrict_type = key_type_lookup(type); | |
| 1012 | + | |
| 1013 | + if (IS_ERR(restrict_type)) | |
| 1014 | + return PTR_ERR(restrict_type); | |
| 1015 | + | |
| 1016 | + if (!restrict_type->lookup_restriction) { | |
| 1017 | + ret = -ENOENT; | |
| 1018 | + goto error; | |
| 1019 | + } | |
| 1020 | + | |
| 1021 | + restrict_link = restrict_type->lookup_restriction(restriction); | |
| 1022 | + } | |
| 1023 | + | |
| 1024 | + if (IS_ERR(restrict_link)) { | |
| 1025 | + ret = PTR_ERR(restrict_link); | |
| 1026 | + goto error; | |
| 1027 | + } | |
| 1028 | + | |
| 1029 | + down_write(&keyring->sem); | |
| 1030 | + down_write(&keyring_serialise_restrict_sem); | |
| 1031 | + | |
| 1032 | + if (keyring->restrict_link) | |
| 1033 | + ret = -EEXIST; | |
| 1034 | + else if (keyring_detect_restriction_cycle(keyring, restrict_link)) | |
| 1035 | + ret = -EDEADLK; | |
| 1036 | + else | |
| 1037 | + keyring->restrict_link = restrict_link; | |
| 1038 | + | |
| 1039 | + up_write(&keyring_serialise_restrict_sem); | |
| 1040 | + up_write(&keyring->sem); | |
| 1041 | + | |
| 1042 | + if (ret < 0) { | |
| 1043 | + key_put(restrict_link->key); | |
| 1044 | + kfree(restrict_link); | |
| 1045 | + } | |
| 1046 | + | |
| 1047 | +error: | |
| 1048 | + if (restrict_type) | |
| 1049 | + key_type_put(restrict_type); | |
| 1050 | + | |
| 1051 | + return ret; | |
| 1052 | +} | |
| 1053 | +EXPORT_SYMBOL(keyring_restrict); | |
| 1054 | + | |
| 943 | 1055 | /* |
| 944 | 1056 | * Search the given keyring for a key that might be updated. |
| 945 | 1057 | * |
| @@ -1033,7 +1145,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) · 87 unmodified lines | ||
| 1033 | 1145 | /* we've got a match but we might end up racing with |
| 1034 | 1146 | * key_cleanup() if the keyring is currently 'dead' |
| 1035 | 1147 | * (ie. it has a zero usage count) */ |
| 1036 | − if (!atomic_inc_not_zero(&keyring->usage)) | |
| 1148 | + if (!refcount_inc_not_zero(&keyring->usage)) | |
| 1037 | 1149 | continue; |
| 1038 | 1150 | keyring->last_used_at = current_kernel_time().tv_sec; |
| 1039 | 1151 | goto out; |
| @@ -1220,9 +1332,10 @@ void __key_link_end(struct key *keyring, · 180 unmodified lines | ||
| 1220 | 1332 | */ |
| 1221 | 1333 | static int __key_link_check_restriction(struct key *keyring, struct key *key) |
| 1222 | 1334 | { |
| 1223 | − if (!keyring->restrict_link) | |
| 1335 | + if (!keyring->restrict_link || !keyring->restrict_link->check) | |
| 1224 | 1336 | return 0; |
| 1225 | − return keyring->restrict_link(keyring, key->type, &key->payload); | |
| 1337 | + return keyring->restrict_link->check(keyring, key->type, &key->payload, | |
| 1338 | + keyring->restrict_link->key); | |
| 1226 | 1339 | } |
| 1227 | 1340 | |
| 1228 | 1341 | /** |
| @@ -1250,14 +1363,14 @@ int key_link(struct key *keyring, struct key *key) · 21 unmodified lines | ||
| 1250 | 1363 | struct assoc_array_edit *edit; |
| 1251 | 1364 | int ret; |
| 1252 | 1365 | |
| 1253 | − kenter("{%d,%d}", keyring->serial, atomic_read(&keyring->usage)); | |
| 1366 | + kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage)); | |
| 1254 | 1367 | |
| 1255 | 1368 | key_check(keyring); |
| 1256 | 1369 | key_check(key); |
| 1257 | 1370 | |
| 1258 | 1371 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
| 1259 | 1372 | if (ret == 0) { |
| 1260 | − kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage)); | |
| 1373 | + kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage)); | |
| 1261 | 1374 | ret = __key_link_check_restriction(keyring, key); |
| 1262 | 1375 | if (ret == 0) |
| 1263 | 1376 | ret = __key_link_check_live_key(keyring, key); |
| @@ -1266,7 +1379,7 @@ int key_link(struct key *keyring, struct key *key) · 2 unmodified lines | ||
| 1266 | 1379 | __key_link_end(keyring, &key->index_key, edit); |
| 1267 | 1380 | } |
| 1268 | 1381 | |
| 1269 | − kleave(" = %d {%d,%d}", ret, keyring->serial, atomic_read(&keyring->usage)); | |
| 1382 | + kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage)); | |
| 1270 | 1383 | return ret; |
| 1271 | 1384 | } |
| 1272 | 1385 | EXPORT_SYMBOL(key_link); |
| @@ -1426,3 +1539,53 @@ do_gc: · 153 unmodified lines | ||
| 1426 | 1539 | up_write(&keyring->sem); |
| 1427 | 1540 | kleave(" [gc]"); |
| 1428 | 1541 | } |
| 1542 | + | |
| 1543 | +/* | |
| 1544 | + * Garbage collect restriction pointers from a keyring. | |
| 1545 | + * | |
| 1546 | + * Keyring restrictions are associated with a key type, and must be cleaned | |
| 1547 | + * up if the key type is unregistered. The restriction is altered to always | |
| 1548 | + * reject additional keys so a keyring cannot be opened up by unregistering | |
| 1549 | + * a key type. | |
| 1550 | + * | |
| 1551 | + * Not called with any keyring locks held. The keyring's key struct will not | |
| 1552 | + * be deallocated under us as only our caller may deallocate it. | |
| 1553 | + * | |
| 1554 | + * The caller is required to hold key_types_sem and dead_type->sem. This is | |
| 1555 | + * fulfilled by key_gc_keytype() holding the locks on behalf of | |
| 1556 | + * key_garbage_collector(), which it invokes on a workqueue. | |
| 1557 | + */ | |
| 1558 | +void keyring_restriction_gc(struct key *keyring, struct key_type *dead_type) | |
| 1559 | +{ | |
| 1560 | + struct key_restriction *keyres; | |
| 1561 | + | |
| 1562 | + kenter("%x{%s}", keyring->serial, keyring->description ?: ""); | |
| 1563 | + | |
| 1564 | + /* | |
| 1565 | + * keyring->restrict_link is only assigned at key allocation time | |
| 1566 | + * or with the key type locked, so the only values that could be | |
| 1567 | + * concurrently assigned to keyring->restrict_link are for key | |
| 1568 | + * types other than dead_type. Given this, it's ok to check | |
| 1569 | + * the key type before acquiring keyring->sem. | |
| 1570 | + */ | |
| 1571 | + if (!dead_type || !keyring->restrict_link || | |
| 1572 | + keyring->restrict_link->keytype != dead_type) { | |
| 1573 | + kleave(" [no restriction gc]"); | |
| 1574 | + return; | |
| 1575 | + } | |
| 1576 | + | |
| 1577 | + /* Lock the keyring to ensure that a link is not in progress */ | |
| 1578 | + down_write(&keyring->sem); | |
| 1579 | + | |
| 1580 | + keyres = keyring->restrict_link; | |
| 1581 | + | |
| 1582 | + keyres->check = restrict_link_reject; | |
| 1583 | + | |
| 1584 | + key_put(keyres->key); | |
| 1585 | + keyres->key = NULL; | |
| 1586 | + keyres->keytype = NULL; | |
| 1587 | + | |
| 1588 | + up_write(&keyring->sem); | |
| 1589 | + | |
| 1590 | + kleave(" [restriction gc]"); | |
| 1591 | +} | |
| @@ -252,7 +252,7 @@ static int proc_keys_show(struct seq_file *m, void *v) · 251 unmodified lines | ||
| 252 | 252 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), |
| 253 | 253 | showflag(key, 'N', KEY_FLAG_NEGATIVE), |
| 254 | 254 | showflag(key, 'i', KEY_FLAG_INVALIDATED), |
| 255 | − atomic_read(&key->usage), | |
| 255 | + refcount_read(&key->usage), | |
| 256 | 256 | xbuf, |
| 257 | 257 | key->perm, |
| 258 | 258 | from_kuid_munged(seq_user_ns(m), key->uid), |
| @@ -340,7 +340,7 @@ static int proc_key_users_show(struct seq_file *m, void *v) · 81 unmodified lines | ||
| 340 | 340 | |
| 341 | 341 | seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", |
| 342 | 342 | from_kuid_munged(seq_user_ns(m), user->uid), |
| 343 | − atomic_read(&user->usage), | |
| 343 | + refcount_read(&user->usage), | |
| 344 | 344 | atomic_read(&user->nkeys), |
| 345 | 345 | atomic_read(&user->nikeys), |
| 346 | 346 | user->qnkeys, |
| @@ -30,7 +30,7 @@ static DEFINE_MUTEX(key_user_keyring_mutex); · 29 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | /* The root user's tracking struct */ |
| 32 | 32 | struct key_user root_key_user = { |
| 33 | − .usage = ATOMIC_INIT(3), | |
| 33 | + .usage = REFCOUNT_INIT(3), | |
| 34 | 34 | .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), |
| 35 | 35 | .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), |
| 36 | 36 | .nkeys = ATOMIC_INIT(2), |
| @@ -213,7 +213,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, · 212 unmodified lines | ||
| 213 | 213 | if (ret < 0) |
| 214 | 214 | goto error_inst; |
| 215 | 215 | |
| 216 | − kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage)); | |
| 216 | + kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage)); | |
| 217 | 217 | return authkey; |
| 218 | 218 | |
| 219 | 219 | auth_key_revoked: |
| @@ -174,7 +174,7 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) · 173 unmodified lines | ||
| 174 | 174 | return 0; |
| 175 | 175 | } |
| 176 | 176 | |
| 177 | −static struct security_hook_list loadpin_hooks[] = { | |
| 177 | +static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = { | |
| 178 | 178 | LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security), |
| 179 | 179 | LSM_HOOK_INIT(kernel_read_file, loadpin_read_file), |
| 180 | 180 | }; |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | /* Maximum number of letters for an LSM name string */ |
| 33 | 33 | #define SECURITY_NAME_MAX 10 |
| 34 | 34 | |
| 35 | +struct security_hook_heads security_hook_heads __lsm_ro_after_init; | |
| 35 | 36 | char *lsm_names; |
| 36 | 37 | /* Boot-time LSM user choice */ |
| 37 | 38 | static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = |
| @@ -54,6 +55,12 @@ static void __init do_security_initcalls(void) · 16 unmodified lines | ||
| 54 | 55 | */ |
| 55 | 56 | int __init security_init(void) |
| 56 | 57 | { |
| 58 | + int i; | |
| 59 | + struct list_head *list = (struct list_head *) &security_hook_heads; | |
| 60 | + | |
| 61 | + for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct list_head); | |
| 62 | + i++) | |
| 63 | + INIT_LIST_HEAD(&list[i]); | |
| 57 | 64 | pr_info("Security Framework initialized\n"); |
| 58 | 65 | |
| 59 | 66 | /* |
| @@ -934,6 +941,11 @@ int security_task_create(unsigned long clone_flags) · 874 unmodified lines | ||
| 934 | 941 | return call_int_hook(task_create, 0, clone_flags); |
| 935 | 942 | } |
| 936 | 943 | |
| 944 | +int security_task_alloc(struct task_struct *task, unsigned long clone_flags) | |
| 945 | +{ | |
| 946 | + return call_int_hook(task_alloc, 0, task, clone_flags); | |
| 947 | +} | |
| 948 | + | |
| 937 | 949 | void security_task_free(struct task_struct *task) |
| 938 | 950 | { |
| 939 | 951 | call_void_hook(task_free, task); |
| @@ -1040,6 +1052,12 @@ int security_task_getioprio(struct task_struct *p) · 100 unmodified lines | ||
| 1040 | 1052 | return call_int_hook(task_getioprio, 0, p); |
| 1041 | 1053 | } |
| 1042 | 1054 | |
| 1055 | +int security_task_prlimit(const struct cred *cred, const struct cred *tcred, | |
| 1056 | + unsigned int flags) | |
| 1057 | +{ | |
| 1058 | + return call_int_hook(task_prlimit, 0, cred, tcred, flags); | |
| 1059 | +} | |
| 1060 | + | |
| 1043 | 1061 | int security_task_setrlimit(struct task_struct *p, unsigned int resource, |
| 1044 | 1062 | struct rlimit *new_rlim) |
| 1045 | 1063 | { |
| @@ -1625,355 +1643,3 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, · 579 unmodified lines | ||
| 1625 | 1643 | actx); |
| 1626 | 1644 | } |
| 1627 | 1645 | #endif /* CONFIG_AUDIT */ |
| 1628 | − | |
| 1629 | −struct security_hook_heads security_hook_heads = { | |
| 1630 | − .binder_set_context_mgr = | |
| 1631 | − LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr), | |
| 1632 | − .binder_transaction = | |
| 1633 | − LIST_HEAD_INIT(security_hook_heads.binder_transaction), | |
| 1634 | − .binder_transfer_binder = | |
| 1635 | − LIST_HEAD_INIT(security_hook_heads.binder_transfer_binder), | |
| 1636 | − .binder_transfer_file = | |
| 1637 | − LIST_HEAD_INIT(security_hook_heads.binder_transfer_file), | |
| 1638 | − | |
| 1639 | − .ptrace_access_check = | |
| 1640 | − LIST_HEAD_INIT(security_hook_heads.ptrace_access_check), | |
| 1641 | − .ptrace_traceme = | |
| 1642 | − LIST_HEAD_INIT(security_hook_heads.ptrace_traceme), | |
| 1643 | − .capget = LIST_HEAD_INIT(security_hook_heads.capget), | |
| 1644 | − .capset = LIST_HEAD_INIT(security_hook_heads.capset), | |
| 1645 | − .capable = LIST_HEAD_INIT(security_hook_heads.capable), | |
| 1646 | − .quotactl = LIST_HEAD_INIT(security_hook_heads.quotactl), | |
| 1647 | − .quota_on = LIST_HEAD_INIT(security_hook_heads.quota_on), | |
| 1648 | − .syslog = LIST_HEAD_INIT(security_hook_heads.syslog), | |
| 1649 | − .settime = LIST_HEAD_INIT(security_hook_heads.settime), | |
| 1650 | − .vm_enough_memory = | |
| 1651 | − LIST_HEAD_INIT(security_hook_heads.vm_enough_memory), | |
| 1652 | − .bprm_set_creds = | |
| 1653 | − LIST_HEAD_INIT(security_hook_heads.bprm_set_creds), | |
| 1654 | − .bprm_check_security = | |
| 1655 | − LIST_HEAD_INIT(security_hook_heads.bprm_check_security), | |
| 1656 | − .bprm_secureexec = | |
| 1657 | − LIST_HEAD_INIT(security_hook_heads.bprm_secureexec), | |
| 1658 | − .bprm_committing_creds = | |
| 1659 | − LIST_HEAD_INIT(security_hook_heads.bprm_committing_creds), | |
| 1660 | − .bprm_committed_creds = | |
| 1661 | − LIST_HEAD_INIT(security_hook_heads.bprm_committed_creds), | |
| 1662 | − .sb_alloc_security = | |
| 1663 | − LIST_HEAD_INIT(security_hook_heads.sb_alloc_security), | |
| 1664 | − .sb_free_security = | |
| 1665 | − LIST_HEAD_INIT(security_hook_heads.sb_free_security), | |
| 1666 | − .sb_copy_data = LIST_HEAD_INIT(security_hook_heads.sb_copy_data), | |
| 1667 | − .sb_remount = LIST_HEAD_INIT(security_hook_heads.sb_remount), | |
| 1668 | − .sb_kern_mount = | |
| 1669 | − LIST_HEAD_INIT(security_hook_heads.sb_kern_mount), | |
| 1670 | − .sb_show_options = | |
| 1671 | − LIST_HEAD_INIT(security_hook_heads.sb_show_options), | |
| 1672 | − .sb_statfs = LIST_HEAD_INIT(security_hook_heads.sb_statfs), | |
| 1673 | − .sb_mount = LIST_HEAD_INIT(security_hook_heads.sb_mount), | |
| 1674 | − .sb_umount = LIST_HEAD_INIT(security_hook_heads.sb_umount), | |
| 1675 | − .sb_pivotroot = LIST_HEAD_INIT(security_hook_heads.sb_pivotroot), | |
| 1676 | − .sb_set_mnt_opts = | |
| 1677 | − LIST_HEAD_INIT(security_hook_heads.sb_set_mnt_opts), | |
| 1678 | − .sb_clone_mnt_opts = | |
| 1679 | − LIST_HEAD_INIT(security_hook_heads.sb_clone_mnt_opts), | |
| 1680 | − .sb_parse_opts_str = | |
| 1681 | − LIST_HEAD_INIT(security_hook_heads.sb_parse_opts_str), | |
| 1682 | − .dentry_init_security = | |
| 1683 | − LIST_HEAD_INIT(security_hook_heads.dentry_init_security), | |
| 1684 | − .dentry_create_files_as = | |
| 1685 | − LIST_HEAD_INIT(security_hook_heads.dentry_create_files_as), | |
| 1686 | −#ifdef CONFIG_SECURITY_PATH | |
| 1687 | − .path_unlink = LIST_HEAD_INIT(security_hook_heads.path_unlink), | |
| 1688 | − .path_mkdir = LIST_HEAD_INIT(security_hook_heads.path_mkdir), | |
| 1689 | − .path_rmdir = LIST_HEAD_INIT(security_hook_heads.path_rmdir), | |
| 1690 | − .path_mknod = LIST_HEAD_INIT(security_hook_heads.path_mknod), | |
| 1691 | − .path_truncate = | |
| 1692 | − LIST_HEAD_INIT(security_hook_heads.path_truncate), | |
| 1693 | − .path_symlink = LIST_HEAD_INIT(security_hook_heads.path_symlink), | |
| 1694 | − .path_link = LIST_HEAD_INIT(security_hook_heads.path_link), | |
| 1695 | − .path_rename = LIST_HEAD_INIT(security_hook_heads.path_rename), | |
| 1696 | − .path_chmod = LIST_HEAD_INIT(security_hook_heads.path_chmod), | |
| 1697 | − .path_chown = LIST_HEAD_INIT(security_hook_heads.path_chown), | |
| 1698 | − .path_chroot = LIST_HEAD_INIT(security_hook_heads.path_chroot), | |
| 1699 | −#endif | |
| 1700 | − .inode_alloc_security = | |
| 1701 | − LIST_HEAD_INIT(security_hook_heads.inode_alloc_security), | |
| 1702 | − .inode_free_security = | |
| 1703 | − LIST_HEAD_INIT(security_hook_heads.inode_free_security), | |
| 1704 | − .inode_init_security = | |
| 1705 | − LIST_HEAD_INIT(security_hook_heads.inode_init_security), | |
| 1706 | − .inode_create = LIST_HEAD_INIT(security_hook_heads.inode_create), | |
| 1707 | − .inode_link = LIST_HEAD_INIT(security_hook_heads.inode_link), | |
| 1708 | − .inode_unlink = LIST_HEAD_INIT(security_hook_heads.inode_unlink), | |
| 1709 | − .inode_symlink = | |
| 1710 | − LIST_HEAD_INIT(security_hook_heads.inode_symlink), | |
| 1711 | − .inode_mkdir = LIST_HEAD_INIT(security_hook_heads.inode_mkdir), | |
| 1712 | − .inode_rmdir = LIST_HEAD_INIT(security_hook_heads.inode_rmdir), | |
| 1713 | − .inode_mknod = LIST_HEAD_INIT(security_hook_heads.inode_mknod), | |
| 1714 | − .inode_rename = LIST_HEAD_INIT(security_hook_heads.inode_rename), | |
| 1715 | − .inode_readlink = | |
| 1716 | − LIST_HEAD_INIT(security_hook_heads.inode_readlink), | |
| 1717 | − .inode_follow_link = | |
| 1718 | − LIST_HEAD_INIT(security_hook_heads.inode_follow_link), | |
| 1719 | − .inode_permission = | |
| 1720 | − LIST_HEAD_INIT(security_hook_heads.inode_permission), | |
| 1721 | − .inode_setattr = | |
| 1722 | − LIST_HEAD_INIT(security_hook_heads.inode_setattr), | |
| 1723 | − .inode_getattr = | |
| 1724 | − LIST_HEAD_INIT(security_hook_heads.inode_getattr), | |
| 1725 | − .inode_setxattr = | |
| 1726 | − LIST_HEAD_INIT(security_hook_heads.inode_setxattr), | |
| 1727 | − .inode_post_setxattr = | |
| 1728 | − LIST_HEAD_INIT(security_hook_heads.inode_post_setxattr), | |
| 1729 | − .inode_getxattr = | |
| 1730 | − LIST_HEAD_INIT(security_hook_heads.inode_getxattr), | |
| 1731 | − .inode_listxattr = | |
| 1732 | − LIST_HEAD_INIT(security_hook_heads.inode_listxattr), | |
| 1733 | − .inode_removexattr = | |
| 1734 | − LIST_HEAD_INIT(security_hook_heads.inode_removexattr), | |
| 1735 | − .inode_need_killpriv = | |
| 1736 | − LIST_HEAD_INIT(security_hook_heads.inode_need_killpriv), | |
| 1737 | − .inode_killpriv = | |
| 1738 | − LIST_HEAD_INIT(security_hook_heads.inode_killpriv), | |
| 1739 | − .inode_getsecurity = | |
| 1740 | − LIST_HEAD_INIT(security_hook_heads.inode_getsecurity), | |
| 1741 | − .inode_setsecurity = | |
| 1742 | − LIST_HEAD_INIT(security_hook_heads.inode_setsecurity), | |
| 1743 | − .inode_listsecurity = | |
| 1744 | − LIST_HEAD_INIT(security_hook_heads.inode_listsecurity), | |
| 1745 | − .inode_getsecid = | |
| 1746 | − LIST_HEAD_INIT(security_hook_heads.inode_getsecid), | |
| 1747 | − .inode_copy_up = | |
| 1748 | − LIST_HEAD_INIT(security_hook_heads.inode_copy_up), | |
| 1749 | − .inode_copy_up_xattr = | |
| 1750 | − LIST_HEAD_INIT(security_hook_heads.inode_copy_up_xattr), | |
| 1751 | − .file_permission = | |
| 1752 | − LIST_HEAD_INIT(security_hook_heads.file_permission), | |
| 1753 | − .file_alloc_security = | |
| 1754 | − LIST_HEAD_INIT(security_hook_heads.file_alloc_security), | |
| 1755 | − .file_free_security = | |
| 1756 | − LIST_HEAD_INIT(security_hook_heads.file_free_security), | |
| 1757 | − .file_ioctl = LIST_HEAD_INIT(security_hook_heads.file_ioctl), | |
| 1758 | − .mmap_addr = LIST_HEAD_INIT(security_hook_heads.mmap_addr), | |
| 1759 | − .mmap_file = LIST_HEAD_INIT(security_hook_heads.mmap_file), | |
| 1760 | − .file_mprotect = | |
| 1761 | − LIST_HEAD_INIT(security_hook_heads.file_mprotect), | |
| 1762 | − .file_lock = LIST_HEAD_INIT(security_hook_heads.file_lock), | |
| 1763 | − .file_fcntl = LIST_HEAD_INIT(security_hook_heads.file_fcntl), | |
| 1764 | − .file_set_fowner = | |
| 1765 | − LIST_HEAD_INIT(security_hook_heads.file_set_fowner), | |
| 1766 | − .file_send_sigiotask = | |
| 1767 | − LIST_HEAD_INIT(security_hook_heads.file_send_sigiotask), | |
| 1768 | − .file_receive = LIST_HEAD_INIT(security_hook_heads.file_receive), | |
| 1769 | − .file_open = LIST_HEAD_INIT(security_hook_heads.file_open), | |
| 1770 | − .task_create = LIST_HEAD_INIT(security_hook_heads.task_create), | |
| 1771 | − .task_free = LIST_HEAD_INIT(security_hook_heads.task_free), | |
| 1772 | − .cred_alloc_blank = | |
| 1773 | − LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank), | |
| 1774 | − .cred_free = LIST_HEAD_INIT(security_hook_heads.cred_free), | |
| 1775 | − .cred_prepare = LIST_HEAD_INIT(security_hook_heads.cred_prepare), | |
| 1776 | − .cred_transfer = | |
| 1777 | − LIST_HEAD_INIT(security_hook_heads.cred_transfer), | |
| 1778 | − .kernel_act_as = | |
| 1779 | − LIST_HEAD_INIT(security_hook_heads.kernel_act_as), | |
| 1780 | − .kernel_create_files_as = | |
| 1781 | − LIST_HEAD_INIT(security_hook_heads.kernel_create_files_as), | |
| 1782 | − .kernel_module_request = | |
| 1783 | − LIST_HEAD_INIT(security_hook_heads.kernel_module_request), | |
| 1784 | − .kernel_read_file = | |
| 1785 | − LIST_HEAD_INIT(security_hook_heads.kernel_read_file), | |
| 1786 | − .kernel_post_read_file = | |
| 1787 | − LIST_HEAD_INIT(security_hook_heads.kernel_post_read_file), | |
| 1788 | − .task_fix_setuid = | |
| 1789 | − LIST_HEAD_INIT(security_hook_heads.task_fix_setuid), | |
| 1790 | − .task_setpgid = LIST_HEAD_INIT(security_hook_heads.task_setpgid), | |
| 1791 | − .task_getpgid = LIST_HEAD_INIT(security_hook_heads.task_getpgid), | |
| 1792 | − .task_getsid = LIST_HEAD_INIT(security_hook_heads.task_getsid), | |
| 1793 | − .task_getsecid = | |
| 1794 | − LIST_HEAD_INIT(security_hook_heads.task_getsecid), | |
| 1795 | − .task_setnice = LIST_HEAD_INIT(security_hook_heads.task_setnice), | |
| 1796 | − .task_setioprio = | |
| 1797 | − LIST_HEAD_INIT(security_hook_heads.task_setioprio), | |
| 1798 | − .task_getioprio = | |
| 1799 | − LIST_HEAD_INIT(security_hook_heads.task_getioprio), | |
| 1800 | − .task_setrlimit = | |
| 1801 | − LIST_HEAD_INIT(security_hook_heads.task_setrlimit), | |
| 1802 | − .task_setscheduler = | |
| 1803 | − LIST_HEAD_INIT(security_hook_heads.task_setscheduler), | |
| 1804 | − .task_getscheduler = | |
| 1805 | − LIST_HEAD_INIT(security_hook_heads.task_getscheduler), | |
| 1806 | − .task_movememory = | |
| 1807 | − LIST_HEAD_INIT(security_hook_heads.task_movememory), | |
| 1808 | − .task_kill = LIST_HEAD_INIT(security_hook_heads.task_kill), | |
| 1809 | − .task_prctl = LIST_HEAD_INIT(security_hook_heads.task_prctl), | |
| 1810 | − .task_to_inode = | |
| 1811 | − LIST_HEAD_INIT(security_hook_heads.task_to_inode), | |
| 1812 | − .ipc_permission = | |
| 1813 | − LIST_HEAD_INIT(security_hook_heads.ipc_permission), | |
| 1814 | − .ipc_getsecid = LIST_HEAD_INIT(security_hook_heads.ipc_getsecid), | |
| 1815 | − .msg_msg_alloc_security = | |
| 1816 | − LIST_HEAD_INIT(security_hook_heads.msg_msg_alloc_security), | |
| 1817 | − .msg_msg_free_security = | |
| 1818 | − LIST_HEAD_INIT(security_hook_heads.msg_msg_free_security), | |
| 1819 | − .msg_queue_alloc_security = | |
| 1820 | − LIST_HEAD_INIT(security_hook_heads.msg_queue_alloc_security), | |
| 1821 | − .msg_queue_free_security = | |
| 1822 | − LIST_HEAD_INIT(security_hook_heads.msg_queue_free_security), | |
| 1823 | − .msg_queue_associate = | |
| 1824 | − LIST_HEAD_INIT(security_hook_heads.msg_queue_associate), | |
| 1825 | − .msg_queue_msgctl = | |
| 1826 | − LIST_HEAD_INIT(security_hook_heads.msg_queue_msgctl), | |
| 1827 | − .msg_queue_msgsnd = | |
| 1828 | − LIST_HEAD_INIT(security_hook_heads.msg_queue_msgsnd), | |
| 1829 | − .msg_queue_msgrcv = | |
| 1830 | − LIST_HEAD_INIT(security_hook_heads.msg_queue_msgrcv), | |
| 1831 | − .shm_alloc_security = | |
| 1832 | − LIST_HEAD_INIT(security_hook_heads.shm_alloc_security), | |
| 1833 | − .shm_free_security = | |
| 1834 | − LIST_HEAD_INIT(security_hook_heads.shm_free_security), | |
| 1835 | − .shm_associate = | |
| 1836 | − LIST_HEAD_INIT(security_hook_heads.shm_associate), | |
| 1837 | − .shm_shmctl = LIST_HEAD_INIT(security_hook_heads.shm_shmctl), | |
| 1838 | − .shm_shmat = LIST_HEAD_INIT(security_hook_heads.shm_shmat), | |
| 1839 | − .sem_alloc_security = | |
| 1840 | − LIST_HEAD_INIT(security_hook_heads.sem_alloc_security), | |
| 1841 | − .sem_free_security = | |
| 1842 | − LIST_HEAD_INIT(security_hook_heads.sem_free_security), | |
| 1843 | − .sem_associate = | |
| 1844 | − LIST_HEAD_INIT(security_hook_heads.sem_associate), | |
| 1845 | − .sem_semctl = LIST_HEAD_INIT(security_hook_heads.sem_semctl), | |
| 1846 | − .sem_semop = LIST_HEAD_INIT(security_hook_heads.sem_semop), | |
| 1847 | − .netlink_send = LIST_HEAD_INIT(security_hook_heads.netlink_send), | |
| 1848 | − .d_instantiate = | |
| 1849 | − LIST_HEAD_INIT(security_hook_heads.d_instantiate), | |
| 1850 | − .getprocattr = LIST_HEAD_INIT(security_hook_heads.getprocattr), | |
| 1851 | − .setprocattr = LIST_HEAD_INIT(security_hook_heads.setprocattr), | |
| 1852 | − .ismaclabel = LIST_HEAD_INIT(security_hook_heads.ismaclabel), | |
| 1853 | − .secid_to_secctx = | |
| 1854 | − LIST_HEAD_INIT(security_hook_heads.secid_to_secctx), | |
| 1855 | − .secctx_to_secid = | |
| 1856 | − LIST_HEAD_INIT(security_hook_heads.secctx_to_secid), | |
| 1857 | − .release_secctx = | |
| 1858 | − LIST_HEAD_INIT(security_hook_heads.release_secctx), | |
| 1859 | − .inode_invalidate_secctx = | |
| 1860 | − LIST_HEAD_INIT(security_hook_heads.inode_invalidate_secctx), | |
| 1861 | − .inode_notifysecctx = | |
| 1862 | − LIST_HEAD_INIT(security_hook_heads.inode_notifysecctx), | |
| 1863 | − .inode_setsecctx = | |
| 1864 | − LIST_HEAD_INIT(security_hook_heads.inode_setsecctx), | |
| 1865 | − .inode_getsecctx = | |
| 1866 | − LIST_HEAD_INIT(security_hook_heads.inode_getsecctx), | |
| 1867 | −#ifdef CONFIG_SECURITY_NETWORK | |
| 1868 | − .unix_stream_connect = | |
| 1869 | − LIST_HEAD_INIT(security_hook_heads.unix_stream_connect), | |
| 1870 | − .unix_may_send = | |
| 1871 | − LIST_HEAD_INIT(security_hook_heads.unix_may_send), | |
| 1872 | − .socket_create = | |
| 1873 | − LIST_HEAD_INIT(security_hook_heads.socket_create), | |
| 1874 | − .socket_post_create = | |
| 1875 | − LIST_HEAD_INIT(security_hook_heads.socket_post_create), | |
| 1876 | − .socket_bind = LIST_HEAD_INIT(security_hook_heads.socket_bind), | |
| 1877 | − .socket_connect = | |
| 1878 | − LIST_HEAD_INIT(security_hook_heads.socket_connect), | |
| 1879 | − .socket_listen = | |
| 1880 | − LIST_HEAD_INIT(security_hook_heads.socket_listen), | |
| 1881 | − .socket_accept = | |
| 1882 | − LIST_HEAD_INIT(security_hook_heads.socket_accept), | |
| 1883 | − .socket_sendmsg = | |
| 1884 | − LIST_HEAD_INIT(security_hook_heads.socket_sendmsg), | |
| 1885 | − .socket_recvmsg = | |
| 1886 | − LIST_HEAD_INIT(security_hook_heads.socket_recvmsg), | |
| 1887 | − .socket_getsockname = | |
| 1888 | − LIST_HEAD_INIT(security_hook_heads.socket_getsockname), | |
| 1889 | − .socket_getpeername = | |
| 1890 | − LIST_HEAD_INIT(security_hook_heads.socket_getpeername), | |
| 1891 | − .socket_getsockopt = | |
| 1892 | − LIST_HEAD_INIT(security_hook_heads.socket_getsockopt), | |
| 1893 | − .socket_setsockopt = | |
| 1894 | − LIST_HEAD_INIT(security_hook_heads.socket_setsockopt), | |
| 1895 | − .socket_shutdown = | |
| 1896 | − LIST_HEAD_INIT(security_hook_heads.socket_shutdown), | |
| 1897 | − .socket_sock_rcv_skb = | |
| 1898 | − LIST_HEAD_INIT(security_hook_heads.socket_sock_rcv_skb), | |
| 1899 | − .socket_getpeersec_stream = | |
| 1900 | − LIST_HEAD_INIT(security_hook_heads.socket_getpeersec_stream), | |
| 1901 | − .socket_getpeersec_dgram = | |
| 1902 | − LIST_HEAD_INIT(security_hook_heads.socket_getpeersec_dgram), | |
| 1903 | − .sk_alloc_security = | |
| 1904 | − LIST_HEAD_INIT(security_hook_heads.sk_alloc_security), | |
| 1905 | − .sk_free_security = | |
| 1906 | − LIST_HEAD_INIT(security_hook_heads.sk_free_security), | |
| 1907 | − .sk_clone_security = | |
| 1908 | − LIST_HEAD_INIT(security_hook_heads.sk_clone_security), | |
| 1909 | − .sk_getsecid = LIST_HEAD_INIT(security_hook_heads.sk_getsecid), | |
| 1910 | − .sock_graft = LIST_HEAD_INIT(security_hook_heads.sock_graft), | |
| 1911 | − .inet_conn_request = | |
| 1912 | − LIST_HEAD_INIT(security_hook_heads.inet_conn_request), | |
| 1913 | − .inet_csk_clone = | |
| 1914 | − LIST_HEAD_INIT(security_hook_heads.inet_csk_clone), | |
| 1915 | − .inet_conn_established = | |
| 1916 | − LIST_HEAD_INIT(security_hook_heads.inet_conn_established), | |
| 1917 | − .secmark_relabel_packet = | |
| 1918 | − LIST_HEAD_INIT(security_hook_heads.secmark_relabel_packet), | |
| 1919 | − .secmark_refcount_inc = | |
| 1920 | − LIST_HEAD_INIT(security_hook_heads.secmark_refcount_inc), | |
| 1921 | − .secmark_refcount_dec = | |
| 1922 | − LIST_HEAD_INIT(security_hook_heads.secmark_refcount_dec), | |
| 1923 | − .req_classify_flow = | |
| 1924 | − LIST_HEAD_INIT(security_hook_heads.req_classify_flow), | |
| 1925 | − .tun_dev_alloc_security = | |
| 1926 | − LIST_HEAD_INIT(security_hook_heads.tun_dev_alloc_security), | |
| 1927 | − .tun_dev_free_security = | |
| 1928 | − LIST_HEAD_INIT(security_hook_heads.tun_dev_free_security), | |
| 1929 | − .tun_dev_create = | |
| 1930 | − LIST_HEAD_INIT(security_hook_heads.tun_dev_create), | |
| 1931 | − .tun_dev_attach_queue = | |
| 1932 | − LIST_HEAD_INIT(security_hook_heads.tun_dev_attach_queue), | |
| 1933 | − .tun_dev_attach = | |
| 1934 | − LIST_HEAD_INIT(security_hook_heads.tun_dev_attach), | |
| 1935 | − .tun_dev_open = LIST_HEAD_INIT(security_hook_heads.tun_dev_open), | |
| 1936 | −#endif /* CONFIG_SECURITY_NETWORK */ | |
| 1937 | −#ifdef CONFIG_SECURITY_NETWORK_XFRM | |
| 1938 | − .xfrm_policy_alloc_security = | |
| 1939 | − LIST_HEAD_INIT(security_hook_heads.xfrm_policy_alloc_security), | |
| 1940 | − .xfrm_policy_clone_security = | |
| 1941 | − LIST_HEAD_INIT(security_hook_heads.xfrm_policy_clone_security), | |
| 1942 | − .xfrm_policy_free_security = | |
| 1943 | − LIST_HEAD_INIT(security_hook_heads.xfrm_policy_free_security), | |
| 1944 | − .xfrm_policy_delete_security = | |
| 1945 | − LIST_HEAD_INIT(security_hook_heads.xfrm_policy_delete_security), | |
| 1946 | − .xfrm_state_alloc = | |
| 1947 | − LIST_HEAD_INIT(security_hook_heads.xfrm_state_alloc), | |
| 1948 | − .xfrm_state_alloc_acquire = | |
| 1949 | − LIST_HEAD_INIT(security_hook_heads.xfrm_state_alloc_acquire), | |
| 1950 | − .xfrm_state_free_security = | |
| 1951 | − LIST_HEAD_INIT(security_hook_heads.xfrm_state_free_security), | |
| 1952 | − .xfrm_state_delete_security = | |
| 1953 | − LIST_HEAD_INIT(security_hook_heads.xfrm_state_delete_security), | |
| 1954 | − .xfrm_policy_lookup = | |
| 1955 | − LIST_HEAD_INIT(security_hook_heads.xfrm_policy_lookup), | |
| 1956 | − .xfrm_state_pol_flow_match = | |
| 1957 | − LIST_HEAD_INIT(security_hook_heads.xfrm_state_pol_flow_match), | |
| 1958 | − .xfrm_decode_session = | |
| 1959 | − LIST_HEAD_INIT(security_hook_heads.xfrm_decode_session), | |
| 1960 | −#endif /* CONFIG_SECURITY_NETWORK_XFRM */ | |
| 1961 | −#ifdef CONFIG_KEYS | |
| 1962 | − .key_alloc = LIST_HEAD_INIT(security_hook_heads.key_alloc), | |
| 1963 | − .key_free = LIST_HEAD_INIT(security_hook_heads.key_free), | |
| 1964 | − .key_permission = | |
| 1965 | − LIST_HEAD_INIT(security_hook_heads.key_permission), | |
| 1966 | − .key_getsecurity = | |
| 1967 | − LIST_HEAD_INIT(security_hook_heads.key_getsecurity), | |
| 1968 | −#endif /* CONFIG_KEYS */ | |
| 1969 | −#ifdef CONFIG_AUDIT | |
| 1970 | − .audit_rule_init = | |
| 1971 | − LIST_HEAD_INIT(security_hook_heads.audit_rule_init), | |
| 1972 | − .audit_rule_known = | |
| 1973 | − LIST_HEAD_INIT(security_hook_heads.audit_rule_known), | |
| 1974 | − .audit_rule_match = | |
| 1975 | − LIST_HEAD_INIT(security_hook_heads.audit_rule_match), | |
| 1976 | − .audit_rule_free = | |
| 1977 | − LIST_HEAD_INIT(security_hook_heads.audit_rule_free), | |
| 1978 | −#endif /* CONFIG_AUDIT */ | |
| 1979 | −}; | |
| @@ -40,6 +40,7 @@ config SECURITY_SELINUX_BOOTPARAM_VALUE · 39 unmodified lines | ||
| 40 | 40 | config SECURITY_SELINUX_DISABLE |
| 41 | 41 | bool "NSA SELinux runtime disable" |
| 42 | 42 | depends on SECURITY_SELINUX |
| 43 | + select SECURITY_WRITABLE_HOOKS | |
| 43 | 44 | default n |
| 44 | 45 | help |
| 45 | 46 | This option enables writing to a selinuxfs node 'disable', which |
| @@ -50,6 +51,11 @@ config SECURITY_SELINUX_DISABLE · 4 unmodified lines | ||
| 50 | 51 | portability across platforms where boot parameters are difficult |
| 51 | 52 | to employ. |
| 52 | 53 | |
| 54 | + NOTE: selecting this option will disable the '__ro_after_init' | |
| 55 | + kernel hardening feature for security hooks. Please consider | |
| 56 | + using the selinux=0 boot parameter instead of enabling this | |
| 57 | + option. | |
| 58 | + | |
| 53 | 59 | If you are unsure how to answer this question, answer N. |
| 54 | 60 | |
| 55 | 61 | config SECURITY_SELINUX_DEVELOP |
| @@ -3920,6 +3920,21 @@ static int selinux_task_getioprio(struct task_struct *p) · 3919 unmodified lines | ||
| 3920 | 3920 | PROCESS__GETSCHED, NULL); |
| 3921 | 3921 | } |
| 3922 | 3922 | |
| 3923 | +int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, | |
| 3924 | + unsigned int flags) | |
| 3925 | +{ | |
| 3926 | + u32 av = 0; | |
| 3927 | + | |
| 3928 | + if (!flags) | |
| 3929 | + return 0; | |
| 3930 | + if (flags & LSM_PRLIMIT_WRITE) | |
| 3931 | + av |= PROCESS__SETRLIMIT; | |
| 3932 | + if (flags & LSM_PRLIMIT_READ) | |
| 3933 | + av |= PROCESS__GETRLIMIT; | |
| 3934 | + return avc_has_perm(cred_sid(cred), cred_sid(tcred), | |
| 3935 | + SECCLASS_PROCESS, av, NULL); | |
| 3936 | +} | |
| 3937 | + | |
| 3923 | 3938 | static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, |
| 3924 | 3939 | struct rlimit *new_rlim) |
| 3925 | 3940 | { |
| @@ -4352,10 +4367,18 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in · 426 unmodified lines | ||
| 4352 | 4367 | u32 sid, node_perm; |
| 4353 | 4368 | |
| 4354 | 4369 | if (family == PF_INET) { |
| 4370 | + if (addrlen < sizeof(struct sockaddr_in)) { | |
| 4371 | + err = -EINVAL; | |
| 4372 | + goto out; | |
| 4373 | + } | |
| 4355 | 4374 | addr4 = (struct sockaddr_in *)address; |
| 4356 | 4375 | snum = ntohs(addr4->sin_port); |
| 4357 | 4376 | addrp = (char *)&addr4->sin_addr.s_addr; |
| 4358 | 4377 | } else { |
| 4378 | + if (addrlen < SIN6_LEN_RFC2133) { | |
| 4379 | + err = -EINVAL; | |
| 4380 | + goto out; | |
| 4381 | + } | |
| 4359 | 4382 | addr6 = (struct sockaddr_in6 *)address; |
| 4360 | 4383 | snum = ntohs(addr6->sin6_port); |
| 4361 | 4384 | addrp = (char *)&addr6->sin6_addr.s6_addr; |
| @@ -6108,7 +6131,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) · 1746 unmodified lines | ||
| 6108 | 6131 | |
| 6109 | 6132 | #endif |
| 6110 | 6133 | |
| 6111 | −static struct security_hook_list selinux_hooks[] = { | |
| 6134 | +static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |
| 6112 | 6135 | LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), |
| 6113 | 6136 | LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), |
| 6114 | 6137 | LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder), |
| @@ -6206,6 +6229,7 @@ static struct security_hook_list selinux_hooks[] = { · 91 unmodified lines | ||
| 6206 | 6229 | LSM_HOOK_INIT(task_setnice, selinux_task_setnice), |
| 6207 | 6230 | LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio), |
| 6208 | 6231 | LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio), |
| 6232 | + LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit), | |
| 6209 | 6233 | LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit), |
| 6210 | 6234 | LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler), |
| 6211 | 6235 | LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler), |
| @@ -47,7 +47,7 @@ struct security_class_mapping secclass_map[] = { · 46 unmodified lines | ||
| 47 | 47 | "getattr", "setexec", "setfscreate", "noatsecure", "siginh", |
| 48 | 48 | "setrlimit", "rlimitinh", "dyntransition", "setcurrent", |
| 49 | 49 | "execmem", "execstack", "execheap", "setkeycreate", |
| 50 | − "setsockcreate", NULL } }, | |
| 50 | + "setsockcreate", "getrlimit", NULL } }, | |
| 51 | 51 | { "system", |
| 52 | 52 | { "ipc_info", "syslog_read", "syslog_mod", |
| 53 | 53 | "syslog_console", "module_request", "module_load", NULL } }, |
| @@ -28,7 +28,7 @@ struct nlmsg_perm { · 27 unmodified lines | ||
| 28 | 28 | u32 perm; |
| 29 | 29 | }; |
| 30 | 30 | |
| 31 | −static struct nlmsg_perm nlmsg_route_perms[] = | |
| 31 | +static const struct nlmsg_perm nlmsg_route_perms[] = | |
| 32 | 32 | { |
| 33 | 33 | { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, |
| 34 | 34 | { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, |
| @@ -81,7 +81,7 @@ static struct nlmsg_perm nlmsg_route_perms[] = · 46 unmodified lines | ||
| 81 | 81 | { RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
| 82 | 82 | }; |
| 83 | 83 | |
| 84 | −static struct nlmsg_perm nlmsg_tcpdiag_perms[] = | |
| 84 | +static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = | |
| 85 | 85 | { |
| 86 | 86 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, |
| 87 | 87 | { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, |
| @@ -89,7 +89,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] = · 1 unmodified line | ||
| 89 | 89 | { SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE }, |
| 90 | 90 | }; |
| 91 | 91 | |
| 92 | −static struct nlmsg_perm nlmsg_xfrm_perms[] = | |
| 92 | +static const struct nlmsg_perm nlmsg_xfrm_perms[] = | |
| 93 | 93 | { |
| 94 | 94 | { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, |
| 95 | 95 | { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, |
| @@ -116,7 +116,7 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = · 20 unmodified lines | ||
| 116 | 116 | { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ }, |
| 117 | 117 | }; |
| 118 | 118 | |
| 119 | −static struct nlmsg_perm nlmsg_audit_perms[] = | |
| 119 | +static const struct nlmsg_perm nlmsg_audit_perms[] = | |
| 120 | 120 | { |
| 121 | 121 | { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, |
| 122 | 122 | { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, |
| @@ -137,7 +137,7 @@ static struct nlmsg_perm nlmsg_audit_perms[] = · 14 unmodified lines | ||
| 137 | 137 | }; |
| 138 | 138 | |
| 139 | 139 | |
| 140 | −static int nlmsg_perm(u16 nlmsg_type, u32 *perm, struct nlmsg_perm *tab, size_t tabsize) | |
| 140 | +static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab, size_t tabsize) | |
| 141 | 141 | { |
| 142 | 142 | int i, err = -EINVAL; |
| 143 | 143 | |
| @@ -1456,10 +1456,10 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v) · 1455 unmodified lines | ||
| 1456 | 1456 | { |
| 1457 | 1457 | struct avc_cache_stats *st = v; |
| 1458 | 1458 | |
| 1459 | − if (v == SEQ_START_TOKEN) | |
| 1460 | − seq_printf(seq, "lookups hits misses allocations reclaims " | |
| 1461 | − "frees\n"); | |
| 1462 | − else { | |
| 1459 | + if (v == SEQ_START_TOKEN) { | |
| 1460 | + seq_puts(seq, | |
| 1461 | + "lookups hits misses allocations reclaims frees\n"); | |
| 1462 | + } else { | |
| 1463 | 1463 | unsigned int lookups = st->lookups; |
| 1464 | 1464 | unsigned int misses = st->misses; |
| 1465 | 1465 | unsigned int hits = lookups - misses; |
| @@ -176,8 +176,9 @@ void cond_policydb_destroy(struct policydb *p) · 175 unmodified lines | ||
| 176 | 176 | int cond_init_bool_indexes(struct policydb *p) |
| 177 | 177 | { |
| 178 | 178 | kfree(p->bool_val_to_struct); |
| 179 | − p->bool_val_to_struct = | |
| 180 | − kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL); | |
| 179 | + p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim, | |
| 180 | + sizeof(*p->bool_val_to_struct), | |
| 181 | + GFP_KERNEL); | |
| 181 | 182 | if (!p->bool_val_to_struct) |
| 182 | 183 | return -ENOMEM; |
| 183 | 184 | return 0; |
| @@ -226,7 +227,7 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp) · 42 unmodified lines | ||
| 226 | 227 | u32 len; |
| 227 | 228 | int rc; |
| 228 | 229 | |
| 229 | − booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL); | |
| 230 | + booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL); | |
| 230 | 231 | if (!booldatum) |
| 231 | 232 | return -ENOMEM; |
| 232 | 233 | |
| @@ -331,7 +332,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum · 98 unmodified lines | ||
| 331 | 332 | goto err; |
| 332 | 333 | } |
| 333 | 334 | |
| 334 | − list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL); | |
| 335 | + list = kzalloc(sizeof(*list), GFP_KERNEL); | |
| 335 | 336 | if (!list) { |
| 336 | 337 | rc = -ENOMEM; |
| 337 | 338 | goto err; |
| @@ -420,7 +421,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) · 82 unmodified lines | ||
| 420 | 421 | goto err; |
| 421 | 422 | |
| 422 | 423 | rc = -ENOMEM; |
| 423 | − expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL); | |
| 424 | + expr = kzalloc(sizeof(*expr), GFP_KERNEL); | |
| 424 | 425 | if (!expr) |
| 425 | 426 | goto err; |
| 426 | 427 | |
| @@ -471,7 +472,7 @@ int cond_read_list(struct policydb *p, void *fp) · 44 unmodified lines | ||
| 471 | 472 | |
| 472 | 473 | for (i = 0; i < len; i++) { |
| 473 | 474 | rc = -ENOMEM; |
| 474 | − node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); | |
| 475 | + node = kzalloc(sizeof(*node), GFP_KERNEL); | |
| 475 | 476 | if (!node) |
| 476 | 477 | goto err; |
| 477 | 478 | |
| @@ -663,5 +664,4 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, · 185 unmodified lines | ||
| 663 | 664 | (node->key.specified & AVTAB_XPERMS)) |
| 664 | 665 | services_compute_xperms_drivers(xperms, node); |
| 665 | 666 | } |
| 666 | − return; | |
| 667 | 667 | } |
| @@ -17,15 +17,15 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void * · 16 unmodified lines | ||
| 17 | 17 | u32 i; |
| 18 | 18 | |
| 19 | 19 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 20 | − if (p == NULL) | |
| 20 | + if (!p) | |
| 21 | 21 | return p; |
| 22 | 22 | |
| 23 | 23 | p->size = size; |
| 24 | 24 | p->nel = 0; |
| 25 | 25 | p->hash_value = hash_value; |
| 26 | 26 | p->keycmp = keycmp; |
| 27 | − p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL); | |
| 28 | − if (p->htable == NULL) { | |
| 27 | + p->htable = kmalloc_array(size, sizeof(*p->htable), GFP_KERNEL); | |
| 28 | + if (!p->htable) { | |
| 29 | 29 | kfree(p); |
| 30 | 30 | return NULL; |
| 31 | 31 | } |
| @@ -58,7 +58,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum) · 26 unmodified lines | ||
| 58 | 58 | return -EEXIST; |
| 59 | 59 | |
| 60 | 60 | newnode = kzalloc(sizeof(*newnode), GFP_KERNEL); |
| 61 | − if (newnode == NULL) | |
| 61 | + if (!newnode) | |
| 62 | 62 | return -ENOMEM; |
| 63 | 63 | newnode->key = key; |
| 64 | 64 | newnode->datum = datum; |
| @@ -87,7 +87,7 @@ void *hashtab_search(struct hashtab *h, const void *key) · 22 unmodified lines | ||
| 87 | 87 | while (cur && h->keycmp(h, key, cur->key) > 0) |
| 88 | 88 | cur = cur->next; |
| 89 | 89 | |
| 90 | − if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) | |
| 90 | + if (!cur || (h->keycmp(h, key, cur->key) != 0)) | |
| 91 | 91 | return NULL; |
| 92 | 92 | |
| 93 | 93 | return cur->datum; |
| @@ -178,10 +178,9 @@ static int roles_init(struct policydb *p) · 177 unmodified lines | ||
| 178 | 178 | int rc; |
| 179 | 179 | struct role_datum *role; |
| 180 | 180 | |
| 181 | − rc = -ENOMEM; | |
| 182 | 181 | role = kzalloc(sizeof(*role), GFP_KERNEL); |
| 183 | 182 | if (!role) |
| 184 | − goto out; | |
| 183 | + return -ENOMEM; | |
| 185 | 184 | |
| 186 | 185 | rc = -EINVAL; |
| 187 | 186 | role->value = ++p->p_roles.nprim; |
| @@ -540,23 +539,23 @@ static int policydb_index(struct policydb *p) · 352 unmodified lines | ||
| 540 | 539 | #endif |
| 541 | 540 | |
| 542 | 541 | rc = -ENOMEM; |
| 543 | − p->class_val_to_struct = | |
| 544 | − kzalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), | |
| 545 | − GFP_KERNEL); | |
| 542 | + p->class_val_to_struct = kcalloc(p->p_classes.nprim, | |
| 543 | + sizeof(*p->class_val_to_struct), | |
| 544 | + GFP_KERNEL); | |
| 546 | 545 | if (!p->class_val_to_struct) |
| 547 | 546 | goto out; |
| 548 | 547 | |
| 549 | 548 | rc = -ENOMEM; |
| 550 | − p->role_val_to_struct = | |
| 551 | − kzalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)), | |
| 552 | − GFP_KERNEL); | |
| 549 | + p->role_val_to_struct = kcalloc(p->p_roles.nprim, | |
| 550 | + sizeof(*p->role_val_to_struct), | |
| 551 | + GFP_KERNEL); | |
| 553 | 552 | if (!p->role_val_to_struct) |
| 554 | 553 | goto out; |
| 555 | 554 | |
| 556 | 555 | rc = -ENOMEM; |
| 557 | − p->user_val_to_struct = | |
| 558 | − kzalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), | |
| 559 | − GFP_KERNEL); | |
| 556 | + p->user_val_to_struct = kcalloc(p->p_users.nprim, | |
| 557 | + sizeof(*p->user_val_to_struct), | |
| 558 | + GFP_KERNEL); | |
| 560 | 559 | if (!p->user_val_to_struct) |
| 561 | 560 | goto out; |
| 562 | 561 | |
| @@ -880,8 +879,6 @@ void policydb_destroy(struct policydb *p) · 317 unmodified lines | ||
| 880 | 879 | ebitmap_destroy(&p->filename_trans_ttypes); |
| 881 | 880 | ebitmap_destroy(&p->policycaps); |
| 882 | 881 | ebitmap_destroy(&p->permissive_map); |
| 883 | − | |
| 884 | − return; | |
| 885 | 882 | } |
| 886 | 883 | |
| 887 | 884 | /* |
| @@ -1120,10 +1117,9 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) · 232 unmodified lines | ||
| 1120 | 1117 | __le32 buf[2]; |
| 1121 | 1118 | u32 len; |
| 1122 | 1119 | |
| 1123 | − rc = -ENOMEM; | |
| 1124 | 1120 | perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL); |
| 1125 | 1121 | if (!perdatum) |
| 1126 | − goto bad; | |
| 1122 | + return -ENOMEM; | |
| 1127 | 1123 | |
| 1128 | 1124 | rc = next_entry(buf, fp, sizeof buf); |
| 1129 | 1125 | if (rc) |
| @@ -1154,10 +1150,9 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) · 24 unmodified lines | ||
| 1154 | 1150 | u32 len, nel; |
| 1155 | 1151 | int i, rc; |
| 1156 | 1152 | |
| 1157 | − rc = -ENOMEM; | |
| 1158 | 1153 | comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL); |
| 1159 | 1154 | if (!comdatum) |
| 1160 | − goto bad; | |
| 1155 | + return -ENOMEM; | |
| 1161 | 1156 | |
| 1162 | 1157 | rc = next_entry(buf, fp, sizeof buf); |
| 1163 | 1158 | if (rc) |
| @@ -1320,10 +1315,9 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) · 156 unmodified lines | ||
| 1320 | 1315 | u32 len, len2, ncons, nel; |
| 1321 | 1316 | int i, rc; |
| 1322 | 1317 | |
| 1323 | − rc = -ENOMEM; | |
| 1324 | 1318 | cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL); |
| 1325 | 1319 | if (!cladatum) |
| 1326 | − goto bad; | |
| 1320 | + return -ENOMEM; | |
| 1327 | 1321 | |
| 1328 | 1322 | rc = next_entry(buf, fp, sizeof(u32)*6); |
| 1329 | 1323 | if (rc) |
| @@ -1414,10 +1408,9 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) · 84 unmodified lines | ||
| 1414 | 1408 | __le32 buf[3]; |
| 1415 | 1409 | u32 len; |
| 1416 | 1410 | |
| 1417 | − rc = -ENOMEM; | |
| 1418 | 1411 | role = kzalloc(sizeof(*role), GFP_KERNEL); |
| 1419 | 1412 | if (!role) |
| 1420 | − goto bad; | |
| 1413 | + return -ENOMEM; | |
| 1421 | 1414 | |
| 1422 | 1415 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
| 1423 | 1416 | to_read = 3; |
| @@ -1471,10 +1464,9 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) · 47 unmodified lines | ||
| 1471 | 1464 | __le32 buf[4]; |
| 1472 | 1465 | u32 len; |
| 1473 | 1466 | |
| 1474 | − rc = -ENOMEM; | |
| 1475 | 1467 | typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); |
| 1476 | 1468 | if (!typdatum) |
| 1477 | − goto bad; | |
| 1469 | + return -ENOMEM; | |
| 1478 | 1470 | |
| 1479 | 1471 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
| 1480 | 1472 | to_read = 4; |
| @@ -1546,10 +1538,9 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) · 65 unmodified lines | ||
| 1546 | 1538 | __le32 buf[3]; |
| 1547 | 1539 | u32 len; |
| 1548 | 1540 | |
| 1549 | − rc = -ENOMEM; | |
| 1550 | 1541 | usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); |
| 1551 | 1542 | if (!usrdatum) |
| 1552 | − goto bad; | |
| 1543 | + return -ENOMEM; | |
| 1553 | 1544 | |
| 1554 | 1545 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
| 1555 | 1546 | to_read = 3; |
| @@ -1597,10 +1588,9 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) · 41 unmodified lines | ||
| 1597 | 1588 | __le32 buf[2]; |
| 1598 | 1589 | u32 len; |
| 1599 | 1590 | |
| 1600 | − rc = -ENOMEM; | |
| 1601 | 1591 | levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC); |
| 1602 | 1592 | if (!levdatum) |
| 1603 | − goto bad; | |
| 1593 | + return -ENOMEM; | |
| 1604 | 1594 | |
| 1605 | 1595 | rc = next_entry(buf, fp, sizeof buf); |
| 1606 | 1596 | if (rc) |
| @@ -1614,7 +1604,7 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) · 7 unmodified lines | ||
| 1614 | 1604 | goto bad; |
| 1615 | 1605 | |
| 1616 | 1606 | rc = -ENOMEM; |
| 1617 | − levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); | |
| 1607 | + levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_ATOMIC); | |
| 1618 | 1608 | if (!levdatum->level) |
| 1619 | 1609 | goto bad; |
| 1620 | 1610 | |
| @@ -1639,10 +1629,9 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp) · 18 unmodified lines | ||
| 1639 | 1629 | __le32 buf[3]; |
| 1640 | 1630 | u32 len; |
| 1641 | 1631 | |
| 1642 | − rc = -ENOMEM; | |
| 1643 | 1632 | catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC); |
| 1644 | 1633 | if (!catdatum) |
| 1645 | − goto bad; | |
| 1634 | + return -ENOMEM; | |
| 1646 | 1635 | |
| 1647 | 1636 | rc = next_entry(buf, fp, sizeof buf); |
| 1648 | 1637 | if (rc) |
| @@ -1854,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp) · 205 unmodified lines | ||
| 1854 | 1843 | |
| 1855 | 1844 | rc = next_entry(buf, fp, sizeof(u32)); |
| 1856 | 1845 | if (rc) |
| 1857 | − goto out; | |
| 1846 | + return rc; | |
| 1858 | 1847 | |
| 1859 | 1848 | nel = le32_to_cpu(buf[0]); |
| 1860 | 1849 | for (i = 0; i < nel; i++) { |
| @@ -1931,7 +1920,6 @@ static int filename_trans_read(struct policydb *p, void *fp) · 70 unmodified lines | ||
| 1931 | 1920 | nel = le32_to_cpu(buf[0]); |
| 1932 | 1921 | |
| 1933 | 1922 | for (i = 0; i < nel; i++) { |
| 1934 | − ft = NULL; | |
| 1935 | 1923 | otype = NULL; |
| 1936 | 1924 | name = NULL; |
| 1937 | 1925 | |
| @@ -2008,7 +1996,7 @@ static int genfs_read(struct policydb *p, void *fp) · 70 unmodified lines | ||
| 2008 | 1996 | |
| 2009 | 1997 | rc = next_entry(buf, fp, sizeof(u32)); |
| 2010 | 1998 | if (rc) |
| 2011 | − goto out; | |
| 1999 | + return rc; | |
| 2012 | 2000 | nel = le32_to_cpu(buf[0]); |
| 2013 | 2001 | |
| 2014 | 2002 | for (i = 0; i < nel; i++) { |
| @@ -2100,9 +2088,10 @@ static int genfs_read(struct policydb *p, void *fp) · 85 unmodified lines | ||
| 2100 | 2088 | } |
| 2101 | 2089 | rc = 0; |
| 2102 | 2090 | out: |
| 2103 | − if (newgenfs) | |
| 2091 | + if (newgenfs) { | |
| 2104 | 2092 | kfree(newgenfs->fstype); |
| 2105 | − kfree(newgenfs); | |
| 2093 | + kfree(newgenfs); | |
| 2094 | + } | |
| 2106 | 2095 | ocontext_destroy(newc, OCON_FSUSE); |
| 2107 | 2096 | |
| 2108 | 2097 | return rc; |
| @@ -157,7 +157,7 @@ static int selinux_set_mapping(struct policydb *pol, · 156 unmodified lines | ||
| 157 | 157 | } |
| 158 | 158 | |
| 159 | 159 | k = 0; |
| 160 | − while (p_in->perms && p_in->perms[k]) { | |
| 160 | + while (p_in->perms[k]) { | |
| 161 | 161 | /* An empty permission string skips ahead */ |
| 162 | 162 | if (!*p_in->perms[k]) { |
| 163 | 163 | k++; |
| @@ -18,7 +18,7 @@ int sidtab_init(struct sidtab *s) · 17 unmodified lines | ||
| 18 | 18 | { |
| 19 | 19 | int i; |
| 20 | 20 | |
| 21 | − s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC); | |
| 21 | + s->htable = kmalloc_array(SIDTAB_SIZE, sizeof(*s->htable), GFP_ATOMIC); | |
| 22 | 22 | if (!s->htable) |
| 23 | 23 | return -ENOMEM; |
| 24 | 24 | for (i = 0; i < SIDTAB_SIZE; i++) |
| @@ -54,7 +54,7 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) · 29 unmodified lines | ||
| 54 | 54 | } |
| 55 | 55 | |
| 56 | 56 | newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC); |
| 57 | − if (newnode == NULL) { | |
| 57 | + if (!newnode) { | |
| 58 | 58 | rc = -ENOMEM; |
| 59 | 59 | goto out; |
| 60 | 60 | } |
| @@ -98,7 +98,7 @@ static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) · 37 unmodified lines | ||
| 98 | 98 | if (force && cur && sid == cur->sid && cur->context.len) |
| 99 | 99 | return &cur->context; |
| 100 | 100 | |
| 101 | − if (cur == NULL || sid != cur->sid || cur->context.len) { | |
| 101 | + if (!cur || sid != cur->sid || cur->context.len) { | |
| 102 | 102 | /* Remap invalid SIDs to the unlabeled SID. */ |
| 103 | 103 | sid = SECINITSID_UNLABELED; |
| 104 | 104 | hvalue = SIDTAB_HASH(sid); |
| @@ -504,7 +504,7 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, · 503 unmodified lines | ||
| 504 | 504 | if ((m & *cp) == 0) |
| 505 | 505 | continue; |
| 506 | 506 | rc = netlbl_catmap_setbit(&sap->attr.mls.cat, |
| 507 | − cat, GFP_ATOMIC); | |
| 507 | + cat, GFP_KERNEL); | |
| 508 | 508 | if (rc < 0) { |
| 509 | 509 | netlbl_catmap_free(sap->attr.mls.cat); |
| 510 | 510 | return rc; |
| @@ -695,10 +695,8 @@ static int smack_parse_opts_str(char *options, · 694 unmodified lines | ||
| 695 | 695 | |
| 696 | 696 | opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS, sizeof(int), |
| 697 | 697 | GFP_KERNEL); |
| 698 | − if (!opts->mnt_opts_flags) { | |
| 699 | − kfree(opts->mnt_opts); | |
| 698 | + if (!opts->mnt_opts_flags) | |
| 700 | 699 | goto out_err; |
| 701 | − } | |
| 702 | 700 | |
| 703 | 701 | if (fsdefault) { |
| 704 | 702 | opts->mnt_opts[num_mnt_opts] = fsdefault; |
| @@ -4633,7 +4631,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) · 3928 unmodified lines | ||
| 4633 | 4631 | return 0; |
| 4634 | 4632 | } |
| 4635 | 4633 | |
| 4636 | −static struct security_hook_list smack_hooks[] = { | |
| 4634 | +static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { | |
| 4637 | 4635 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), |
| 4638 | 4636 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), |
| 4639 | 4637 | LSM_HOOK_INIT(syslog, smack_syslog), |
| @@ -692,7 +692,7 @@ int tomoyo_path_number_perm(const u8 type, const struct path *path, · 691 unmodified lines | ||
| 692 | 692 | { |
| 693 | 693 | struct tomoyo_request_info r; |
| 694 | 694 | struct tomoyo_obj_info obj = { |
| 695 | − .path1 = *path, | |
| 695 | + .path1 = { .mnt = path->mnt, .dentry = path->dentry }, | |
| 696 | 696 | }; |
| 697 | 697 | int error = -ENOMEM; |
| 698 | 698 | struct tomoyo_path_info buf; |
| @@ -740,7 +740,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, · 41 unmodified lines | ||
| 740 | 740 | struct tomoyo_path_info buf; |
| 741 | 741 | struct tomoyo_request_info r; |
| 742 | 742 | struct tomoyo_obj_info obj = { |
| 743 | − .path1 = *path, | |
| 743 | + .path1 = { .mnt = path->mnt, .dentry = path->dentry }, | |
| 744 | 744 | }; |
| 745 | 745 | int idx; |
| 746 | 746 | |
| @@ -786,7 +786,7 @@ int tomoyo_path_perm(const u8 operation, const struct path *path, const char *ta · 39 unmodified lines | ||
| 786 | 786 | { |
| 787 | 787 | struct tomoyo_request_info r; |
| 788 | 788 | struct tomoyo_obj_info obj = { |
| 789 | − .path1 = *path, | |
| 789 | + .path1 = { .mnt = path->mnt, .dentry = path->dentry }, | |
| 790 | 790 | }; |
| 791 | 791 | int error; |
| 792 | 792 | struct tomoyo_path_info buf; |
| @@ -843,7 +843,7 @@ int tomoyo_mkdev_perm(const u8 operation, const struct path *path, · 50 unmodified lines | ||
| 843 | 843 | { |
| 844 | 844 | struct tomoyo_request_info r; |
| 845 | 845 | struct tomoyo_obj_info obj = { |
| 846 | − .path1 = *path, | |
| 846 | + .path1 = { .mnt = path->mnt, .dentry = path->dentry }, | |
| 847 | 847 | }; |
| 848 | 848 | int error = -ENOMEM; |
| 849 | 849 | struct tomoyo_path_info buf; |
| @@ -890,8 +890,8 @@ int tomoyo_path2_perm(const u8 operation, const struct path *path1, · 40 unmodified lines | ||
| 890 | 890 | struct tomoyo_path_info buf2; |
| 891 | 891 | struct tomoyo_request_info r; |
| 892 | 892 | struct tomoyo_obj_info obj = { |
| 893 | − .path1 = *path1, | |
| 894 | − .path2 = *path2, | |
| 893 | + .path1 = { .mnt = path1->mnt, .dentry = path1->dentry }, | |
| 894 | + .path2 = { .mnt = path2->mnt, .dentry = path2->dentry } | |
| 895 | 895 | }; |
| 896 | 896 | int idx; |
| 897 | 897 | |
| @@ -165,7 +165,7 @@ static int tomoyo_path_truncate(const struct path *path) · 164 unmodified lines | ||
| 165 | 165 | */ |
| 166 | 166 | static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) |
| 167 | 167 | { |
| 168 | − struct path path = { parent->mnt, dentry }; | |
| 168 | + struct path path = { .mnt = parent->mnt, .dentry = dentry }; | |
| 169 | 169 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); |
| 170 | 170 | } |
| 171 | 171 | |
| @@ -181,7 +181,7 @@ static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) · 9 unmodified lines | ||
| 181 | 181 | static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, |
| 182 | 182 | umode_t mode) |
| 183 | 183 | { |
| 184 | − struct path path = { parent->mnt, dentry }; | |
| 184 | + struct path path = { .mnt = parent->mnt, .dentry = dentry }; | |
| 185 | 185 | return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, |
| 186 | 186 | mode & S_IALLUGO); |
| 187 | 187 | } |
| @@ -196,7 +196,7 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, · 8 unmodified lines | ||
| 196 | 196 | */ |
| 197 | 197 | static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) |
| 198 | 198 | { |
| 199 | − struct path path = { parent->mnt, dentry }; | |
| 199 | + struct path path = { .mnt = parent->mnt, .dentry = dentry }; | |
| 200 | 200 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); |
| 201 | 201 | } |
| 202 | 202 | |
| @@ -212,7 +212,7 @@ static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) · 9 unmodified lines | ||
| 212 | 212 | static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, |
| 213 | 213 | const char *old_name) |
| 214 | 214 | { |
| 215 | − struct path path = { parent->mnt, dentry }; | |
| 215 | + struct path path = { .mnt = parent->mnt, .dentry = dentry }; | |
| 216 | 216 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); |
| 217 | 217 | } |
| 218 | 218 | |
| @@ -229,7 +229,7 @@ static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, · 10 unmodified lines | ||
| 229 | 229 | static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry, |
| 230 | 230 | umode_t mode, unsigned int dev) |
| 231 | 231 | { |
| 232 | − struct path path = { parent->mnt, dentry }; | |
| 232 | + struct path path = { .mnt = parent->mnt, .dentry = dentry }; | |
| 233 | 233 | int type = TOMOYO_TYPE_CREATE; |
| 234 | 234 | const unsigned int perm = mode & S_IALLUGO; |
| 235 | 235 | |
| @@ -268,8 +268,8 @@ static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry, · 32 unmodified lines | ||
| 268 | 268 | static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_dir, |
| 269 | 269 | struct dentry *new_dentry) |
| 270 | 270 | { |
| 271 | − struct path path1 = { new_dir->mnt, old_dentry }; | |
| 272 | − struct path path2 = { new_dir->mnt, new_dentry }; | |
| 271 | + struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; | |
| 272 | + struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; | |
| 273 | 273 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); |
| 274 | 274 | } |
| 275 | 275 | |
| @@ -288,8 +288,8 @@ static int tomoyo_path_rename(const struct path *old_parent, · 12 unmodified lines | ||
| 288 | 288 | const struct path *new_parent, |
| 289 | 289 | struct dentry *new_dentry) |
| 290 | 290 | { |
| 291 | − struct path path1 = { old_parent->mnt, old_dentry }; | |
| 292 | − struct path path2 = { new_parent->mnt, new_dentry }; | |
| 291 | + struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; | |
| 292 | + struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; | |
| 293 | 293 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); |
| 294 | 294 | } |
| 295 | 295 | |
| @@ -417,7 +417,7 @@ static int tomoyo_sb_mount(const char *dev_name, const struct path *path, · 121 unmodified lines | ||
| 417 | 417 | */ |
| 418 | 418 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) |
| 419 | 419 | { |
| 420 | − struct path path = { mnt, mnt->mnt_root }; | |
| 420 | + struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; | |
| 421 | 421 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); |
| 422 | 422 | } |
| 423 | 423 | |
| @@ -496,7 +496,7 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, · 72 unmodified lines | ||
| 496 | 496 | * tomoyo_security_ops is a "struct security_operations" which is used for |
| 497 | 497 | * registering TOMOYO. |
| 498 | 498 | */ |
| 499 | −static struct security_hook_list tomoyo_hooks[] = { | |
| 499 | +static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { | |
| 500 | 500 | LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank), |
| 501 | 501 | LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), |
| 502 | 502 | LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer), |
| @@ -428,7 +428,7 @@ int yama_ptrace_traceme(struct task_struct *parent) · 427 unmodified lines | ||
| 428 | 428 | return rc; |
| 429 | 429 | } |
| 430 | 430 | |
| 431 | −static struct security_hook_list yama_hooks[] = { | |
| 431 | +static struct security_hook_list yama_hooks[] __lsm_ro_after_init = { | |
| 432 | 432 | LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check), |
| 433 | 433 | LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme), |
| 434 | 434 | LSM_HOOK_INIT(task_prctl, yama_task_prctl), |