diff options
82 files changed, 1915 insertions, 807 deletions
diff --git a/Documentation/security/LoadPin.txt b/Documentation/security/LoadPin.txt new file mode 100644 index 000000000000..e11877f5d3d4 --- /dev/null +++ b/Documentation/security/LoadPin.txt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | LoadPin is a Linux Security Module that ensures all kernel-loaded files | ||
| 2 | (modules, firmware, etc) all originate from the same filesystem, with | ||
| 3 | the expectation that such a filesystem is backed by a read-only device | ||
| 4 | such as dm-verity or CDROM. This allows systems that have a verified | ||
| 5 | and/or unchangeable filesystem to enforce module and firmware loading | ||
| 6 | restrictions without needing to sign the files individually. | ||
| 7 | |||
| 8 | The LSM is selectable at build-time with CONFIG_SECURITY_LOADPIN, and | ||
| 9 | can be controlled at boot-time with the kernel command line option | ||
| 10 | "loadpin.enabled". By default, it is enabled, but can be disabled at | ||
| 11 | boot ("loadpin.enabled=0"). | ||
| 12 | |||
| 13 | LoadPin starts pinning when it sees the first file loaded. If the | ||
| 14 | block device backing the filesystem is not read-only, a sysctl is | ||
| 15 | created to toggle pinning: /proc/sys/kernel/loadpin/enabled. (Having | ||
| 16 | a mutable filesystem means pinning is mutable too, but having the | ||
| 17 | sysctl allows for easy testing on systems with a mutable filesystem.) | ||
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index 8c183873b2b7..20d05719bceb 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt | |||
| @@ -823,6 +823,36 @@ The keyctl syscall functions are: | |||
| 823 | A process must have search permission on the key for this function to be | 823 | A process must have search permission on the key for this function to be |
| 824 | successful. | 824 | successful. |
| 825 | 825 | ||
| 826 | (*) Compute a Diffie-Hellman shared secret or public key | ||
| 827 | |||
| 828 | long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params, | ||
| 829 | char *buffer, size_t buflen); | ||
| 830 | |||
| 831 | The params struct contains serial numbers for three keys: | ||
| 832 | |||
| 833 | - The prime, p, known to both parties | ||
| 834 | - The local private key | ||
| 835 | - The base integer, which is either a shared generator or the | ||
| 836 | remote public key | ||
| 837 | |||
| 838 | The value computed is: | ||
| 839 | |||
| 840 | result = base ^ private (mod prime) | ||
| 841 | |||
| 842 | If the base is the shared generator, the result is the local | ||
| 843 | public key. If the base is the remote public key, the result is | ||
| 844 | the shared secret. | ||
| 845 | |||
| 846 | The buffer length must be at least the length of the prime, or zero. | ||
| 847 | |||
| 848 | If the buffer length is nonzero, the length of the result is | ||
| 849 | returned when it is successfully calculated and copied in to the | ||
| 850 | buffer. When the buffer length is zero, the minimum required | ||
| 851 | buffer length is returned. | ||
| 852 | |||
| 853 | This function will return error EOPNOTSUPP if the key type is not | ||
| 854 | supported, error ENOKEY if the key could not be found, or error | ||
| 855 | EACCES if the key is not readable by the caller. | ||
| 826 | 856 | ||
| 827 | =============== | 857 | =============== |
| 828 | KERNEL SERVICES | 858 | KERNEL SERVICES |
| @@ -999,6 +1029,10 @@ payload contents" for more information. | |||
| 999 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | 1029 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, |
| 1000 | const struct cred *cred, | 1030 | const struct cred *cred, |
| 1001 | key_perm_t perm, | 1031 | key_perm_t perm, |
| 1032 | int (*restrict_link)(struct key *, | ||
| 1033 | const struct key_type *, | ||
| 1034 | unsigned long, | ||
| 1035 | const union key_payload *), | ||
| 1002 | unsigned long flags, | 1036 | unsigned long flags, |
| 1003 | struct key *dest); | 1037 | struct key *dest); |
| 1004 | 1038 | ||
| @@ -1010,6 +1044,24 @@ payload contents" for more information. | |||
| 1010 | KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted | 1044 | KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted |
| 1011 | towards the user's quota). Error ENOMEM can also be returned. | 1045 | towards the user's quota). Error ENOMEM can also be returned. |
| 1012 | 1046 | ||
| 1047 | If restrict_link not NULL, it should point to a function that will be | ||
| 1048 | called each time an attempt is made to link a key into the new keyring. | ||
| 1049 | This function is called to check whether a key may be added into the keying | ||
| 1050 | or not. Callers of key_create_or_update() within the kernel can pass | ||
| 1051 | KEY_ALLOC_BYPASS_RESTRICTION to suppress the check. An example of using | ||
| 1052 | this is to manage rings of cryptographic keys that are set up when the | ||
| 1053 | kernel boots where userspace is also permitted to add keys - provided they | ||
| 1054 | can be verified by a key the kernel already has. | ||
| 1055 | |||
| 1056 | When called, the restriction function will be passed the keyring being | ||
| 1057 | added to, the key flags value and the type and payload of the key being | ||
| 1058 | added. Note that when a new key is being created, this is called between | ||
| 1059 | payload preparsing and actual key creation. The function should return 0 | ||
| 1060 | to allow the link or an error to reject it. | ||
| 1061 | |||
| 1062 | A convenience function, restrict_link_reject, exists to always return | ||
| 1063 | -EPERM to in this case. | ||
| 1064 | |||
| 1013 | 1065 | ||
| 1014 | (*) To check the validity of a key, this function can be called: | 1066 | (*) To check the validity of a key, this function can be called: |
| 1015 | 1067 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index add406a46231..71bcef4a161c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -10025,6 +10025,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git | |||
| 10025 | S: Supported | 10025 | S: Supported |
| 10026 | F: security/apparmor/ | 10026 | F: security/apparmor/ |
| 10027 | 10027 | ||
| 10028 | LOADPIN SECURITY MODULE | ||
| 10029 | M: Kees Cook <keescook@chromium.org> | ||
| 10030 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin | ||
| 10031 | S: Supported | ||
| 10032 | F: security/loadpin/ | ||
| 10033 | |||
| 10028 | YAMA SECURITY MODULE | 10034 | YAMA SECURITY MODULE |
| 10029 | M: Kees Cook <keescook@chromium.org> | 10035 | M: Kees Cook <keescook@chromium.org> |
| 10030 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip | 10036 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip |
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index 2af478e3fd4e..f2356bda2b05 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c | |||
| @@ -19,8 +19,7 @@ | |||
| 19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
| 20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
| 21 | #include <linux/efi.h> | 21 | #include <linux/efi.h> |
| 22 | #include <linux/verify_pefile.h> | 22 | #include <linux/verification.h> |
| 23 | #include <keys/system_keyring.h> | ||
| 24 | 23 | ||
| 25 | #include <asm/bootparam.h> | 24 | #include <asm/bootparam.h> |
| 26 | #include <asm/setup.h> | 25 | #include <asm/setup.h> |
| @@ -529,18 +528,9 @@ static int bzImage64_cleanup(void *loader_data) | |||
| 529 | #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG | 528 | #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG |
| 530 | static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) | 529 | static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) |
| 531 | { | 530 | { |
| 532 | bool trusted; | 531 | return verify_pefile_signature(kernel, kernel_len, |
| 533 | int ret; | 532 | NULL, |
| 534 | 533 | VERIFYING_KEXEC_PE_SIGNATURE); | |
| 535 | ret = verify_pefile_signature(kernel, kernel_len, | ||
| 536 | system_trusted_keyring, | ||
| 537 | VERIFYING_KEXEC_PE_SIGNATURE, | ||
| 538 | &trusted); | ||
| 539 | if (ret < 0) | ||
| 540 | return ret; | ||
| 541 | if (!trusted) | ||
| 542 | return -EKEYREJECTED; | ||
| 543 | return 0; | ||
| 544 | } | 534 | } |
| 545 | #endif | 535 | #endif |
| 546 | 536 | ||
diff --git a/certs/Kconfig b/certs/Kconfig index f0f8a4433685..fc5955f5fc8a 100644 --- a/certs/Kconfig +++ b/certs/Kconfig | |||
| @@ -17,6 +17,7 @@ config MODULE_SIG_KEY | |||
| 17 | config SYSTEM_TRUSTED_KEYRING | 17 | config SYSTEM_TRUSTED_KEYRING |
| 18 | bool "Provide system-wide ring of trusted keys" | 18 | bool "Provide system-wide ring of trusted keys" |
| 19 | depends on KEYS | 19 | depends on KEYS |
| 20 | depends on ASYMMETRIC_KEY_TYPE | ||
| 20 | help | 21 | help |
| 21 | Provide a system keyring to which trusted keys can be added. Keys in | 22 | Provide a system keyring to which trusted keys can be added. Keys in |
| 22 | the keyring are considered to be trusted. Keys may be added at will | 23 | the keyring are considered to be trusted. Keys may be added at will |
| @@ -55,4 +56,12 @@ config SYSTEM_EXTRA_CERTIFICATE_SIZE | |||
| 55 | This is the number of bytes reserved in the kernel image for a | 56 | This is the number of bytes reserved in the kernel image for a |
| 56 | certificate to be inserted. | 57 | certificate to be inserted. |
| 57 | 58 | ||
| 59 | config SECONDARY_TRUSTED_KEYRING | ||
| 60 | bool "Provide a keyring to which extra trustable keys may be added" | ||
| 61 | depends on SYSTEM_TRUSTED_KEYRING | ||
| 62 | help | ||
| 63 | If set, provide a keyring to which extra keys may be added, provided | ||
| 64 | those keys are not blacklisted and are vouched for by a key built | ||
| 65 | into the kernel or already in the secondary trusted keyring. | ||
| 66 | |||
| 58 | endmenu | 67 | endmenu |
diff --git a/certs/system_keyring.c b/certs/system_keyring.c index f4180326c2e1..50979d6dcecd 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c | |||
| @@ -18,29 +18,88 @@ | |||
| 18 | #include <keys/system_keyring.h> | 18 | #include <keys/system_keyring.h> |
| 19 | #include <crypto/pkcs7.h> | 19 | #include <crypto/pkcs7.h> |
| 20 | 20 | ||
| 21 | struct key *system_trusted_keyring; | 21 | static struct key *builtin_trusted_keys; |
| 22 | EXPORT_SYMBOL_GPL(system_trusted_keyring); | 22 | #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING |
| 23 | static struct key *secondary_trusted_keys; | ||
| 24 | #endif | ||
| 23 | 25 | ||
| 24 | extern __initconst const u8 system_certificate_list[]; | 26 | extern __initconst const u8 system_certificate_list[]; |
| 25 | extern __initconst const unsigned long system_certificate_list_size; | 27 | extern __initconst const unsigned long system_certificate_list_size; |
| 26 | 28 | ||
| 29 | /** | ||
| 30 | * restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA | ||
| 31 | * | ||
| 32 | * Restrict the addition of keys into a keyring based on the key-to-be-added | ||
| 33 | * being vouched for by a key in the built in system keyring. | ||
| 34 | */ | ||
| 35 | int restrict_link_by_builtin_trusted(struct key *keyring, | ||
| 36 | const struct key_type *type, | ||
| 37 | const union key_payload *payload) | ||
| 38 | { | ||
| 39 | return restrict_link_by_signature(builtin_trusted_keys, type, payload); | ||
| 40 | } | ||
| 41 | |||
| 42 | #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING | ||
| 43 | /** | ||
| 44 | * restrict_link_by_builtin_and_secondary_trusted - Restrict keyring | ||
| 45 | * addition by both builtin and secondary keyrings | ||
| 46 | * | ||
| 47 | * Restrict the addition of keys into a keyring based on the key-to-be-added | ||
| 48 | * being vouched for by a key in either the built-in or the secondary system | ||
| 49 | * keyrings. | ||
| 50 | */ | ||
| 51 | int restrict_link_by_builtin_and_secondary_trusted( | ||
| 52 | struct key *keyring, | ||
| 53 | const struct key_type *type, | ||
| 54 | const union key_payload *payload) | ||
| 55 | { | ||
| 56 | /* If we have a secondary trusted keyring, then that contains a link | ||
| 57 | * through to the builtin keyring and the search will follow that link. | ||
| 58 | */ | ||
| 59 | if (type == &key_type_keyring && | ||
| 60 | keyring == secondary_trusted_keys && | ||
| 61 | payload == &builtin_trusted_keys->payload) | ||
| 62 | /* Allow the builtin keyring to be added to the secondary */ | ||
| 63 | return 0; | ||
| 64 | |||
| 65 | return restrict_link_by_signature(secondary_trusted_keys, type, payload); | ||
| 66 | } | ||
| 67 | #endif | ||
| 68 | |||
| 27 | /* | 69 | /* |
| 28 | * Load the compiled-in keys | 70 | * Create the trusted keyrings |
| 29 | */ | 71 | */ |
| 30 | static __init int system_trusted_keyring_init(void) | 72 | static __init int system_trusted_keyring_init(void) |
| 31 | { | 73 | { |
| 32 | pr_notice("Initialise system trusted keyring\n"); | 74 | pr_notice("Initialise system trusted keyrings\n"); |
| 33 | 75 | ||
| 34 | system_trusted_keyring = | 76 | builtin_trusted_keys = |
| 35 | keyring_alloc(".system_keyring", | 77 | keyring_alloc(".builtin_trusted_keys", |
| 36 | KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), | 78 | KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), |
| 37 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | 79 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 38 | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH), | 80 | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH), |
| 39 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | 81 | KEY_ALLOC_NOT_IN_QUOTA, |
| 40 | if (IS_ERR(system_trusted_keyring)) | 82 | NULL, NULL); |
| 41 | panic("Can't allocate system trusted keyring\n"); | 83 | if (IS_ERR(builtin_trusted_keys)) |
| 84 | panic("Can't allocate builtin trusted keyring\n"); | ||
| 85 | |||
| 86 | #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING | ||
| 87 | secondary_trusted_keys = | ||
| 88 | keyring_alloc(".secondary_trusted_keys", | ||
| 89 | KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), | ||
| 90 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
| 91 | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH | | ||
| 92 | KEY_USR_WRITE), | ||
| 93 | KEY_ALLOC_NOT_IN_QUOTA, | ||
| 94 | restrict_link_by_builtin_and_secondary_trusted, | ||
| 95 | NULL); | ||
| 96 | if (IS_ERR(secondary_trusted_keys)) | ||
| 97 | panic("Can't allocate secondary trusted keyring\n"); | ||
| 98 | |||
| 99 | if (key_link(secondary_trusted_keys, builtin_trusted_keys) < 0) | ||
| 100 | panic("Can't link trusted keyrings\n"); | ||
| 101 | #endif | ||
| 42 | 102 | ||
| 43 | set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags); | ||
| 44 | return 0; | 103 | return 0; |
| 45 | } | 104 | } |
| 46 | 105 | ||
| @@ -76,7 +135,7 @@ static __init int load_system_certificate_list(void) | |||
| 76 | if (plen > end - p) | 135 | if (plen > end - p) |
| 77 | goto dodgy_cert; | 136 | goto dodgy_cert; |
| 78 | 137 | ||
| 79 | key = key_create_or_update(make_key_ref(system_trusted_keyring, 1), | 138 | key = key_create_or_update(make_key_ref(builtin_trusted_keys, 1), |
| 80 | "asymmetric", | 139 | "asymmetric", |
| 81 | NULL, | 140 | NULL, |
| 82 | p, | 141 | p, |
| @@ -84,8 +143,8 @@ static __init int load_system_certificate_list(void) | |||
| 84 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | 143 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 85 | KEY_USR_VIEW | KEY_USR_READ), | 144 | KEY_USR_VIEW | KEY_USR_READ), |
| 86 | KEY_ALLOC_NOT_IN_QUOTA | | 145 | KEY_ALLOC_NOT_IN_QUOTA | |
| 87 | KEY_ALLOC_TRUSTED | | 146 | KEY_ALLOC_BUILT_IN | |
| 88 | KEY_ALLOC_BUILT_IN); | 147 | KEY_ALLOC_BYPASS_RESTRICTION); |
| 89 | if (IS_ERR(key)) { | 148 | if (IS_ERR(key)) { |
| 90 | pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", | 149 | pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", |
| 91 | PTR_ERR(key)); | 150 | PTR_ERR(key)); |
| @@ -108,19 +167,27 @@ late_initcall(load_system_certificate_list); | |||
| 108 | #ifdef CONFIG_SYSTEM_DATA_VERIFICATION | 167 | #ifdef CONFIG_SYSTEM_DATA_VERIFICATION |
| 109 | 168 | ||
| 110 | /** | 169 | /** |
| 111 | * Verify a PKCS#7-based signature on system data. | 170 | * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data. |
| 112 | * @data: The data to be verified. | 171 | * @data: The data to be verified (NULL if expecting internal data). |
| 113 | * @len: Size of @data. | 172 | * @len: Size of @data. |
| 114 | * @raw_pkcs7: The PKCS#7 message that is the signature. | 173 | * @raw_pkcs7: The PKCS#7 message that is the signature. |
| 115 | * @pkcs7_len: The size of @raw_pkcs7. | 174 | * @pkcs7_len: The size of @raw_pkcs7. |
| 175 | * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only, | ||
| 176 | * (void *)1UL for all trusted keys). | ||
| 116 | * @usage: The use to which the key is being put. | 177 | * @usage: The use to which the key is being put. |
| 178 | * @view_content: Callback to gain access to content. | ||
| 179 | * @ctx: Context for callback. | ||
| 117 | */ | 180 | */ |
| 118 | int system_verify_data(const void *data, unsigned long len, | 181 | int verify_pkcs7_signature(const void *data, size_t len, |
| 119 | const void *raw_pkcs7, size_t pkcs7_len, | 182 | const void *raw_pkcs7, size_t pkcs7_len, |
| 120 | enum key_being_used_for usage) | 183 | struct key *trusted_keys, |
| 184 | enum key_being_used_for usage, | ||
| 185 | int (*view_content)(void *ctx, | ||
| 186 | const void *data, size_t len, | ||
| 187 | size_t asn1hdrlen), | ||
| 188 | void *ctx) | ||
| 121 | { | 189 | { |
| 122 | struct pkcs7_message *pkcs7; | 190 | struct pkcs7_message *pkcs7; |
| 123 | bool trusted; | ||
| 124 | int ret; | 191 | int ret; |
| 125 | 192 | ||
| 126 | pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len); | 193 | pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len); |
| @@ -128,7 +195,7 @@ int system_verify_data(const void *data, unsigned long len, | |||
| 128 | return PTR_ERR(pkcs7); | 195 | return PTR_ERR(pkcs7); |
| 129 | 196 | ||
| 130 | /* The data should be detached - so we need to supply it. */ | 197 | /* The data should be detached - so we need to supply it. */ |
| 131 | if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) { | 198 | if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) { |
| 132 | pr_err("PKCS#7 signature with non-detached data\n"); | 199 | pr_err("PKCS#7 signature with non-detached data\n"); |
| 133 | ret = -EBADMSG; | 200 | ret = -EBADMSG; |
| 134 | goto error; | 201 | goto error; |
| @@ -138,13 +205,33 @@ int system_verify_data(const void *data, unsigned long len, | |||
| 138 | if (ret < 0) | 205 | if (ret < 0) |
| 139 | goto error; | 206 | goto error; |
| 140 | 207 | ||
| 141 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | 208 | if (!trusted_keys) { |
| 142 | if (ret < 0) | 209 | trusted_keys = builtin_trusted_keys; |
| 210 | } else if (trusted_keys == (void *)1UL) { | ||
| 211 | #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING | ||
| 212 | trusted_keys = secondary_trusted_keys; | ||
| 213 | #else | ||
| 214 | trusted_keys = builtin_trusted_keys; | ||
| 215 | #endif | ||
| 216 | } | ||
| 217 | ret = pkcs7_validate_trust(pkcs7, trusted_keys); | ||
| 218 | if (ret < 0) { | ||
| 219 | if (ret == -ENOKEY) | ||
| 220 | pr_err("PKCS#7 signature not signed with a trusted key\n"); | ||
| 143 | goto error; | 221 | goto error; |
| 222 | } | ||
| 223 | |||
| 224 | if (view_content) { | ||
| 225 | size_t asn1hdrlen; | ||
| 226 | |||
| 227 | ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen); | ||
| 228 | if (ret < 0) { | ||
| 229 | if (ret == -ENODATA) | ||
| 230 | pr_devel("PKCS#7 message does not contain data\n"); | ||
| 231 | goto error; | ||
| 232 | } | ||
| 144 | 233 | ||
| 145 | if (!trusted) { | 234 | ret = view_content(ctx, data, len, asn1hdrlen); |
| 146 | pr_err("PKCS#7 signature not signed with a trusted key\n"); | ||
| 147 | ret = -ENOKEY; | ||
| 148 | } | 235 | } |
| 149 | 236 | ||
| 150 | error: | 237 | error: |
| @@ -152,6 +239,6 @@ error: | |||
| 152 | pr_devel("<==%s() = %d\n", __func__, ret); | 239 | pr_devel("<==%s() = %d\n", __func__, ret); |
| 153 | return ret; | 240 | return ret; |
| 154 | } | 241 | } |
| 155 | EXPORT_SYMBOL_GPL(system_verify_data); | 242 | EXPORT_SYMBOL_GPL(verify_pkcs7_signature); |
| 156 | 243 | ||
| 157 | #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ | 244 | #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ |
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 91a7e047a765..e28e912000a7 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | menuconfig ASYMMETRIC_KEY_TYPE | 1 | menuconfig ASYMMETRIC_KEY_TYPE |
| 2 | tristate "Asymmetric (public-key cryptographic) key type" | 2 | bool "Asymmetric (public-key cryptographic) key type" |
| 3 | depends on KEYS | 3 | depends on KEYS |
| 4 | help | 4 | help |
| 5 | This option provides support for a key type that holds the data for | 5 | This option provides support for a key type that holds the data for |
| @@ -40,8 +40,7 @@ config PKCS7_MESSAGE_PARSER | |||
| 40 | 40 | ||
| 41 | config PKCS7_TEST_KEY | 41 | config PKCS7_TEST_KEY |
| 42 | tristate "PKCS#7 testing key type" | 42 | tristate "PKCS#7 testing key type" |
| 43 | depends on PKCS7_MESSAGE_PARSER | 43 | depends on SYSTEM_DATA_VERIFICATION |
| 44 | select SYSTEM_TRUSTED_KEYRING | ||
| 45 | help | 44 | help |
| 46 | This option provides a type of key that can be loaded up from a | 45 | This option provides a type of key that can be loaded up from a |
| 47 | PKCS#7 message - provided the message is signed by a trusted key. If | 46 | PKCS#7 message - provided the message is signed by a trusted key. If |
| @@ -54,6 +53,7 @@ config PKCS7_TEST_KEY | |||
| 54 | config SIGNED_PE_FILE_VERIFICATION | 53 | config SIGNED_PE_FILE_VERIFICATION |
| 55 | bool "Support for PE file signature verification" | 54 | bool "Support for PE file signature verification" |
| 56 | depends on PKCS7_MESSAGE_PARSER=y | 55 | depends on PKCS7_MESSAGE_PARSER=y |
| 56 | depends on SYSTEM_DATA_VERIFICATION | ||
| 57 | select ASN1 | 57 | select ASN1 |
| 58 | select OID_REGISTRY | 58 | select OID_REGISTRY |
| 59 | help | 59 | help |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index f90486256f01..6516855bec18 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
| @@ -4,7 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o | 5 | obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o |
| 6 | 6 | ||
| 7 | asymmetric_keys-y := asymmetric_type.o signature.o | 7 | asymmetric_keys-y := \ |
| 8 | asymmetric_type.o \ | ||
| 9 | restrict.o \ | ||
| 10 | signature.o | ||
| 8 | 11 | ||
| 9 | obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o | 12 | obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o |
| 10 | 13 | ||
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h index 1d450b580245..ca8e9ac34ce6 100644 --- a/crypto/asymmetric_keys/asymmetric_keys.h +++ b/crypto/asymmetric_keys/asymmetric_keys.h | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <keys/asymmetric-type.h> | ||
| 13 | |||
| 12 | extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id); | 14 | extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id); |
| 13 | 15 | ||
| 14 | extern int __asymmetric_key_hex_to_key_id(const char *id, | 16 | extern int __asymmetric_key_hex_to_key_id(const char *id, |
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index 9f2165b27d52..6600181d5d01 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
| @@ -35,6 +35,95 @@ static LIST_HEAD(asymmetric_key_parsers); | |||
| 35 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 35 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
| 36 | 36 | ||
| 37 | /** | 37 | /** |
| 38 | * find_asymmetric_key - Find a key by ID. | ||
| 39 | * @keyring: The keys to search. | ||
| 40 | * @id_0: The first ID to look for or NULL. | ||
| 41 | * @id_1: The second ID to look for or NULL. | ||
| 42 | * @partial: Use partial match if true, exact if false. | ||
| 43 | * | ||
| 44 | * Find a key in the given keyring by identifier. The preferred identifier is | ||
| 45 | * the id_0 and the fallback identifier is the id_1. If both are given, the | ||
| 46 | * lookup is by the former, but the latter must also match. | ||
| 47 | */ | ||
| 48 | struct key *find_asymmetric_key(struct key *keyring, | ||
| 49 | const struct asymmetric_key_id *id_0, | ||
| 50 | const struct asymmetric_key_id *id_1, | ||
| 51 | bool partial) | ||
| 52 | { | ||
| 53 | struct key *key; | ||
| 54 | key_ref_t ref; | ||
| 55 | const char *lookup; | ||
| 56 | char *req, *p; | ||
| 57 | int len; | ||
| 58 | |||
| 59 | if (id_0) { | ||
| 60 | lookup = id_0->data; | ||
| 61 | len = id_0->len; | ||
| 62 | } else { | ||
| 63 | lookup = id_1->data; | ||
| 64 | len = id_1->len; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* Construct an identifier "id:<keyid>". */ | ||
| 68 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); | ||
| 69 | if (!req) | ||
| 70 | return ERR_PTR(-ENOMEM); | ||
| 71 | |||
| 72 | if (partial) { | ||
| 73 | *p++ = 'i'; | ||
| 74 | *p++ = 'd'; | ||
| 75 | } else { | ||
| 76 | *p++ = 'e'; | ||
| 77 | *p++ = 'x'; | ||
| 78 | } | ||
| 79 | *p++ = ':'; | ||
| 80 | p = bin2hex(p, lookup, len); | ||
| 81 | *p = 0; | ||
| 82 | |||
| 83 | pr_debug("Look up: \"%s\"\n", req); | ||
| 84 | |||
| 85 | ref = keyring_search(make_key_ref(keyring, 1), | ||
| 86 | &key_type_asymmetric, req); | ||
| 87 | if (IS_ERR(ref)) | ||
| 88 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); | ||
| 89 | kfree(req); | ||
| 90 | |||
| 91 | if (IS_ERR(ref)) { | ||
| 92 | switch (PTR_ERR(ref)) { | ||
| 93 | /* Hide some search errors */ | ||
| 94 | case -EACCES: | ||
| 95 | case -ENOTDIR: | ||
| 96 | case -EAGAIN: | ||
| 97 | return ERR_PTR(-ENOKEY); | ||
| 98 | default: | ||
| 99 | return ERR_CAST(ref); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | key = key_ref_to_ptr(ref); | ||
| 104 | if (id_0 && id_1) { | ||
| 105 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | ||
| 106 | |||
| 107 | if (!kids->id[0]) { | ||
| 108 | pr_debug("First ID matches, but second is missing\n"); | ||
| 109 | goto reject; | ||
| 110 | } | ||
| 111 | if (!asymmetric_key_id_same(id_1, kids->id[1])) { | ||
| 112 | pr_debug("First ID matches, but second does not\n"); | ||
| 113 | goto reject; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | ||
| 118 | return key; | ||
| 119 | |||
| 120 | reject: | ||
| 121 | key_put(key); | ||
| 122 | return ERR_PTR(-EKEYREJECTED); | ||
| 123 | } | ||
| 124 | EXPORT_SYMBOL_GPL(find_asymmetric_key); | ||
| 125 | |||
| 126 | /** | ||
| 38 | * asymmetric_key_generate_id: Construct an asymmetric key ID | 127 | * asymmetric_key_generate_id: Construct an asymmetric key ID |
| 39 | * @val_1: First binary blob | 128 | * @val_1: First binary blob |
| 40 | * @len_1: Length of first binary blob | 129 | * @len_1: Length of first binary blob |
| @@ -331,7 +420,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | |||
| 331 | pr_devel("==>%s()\n", __func__); | 420 | pr_devel("==>%s()\n", __func__); |
| 332 | 421 | ||
| 333 | if (subtype) { | 422 | if (subtype) { |
| 334 | subtype->destroy(prep->payload.data[asym_crypto]); | 423 | subtype->destroy(prep->payload.data[asym_crypto], |
| 424 | prep->payload.data[asym_auth]); | ||
| 335 | module_put(subtype->owner); | 425 | module_put(subtype->owner); |
| 336 | } | 426 | } |
| 337 | asymmetric_key_free_kids(kids); | 427 | asymmetric_key_free_kids(kids); |
| @@ -346,13 +436,15 @@ static void asymmetric_key_destroy(struct key *key) | |||
| 346 | struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | 436 | struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); |
| 347 | struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids]; | 437 | struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids]; |
| 348 | void *data = key->payload.data[asym_crypto]; | 438 | void *data = key->payload.data[asym_crypto]; |
| 439 | void *auth = key->payload.data[asym_auth]; | ||
| 349 | 440 | ||
| 350 | key->payload.data[asym_crypto] = NULL; | 441 | key->payload.data[asym_crypto] = NULL; |
| 351 | key->payload.data[asym_subtype] = NULL; | 442 | key->payload.data[asym_subtype] = NULL; |
| 352 | key->payload.data[asym_key_ids] = NULL; | 443 | key->payload.data[asym_key_ids] = NULL; |
| 444 | key->payload.data[asym_auth] = NULL; | ||
| 353 | 445 | ||
| 354 | if (subtype) { | 446 | if (subtype) { |
| 355 | subtype->destroy(data); | 447 | subtype->destroy(data, auth); |
| 356 | module_put(subtype->owner); | 448 | module_put(subtype->owner); |
| 357 | } | 449 | } |
| 358 | 450 | ||
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index 3242cbfaeaa2..6a76d5c70ef6 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c | |||
| @@ -21,19 +21,13 @@ | |||
| 21 | /* | 21 | /* |
| 22 | * Parse a Microsoft Individual Code Signing blob | 22 | * Parse a Microsoft Individual Code Signing blob |
| 23 | */ | 23 | */ |
| 24 | int mscode_parse(struct pefile_context *ctx) | 24 | int mscode_parse(void *_ctx, const void *content_data, size_t data_len, |
| 25 | size_t asn1hdrlen) | ||
| 25 | { | 26 | { |
| 26 | const void *content_data; | 27 | struct pefile_context *ctx = _ctx; |
| 27 | size_t data_len; | ||
| 28 | int ret; | ||
| 29 | |||
| 30 | ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1); | ||
| 31 | |||
| 32 | if (ret) { | ||
| 33 | pr_debug("PKCS#7 message does not contain data\n"); | ||
| 34 | return ret; | ||
| 35 | } | ||
| 36 | 28 | ||
| 29 | content_data -= asn1hdrlen; | ||
| 30 | data_len += asn1hdrlen; | ||
| 37 | pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), | 31 | pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), |
| 38 | content_data); | 32 | content_data); |
| 39 | 33 | ||
| @@ -129,7 +123,6 @@ int mscode_note_digest(void *context, size_t hdrlen, | |||
| 129 | { | 123 | { |
| 130 | struct pefile_context *ctx = context; | 124 | struct pefile_context *ctx = context; |
| 131 | 125 | ||
| 132 | ctx->digest = value; | 126 | ctx->digest = kmemdup(value, vlen, GFP_KERNEL); |
| 133 | ctx->digest_len = vlen; | 127 | return ctx->digest ? 0 : -ENOMEM; |
| 134 | return 0; | ||
| 135 | } | 128 | } |
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c index e2d0edbbc71a..3b92523882e5 100644 --- a/crypto/asymmetric_keys/pkcs7_key_type.c +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
| @@ -13,12 +13,9 @@ | |||
| 13 | #include <linux/key.h> | 13 | #include <linux/key.h> |
| 14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/verification.h> | ||
| 16 | #include <linux/key-type.h> | 17 | #include <linux/key-type.h> |
| 17 | #include <keys/asymmetric-type.h> | ||
| 18 | #include <crypto/pkcs7.h> | ||
| 19 | #include <keys/user-type.h> | 18 | #include <keys/user-type.h> |
| 20 | #include <keys/system_keyring.h> | ||
| 21 | #include "pkcs7_parser.h" | ||
| 22 | 19 | ||
| 23 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
| 24 | MODULE_DESCRIPTION("PKCS#7 testing key type"); | 21 | MODULE_DESCRIPTION("PKCS#7 testing key type"); |
| @@ -29,60 +26,47 @@ MODULE_PARM_DESC(pkcs7_usage, | |||
| 29 | "Usage to specify when verifying the PKCS#7 message"); | 26 | "Usage to specify when verifying the PKCS#7 message"); |
| 30 | 27 | ||
| 31 | /* | 28 | /* |
| 32 | * Preparse a PKCS#7 wrapped and validated data blob. | 29 | * Retrieve the PKCS#7 message content. |
| 33 | */ | 30 | */ |
| 34 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | 31 | static int pkcs7_view_content(void *ctx, const void *data, size_t len, |
| 32 | size_t asn1hdrlen) | ||
| 35 | { | 33 | { |
| 36 | enum key_being_used_for usage = pkcs7_usage; | 34 | struct key_preparsed_payload *prep = ctx; |
| 37 | struct pkcs7_message *pkcs7; | 35 | const void *saved_prep_data; |
| 38 | const void *data, *saved_prep_data; | 36 | size_t saved_prep_datalen; |
| 39 | size_t datalen, saved_prep_datalen; | ||
| 40 | bool trusted; | ||
| 41 | int ret; | 37 | int ret; |
| 42 | 38 | ||
| 43 | kenter(""); | ||
| 44 | |||
| 45 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
| 46 | pr_err("Invalid usage type %d\n", usage); | ||
| 47 | return -EINVAL; | ||
| 48 | } | ||
| 49 | |||
| 50 | saved_prep_data = prep->data; | 39 | saved_prep_data = prep->data; |
| 51 | saved_prep_datalen = prep->datalen; | 40 | saved_prep_datalen = prep->datalen; |
| 52 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | ||
| 53 | if (IS_ERR(pkcs7)) { | ||
| 54 | ret = PTR_ERR(pkcs7); | ||
| 55 | goto error; | ||
| 56 | } | ||
| 57 | |||
| 58 | ret = pkcs7_verify(pkcs7, usage); | ||
| 59 | if (ret < 0) | ||
| 60 | goto error_free; | ||
| 61 | |||
| 62 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | ||
| 63 | if (ret < 0) | ||
| 64 | goto error_free; | ||
| 65 | if (!trusted) | ||
| 66 | pr_warn("PKCS#7 message doesn't chain back to a trusted key\n"); | ||
| 67 | |||
| 68 | ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false); | ||
| 69 | if (ret < 0) | ||
| 70 | goto error_free; | ||
| 71 | |||
| 72 | prep->data = data; | 41 | prep->data = data; |
| 73 | prep->datalen = datalen; | 42 | prep->datalen = len; |
| 43 | |||
| 74 | ret = user_preparse(prep); | 44 | ret = user_preparse(prep); |
| 45 | |||
| 75 | prep->data = saved_prep_data; | 46 | prep->data = saved_prep_data; |
| 76 | prep->datalen = saved_prep_datalen; | 47 | prep->datalen = saved_prep_datalen; |
| 77 | |||
| 78 | error_free: | ||
| 79 | pkcs7_free_message(pkcs7); | ||
| 80 | error: | ||
| 81 | kleave(" = %d", ret); | ||
| 82 | return ret; | 48 | return ret; |
| 83 | } | 49 | } |
| 84 | 50 | ||
| 85 | /* | 51 | /* |
| 52 | * Preparse a PKCS#7 wrapped and validated data blob. | ||
| 53 | */ | ||
| 54 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | ||
| 55 | { | ||
| 56 | enum key_being_used_for usage = pkcs7_usage; | ||
| 57 | |||
| 58 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
| 59 | pr_err("Invalid usage type %d\n", usage); | ||
| 60 | return -EINVAL; | ||
| 61 | } | ||
| 62 | |||
| 63 | return verify_pkcs7_signature(NULL, 0, | ||
| 64 | prep->data, prep->datalen, | ||
| 65 | NULL, usage, | ||
| 66 | pkcs7_view_content, prep); | ||
| 67 | } | ||
| 68 | |||
| 69 | /* | ||
| 86 | * user defined keys take an arbitrary string as the description and an | 70 | * user defined keys take an arbitrary string as the description and an |
| 87 | * arbitrary blob of data as the payload | 71 | * arbitrary blob of data as the payload |
| 88 | */ | 72 | */ |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index bdd0d753ce5d..af4cd8649117 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
| @@ -44,9 +44,7 @@ struct pkcs7_parse_context { | |||
| 44 | static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo) | 44 | static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo) |
| 45 | { | 45 | { |
| 46 | if (sinfo) { | 46 | if (sinfo) { |
| 47 | kfree(sinfo->sig.s); | 47 | public_key_signature_free(sinfo->sig); |
| 48 | kfree(sinfo->sig.digest); | ||
| 49 | kfree(sinfo->signing_cert_id); | ||
| 50 | kfree(sinfo); | 48 | kfree(sinfo); |
| 51 | } | 49 | } |
| 52 | } | 50 | } |
| @@ -125,6 +123,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) | |||
| 125 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); | 123 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); |
| 126 | if (!ctx->sinfo) | 124 | if (!ctx->sinfo) |
| 127 | goto out_no_sinfo; | 125 | goto out_no_sinfo; |
| 126 | ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature), | ||
| 127 | GFP_KERNEL); | ||
| 128 | if (!ctx->sinfo->sig) | ||
| 129 | goto out_no_sig; | ||
| 128 | 130 | ||
| 129 | ctx->data = (unsigned long)data; | 131 | ctx->data = (unsigned long)data; |
| 130 | ctx->ppcerts = &ctx->certs; | 132 | ctx->ppcerts = &ctx->certs; |
| @@ -150,6 +152,7 @@ out: | |||
| 150 | ctx->certs = cert->next; | 152 | ctx->certs = cert->next; |
| 151 | x509_free_certificate(cert); | 153 | x509_free_certificate(cert); |
| 152 | } | 154 | } |
| 155 | out_no_sig: | ||
| 153 | pkcs7_free_signed_info(ctx->sinfo); | 156 | pkcs7_free_signed_info(ctx->sinfo); |
| 154 | out_no_sinfo: | 157 | out_no_sinfo: |
| 155 | pkcs7_free_message(ctx->msg); | 158 | pkcs7_free_message(ctx->msg); |
| @@ -165,24 +168,25 @@ EXPORT_SYMBOL_GPL(pkcs7_parse_message); | |||
| 165 | * @pkcs7: The preparsed PKCS#7 message to access | 168 | * @pkcs7: The preparsed PKCS#7 message to access |
| 166 | * @_data: Place to return a pointer to the data | 169 | * @_data: Place to return a pointer to the data |
| 167 | * @_data_len: Place to return the data length | 170 | * @_data_len: Place to return the data length |
| 168 | * @want_wrapper: True if the ASN.1 object header should be included in the data | 171 | * @_headerlen: Size of ASN.1 header not included in _data |
| 169 | * | 172 | * |
| 170 | * Get access to the data content of the PKCS#7 message, including, optionally, | 173 | * Get access to the data content of the PKCS#7 message. The size of the |
| 171 | * the header of the ASN.1 object that contains it. Returns -ENODATA if the | 174 | * header of the ASN.1 object that contains it is also provided and can be used |
| 172 | * data object was missing from the message. | 175 | * to adjust *_data and *_data_len to get the entire object. |
| 176 | * | ||
| 177 | * Returns -ENODATA if the data object was missing from the message. | ||
| 173 | */ | 178 | */ |
| 174 | int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | 179 | int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, |
| 175 | const void **_data, size_t *_data_len, | 180 | const void **_data, size_t *_data_len, |
| 176 | bool want_wrapper) | 181 | size_t *_headerlen) |
| 177 | { | 182 | { |
| 178 | size_t wrapper; | ||
| 179 | |||
| 180 | if (!pkcs7->data) | 183 | if (!pkcs7->data) |
| 181 | return -ENODATA; | 184 | return -ENODATA; |
| 182 | 185 | ||
| 183 | wrapper = want_wrapper ? pkcs7->data_hdrlen : 0; | 186 | *_data = pkcs7->data; |
| 184 | *_data = pkcs7->data - wrapper; | 187 | *_data_len = pkcs7->data_len; |
| 185 | *_data_len = pkcs7->data_len + wrapper; | 188 | if (_headerlen) |
| 189 | *_headerlen = pkcs7->data_hdrlen; | ||
| 186 | return 0; | 190 | return 0; |
| 187 | } | 191 | } |
| 188 | EXPORT_SYMBOL_GPL(pkcs7_get_content_data); | 192 | EXPORT_SYMBOL_GPL(pkcs7_get_content_data); |
| @@ -218,25 +222,25 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, | |||
| 218 | 222 | ||
| 219 | switch (ctx->last_oid) { | 223 | switch (ctx->last_oid) { |
| 220 | case OID_md4: | 224 | case OID_md4: |
| 221 | ctx->sinfo->sig.hash_algo = "md4"; | 225 | ctx->sinfo->sig->hash_algo = "md4"; |
| 222 | break; | 226 | break; |
| 223 | case OID_md5: | 227 | case OID_md5: |
| 224 | ctx->sinfo->sig.hash_algo = "md5"; | 228 | ctx->sinfo->sig->hash_algo = "md5"; |
| 225 | break; | 229 | break; |
| 226 | case OID_sha1: | 230 | case OID_sha1: |
| 227 | ctx->sinfo->sig.hash_algo = "sha1"; | 231 | ctx->sinfo->sig->hash_algo = "sha1"; |
| 228 | break; | 232 | break; |
| 229 | case OID_sha256: | 233 | case OID_sha256: |
| 230 | ctx->sinfo->sig.hash_algo = "sha256"; | 234 | ctx->sinfo->sig->hash_algo = "sha256"; |
| 231 | break; | 235 | break; |
| 232 | case OID_sha384: | 236 | case OID_sha384: |
| 233 | ctx->sinfo->sig.hash_algo = "sha384"; | 237 | ctx->sinfo->sig->hash_algo = "sha384"; |
| 234 | break; | 238 | break; |
| 235 | case OID_sha512: | 239 | case OID_sha512: |
| 236 | ctx->sinfo->sig.hash_algo = "sha512"; | 240 | ctx->sinfo->sig->hash_algo = "sha512"; |
| 237 | break; | 241 | break; |
| 238 | case OID_sha224: | 242 | case OID_sha224: |
| 239 | ctx->sinfo->sig.hash_algo = "sha224"; | 243 | ctx->sinfo->sig->hash_algo = "sha224"; |
| 240 | break; | 244 | break; |
| 241 | default: | 245 | default: |
| 242 | printk("Unsupported digest algo: %u\n", ctx->last_oid); | 246 | printk("Unsupported digest algo: %u\n", ctx->last_oid); |
| @@ -256,7 +260,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, | |||
| 256 | 260 | ||
| 257 | switch (ctx->last_oid) { | 261 | switch (ctx->last_oid) { |
| 258 | case OID_rsaEncryption: | 262 | case OID_rsaEncryption: |
| 259 | ctx->sinfo->sig.pkey_algo = "rsa"; | 263 | ctx->sinfo->sig->pkey_algo = "rsa"; |
| 260 | break; | 264 | break; |
| 261 | default: | 265 | default: |
| 262 | printk("Unsupported pkey algo: %u\n", ctx->last_oid); | 266 | printk("Unsupported pkey algo: %u\n", ctx->last_oid); |
| @@ -616,11 +620,11 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen, | |||
| 616 | { | 620 | { |
| 617 | struct pkcs7_parse_context *ctx = context; | 621 | struct pkcs7_parse_context *ctx = context; |
| 618 | 622 | ||
| 619 | ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL); | 623 | ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL); |
| 620 | if (!ctx->sinfo->sig.s) | 624 | if (!ctx->sinfo->sig->s) |
| 621 | return -ENOMEM; | 625 | return -ENOMEM; |
| 622 | 626 | ||
| 623 | ctx->sinfo->sig.s_size = vlen; | 627 | ctx->sinfo->sig->s_size = vlen; |
| 624 | return 0; | 628 | return 0; |
| 625 | } | 629 | } |
| 626 | 630 | ||
| @@ -656,12 +660,16 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen, | |||
| 656 | 660 | ||
| 657 | pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data); | 661 | pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data); |
| 658 | 662 | ||
| 659 | sinfo->signing_cert_id = kid; | 663 | sinfo->sig->auth_ids[0] = kid; |
| 660 | sinfo->index = ++ctx->sinfo_index; | 664 | sinfo->index = ++ctx->sinfo_index; |
| 661 | *ctx->ppsinfo = sinfo; | 665 | *ctx->ppsinfo = sinfo; |
| 662 | ctx->ppsinfo = &sinfo->next; | 666 | ctx->ppsinfo = &sinfo->next; |
| 663 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); | 667 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); |
| 664 | if (!ctx->sinfo) | 668 | if (!ctx->sinfo) |
| 665 | return -ENOMEM; | 669 | return -ENOMEM; |
| 670 | ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature), | ||
| 671 | GFP_KERNEL); | ||
| 672 | if (!ctx->sinfo->sig) | ||
| 673 | return -ENOMEM; | ||
| 666 | return 0; | 674 | return 0; |
| 667 | } | 675 | } |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h index a66b19ebcf47..f4e81074f5e0 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.h +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
| @@ -22,7 +22,6 @@ struct pkcs7_signed_info { | |||
| 22 | struct pkcs7_signed_info *next; | 22 | struct pkcs7_signed_info *next; |
| 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ | 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ |
| 24 | unsigned index; | 24 | unsigned index; |
| 25 | bool trusted; | ||
| 26 | bool unsupported_crypto; /* T if not usable due to missing crypto */ | 25 | bool unsupported_crypto; /* T if not usable due to missing crypto */ |
| 27 | 26 | ||
| 28 | /* Message digest - the digest of the Content Data (or NULL) */ | 27 | /* Message digest - the digest of the Content Data (or NULL) */ |
| @@ -41,19 +40,17 @@ struct pkcs7_signed_info { | |||
| 41 | #define sinfo_has_ms_statement_type 5 | 40 | #define sinfo_has_ms_statement_type 5 |
| 42 | time64_t signing_time; | 41 | time64_t signing_time; |
| 43 | 42 | ||
| 44 | /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1] | ||
| 45 | * or issuing cert's SKID [CMS ver 3]. | ||
| 46 | */ | ||
| 47 | struct asymmetric_key_id *signing_cert_id; | ||
| 48 | |||
| 49 | /* Message signature. | 43 | /* Message signature. |
| 50 | * | 44 | * |
| 51 | * This contains the generated digest of _either_ the Content Data or | 45 | * This contains the generated digest of _either_ the Content Data or |
| 52 | * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of | 46 | * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of |
| 53 | * the attributes contains the digest of the the Content Data within | 47 | * the attributes contains the digest of the the Content Data within |
| 54 | * it. | 48 | * it. |
| 49 | * | ||
| 50 | * THis also contains the issuing cert serial number and issuer's name | ||
| 51 | * [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3]. | ||
| 55 | */ | 52 | */ |
| 56 | struct public_key_signature sig; | 53 | struct public_key_signature *sig; |
| 57 | }; | 54 | }; |
| 58 | 55 | ||
| 59 | struct pkcs7_message { | 56 | struct pkcs7_message { |
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 7d7a39b47c62..f6a009d88a33 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
| @@ -27,10 +27,9 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 27 | struct pkcs7_signed_info *sinfo, | 27 | struct pkcs7_signed_info *sinfo, |
| 28 | struct key *trust_keyring) | 28 | struct key *trust_keyring) |
| 29 | { | 29 | { |
| 30 | struct public_key_signature *sig = &sinfo->sig; | 30 | struct public_key_signature *sig = sinfo->sig; |
| 31 | struct x509_certificate *x509, *last = NULL, *p; | 31 | struct x509_certificate *x509, *last = NULL, *p; |
| 32 | struct key *key; | 32 | struct key *key; |
| 33 | bool trusted; | ||
| 34 | int ret; | 33 | int ret; |
| 35 | 34 | ||
| 36 | kenter(",%u,", sinfo->index); | 35 | kenter(",%u,", sinfo->index); |
| @@ -42,10 +41,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 42 | 41 | ||
| 43 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { | 42 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { |
| 44 | if (x509->seen) { | 43 | if (x509->seen) { |
| 45 | if (x509->verified) { | 44 | if (x509->verified) |
| 46 | trusted = x509->trusted; | ||
| 47 | goto verified; | 45 | goto verified; |
| 48 | } | ||
| 49 | kleave(" = -ENOKEY [cached]"); | 46 | kleave(" = -ENOKEY [cached]"); |
| 50 | return -ENOKEY; | 47 | return -ENOKEY; |
| 51 | } | 48 | } |
| @@ -54,9 +51,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 54 | /* Look to see if this certificate is present in the trusted | 51 | /* Look to see if this certificate is present in the trusted |
| 55 | * keys. | 52 | * keys. |
| 56 | */ | 53 | */ |
| 57 | key = x509_request_asymmetric_key(trust_keyring, | 54 | key = find_asymmetric_key(trust_keyring, |
| 58 | x509->id, x509->skid, | 55 | x509->id, x509->skid, false); |
| 59 | false); | ||
| 60 | if (!IS_ERR(key)) { | 56 | if (!IS_ERR(key)) { |
| 61 | /* One of the X.509 certificates in the PKCS#7 message | 57 | /* One of the X.509 certificates in the PKCS#7 message |
| 62 | * is apparently the same as one we already trust. | 58 | * is apparently the same as one we already trust. |
| @@ -80,17 +76,17 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 80 | 76 | ||
| 81 | might_sleep(); | 77 | might_sleep(); |
| 82 | last = x509; | 78 | last = x509; |
| 83 | sig = &last->sig; | 79 | sig = last->sig; |
| 84 | } | 80 | } |
| 85 | 81 | ||
| 86 | /* No match - see if the root certificate has a signer amongst the | 82 | /* No match - see if the root certificate has a signer amongst the |
| 87 | * trusted keys. | 83 | * trusted keys. |
| 88 | */ | 84 | */ |
| 89 | if (last && (last->akid_id || last->akid_skid)) { | 85 | if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) { |
| 90 | key = x509_request_asymmetric_key(trust_keyring, | 86 | key = find_asymmetric_key(trust_keyring, |
| 91 | last->akid_id, | 87 | last->sig->auth_ids[0], |
| 92 | last->akid_skid, | 88 | last->sig->auth_ids[1], |
| 93 | false); | 89 | false); |
| 94 | if (!IS_ERR(key)) { | 90 | if (!IS_ERR(key)) { |
| 95 | x509 = last; | 91 | x509 = last; |
| 96 | pr_devel("sinfo %u: Root cert %u signer is key %x\n", | 92 | pr_devel("sinfo %u: Root cert %u signer is key %x\n", |
| @@ -104,10 +100,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 104 | /* As a last resort, see if we have a trusted public key that matches | 100 | /* As a last resort, see if we have a trusted public key that matches |
| 105 | * the signed info directly. | 101 | * the signed info directly. |
| 106 | */ | 102 | */ |
| 107 | key = x509_request_asymmetric_key(trust_keyring, | 103 | key = find_asymmetric_key(trust_keyring, |
| 108 | sinfo->signing_cert_id, | 104 | sinfo->sig->auth_ids[0], NULL, false); |
| 109 | NULL, | ||
| 110 | false); | ||
| 111 | if (!IS_ERR(key)) { | 105 | if (!IS_ERR(key)) { |
| 112 | pr_devel("sinfo %u: Direct signer is key %x\n", | 106 | pr_devel("sinfo %u: Direct signer is key %x\n", |
| 113 | sinfo->index, key_serial(key)); | 107 | sinfo->index, key_serial(key)); |
| @@ -122,7 +116,6 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 122 | 116 | ||
| 123 | matched: | 117 | matched: |
| 124 | ret = verify_signature(key, sig); | 118 | ret = verify_signature(key, sig); |
| 125 | trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); | ||
| 126 | key_put(key); | 119 | key_put(key); |
| 127 | if (ret < 0) { | 120 | if (ret < 0) { |
| 128 | if (ret == -ENOMEM) | 121 | if (ret == -ENOMEM) |
| @@ -134,12 +127,9 @@ matched: | |||
| 134 | verified: | 127 | verified: |
| 135 | if (x509) { | 128 | if (x509) { |
| 136 | x509->verified = true; | 129 | x509->verified = true; |
| 137 | for (p = sinfo->signer; p != x509; p = p->signer) { | 130 | for (p = sinfo->signer; p != x509; p = p->signer) |
| 138 | p->verified = true; | 131 | p->verified = true; |
| 139 | p->trusted = trusted; | ||
| 140 | } | ||
| 141 | } | 132 | } |
| 142 | sinfo->trusted = trusted; | ||
| 143 | kleave(" = 0"); | 133 | kleave(" = 0"); |
| 144 | return 0; | 134 | return 0; |
| 145 | } | 135 | } |
| @@ -148,7 +138,6 @@ verified: | |||
| 148 | * pkcs7_validate_trust - Validate PKCS#7 trust chain | 138 | * pkcs7_validate_trust - Validate PKCS#7 trust chain |
| 149 | * @pkcs7: The PKCS#7 certificate to validate | 139 | * @pkcs7: The PKCS#7 certificate to validate |
| 150 | * @trust_keyring: Signing certificates to use as starting points | 140 | * @trust_keyring: Signing certificates to use as starting points |
| 151 | * @_trusted: Set to true if trustworth, false otherwise | ||
| 152 | * | 141 | * |
| 153 | * Validate that the certificate chain inside the PKCS#7 message intersects | 142 | * Validate that the certificate chain inside the PKCS#7 message intersects |
| 154 | * keys we already know and trust. | 143 | * keys we already know and trust. |
| @@ -170,16 +159,13 @@ verified: | |||
| 170 | * May also return -ENOMEM. | 159 | * May also return -ENOMEM. |
| 171 | */ | 160 | */ |
| 172 | int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | 161 | int pkcs7_validate_trust(struct pkcs7_message *pkcs7, |
| 173 | struct key *trust_keyring, | 162 | struct key *trust_keyring) |
| 174 | bool *_trusted) | ||
| 175 | { | 163 | { |
| 176 | struct pkcs7_signed_info *sinfo; | 164 | struct pkcs7_signed_info *sinfo; |
| 177 | struct x509_certificate *p; | 165 | struct x509_certificate *p; |
| 178 | int cached_ret = -ENOKEY; | 166 | int cached_ret = -ENOKEY; |
| 179 | int ret; | 167 | int ret; |
| 180 | 168 | ||
| 181 | *_trusted = false; | ||
| 182 | |||
| 183 | for (p = pkcs7->certs; p; p = p->next) | 169 | for (p = pkcs7->certs; p; p = p->next) |
| 184 | p->seen = false; | 170 | p->seen = false; |
| 185 | 171 | ||
| @@ -193,7 +179,6 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | |||
| 193 | cached_ret = -ENOPKG; | 179 | cached_ret = -ENOPKG; |
| 194 | continue; | 180 | continue; |
| 195 | case 0: | 181 | case 0: |
| 196 | *_trusted |= sinfo->trusted; | ||
| 197 | cached_ret = 0; | 182 | cached_ret = 0; |
| 198 | continue; | 183 | continue; |
| 199 | default: | 184 | default: |
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 50be2a15e531..44b746e9df1b 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
| @@ -25,34 +25,36 @@ | |||
| 25 | static int pkcs7_digest(struct pkcs7_message *pkcs7, | 25 | static int pkcs7_digest(struct pkcs7_message *pkcs7, |
| 26 | struct pkcs7_signed_info *sinfo) | 26 | struct pkcs7_signed_info *sinfo) |
| 27 | { | 27 | { |
| 28 | struct public_key_signature *sig = sinfo->sig; | ||
| 28 | struct crypto_shash *tfm; | 29 | struct crypto_shash *tfm; |
| 29 | struct shash_desc *desc; | 30 | struct shash_desc *desc; |
| 30 | size_t digest_size, desc_size; | 31 | size_t desc_size; |
| 31 | void *digest; | ||
| 32 | int ret; | 32 | int ret; |
| 33 | 33 | ||
| 34 | kenter(",%u,%s", sinfo->index, sinfo->sig.hash_algo); | 34 | kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo); |
| 35 | 35 | ||
| 36 | if (!sinfo->sig.hash_algo) | 36 | if (!sinfo->sig->hash_algo) |
| 37 | return -ENOPKG; | 37 | return -ENOPKG; |
| 38 | 38 | ||
| 39 | /* Allocate the hashing algorithm we're going to need and find out how | 39 | /* Allocate the hashing algorithm we're going to need and find out how |
| 40 | * big the hash operational data will be. | 40 | * big the hash operational data will be. |
| 41 | */ | 41 | */ |
| 42 | tfm = crypto_alloc_shash(sinfo->sig.hash_algo, 0, 0); | 42 | tfm = crypto_alloc_shash(sinfo->sig->hash_algo, 0, 0); |
| 43 | if (IS_ERR(tfm)) | 43 | if (IS_ERR(tfm)) |
| 44 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | 44 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); |
| 45 | 45 | ||
| 46 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | 46 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); |
| 47 | sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm); | 47 | sig->digest_size = crypto_shash_digestsize(tfm); |
| 48 | 48 | ||
| 49 | ret = -ENOMEM; | 49 | ret = -ENOMEM; |
| 50 | digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size, | 50 | sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); |
| 51 | GFP_KERNEL); | 51 | if (!sig->digest) |
| 52 | if (!digest) | 52 | goto error_no_desc; |
| 53 | |||
| 54 | desc = kzalloc(desc_size, GFP_KERNEL); | ||
| 55 | if (!desc) | ||
| 53 | goto error_no_desc; | 56 | goto error_no_desc; |
| 54 | 57 | ||
| 55 | desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc)); | ||
| 56 | desc->tfm = tfm; | 58 | desc->tfm = tfm; |
| 57 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 59 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
| 58 | 60 | ||
| @@ -60,10 +62,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 60 | ret = crypto_shash_init(desc); | 62 | ret = crypto_shash_init(desc); |
| 61 | if (ret < 0) | 63 | if (ret < 0) |
| 62 | goto error; | 64 | goto error; |
| 63 | ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest); | 65 | ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, |
| 66 | sig->digest); | ||
| 64 | if (ret < 0) | 67 | if (ret < 0) |
| 65 | goto error; | 68 | goto error; |
| 66 | pr_devel("MsgDigest = [%*ph]\n", 8, digest); | 69 | pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest); |
| 67 | 70 | ||
| 68 | /* However, if there are authenticated attributes, there must be a | 71 | /* However, if there are authenticated attributes, there must be a |
| 69 | * message digest attribute amongst them which corresponds to the | 72 | * message digest attribute amongst them which corresponds to the |
| @@ -78,14 +81,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 78 | goto error; | 81 | goto error; |
| 79 | } | 82 | } |
| 80 | 83 | ||
| 81 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { | 84 | if (sinfo->msgdigest_len != sig->digest_size) { |
| 82 | pr_debug("Sig %u: Invalid digest size (%u)\n", | 85 | pr_debug("Sig %u: Invalid digest size (%u)\n", |
| 83 | sinfo->index, sinfo->msgdigest_len); | 86 | sinfo->index, sinfo->msgdigest_len); |
| 84 | ret = -EBADMSG; | 87 | ret = -EBADMSG; |
| 85 | goto error; | 88 | goto error; |
| 86 | } | 89 | } |
| 87 | 90 | ||
| 88 | if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) { | 91 | if (memcmp(sig->digest, sinfo->msgdigest, |
| 92 | sinfo->msgdigest_len) != 0) { | ||
| 89 | pr_debug("Sig %u: Message digest doesn't match\n", | 93 | pr_debug("Sig %u: Message digest doesn't match\n", |
| 90 | sinfo->index); | 94 | sinfo->index); |
| 91 | ret = -EKEYREJECTED; | 95 | ret = -EKEYREJECTED; |
| @@ -97,7 +101,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 97 | * convert the attributes from a CONT.0 into a SET before we | 101 | * convert the attributes from a CONT.0 into a SET before we |
| 98 | * hash it. | 102 | * hash it. |
| 99 | */ | 103 | */ |
| 100 | memset(digest, 0, sinfo->sig.digest_size); | 104 | memset(sig->digest, 0, sig->digest_size); |
| 101 | 105 | ||
| 102 | ret = crypto_shash_init(desc); | 106 | ret = crypto_shash_init(desc); |
| 103 | if (ret < 0) | 107 | if (ret < 0) |
| @@ -107,17 +111,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 107 | if (ret < 0) | 111 | if (ret < 0) |
| 108 | goto error; | 112 | goto error; |
| 109 | ret = crypto_shash_finup(desc, sinfo->authattrs, | 113 | ret = crypto_shash_finup(desc, sinfo->authattrs, |
| 110 | sinfo->authattrs_len, digest); | 114 | sinfo->authattrs_len, sig->digest); |
| 111 | if (ret < 0) | 115 | if (ret < 0) |
| 112 | goto error; | 116 | goto error; |
| 113 | pr_devel("AADigest = [%*ph]\n", 8, digest); | 117 | pr_devel("AADigest = [%*ph]\n", 8, sig->digest); |
| 114 | } | 118 | } |
| 115 | 119 | ||
| 116 | sinfo->sig.digest = digest; | ||
| 117 | digest = NULL; | ||
| 118 | |||
| 119 | error: | 120 | error: |
| 120 | kfree(digest); | 121 | kfree(desc); |
| 121 | error_no_desc: | 122 | error_no_desc: |
| 122 | crypto_free_shash(tfm); | 123 | crypto_free_shash(tfm); |
| 123 | kleave(" = %d", ret); | 124 | kleave(" = %d", ret); |
| @@ -144,12 +145,12 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, | |||
| 144 | * PKCS#7 message - but I can't be 100% sure of that. It's | 145 | * PKCS#7 message - but I can't be 100% sure of that. It's |
| 145 | * possible this will need element-by-element comparison. | 146 | * possible this will need element-by-element comparison. |
| 146 | */ | 147 | */ |
| 147 | if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id)) | 148 | if (!asymmetric_key_id_same(x509->id, sinfo->sig->auth_ids[0])) |
| 148 | continue; | 149 | continue; |
| 149 | pr_devel("Sig %u: Found cert serial match X.509[%u]\n", | 150 | pr_devel("Sig %u: Found cert serial match X.509[%u]\n", |
| 150 | sinfo->index, certix); | 151 | sinfo->index, certix); |
| 151 | 152 | ||
| 152 | if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) { | 153 | if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) { |
| 153 | pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", | 154 | pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", |
| 154 | sinfo->index); | 155 | sinfo->index); |
| 155 | continue; | 156 | continue; |
| @@ -164,7 +165,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, | |||
| 164 | */ | 165 | */ |
| 165 | pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n", | 166 | pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n", |
| 166 | sinfo->index, | 167 | sinfo->index, |
| 167 | sinfo->signing_cert_id->len, sinfo->signing_cert_id->data); | 168 | sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data); |
| 168 | return 0; | 169 | return 0; |
| 169 | } | 170 | } |
| 170 | 171 | ||
| @@ -174,6 +175,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, | |||
| 174 | static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | 175 | static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, |
| 175 | struct pkcs7_signed_info *sinfo) | 176 | struct pkcs7_signed_info *sinfo) |
| 176 | { | 177 | { |
| 178 | struct public_key_signature *sig; | ||
| 177 | struct x509_certificate *x509 = sinfo->signer, *p; | 179 | struct x509_certificate *x509 = sinfo->signer, *p; |
| 178 | struct asymmetric_key_id *auth; | 180 | struct asymmetric_key_id *auth; |
| 179 | int ret; | 181 | int ret; |
| @@ -188,34 +190,26 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 188 | x509->subject, | 190 | x509->subject, |
| 189 | x509->raw_serial_size, x509->raw_serial); | 191 | x509->raw_serial_size, x509->raw_serial); |
| 190 | x509->seen = true; | 192 | x509->seen = true; |
| 191 | ret = x509_get_sig_params(x509); | 193 | if (x509->unsupported_key) |
| 192 | if (ret < 0) | 194 | goto unsupported_crypto_in_x509; |
| 193 | goto maybe_missing_crypto_in_x509; | ||
| 194 | 195 | ||
| 195 | pr_debug("- issuer %s\n", x509->issuer); | 196 | pr_debug("- issuer %s\n", x509->issuer); |
| 196 | if (x509->akid_id) | 197 | sig = x509->sig; |
| 198 | if (sig->auth_ids[0]) | ||
| 197 | pr_debug("- authkeyid.id %*phN\n", | 199 | pr_debug("- authkeyid.id %*phN\n", |
| 198 | x509->akid_id->len, x509->akid_id->data); | 200 | sig->auth_ids[0]->len, sig->auth_ids[0]->data); |
| 199 | if (x509->akid_skid) | 201 | if (sig->auth_ids[1]) |
| 200 | pr_debug("- authkeyid.skid %*phN\n", | 202 | pr_debug("- authkeyid.skid %*phN\n", |
| 201 | x509->akid_skid->len, x509->akid_skid->data); | 203 | sig->auth_ids[1]->len, sig->auth_ids[1]->data); |
| 202 | 204 | ||
| 203 | if ((!x509->akid_id && !x509->akid_skid) || | 205 | if (x509->self_signed) { |
| 204 | strcmp(x509->subject, x509->issuer) == 0) { | ||
| 205 | /* If there's no authority certificate specified, then | 206 | /* If there's no authority certificate specified, then |
| 206 | * the certificate must be self-signed and is the root | 207 | * the certificate must be self-signed and is the root |
| 207 | * of the chain. Likewise if the cert is its own | 208 | * of the chain. Likewise if the cert is its own |
| 208 | * authority. | 209 | * authority. |
| 209 | */ | 210 | */ |
| 210 | pr_debug("- no auth?\n"); | 211 | if (x509->unsupported_sig) |
| 211 | if (x509->raw_subject_size != x509->raw_issuer_size || | 212 | goto unsupported_crypto_in_x509; |
| 212 | memcmp(x509->raw_subject, x509->raw_issuer, | ||
| 213 | x509->raw_issuer_size) != 0) | ||
| 214 | return 0; | ||
| 215 | |||
| 216 | ret = x509_check_signature(x509->pub, x509); | ||
| 217 | if (ret < 0) | ||
| 218 | goto maybe_missing_crypto_in_x509; | ||
| 219 | x509->signer = x509; | 213 | x509->signer = x509; |
| 220 | pr_debug("- self-signed\n"); | 214 | pr_debug("- self-signed\n"); |
| 221 | return 0; | 215 | return 0; |
| @@ -224,7 +218,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 224 | /* Look through the X.509 certificates in the PKCS#7 message's | 218 | /* Look through the X.509 certificates in the PKCS#7 message's |
| 225 | * list to see if the next one is there. | 219 | * list to see if the next one is there. |
| 226 | */ | 220 | */ |
| 227 | auth = x509->akid_id; | 221 | auth = sig->auth_ids[0]; |
| 228 | if (auth) { | 222 | if (auth) { |
| 229 | pr_debug("- want %*phN\n", auth->len, auth->data); | 223 | pr_debug("- want %*phN\n", auth->len, auth->data); |
| 230 | for (p = pkcs7->certs; p; p = p->next) { | 224 | for (p = pkcs7->certs; p; p = p->next) { |
| @@ -234,7 +228,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 234 | goto found_issuer_check_skid; | 228 | goto found_issuer_check_skid; |
| 235 | } | 229 | } |
| 236 | } else { | 230 | } else { |
| 237 | auth = x509->akid_skid; | 231 | auth = sig->auth_ids[1]; |
| 238 | pr_debug("- want %*phN\n", auth->len, auth->data); | 232 | pr_debug("- want %*phN\n", auth->len, auth->data); |
| 239 | for (p = pkcs7->certs; p; p = p->next) { | 233 | for (p = pkcs7->certs; p; p = p->next) { |
| 240 | if (!p->skid) | 234 | if (!p->skid) |
| @@ -254,8 +248,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 254 | /* We matched issuer + serialNumber, but if there's an | 248 | /* We matched issuer + serialNumber, but if there's an |
| 255 | * authKeyId.keyId, that must match the CA subjKeyId also. | 249 | * authKeyId.keyId, that must match the CA subjKeyId also. |
| 256 | */ | 250 | */ |
| 257 | if (x509->akid_skid && | 251 | if (sig->auth_ids[1] && |
| 258 | !asymmetric_key_id_same(p->skid, x509->akid_skid)) { | 252 | !asymmetric_key_id_same(p->skid, sig->auth_ids[1])) { |
| 259 | pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n", | 253 | pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n", |
| 260 | sinfo->index, x509->index, p->index); | 254 | sinfo->index, x509->index, p->index); |
| 261 | return -EKEYREJECTED; | 255 | return -EKEYREJECTED; |
| @@ -267,7 +261,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 267 | sinfo->index); | 261 | sinfo->index); |
| 268 | return 0; | 262 | return 0; |
| 269 | } | 263 | } |
| 270 | ret = x509_check_signature(p->pub, x509); | 264 | ret = public_key_verify_signature(p->pub, p->sig); |
| 271 | if (ret < 0) | 265 | if (ret < 0) |
| 272 | return ret; | 266 | return ret; |
| 273 | x509->signer = p; | 267 | x509->signer = p; |
| @@ -279,16 +273,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 279 | might_sleep(); | 273 | might_sleep(); |
| 280 | } | 274 | } |
| 281 | 275 | ||
| 282 | maybe_missing_crypto_in_x509: | 276 | unsupported_crypto_in_x509: |
| 283 | /* Just prune the certificate chain at this point if we lack some | 277 | /* Just prune the certificate chain at this point if we lack some |
| 284 | * crypto module to go further. Note, however, we don't want to set | 278 | * crypto module to go further. Note, however, we don't want to set |
| 285 | * sinfo->missing_crypto as the signed info block may still be | 279 | * sinfo->unsupported_crypto as the signed info block may still be |
| 286 | * validatable against an X.509 cert lower in the chain that we have a | 280 | * validatable against an X.509 cert lower in the chain that we have a |
| 287 | * trusted copy of. | 281 | * trusted copy of. |
| 288 | */ | 282 | */ |
| 289 | if (ret == -ENOPKG) | 283 | return 0; |
| 290 | return 0; | ||
| 291 | return ret; | ||
| 292 | } | 284 | } |
| 293 | 285 | ||
| 294 | /* | 286 | /* |
| @@ -332,7 +324,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 332 | } | 324 | } |
| 333 | 325 | ||
| 334 | /* Verify the PKCS#7 binary against the key */ | 326 | /* Verify the PKCS#7 binary against the key */ |
| 335 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | 327 | ret = public_key_verify_signature(sinfo->signer->pub, sinfo->sig); |
| 336 | if (ret < 0) | 328 | if (ret < 0) |
| 337 | return ret; | 329 | return ret; |
| 338 | 330 | ||
| @@ -375,9 +367,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, | |||
| 375 | enum key_being_used_for usage) | 367 | enum key_being_used_for usage) |
| 376 | { | 368 | { |
| 377 | struct pkcs7_signed_info *sinfo; | 369 | struct pkcs7_signed_info *sinfo; |
| 378 | struct x509_certificate *x509; | ||
| 379 | int enopkg = -ENOPKG; | 370 | int enopkg = -ENOPKG; |
| 380 | int ret, n; | 371 | int ret; |
| 381 | 372 | ||
| 382 | kenter(""); | 373 | kenter(""); |
| 383 | 374 | ||
| @@ -419,12 +410,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, | |||
| 419 | return -EINVAL; | 410 | return -EINVAL; |
| 420 | } | 411 | } |
| 421 | 412 | ||
| 422 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | ||
| 423 | ret = x509_get_sig_params(x509); | ||
| 424 | if (ret < 0) | ||
| 425 | return ret; | ||
| 426 | } | ||
| 427 | |||
| 428 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 413 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
| 429 | ret = pkcs7_verify_one(pkcs7, sinfo); | 414 | ret = pkcs7_verify_one(pkcs7, sinfo); |
| 430 | if (ret < 0) { | 415 | if (ret < 0) { |
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 0f8b264b3961..fd76b5fc3b3a 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c | |||
| @@ -39,15 +39,23 @@ static void public_key_describe(const struct key *asymmetric_key, | |||
| 39 | /* | 39 | /* |
| 40 | * Destroy a public key algorithm key. | 40 | * Destroy a public key algorithm key. |
| 41 | */ | 41 | */ |
| 42 | void public_key_destroy(void *payload) | 42 | void public_key_free(struct public_key *key) |
| 43 | { | 43 | { |
| 44 | struct public_key *key = payload; | 44 | if (key) { |
| 45 | |||
| 46 | if (key) | ||
| 47 | kfree(key->key); | 45 | kfree(key->key); |
| 48 | kfree(key); | 46 | kfree(key); |
| 47 | } | ||
| 48 | } | ||
| 49 | EXPORT_SYMBOL_GPL(public_key_free); | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Destroy a public key algorithm key. | ||
| 53 | */ | ||
| 54 | static void public_key_destroy(void *payload0, void *payload3) | ||
| 55 | { | ||
| 56 | public_key_free(payload0); | ||
| 57 | public_key_signature_free(payload3); | ||
| 49 | } | 58 | } |
| 50 | EXPORT_SYMBOL_GPL(public_key_destroy); | ||
| 51 | 59 | ||
| 52 | struct public_key_completion { | 60 | struct public_key_completion { |
| 53 | struct completion completion; | 61 | struct completion completion; |
diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c new file mode 100644 index 000000000000..ac4bddf669de --- /dev/null +++ b/crypto/asymmetric_keys/restrict.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | /* Instantiate a public key crypto key from an X.509 Certificate | ||
| 2 | * | ||
| 3 | * Copyright (C) 2012, 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) "ASYM: "fmt | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <crypto/public_key.h> | ||
| 17 | #include "asymmetric_keys.h" | ||
| 18 | |||
| 19 | static bool use_builtin_keys; | ||
| 20 | static struct asymmetric_key_id *ca_keyid; | ||
| 21 | |||
| 22 | #ifndef MODULE | ||
| 23 | static struct { | ||
| 24 | struct asymmetric_key_id id; | ||
| 25 | unsigned char data[10]; | ||
| 26 | } cakey; | ||
| 27 | |||
| 28 | static int __init ca_keys_setup(char *str) | ||
| 29 | { | ||
| 30 | if (!str) /* default system keyring */ | ||
| 31 | return 1; | ||
| 32 | |||
| 33 | if (strncmp(str, "id:", 3) == 0) { | ||
| 34 | struct asymmetric_key_id *p = &cakey.id; | ||
| 35 | size_t hexlen = (strlen(str) - 3) / 2; | ||
| 36 | int ret; | ||
| 37 | |||
| 38 | if (hexlen == 0 || hexlen > sizeof(cakey.data)) { | ||
| 39 | pr_err("Missing or invalid ca_keys id\n"); | ||
| 40 | return 1; | ||
| 41 | } | ||
| 42 | |||
| 43 | ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); | ||
| 44 | if (ret < 0) | ||
| 45 | pr_err("Unparsable ca_keys id hex string\n"); | ||
| 46 | else | ||
| 47 | ca_keyid = p; /* owner key 'id:xxxxxx' */ | ||
| 48 | } else if (strcmp(str, "builtin") == 0) { | ||
| 49 | use_builtin_keys = true; | ||
| 50 | } | ||
| 51 | |||
| 52 | return 1; | ||
| 53 | } | ||
| 54 | __setup("ca_keys=", ca_keys_setup); | ||
| 55 | #endif | ||
| 56 | |||
| 57 | /** | ||
| 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. | ||
| 60 | * @type: The type of key being added. | ||
| 61 | * @payload: The payload of the new key. | ||
| 62 | * | ||
| 63 | * Check the new certificate against the ones in the trust keyring. If one of | ||
| 64 | * those is the signing key and validates the new certificate, then mark the | ||
| 65 | * new certificate as being trusted. | ||
| 66 | * | ||
| 67 | * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a | ||
| 68 | * matching parent certificate in the trusted list, -EKEYREJECTED if the | ||
| 69 | * signature check fails or the key is blacklisted and some other error if | ||
| 70 | * there is a matching certificate but the signature check cannot be performed. | ||
| 71 | */ | ||
| 72 | int restrict_link_by_signature(struct key *trust_keyring, | ||
| 73 | const struct key_type *type, | ||
| 74 | const union key_payload *payload) | ||
| 75 | { | ||
| 76 | const struct public_key_signature *sig; | ||
| 77 | struct key *key; | ||
| 78 | int ret; | ||
| 79 | |||
| 80 | pr_devel("==>%s()\n", __func__); | ||
| 81 | |||
| 82 | if (!trust_keyring) | ||
| 83 | return -ENOKEY; | ||
| 84 | |||
| 85 | if (type != &key_type_asymmetric) | ||
| 86 | return -EOPNOTSUPP; | ||
| 87 | |||
| 88 | sig = payload->data[asym_auth]; | ||
| 89 | if (!sig->auth_ids[0] && !sig->auth_ids[1]) | ||
| 90 | return 0; | ||
| 91 | |||
| 92 | if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) | ||
| 93 | return -EPERM; | ||
| 94 | |||
| 95 | /* See if we have a key that signed this one. */ | ||
| 96 | key = find_asymmetric_key(trust_keyring, | ||
| 97 | sig->auth_ids[0], sig->auth_ids[1], | ||
| 98 | false); | ||
| 99 | if (IS_ERR(key)) | ||
| 100 | return -ENOKEY; | ||
| 101 | |||
| 102 | if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags)) | ||
| 103 | ret = -ENOKEY; | ||
| 104 | else | ||
| 105 | ret = verify_signature(key, sig); | ||
| 106 | key_put(key); | ||
| 107 | return ret; | ||
| 108 | } | ||
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c index 004d5fc8e56b..11b7ba170904 100644 --- a/crypto/asymmetric_keys/signature.c +++ b/crypto/asymmetric_keys/signature.c | |||
| @@ -15,9 +15,27 @@ | |||
| 15 | #include <keys/asymmetric-subtype.h> | 15 | #include <keys/asymmetric-subtype.h> |
| 16 | #include <linux/export.h> | 16 | #include <linux/export.h> |
| 17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
| 18 | #include <linux/slab.h> | ||
| 18 | #include <crypto/public_key.h> | 19 | #include <crypto/public_key.h> |
| 19 | #include "asymmetric_keys.h" | 20 | #include "asymmetric_keys.h" |
| 20 | 21 | ||
| 22 | /* | ||
| 23 | * Destroy a public key signature. | ||
| 24 | */ | ||
| 25 | void public_key_signature_free(struct public_key_signature *sig) | ||
| 26 | { | ||
| 27 | int i; | ||
| 28 | |||
| 29 | if (sig) { | ||
| 30 | for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++) | ||
| 31 | kfree(sig->auth_ids[i]); | ||
| 32 | kfree(sig->s); | ||
| 33 | kfree(sig->digest); | ||
| 34 | kfree(sig); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | EXPORT_SYMBOL_GPL(public_key_signature_free); | ||
| 38 | |||
| 21 | /** | 39 | /** |
| 22 | * verify_signature - Initiate the use of an asymmetric key to verify a signature | 40 | * verify_signature - Initiate the use of an asymmetric key to verify a signature |
| 23 | * @key: The asymmetric key to verify against | 41 | * @key: The asymmetric key to verify against |
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 7e8c2338ae25..672a94c2c3ff 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 17 | #include <linux/pe.h> | 17 | #include <linux/pe.h> |
| 18 | #include <linux/asn1.h> | 18 | #include <linux/asn1.h> |
| 19 | #include <crypto/pkcs7.h> | 19 | #include <linux/verification.h> |
| 20 | #include <crypto/hash.h> | 20 | #include <crypto/hash.h> |
| 21 | #include "verify_pefile.h" | 21 | #include "verify_pefile.h" |
| 22 | 22 | ||
| @@ -392,9 +392,8 @@ error_no_desc: | |||
| 392 | * verify_pefile_signature - Verify the signature on a PE binary image | 392 | * verify_pefile_signature - Verify the signature on a PE binary image |
| 393 | * @pebuf: Buffer containing the PE binary image | 393 | * @pebuf: Buffer containing the PE binary image |
| 394 | * @pelen: Length of the binary image | 394 | * @pelen: Length of the binary image |
| 395 | * @trust_keyring: Signing certificates to use as starting points | 395 | * @trust_keys: Signing certificate(s) to use as starting points |
| 396 | * @usage: The use to which the key is being put. | 396 | * @usage: The use to which the key is being put. |
| 397 | * @_trusted: Set to true if trustworth, false otherwise | ||
| 398 | * | 397 | * |
| 399 | * Validate that the certificate chain inside the PKCS#7 message inside the PE | 398 | * Validate that the certificate chain inside the PKCS#7 message inside the PE |
| 400 | * binary image intersects keys we already know and trust. | 399 | * binary image intersects keys we already know and trust. |
| @@ -418,14 +417,10 @@ error_no_desc: | |||
| 418 | * May also return -ENOMEM. | 417 | * May also return -ENOMEM. |
| 419 | */ | 418 | */ |
| 420 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | 419 | int verify_pefile_signature(const void *pebuf, unsigned pelen, |
| 421 | struct key *trusted_keyring, | 420 | struct key *trusted_keys, |
| 422 | enum key_being_used_for usage, | 421 | enum key_being_used_for usage) |
| 423 | bool *_trusted) | ||
| 424 | { | 422 | { |
| 425 | struct pkcs7_message *pkcs7; | ||
| 426 | struct pefile_context ctx; | 423 | struct pefile_context ctx; |
| 427 | const void *data; | ||
| 428 | size_t datalen; | ||
| 429 | int ret; | 424 | int ret; |
| 430 | 425 | ||
| 431 | kenter(""); | 426 | kenter(""); |
| @@ -439,19 +434,10 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
| 439 | if (ret < 0) | 434 | if (ret < 0) |
| 440 | return ret; | 435 | return ret; |
| 441 | 436 | ||
| 442 | pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len); | 437 | ret = verify_pkcs7_signature(NULL, 0, |
| 443 | if (IS_ERR(pkcs7)) | 438 | pebuf + ctx.sig_offset, ctx.sig_len, |
| 444 | return PTR_ERR(pkcs7); | 439 | trusted_keys, usage, |
| 445 | ctx.pkcs7 = pkcs7; | 440 | mscode_parse, &ctx); |
| 446 | |||
| 447 | ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false); | ||
| 448 | if (ret < 0 || datalen == 0) { | ||
| 449 | pr_devel("PKCS#7 message does not contain data\n"); | ||
| 450 | ret = -EBADMSG; | ||
| 451 | goto error; | ||
| 452 | } | ||
| 453 | |||
| 454 | ret = mscode_parse(&ctx); | ||
| 455 | if (ret < 0) | 441 | if (ret < 0) |
| 456 | goto error; | 442 | goto error; |
| 457 | 443 | ||
| @@ -462,16 +448,8 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
| 462 | * contents. | 448 | * contents. |
| 463 | */ | 449 | */ |
| 464 | ret = pefile_digest_pe(pebuf, pelen, &ctx); | 450 | ret = pefile_digest_pe(pebuf, pelen, &ctx); |
| 465 | if (ret < 0) | ||
| 466 | goto error; | ||
| 467 | |||
| 468 | ret = pkcs7_verify(pkcs7, usage); | ||
| 469 | if (ret < 0) | ||
| 470 | goto error; | ||
| 471 | |||
| 472 | ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted); | ||
| 473 | 451 | ||
| 474 | error: | 452 | error: |
| 475 | pkcs7_free_message(ctx.pkcs7); | 453 | kfree(ctx.digest); |
| 476 | return ret; | 454 | return ret; |
| 477 | } | 455 | } |
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h index a133eb81a492..cd4d20930728 100644 --- a/crypto/asymmetric_keys/verify_pefile.h +++ b/crypto/asymmetric_keys/verify_pefile.h | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/verify_pefile.h> | ||
| 13 | #include <crypto/pkcs7.h> | 12 | #include <crypto/pkcs7.h> |
| 14 | #include <crypto/hash_info.h> | 13 | #include <crypto/hash_info.h> |
| 15 | 14 | ||
| @@ -23,7 +22,6 @@ struct pefile_context { | |||
| 23 | unsigned sig_offset; | 22 | unsigned sig_offset; |
| 24 | unsigned sig_len; | 23 | unsigned sig_len; |
| 25 | const struct section_header *secs; | 24 | const struct section_header *secs; |
| 26 | struct pkcs7_message *pkcs7; | ||
| 27 | 25 | ||
| 28 | /* PKCS#7 MS Individual Code Signing content */ | 26 | /* PKCS#7 MS Individual Code Signing content */ |
| 29 | const void *digest; /* Digest */ | 27 | const void *digest; /* Digest */ |
| @@ -39,4 +37,5 @@ struct pefile_context { | |||
| 39 | /* | 37 | /* |
| 40 | * mscode_parser.c | 38 | * mscode_parser.c |
| 41 | */ | 39 | */ |
| 42 | extern int mscode_parse(struct pefile_context *ctx); | 40 | extern int mscode_parse(void *_ctx, const void *content_data, size_t data_len, |
| 41 | size_t asn1hdrlen); | ||
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 4a29bac70060..865f46ea724f 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
| @@ -47,15 +47,12 @@ struct x509_parse_context { | |||
| 47 | void x509_free_certificate(struct x509_certificate *cert) | 47 | void x509_free_certificate(struct x509_certificate *cert) |
| 48 | { | 48 | { |
| 49 | if (cert) { | 49 | if (cert) { |
| 50 | public_key_destroy(cert->pub); | 50 | public_key_free(cert->pub); |
| 51 | public_key_signature_free(cert->sig); | ||
| 51 | kfree(cert->issuer); | 52 | kfree(cert->issuer); |
| 52 | kfree(cert->subject); | 53 | kfree(cert->subject); |
| 53 | kfree(cert->id); | 54 | kfree(cert->id); |
| 54 | kfree(cert->skid); | 55 | kfree(cert->skid); |
| 55 | kfree(cert->akid_id); | ||
| 56 | kfree(cert->akid_skid); | ||
| 57 | kfree(cert->sig.digest); | ||
| 58 | kfree(cert->sig.s); | ||
| 59 | kfree(cert); | 56 | kfree(cert); |
| 60 | } | 57 | } |
| 61 | } | 58 | } |
| @@ -78,6 +75,9 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
| 78 | cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); | 75 | cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); |
| 79 | if (!cert->pub) | 76 | if (!cert->pub) |
| 80 | goto error_no_ctx; | 77 | goto error_no_ctx; |
| 78 | cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL); | ||
| 79 | if (!cert->sig) | ||
| 80 | goto error_no_ctx; | ||
| 81 | ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); | 81 | ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); |
| 82 | if (!ctx) | 82 | if (!ctx) |
| 83 | goto error_no_ctx; | 83 | goto error_no_ctx; |
| @@ -108,6 +108,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
| 108 | 108 | ||
| 109 | cert->pub->keylen = ctx->key_size; | 109 | cert->pub->keylen = ctx->key_size; |
| 110 | 110 | ||
| 111 | /* Grab the signature bits */ | ||
| 112 | ret = x509_get_sig_params(cert); | ||
| 113 | if (ret < 0) | ||
| 114 | goto error_decode; | ||
| 115 | |||
| 111 | /* Generate cert issuer + serial number key ID */ | 116 | /* Generate cert issuer + serial number key ID */ |
| 112 | kid = asymmetric_key_generate_id(cert->raw_serial, | 117 | kid = asymmetric_key_generate_id(cert->raw_serial, |
| 113 | cert->raw_serial_size, | 118 | cert->raw_serial_size, |
| @@ -119,6 +124,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
| 119 | } | 124 | } |
| 120 | cert->id = kid; | 125 | cert->id = kid; |
| 121 | 126 | ||
| 127 | /* Detect self-signed certificates */ | ||
| 128 | ret = x509_check_for_self_signed(cert); | ||
| 129 | if (ret < 0) | ||
| 130 | goto error_decode; | ||
| 131 | |||
| 122 | kfree(ctx); | 132 | kfree(ctx); |
| 123 | return cert; | 133 | return cert; |
| 124 | 134 | ||
| @@ -188,33 +198,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, | |||
| 188 | return -ENOPKG; /* Unsupported combination */ | 198 | return -ENOPKG; /* Unsupported combination */ |
| 189 | 199 | ||
| 190 | case OID_md4WithRSAEncryption: | 200 | case OID_md4WithRSAEncryption: |
| 191 | ctx->cert->sig.hash_algo = "md4"; | 201 | ctx->cert->sig->hash_algo = "md4"; |
| 192 | ctx->cert->sig.pkey_algo = "rsa"; | 202 | ctx->cert->sig->pkey_algo = "rsa"; |
| 193 | break; | 203 | break; |
| 194 | 204 | ||
| 195 | case OID_sha1WithRSAEncryption: | 205 | case OID_sha1WithRSAEncryption: |
| 196 | ctx->cert->sig.hash_algo = "sha1"; | 206 | ctx->cert->sig->hash_algo = "sha1"; |
| 197 | ctx->cert->sig.pkey_algo = "rsa"; | 207 | ctx->cert->sig->pkey_algo = "rsa"; |
| 198 | break; | 208 | break; |
| 199 | 209 | ||
| 200 | case OID_sha256WithRSAEncryption: | 210 | case OID_sha256WithRSAEncryption: |
| 201 | ctx->cert->sig.hash_algo = "sha256"; | 211 | ctx->cert->sig->hash_algo = "sha256"; |
| 202 | ctx->cert->sig.pkey_algo = "rsa"; | 212 | ctx->cert->sig->pkey_algo = "rsa"; |
| 203 | break; | 213 | break; |
| 204 | 214 | ||
| 205 | case OID_sha384WithRSAEncryption: | 215 | case OID_sha384WithRSAEncryption: |
| 206 | ctx->cert->sig.hash_algo = "sha384"; | 216 | ctx->cert->sig->hash_algo = "sha384"; |
| 207 | ctx->cert->sig.pkey_algo = "rsa"; | 217 | ctx->cert->sig->pkey_algo = "rsa"; |
| 208 | break; | 218 | break; |
| 209 | 219 | ||
| 210 | case OID_sha512WithRSAEncryption: | 220 | case OID_sha512WithRSAEncryption: |
| 211 | ctx->cert->sig.hash_algo = "sha512"; | 221 | ctx->cert->sig->hash_algo = "sha512"; |
| 212 | ctx->cert->sig.pkey_algo = "rsa"; | 222 | ctx->cert->sig->pkey_algo = "rsa"; |
| 213 | break; | 223 | break; |
| 214 | 224 | ||
| 215 | case OID_sha224WithRSAEncryption: | 225 | case OID_sha224WithRSAEncryption: |
| 216 | ctx->cert->sig.hash_algo = "sha224"; | 226 | ctx->cert->sig->hash_algo = "sha224"; |
| 217 | ctx->cert->sig.pkey_algo = "rsa"; | 227 | ctx->cert->sig->pkey_algo = "rsa"; |
| 218 | break; | 228 | break; |
| 219 | } | 229 | } |
| 220 | 230 | ||
| @@ -572,14 +582,14 @@ int x509_akid_note_kid(void *context, size_t hdrlen, | |||
| 572 | 582 | ||
| 573 | pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); | 583 | pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); |
| 574 | 584 | ||
| 575 | if (ctx->cert->akid_skid) | 585 | if (ctx->cert->sig->auth_ids[1]) |
| 576 | return 0; | 586 | return 0; |
| 577 | 587 | ||
| 578 | kid = asymmetric_key_generate_id(value, vlen, "", 0); | 588 | kid = asymmetric_key_generate_id(value, vlen, "", 0); |
| 579 | if (IS_ERR(kid)) | 589 | if (IS_ERR(kid)) |
| 580 | return PTR_ERR(kid); | 590 | return PTR_ERR(kid); |
| 581 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | 591 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); |
| 582 | ctx->cert->akid_skid = kid; | 592 | ctx->cert->sig->auth_ids[1] = kid; |
| 583 | return 0; | 593 | return 0; |
| 584 | } | 594 | } |
| 585 | 595 | ||
| @@ -611,7 +621,7 @@ int x509_akid_note_serial(void *context, size_t hdrlen, | |||
| 611 | 621 | ||
| 612 | pr_debug("AKID: serial: %*phN\n", (int)vlen, value); | 622 | pr_debug("AKID: serial: %*phN\n", (int)vlen, value); |
| 613 | 623 | ||
| 614 | if (!ctx->akid_raw_issuer || ctx->cert->akid_id) | 624 | if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0]) |
| 615 | return 0; | 625 | return 0; |
| 616 | 626 | ||
| 617 | kid = asymmetric_key_generate_id(value, | 627 | kid = asymmetric_key_generate_id(value, |
| @@ -622,6 +632,6 @@ int x509_akid_note_serial(void *context, size_t hdrlen, | |||
| 622 | return PTR_ERR(kid); | 632 | return PTR_ERR(kid); |
| 623 | 633 | ||
| 624 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | 634 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); |
| 625 | ctx->cert->akid_id = kid; | 635 | ctx->cert->sig->auth_ids[0] = kid; |
| 626 | return 0; | 636 | return 0; |
| 627 | } | 637 | } |
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index dbeed6018e63..05eef1c68881 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
| @@ -17,13 +17,11 @@ struct x509_certificate { | |||
| 17 | struct x509_certificate *next; | 17 | struct x509_certificate *next; |
| 18 | struct x509_certificate *signer; /* Certificate that signed this one */ | 18 | struct x509_certificate *signer; /* Certificate that signed this one */ |
| 19 | struct public_key *pub; /* Public key details */ | 19 | struct public_key *pub; /* Public key details */ |
| 20 | struct public_key_signature sig; /* Signature parameters */ | 20 | struct public_key_signature *sig; /* Signature parameters */ |
| 21 | char *issuer; /* Name of certificate issuer */ | 21 | char *issuer; /* Name of certificate issuer */ |
| 22 | char *subject; /* Name of certificate subject */ | 22 | char *subject; /* Name of certificate subject */ |
| 23 | struct asymmetric_key_id *id; /* Issuer + Serial number */ | 23 | struct asymmetric_key_id *id; /* Issuer + Serial number */ |
| 24 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ | 24 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ |
| 25 | struct asymmetric_key_id *akid_id; /* CA AuthKeyId matching ->id (optional) */ | ||
| 26 | struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */ | ||
| 27 | time64_t valid_from; | 25 | time64_t valid_from; |
| 28 | time64_t valid_to; | 26 | time64_t valid_to; |
| 29 | const void *tbs; /* Signed data */ | 27 | const void *tbs; /* Signed data */ |
| @@ -41,8 +39,9 @@ struct x509_certificate { | |||
| 41 | unsigned index; | 39 | unsigned index; |
| 42 | bool seen; /* Infinite recursion prevention */ | 40 | bool seen; /* Infinite recursion prevention */ |
| 43 | bool verified; | 41 | bool verified; |
| 44 | bool trusted; | 42 | bool self_signed; /* T if self-signed (check unsupported_sig too) */ |
| 45 | bool unsupported_crypto; /* T if can't be verified due to missing crypto */ | 43 | bool unsupported_key; /* T if key uses unsupported crypto */ |
| 44 | bool unsupported_sig; /* T if signature uses unsupported crypto */ | ||
| 46 | }; | 45 | }; |
| 47 | 46 | ||
| 48 | /* | 47 | /* |
| @@ -58,5 +57,4 @@ extern int x509_decode_time(time64_t *_t, size_t hdrlen, | |||
| 58 | * x509_public_key.c | 57 | * x509_public_key.c |
| 59 | */ | 58 | */ |
| 60 | extern int x509_get_sig_params(struct x509_certificate *cert); | 59 | extern int x509_get_sig_params(struct x509_certificate *cert); |
| 61 | extern int x509_check_signature(const struct public_key *pub, | 60 | extern int x509_check_for_self_signed(struct x509_certificate *cert); |
| 62 | struct x509_certificate *cert); | ||
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 733c046aacc6..fb732296cd36 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
| @@ -20,256 +20,133 @@ | |||
| 20 | #include "asymmetric_keys.h" | 20 | #include "asymmetric_keys.h" |
| 21 | #include "x509_parser.h" | 21 | #include "x509_parser.h" |
| 22 | 22 | ||
| 23 | static bool use_builtin_keys; | ||
| 24 | static struct asymmetric_key_id *ca_keyid; | ||
| 25 | |||
| 26 | #ifndef MODULE | ||
| 27 | static struct { | ||
| 28 | struct asymmetric_key_id id; | ||
| 29 | unsigned char data[10]; | ||
| 30 | } cakey; | ||
| 31 | |||
| 32 | static int __init ca_keys_setup(char *str) | ||
| 33 | { | ||
| 34 | if (!str) /* default system keyring */ | ||
| 35 | return 1; | ||
| 36 | |||
| 37 | if (strncmp(str, "id:", 3) == 0) { | ||
| 38 | struct asymmetric_key_id *p = &cakey.id; | ||
| 39 | size_t hexlen = (strlen(str) - 3) / 2; | ||
| 40 | int ret; | ||
| 41 | |||
| 42 | if (hexlen == 0 || hexlen > sizeof(cakey.data)) { | ||
| 43 | pr_err("Missing or invalid ca_keys id\n"); | ||
| 44 | return 1; | ||
| 45 | } | ||
| 46 | |||
| 47 | ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); | ||
| 48 | if (ret < 0) | ||
| 49 | pr_err("Unparsable ca_keys id hex string\n"); | ||
| 50 | else | ||
| 51 | ca_keyid = p; /* owner key 'id:xxxxxx' */ | ||
| 52 | } else if (strcmp(str, "builtin") == 0) { | ||
| 53 | use_builtin_keys = true; | ||
| 54 | } | ||
| 55 | |||
| 56 | return 1; | ||
| 57 | } | ||
| 58 | __setup("ca_keys=", ca_keys_setup); | ||
| 59 | #endif | ||
| 60 | |||
| 61 | /** | ||
| 62 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. | ||
| 63 | * @keyring: The keys to search. | ||
| 64 | * @id: The issuer & serialNumber to look for or NULL. | ||
| 65 | * @skid: The subjectKeyIdentifier to look for or NULL. | ||
| 66 | * @partial: Use partial match if true, exact if false. | ||
| 67 | * | ||
| 68 | * Find a key in the given keyring by identifier. The preferred identifier is | ||
| 69 | * the issuer + serialNumber and the fallback identifier is the | ||
| 70 | * subjectKeyIdentifier. If both are given, the lookup is by the former, but | ||
| 71 | * the latter must also match. | ||
| 72 | */ | ||
| 73 | struct key *x509_request_asymmetric_key(struct key *keyring, | ||
| 74 | const struct asymmetric_key_id *id, | ||
| 75 | const struct asymmetric_key_id *skid, | ||
| 76 | bool partial) | ||
| 77 | { | ||
| 78 | struct key *key; | ||
| 79 | key_ref_t ref; | ||
| 80 | const char *lookup; | ||
| 81 | char *req, *p; | ||
| 82 | int len; | ||
| 83 | |||
| 84 | if (id) { | ||
| 85 | lookup = id->data; | ||
| 86 | len = id->len; | ||
| 87 | } else { | ||
| 88 | lookup = skid->data; | ||
| 89 | len = skid->len; | ||
| 90 | } | ||
| 91 | |||
| 92 | /* Construct an identifier "id:<keyid>". */ | ||
| 93 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); | ||
| 94 | if (!req) | ||
| 95 | return ERR_PTR(-ENOMEM); | ||
| 96 | |||
| 97 | if (partial) { | ||
| 98 | *p++ = 'i'; | ||
| 99 | *p++ = 'd'; | ||
| 100 | } else { | ||
| 101 | *p++ = 'e'; | ||
| 102 | *p++ = 'x'; | ||
| 103 | } | ||
| 104 | *p++ = ':'; | ||
| 105 | p = bin2hex(p, lookup, len); | ||
| 106 | *p = 0; | ||
| 107 | |||
| 108 | pr_debug("Look up: \"%s\"\n", req); | ||
| 109 | |||
| 110 | ref = keyring_search(make_key_ref(keyring, 1), | ||
| 111 | &key_type_asymmetric, req); | ||
| 112 | if (IS_ERR(ref)) | ||
| 113 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); | ||
| 114 | kfree(req); | ||
| 115 | |||
| 116 | if (IS_ERR(ref)) { | ||
| 117 | switch (PTR_ERR(ref)) { | ||
| 118 | /* Hide some search errors */ | ||
| 119 | case -EACCES: | ||
| 120 | case -ENOTDIR: | ||
| 121 | case -EAGAIN: | ||
| 122 | return ERR_PTR(-ENOKEY); | ||
| 123 | default: | ||
| 124 | return ERR_CAST(ref); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | key = key_ref_to_ptr(ref); | ||
| 129 | if (id && skid) { | ||
| 130 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | ||
| 131 | if (!kids->id[1]) { | ||
| 132 | pr_debug("issuer+serial match, but expected SKID missing\n"); | ||
| 133 | goto reject; | ||
| 134 | } | ||
| 135 | if (!asymmetric_key_id_same(skid, kids->id[1])) { | ||
| 136 | pr_debug("issuer+serial match, but SKID does not\n"); | ||
| 137 | goto reject; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | ||
| 142 | return key; | ||
| 143 | |||
| 144 | reject: | ||
| 145 | key_put(key); | ||
| 146 | return ERR_PTR(-EKEYREJECTED); | ||
| 147 | } | ||
| 148 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); | ||
| 149 | |||
| 150 | /* | 23 | /* |
| 151 | * Set up the signature parameters in an X.509 certificate. This involves | 24 | * Set up the signature parameters in an X.509 certificate. This involves |
| 152 | * digesting the signed data and extracting the signature. | 25 | * digesting the signed data and extracting the signature. |
| 153 | */ | 26 | */ |
| 154 | int x509_get_sig_params(struct x509_certificate *cert) | 27 | int x509_get_sig_params(struct x509_certificate *cert) |
| 155 | { | 28 | { |
| 29 | struct public_key_signature *sig = cert->sig; | ||
| 156 | struct crypto_shash *tfm; | 30 | struct crypto_shash *tfm; |
| 157 | struct shash_desc *desc; | 31 | struct shash_desc *desc; |
| 158 | size_t digest_size, desc_size; | 32 | size_t desc_size; |
| 159 | void *digest; | ||
| 160 | int ret; | 33 | int ret; |
| 161 | 34 | ||
| 162 | pr_devel("==>%s()\n", __func__); | 35 | pr_devel("==>%s()\n", __func__); |
| 163 | 36 | ||
| 164 | if (cert->unsupported_crypto) | 37 | if (!cert->pub->pkey_algo) |
| 165 | return -ENOPKG; | 38 | cert->unsupported_key = true; |
| 166 | if (cert->sig.s) | 39 | |
| 40 | if (!sig->pkey_algo) | ||
| 41 | cert->unsupported_sig = true; | ||
| 42 | |||
| 43 | /* We check the hash if we can - even if we can't then verify it */ | ||
| 44 | if (!sig->hash_algo) { | ||
| 45 | cert->unsupported_sig = true; | ||
| 167 | return 0; | 46 | return 0; |
| 47 | } | ||
| 168 | 48 | ||
| 169 | cert->sig.s = kmemdup(cert->raw_sig, cert->raw_sig_size, | 49 | sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); |
| 170 | GFP_KERNEL); | 50 | if (!sig->s) |
| 171 | if (!cert->sig.s) | ||
| 172 | return -ENOMEM; | 51 | return -ENOMEM; |
| 173 | 52 | ||
| 174 | cert->sig.s_size = cert->raw_sig_size; | 53 | sig->s_size = cert->raw_sig_size; |
| 175 | 54 | ||
| 176 | /* Allocate the hashing algorithm we're going to need and find out how | 55 | /* Allocate the hashing algorithm we're going to need and find out how |
| 177 | * big the hash operational data will be. | 56 | * big the hash operational data will be. |
| 178 | */ | 57 | */ |
| 179 | tfm = crypto_alloc_shash(cert->sig.hash_algo, 0, 0); | 58 | tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); |
| 180 | if (IS_ERR(tfm)) { | 59 | if (IS_ERR(tfm)) { |
| 181 | if (PTR_ERR(tfm) == -ENOENT) { | 60 | if (PTR_ERR(tfm) == -ENOENT) { |
| 182 | cert->unsupported_crypto = true; | 61 | cert->unsupported_sig = true; |
| 183 | return -ENOPKG; | 62 | return 0; |
| 184 | } | 63 | } |
| 185 | return PTR_ERR(tfm); | 64 | return PTR_ERR(tfm); |
| 186 | } | 65 | } |
| 187 | 66 | ||
| 188 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | 67 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); |
| 189 | digest_size = crypto_shash_digestsize(tfm); | 68 | sig->digest_size = crypto_shash_digestsize(tfm); |
| 190 | 69 | ||
| 191 | /* We allocate the hash operational data storage on the end of the | ||
| 192 | * digest storage space. | ||
| 193 | */ | ||
| 194 | ret = -ENOMEM; | 70 | ret = -ENOMEM; |
| 195 | digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size, | 71 | sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); |
| 196 | GFP_KERNEL); | 72 | if (!sig->digest) |
| 197 | if (!digest) | ||
| 198 | goto error; | 73 | goto error; |
| 199 | 74 | ||
| 200 | cert->sig.digest = digest; | 75 | desc = kzalloc(desc_size, GFP_KERNEL); |
| 201 | cert->sig.digest_size = digest_size; | 76 | if (!desc) |
| 77 | goto error; | ||
| 202 | 78 | ||
| 203 | desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc)); | ||
| 204 | desc->tfm = tfm; | 79 | desc->tfm = tfm; |
| 205 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 80 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
| 206 | 81 | ||
| 207 | ret = crypto_shash_init(desc); | 82 | ret = crypto_shash_init(desc); |
| 208 | if (ret < 0) | 83 | if (ret < 0) |
| 209 | goto error; | 84 | goto error_2; |
| 210 | might_sleep(); | 85 | might_sleep(); |
| 211 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest); | 86 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); |
| 87 | |||
| 88 | error_2: | ||
| 89 | kfree(desc); | ||
| 212 | error: | 90 | error: |
| 213 | crypto_free_shash(tfm); | 91 | crypto_free_shash(tfm); |
| 214 | pr_devel("<==%s() = %d\n", __func__, ret); | 92 | pr_devel("<==%s() = %d\n", __func__, ret); |
| 215 | return ret; | 93 | return ret; |
| 216 | } | 94 | } |
| 217 | EXPORT_SYMBOL_GPL(x509_get_sig_params); | ||
| 218 | 95 | ||
| 219 | /* | 96 | /* |
| 220 | * Check the signature on a certificate using the provided public key | 97 | * Check for self-signedness in an X.509 cert and if found, check the signature |
| 98 | * immediately if we can. | ||
| 221 | */ | 99 | */ |
| 222 | int x509_check_signature(const struct public_key *pub, | 100 | int x509_check_for_self_signed(struct x509_certificate *cert) |
| 223 | struct x509_certificate *cert) | ||
| 224 | { | 101 | { |
| 225 | int ret; | 102 | int ret = 0; |
| 226 | 103 | ||
| 227 | pr_devel("==>%s()\n", __func__); | 104 | pr_devel("==>%s()\n", __func__); |
| 228 | 105 | ||
| 229 | ret = x509_get_sig_params(cert); | 106 | if (cert->raw_subject_size != cert->raw_issuer_size || |
| 230 | if (ret < 0) | 107 | memcmp(cert->raw_subject, cert->raw_issuer, |
| 231 | return ret; | 108 | cert->raw_issuer_size) != 0) |
| 109 | goto not_self_signed; | ||
| 110 | |||
| 111 | if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) { | ||
| 112 | /* If the AKID is present it may have one or two parts. If | ||
| 113 | * both are supplied, both must match. | ||
| 114 | */ | ||
| 115 | bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]); | ||
| 116 | bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]); | ||
| 117 | |||
| 118 | if (!a && !b) | ||
| 119 | goto not_self_signed; | ||
| 120 | |||
| 121 | ret = -EKEYREJECTED; | ||
| 122 | if (((a && !b) || (b && !a)) && | ||
| 123 | cert->sig->auth_ids[0] && cert->sig->auth_ids[1]) | ||
| 124 | goto out; | ||
| 125 | } | ||
| 232 | 126 | ||
| 233 | ret = public_key_verify_signature(pub, &cert->sig); | 127 | ret = -EKEYREJECTED; |
| 234 | if (ret == -ENOPKG) | 128 | if (cert->pub->pkey_algo != cert->sig->pkey_algo) |
| 235 | cert->unsupported_crypto = true; | 129 | goto out; |
| 236 | pr_debug("Cert Verification: %d\n", ret); | ||
| 237 | return ret; | ||
| 238 | } | ||
| 239 | EXPORT_SYMBOL_GPL(x509_check_signature); | ||
| 240 | 130 | ||
| 241 | /* | 131 | ret = public_key_verify_signature(cert->pub, cert->sig); |
| 242 | * Check the new certificate against the ones in the trust keyring. If one of | 132 | if (ret < 0) { |
| 243 | * those is the signing key and validates the new certificate, then mark the | 133 | if (ret == -ENOPKG) { |
| 244 | * new certificate as being trusted. | 134 | cert->unsupported_sig = true; |
| 245 | * | 135 | ret = 0; |
| 246 | * Return 0 if the new certificate was successfully validated, 1 if we couldn't | 136 | } |
| 247 | * find a matching parent certificate in the trusted list and an error if there | 137 | goto out; |
| 248 | * is a matching certificate but the signature check fails. | ||
| 249 | */ | ||
| 250 | static int x509_validate_trust(struct x509_certificate *cert, | ||
| 251 | struct key *trust_keyring) | ||
| 252 | { | ||
| 253 | struct key *key; | ||
| 254 | int ret = 1; | ||
| 255 | |||
| 256 | if (!trust_keyring) | ||
| 257 | return -EOPNOTSUPP; | ||
| 258 | |||
| 259 | if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid)) | ||
| 260 | return -EPERM; | ||
| 261 | |||
| 262 | key = x509_request_asymmetric_key(trust_keyring, | ||
| 263 | cert->akid_id, cert->akid_skid, | ||
| 264 | false); | ||
| 265 | if (!IS_ERR(key)) { | ||
| 266 | if (!use_builtin_keys | ||
| 267 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) | ||
| 268 | ret = x509_check_signature(key->payload.data[asym_crypto], | ||
| 269 | cert); | ||
| 270 | key_put(key); | ||
| 271 | } | 138 | } |
| 139 | |||
| 140 | pr_devel("Cert Self-signature verified"); | ||
| 141 | cert->self_signed = true; | ||
| 142 | |||
| 143 | out: | ||
| 144 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 272 | return ret; | 145 | return ret; |
| 146 | |||
| 147 | not_self_signed: | ||
| 148 | pr_devel("<==%s() = 0 [not]\n", __func__); | ||
| 149 | return 0; | ||
| 273 | } | 150 | } |
| 274 | 151 | ||
| 275 | /* | 152 | /* |
| @@ -291,34 +168,22 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 291 | pr_devel("Cert Issuer: %s\n", cert->issuer); | 168 | pr_devel("Cert Issuer: %s\n", cert->issuer); |
| 292 | pr_devel("Cert Subject: %s\n", cert->subject); | 169 | pr_devel("Cert Subject: %s\n", cert->subject); |
| 293 | 170 | ||
| 294 | if (!cert->pub->pkey_algo || | 171 | if (cert->unsupported_key) { |
| 295 | !cert->sig.pkey_algo || | ||
| 296 | !cert->sig.hash_algo) { | ||
| 297 | ret = -ENOPKG; | 172 | ret = -ENOPKG; |
| 298 | goto error_free_cert; | 173 | goto error_free_cert; |
| 299 | } | 174 | } |
| 300 | 175 | ||
| 301 | pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); | 176 | pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); |
| 302 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); | 177 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); |
| 303 | pr_devel("Cert Signature: %s + %s\n", | ||
| 304 | cert->sig.pkey_algo, | ||
| 305 | cert->sig.hash_algo); | ||
| 306 | 178 | ||
| 307 | cert->pub->id_type = "X509"; | 179 | cert->pub->id_type = "X509"; |
| 308 | 180 | ||
| 309 | /* Check the signature on the key if it appears to be self-signed */ | 181 | if (cert->unsupported_sig) { |
| 310 | if ((!cert->akid_skid && !cert->akid_id) || | 182 | public_key_signature_free(cert->sig); |
| 311 | asymmetric_key_id_same(cert->skid, cert->akid_skid) || | 183 | cert->sig = NULL; |
| 312 | asymmetric_key_id_same(cert->id, cert->akid_id)) { | 184 | } else { |
| 313 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ | 185 | pr_devel("Cert Signature: %s + %s\n", |
| 314 | if (ret < 0) | 186 | cert->sig->pkey_algo, cert->sig->hash_algo); |
| 315 | goto error_free_cert; | ||
| 316 | } else if (!prep->trusted) { | ||
| 317 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); | ||
| 318 | if (ret) | ||
| 319 | ret = x509_validate_trust(cert, get_ima_mok_keyring()); | ||
| 320 | if (!ret) | ||
| 321 | prep->trusted = 1; | ||
| 322 | } | 187 | } |
| 323 | 188 | ||
| 324 | /* Propose a description */ | 189 | /* Propose a description */ |
| @@ -353,6 +218,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 353 | prep->payload.data[asym_subtype] = &public_key_subtype; | 218 | prep->payload.data[asym_subtype] = &public_key_subtype; |
| 354 | prep->payload.data[asym_key_ids] = kids; | 219 | prep->payload.data[asym_key_ids] = kids; |
| 355 | prep->payload.data[asym_crypto] = cert->pub; | 220 | prep->payload.data[asym_crypto] = cert->pub; |
| 221 | prep->payload.data[asym_auth] = cert->sig; | ||
| 356 | prep->description = desc; | 222 | prep->description = desc; |
| 357 | prep->quotalen = 100; | 223 | prep->quotalen = 100; |
| 358 | 224 | ||
| @@ -360,6 +226,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 360 | cert->pub = NULL; | 226 | cert->pub = NULL; |
| 361 | cert->id = NULL; | 227 | cert->id = NULL; |
| 362 | cert->skid = NULL; | 228 | cert->skid = NULL; |
| 229 | cert->sig = NULL; | ||
| 363 | desc = NULL; | 230 | desc = NULL; |
| 364 | ret = 0; | 231 | ret = 0; |
| 365 | 232 | ||
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 3f93125916bf..71e8a56e9479 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -360,7 +360,7 @@ init_cifs_idmap(void) | |||
| 360 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, | 360 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, |
| 361 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 361 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 362 | KEY_USR_VIEW | KEY_USR_READ, | 362 | KEY_USR_VIEW | KEY_USR_READ, |
| 363 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | 363 | KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); |
| 364 | if (IS_ERR(keyring)) { | 364 | if (IS_ERR(keyring)) { |
| 365 | ret = PTR_ERR(keyring); | 365 | ret = PTR_ERR(keyring); |
| 366 | goto failed_put_cred; | 366 | goto failed_put_cred; |
| @@ -850,15 +850,25 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, | |||
| 850 | if (ret) | 850 | if (ret) |
| 851 | return ret; | 851 | return ret; |
| 852 | 852 | ||
| 853 | ret = deny_write_access(file); | ||
| 854 | if (ret) | ||
| 855 | return ret; | ||
| 856 | |||
| 853 | i_size = i_size_read(file_inode(file)); | 857 | i_size = i_size_read(file_inode(file)); |
| 854 | if (max_size > 0 && i_size > max_size) | 858 | if (max_size > 0 && i_size > max_size) { |
| 855 | return -EFBIG; | 859 | ret = -EFBIG; |
| 856 | if (i_size <= 0) | 860 | goto out; |
| 857 | return -EINVAL; | 861 | } |
| 862 | if (i_size <= 0) { | ||
| 863 | ret = -EINVAL; | ||
| 864 | goto out; | ||
| 865 | } | ||
| 858 | 866 | ||
| 859 | *buf = vmalloc(i_size); | 867 | *buf = vmalloc(i_size); |
| 860 | if (!*buf) | 868 | if (!*buf) { |
| 861 | return -ENOMEM; | 869 | ret = -ENOMEM; |
| 870 | goto out; | ||
| 871 | } | ||
| 862 | 872 | ||
| 863 | pos = 0; | 873 | pos = 0; |
| 864 | while (pos < i_size) { | 874 | while (pos < i_size) { |
| @@ -876,18 +886,21 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, | |||
| 876 | 886 | ||
| 877 | if (pos != i_size) { | 887 | if (pos != i_size) { |
| 878 | ret = -EIO; | 888 | ret = -EIO; |
| 879 | goto out; | 889 | goto out_free; |
| 880 | } | 890 | } |
| 881 | 891 | ||
| 882 | ret = security_kernel_post_read_file(file, *buf, i_size, id); | 892 | ret = security_kernel_post_read_file(file, *buf, i_size, id); |
| 883 | if (!ret) | 893 | if (!ret) |
| 884 | *size = pos; | 894 | *size = pos; |
| 885 | 895 | ||
| 886 | out: | 896 | out_free: |
| 887 | if (ret < 0) { | 897 | if (ret < 0) { |
| 888 | vfree(*buf); | 898 | vfree(*buf); |
| 889 | *buf = NULL; | 899 | *buf = NULL; |
| 890 | } | 900 | } |
| 901 | |||
| 902 | out: | ||
| 903 | allow_write_access(file); | ||
| 891 | return ret; | 904 | return ret; |
| 892 | } | 905 | } |
| 893 | EXPORT_SYMBOL_GPL(kernel_read_file); | 906 | EXPORT_SYMBOL_GPL(kernel_read_file); |
diff --git a/fs/namei.c b/fs/namei.c index 9d193d336c9f..5375571cf6e1 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -3627,6 +3627,8 @@ retry: | |||
| 3627 | switch (mode & S_IFMT) { | 3627 | switch (mode & S_IFMT) { |
| 3628 | case 0: case S_IFREG: | 3628 | case 0: case S_IFREG: |
| 3629 | error = vfs_create(path.dentry->d_inode,dentry,mode,true); | 3629 | error = vfs_create(path.dentry->d_inode,dentry,mode,true); |
| 3630 | if (!error) | ||
| 3631 | ima_post_path_mknod(dentry); | ||
| 3630 | break; | 3632 | break; |
| 3631 | case S_IFCHR: case S_IFBLK: | 3633 | case S_IFCHR: case S_IFBLK: |
| 3632 | error = vfs_mknod(path.dentry->d_inode,dentry,mode, | 3634 | error = vfs_mknod(path.dentry->d_inode,dentry,mode, |
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c index 5ba22c6b0ffa..c444285bb1b1 100644 --- a/fs/nfs/nfs4idmap.c +++ b/fs/nfs/nfs4idmap.c | |||
| @@ -201,7 +201,7 @@ int nfs_idmap_init(void) | |||
| 201 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, | 201 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, |
| 202 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 202 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 203 | KEY_USR_VIEW | KEY_USR_READ, | 203 | KEY_USR_VIEW | KEY_USR_READ, |
| 204 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | 204 | KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); |
| 205 | if (IS_ERR(keyring)) { | 205 | if (IS_ERR(keyring)) { |
| 206 | ret = PTR_ERR(keyring); | 206 | ret = PTR_ERR(keyring); |
| 207 | goto failed_put_cred; | 207 | goto failed_put_cred; |
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h index 441aff9b5aa7..583f199400a3 100644 --- a/include/crypto/pkcs7.h +++ b/include/crypto/pkcs7.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #ifndef _CRYPTO_PKCS7_H | 12 | #ifndef _CRYPTO_PKCS7_H |
| 13 | #define _CRYPTO_PKCS7_H | 13 | #define _CRYPTO_PKCS7_H |
| 14 | 14 | ||
| 15 | #include <linux/verification.h> | ||
| 15 | #include <crypto/public_key.h> | 16 | #include <crypto/public_key.h> |
| 16 | 17 | ||
| 17 | struct key; | 18 | struct key; |
| @@ -26,14 +27,13 @@ extern void pkcs7_free_message(struct pkcs7_message *pkcs7); | |||
| 26 | 27 | ||
| 27 | extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | 28 | extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, |
| 28 | const void **_data, size_t *_datalen, | 29 | const void **_data, size_t *_datalen, |
| 29 | bool want_wrapper); | 30 | size_t *_headerlen); |
| 30 | 31 | ||
| 31 | /* | 32 | /* |
| 32 | * pkcs7_trust.c | 33 | * pkcs7_trust.c |
| 33 | */ | 34 | */ |
| 34 | extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | 35 | extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, |
| 35 | struct key *trust_keyring, | 36 | struct key *trust_keyring); |
| 36 | bool *_trusted); | ||
| 37 | 37 | ||
| 38 | /* | 38 | /* |
| 39 | * pkcs7_verify.c | 39 | * pkcs7_verify.c |
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index aa730ea7faf8..882ca0e1e7a5 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h | |||
| @@ -15,20 +15,6 @@ | |||
| 15 | #define _LINUX_PUBLIC_KEY_H | 15 | #define _LINUX_PUBLIC_KEY_H |
| 16 | 16 | ||
| 17 | /* | 17 | /* |
| 18 | * The use to which an asymmetric key is being put. | ||
| 19 | */ | ||
| 20 | enum key_being_used_for { | ||
| 21 | VERIFYING_MODULE_SIGNATURE, | ||
| 22 | VERIFYING_FIRMWARE_SIGNATURE, | ||
| 23 | VERIFYING_KEXEC_PE_SIGNATURE, | ||
| 24 | VERIFYING_KEY_SIGNATURE, | ||
| 25 | VERIFYING_KEY_SELF_SIGNATURE, | ||
| 26 | VERIFYING_UNSPECIFIED_SIGNATURE, | ||
| 27 | NR__KEY_BEING_USED_FOR | ||
| 28 | }; | ||
| 29 | extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; | ||
| 30 | |||
| 31 | /* | ||
| 32 | * Cryptographic data for the public-key subtype of the asymmetric key type. | 18 | * Cryptographic data for the public-key subtype of the asymmetric key type. |
| 33 | * | 19 | * |
| 34 | * Note that this may include private part of the key as well as the public | 20 | * Note that this may include private part of the key as well as the public |
| @@ -41,12 +27,13 @@ struct public_key { | |||
| 41 | const char *pkey_algo; | 27 | const char *pkey_algo; |
| 42 | }; | 28 | }; |
| 43 | 29 | ||
| 44 | extern void public_key_destroy(void *payload); | 30 | extern void public_key_free(struct public_key *key); |
| 45 | 31 | ||
| 46 | /* | 32 | /* |
| 47 | * Public key cryptography signature data | 33 | * Public key cryptography signature data |
| 48 | */ | 34 | */ |
| 49 | struct public_key_signature { | 35 | struct public_key_signature { |
| 36 | struct asymmetric_key_id *auth_ids[2]; | ||
| 50 | u8 *s; /* Signature */ | 37 | u8 *s; /* Signature */ |
| 51 | u32 s_size; /* Number of bytes in signature */ | 38 | u32 s_size; /* Number of bytes in signature */ |
| 52 | u8 *digest; | 39 | u8 *digest; |
| @@ -55,17 +42,21 @@ struct public_key_signature { | |||
| 55 | const char *hash_algo; | 42 | const char *hash_algo; |
| 56 | }; | 43 | }; |
| 57 | 44 | ||
| 45 | extern void public_key_signature_free(struct public_key_signature *sig); | ||
| 46 | |||
| 58 | extern struct asymmetric_key_subtype public_key_subtype; | 47 | extern struct asymmetric_key_subtype public_key_subtype; |
| 48 | |||
| 59 | struct key; | 49 | struct key; |
| 50 | struct key_type; | ||
| 51 | union key_payload; | ||
| 52 | |||
| 53 | extern int restrict_link_by_signature(struct key *trust_keyring, | ||
| 54 | const struct key_type *type, | ||
| 55 | const union key_payload *payload); | ||
| 56 | |||
| 60 | extern int verify_signature(const struct key *key, | 57 | extern int verify_signature(const struct key *key, |
| 61 | const struct public_key_signature *sig); | 58 | const struct public_key_signature *sig); |
| 62 | 59 | ||
| 63 | struct asymmetric_key_id; | ||
| 64 | extern struct key *x509_request_asymmetric_key(struct key *keyring, | ||
| 65 | const struct asymmetric_key_id *id, | ||
| 66 | const struct asymmetric_key_id *skid, | ||
| 67 | bool partial); | ||
| 68 | |||
| 69 | int public_key_verify_signature(const struct public_key *pkey, | 60 | int public_key_verify_signature(const struct public_key *pkey, |
| 70 | const struct public_key_signature *sig); | 61 | const struct public_key_signature *sig); |
| 71 | 62 | ||
diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h index 4915d40d3c3c..2480469ce8fb 100644 --- a/include/keys/asymmetric-subtype.h +++ b/include/keys/asymmetric-subtype.h | |||
| @@ -32,7 +32,7 @@ struct asymmetric_key_subtype { | |||
| 32 | void (*describe)(const struct key *key, struct seq_file *m); | 32 | void (*describe)(const struct key *key, struct seq_file *m); |
| 33 | 33 | ||
| 34 | /* Destroy a key of this subtype */ | 34 | /* Destroy a key of this subtype */ |
| 35 | void (*destroy)(void *payload); | 35 | void (*destroy)(void *payload_crypto, void *payload_auth); |
| 36 | 36 | ||
| 37 | /* Verify the signature on a key of this subtype (optional) */ | 37 | /* Verify the signature on a key of this subtype (optional) */ |
| 38 | int (*verify_signature)(const struct key *key, | 38 | int (*verify_signature)(const struct key *key, |
diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h index 59c1df9cf922..b38240716d41 100644 --- a/include/keys/asymmetric-type.h +++ b/include/keys/asymmetric-type.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #define _KEYS_ASYMMETRIC_TYPE_H | 15 | #define _KEYS_ASYMMETRIC_TYPE_H |
| 16 | 16 | ||
| 17 | #include <linux/key-type.h> | 17 | #include <linux/key-type.h> |
| 18 | #include <linux/verification.h> | ||
| 18 | 19 | ||
| 19 | extern struct key_type key_type_asymmetric; | 20 | extern struct key_type key_type_asymmetric; |
| 20 | 21 | ||
| @@ -23,9 +24,10 @@ extern struct key_type key_type_asymmetric; | |||
| 23 | * follows: | 24 | * follows: |
| 24 | */ | 25 | */ |
| 25 | enum asymmetric_payload_bits { | 26 | enum asymmetric_payload_bits { |
| 26 | asym_crypto, | 27 | asym_crypto, /* The data representing the key */ |
| 27 | asym_subtype, | 28 | asym_subtype, /* Pointer to an asymmetric_key_subtype struct */ |
| 28 | asym_key_ids, | 29 | asym_key_ids, /* Pointer to an asymmetric_key_ids struct */ |
| 30 | asym_auth /* The key's authorisation (signature, parent key ID) */ | ||
| 29 | }; | 31 | }; |
| 30 | 32 | ||
| 31 | /* | 33 | /* |
| @@ -74,6 +76,11 @@ const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key) | |||
| 74 | return key->payload.data[asym_key_ids]; | 76 | return key->payload.data[asym_key_ids]; |
| 75 | } | 77 | } |
| 76 | 78 | ||
| 79 | extern struct key *find_asymmetric_key(struct key *keyring, | ||
| 80 | const struct asymmetric_key_id *id_0, | ||
| 81 | const struct asymmetric_key_id *id_1, | ||
| 82 | bool partial); | ||
| 83 | |||
| 77 | /* | 84 | /* |
| 78 | * The payload is at the discretion of the subtype. | 85 | * The payload is at the discretion of the subtype. |
| 79 | */ | 86 | */ |
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index 39fd38cfa8c9..fbd4647767e9 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h | |||
| @@ -12,51 +12,40 @@ | |||
| 12 | #ifndef _KEYS_SYSTEM_KEYRING_H | 12 | #ifndef _KEYS_SYSTEM_KEYRING_H |
| 13 | #define _KEYS_SYSTEM_KEYRING_H | 13 | #define _KEYS_SYSTEM_KEYRING_H |
| 14 | 14 | ||
| 15 | #include <linux/key.h> | ||
| 16 | |||
| 15 | #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING | 17 | #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING |
| 16 | 18 | ||
| 17 | #include <linux/key.h> | 19 | extern int restrict_link_by_builtin_trusted(struct key *keyring, |
| 18 | #include <crypto/public_key.h> | 20 | const struct key_type *type, |
| 21 | const union key_payload *payload); | ||
| 19 | 22 | ||
| 20 | extern struct key *system_trusted_keyring; | ||
| 21 | static inline struct key *get_system_trusted_keyring(void) | ||
| 22 | { | ||
| 23 | return system_trusted_keyring; | ||
| 24 | } | ||
| 25 | #else | 23 | #else |
| 26 | static inline struct key *get_system_trusted_keyring(void) | 24 | #define restrict_link_by_builtin_trusted restrict_link_reject |
| 27 | { | ||
| 28 | return NULL; | ||
| 29 | } | ||
| 30 | #endif | 25 | #endif |
| 31 | 26 | ||
| 32 | #ifdef CONFIG_SYSTEM_DATA_VERIFICATION | 27 | #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING |
| 33 | extern int system_verify_data(const void *data, unsigned long len, | 28 | extern int restrict_link_by_builtin_and_secondary_trusted( |
| 34 | const void *raw_pkcs7, size_t pkcs7_len, | 29 | struct key *keyring, |
| 35 | enum key_being_used_for usage); | 30 | const struct key_type *type, |
| 31 | const union key_payload *payload); | ||
| 32 | #else | ||
| 33 | #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted | ||
| 36 | #endif | 34 | #endif |
| 37 | 35 | ||
| 38 | #ifdef CONFIG_IMA_MOK_KEYRING | 36 | #ifdef CONFIG_IMA_BLACKLIST_KEYRING |
| 39 | extern struct key *ima_mok_keyring; | ||
| 40 | extern struct key *ima_blacklist_keyring; | 37 | extern struct key *ima_blacklist_keyring; |
| 41 | 38 | ||
| 42 | static inline struct key *get_ima_mok_keyring(void) | ||
| 43 | { | ||
| 44 | return ima_mok_keyring; | ||
| 45 | } | ||
| 46 | static inline struct key *get_ima_blacklist_keyring(void) | 39 | static inline struct key *get_ima_blacklist_keyring(void) |
| 47 | { | 40 | { |
| 48 | return ima_blacklist_keyring; | 41 | return ima_blacklist_keyring; |
| 49 | } | 42 | } |
| 50 | #else | 43 | #else |
| 51 | static inline struct key *get_ima_mok_keyring(void) | ||
| 52 | { | ||
| 53 | return NULL; | ||
| 54 | } | ||
| 55 | static inline struct key *get_ima_blacklist_keyring(void) | 44 | static inline struct key *get_ima_blacklist_keyring(void) |
| 56 | { | 45 | { |
| 57 | return NULL; | 46 | return NULL; |
| 58 | } | 47 | } |
| 59 | #endif /* CONFIG_IMA_MOK_KEYRING */ | 48 | #endif /* CONFIG_IMA_BLACKLIST_KEYRING */ |
| 60 | 49 | ||
| 61 | 50 | ||
| 62 | #endif /* _KEYS_SYSTEM_KEYRING_H */ | 51 | #endif /* _KEYS_SYSTEM_KEYRING_H */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 851390c8d75b..10d3d8f8a65b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -2634,15 +2634,34 @@ static inline void i_readcount_inc(struct inode *inode) | |||
| 2634 | #endif | 2634 | #endif |
| 2635 | extern int do_pipe_flags(int *, int); | 2635 | extern int do_pipe_flags(int *, int); |
| 2636 | 2636 | ||
| 2637 | #define __kernel_read_file_id(id) \ | ||
| 2638 | id(UNKNOWN, unknown) \ | ||
| 2639 | id(FIRMWARE, firmware) \ | ||
| 2640 | id(MODULE, kernel-module) \ | ||
| 2641 | id(KEXEC_IMAGE, kexec-image) \ | ||
| 2642 | id(KEXEC_INITRAMFS, kexec-initramfs) \ | ||
| 2643 | id(POLICY, security-policy) \ | ||
| 2644 | id(MAX_ID, ) | ||
| 2645 | |||
| 2646 | #define __fid_enumify(ENUM, dummy) READING_ ## ENUM, | ||
| 2647 | #define __fid_stringify(dummy, str) #str, | ||
| 2648 | |||
| 2637 | enum kernel_read_file_id { | 2649 | enum kernel_read_file_id { |
| 2638 | READING_FIRMWARE = 1, | 2650 | __kernel_read_file_id(__fid_enumify) |
| 2639 | READING_MODULE, | 2651 | }; |
| 2640 | READING_KEXEC_IMAGE, | 2652 | |
| 2641 | READING_KEXEC_INITRAMFS, | 2653 | static const char * const kernel_read_file_str[] = { |
| 2642 | READING_POLICY, | 2654 | __kernel_read_file_id(__fid_stringify) |
| 2643 | READING_MAX_ID | ||
| 2644 | }; | 2655 | }; |
| 2645 | 2656 | ||
| 2657 | static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) | ||
| 2658 | { | ||
| 2659 | if (id < 0 || id >= READING_MAX_ID) | ||
| 2660 | return kernel_read_file_str[READING_UNKNOWN]; | ||
| 2661 | |||
| 2662 | return kernel_read_file_str[id]; | ||
| 2663 | } | ||
| 2664 | |||
| 2646 | extern int kernel_read(struct file *, loff_t, char *, unsigned long); | 2665 | extern int kernel_read(struct file *, loff_t, char *, unsigned long); |
| 2647 | extern int kernel_read_file(struct file *, void **, loff_t *, loff_t, | 2666 | extern int kernel_read_file(struct file *, void **, loff_t *, loff_t, |
| 2648 | enum kernel_read_file_id); | 2667 | enum kernel_read_file_id); |
diff --git a/include/linux/ima.h b/include/linux/ima.h index e6516cbbe9bf..0eb7c2e7f0d6 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h | |||
| @@ -21,6 +21,7 @@ extern int ima_file_mmap(struct file *file, unsigned long prot); | |||
| 21 | extern int ima_read_file(struct file *file, enum kernel_read_file_id id); | 21 | extern int ima_read_file(struct file *file, enum kernel_read_file_id id); |
| 22 | extern int ima_post_read_file(struct file *file, void *buf, loff_t size, | 22 | extern int ima_post_read_file(struct file *file, void *buf, loff_t size, |
| 23 | enum kernel_read_file_id id); | 23 | enum kernel_read_file_id id); |
| 24 | extern void ima_post_path_mknod(struct dentry *dentry); | ||
| 24 | 25 | ||
| 25 | #else | 26 | #else |
| 26 | static inline int ima_bprm_check(struct linux_binprm *bprm) | 27 | static inline int ima_bprm_check(struct linux_binprm *bprm) |
| @@ -54,6 +55,11 @@ static inline int ima_post_read_file(struct file *file, void *buf, loff_t size, | |||
| 54 | return 0; | 55 | return 0; |
| 55 | } | 56 | } |
| 56 | 57 | ||
| 58 | static inline void ima_post_path_mknod(struct dentry *dentry) | ||
| 59 | { | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 57 | #endif /* CONFIG_IMA */ | 63 | #endif /* CONFIG_IMA */ |
| 58 | 64 | ||
| 59 | #ifdef CONFIG_IMA_APPRAISE | 65 | #ifdef CONFIG_IMA_APPRAISE |
diff --git a/include/linux/key-type.h b/include/linux/key-type.h index 7463355a198b..eaee981c5558 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h | |||
| @@ -45,7 +45,6 @@ struct key_preparsed_payload { | |||
| 45 | size_t datalen; /* Raw datalen */ | 45 | size_t datalen; /* Raw datalen */ |
| 46 | size_t quotalen; /* Quota length for proposed payload */ | 46 | size_t quotalen; /* Quota length for proposed payload */ |
| 47 | time_t expiry; /* Expiry time of key */ | 47 | time_t expiry; /* Expiry time of key */ |
| 48 | bool trusted; /* True if key is trusted */ | ||
| 49 | }; | 48 | }; |
| 50 | 49 | ||
| 51 | typedef int (*request_key_actor_t)(struct key_construction *key, | 50 | typedef int (*request_key_actor_t)(struct key_construction *key, |
diff --git a/include/linux/key.h b/include/linux/key.h index 5f5b1129dc92..722914798f37 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -173,11 +173,9 @@ struct key { | |||
| 173 | #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ | 173 | #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ |
| 174 | #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ | 174 | #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ |
| 175 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ | 175 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ |
| 176 | #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ | 176 | #define KEY_FLAG_BUILTIN 8 /* set if key is built in to the kernel */ |
| 177 | #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ | 177 | #define KEY_FLAG_ROOT_CAN_INVAL 9 /* set if key can be invalidated by root without permission */ |
| 178 | #define KEY_FLAG_BUILTIN 10 /* set if key is builtin */ | 178 | #define KEY_FLAG_KEEP 10 /* set if key should not be removed */ |
| 179 | #define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */ | ||
| 180 | #define KEY_FLAG_KEEP 12 /* set if key should not be removed */ | ||
| 181 | 179 | ||
| 182 | /* the key type and key description string | 180 | /* the key type and key description string |
| 183 | * - the desc is used to match a key against search criteria | 181 | * - the desc is used to match a key against search criteria |
| @@ -205,6 +203,20 @@ struct key { | |||
| 205 | }; | 203 | }; |
| 206 | int reject_error; | 204 | int reject_error; |
| 207 | }; | 205 | }; |
| 206 | |||
| 207 | /* 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 | ||
| 209 | * keyring is open to any addition. It is ignored for non-keyring | ||
| 210 | * keys. | ||
| 211 | * | ||
| 212 | * This is intended for use with rings of trusted keys whereby addition | ||
| 213 | * to the keyring needs to be controlled. KEY_ALLOC_BYPASS_RESTRICTION | ||
| 214 | * overrides this, allowing the kernel to add extra keys without | ||
| 215 | * restriction. | ||
| 216 | */ | ||
| 217 | int (*restrict_link)(struct key *keyring, | ||
| 218 | const struct key_type *type, | ||
| 219 | const union key_payload *payload); | ||
| 208 | }; | 220 | }; |
| 209 | 221 | ||
| 210 | extern struct key *key_alloc(struct key_type *type, | 222 | extern struct key *key_alloc(struct key_type *type, |
| @@ -212,14 +224,17 @@ extern struct key *key_alloc(struct key_type *type, | |||
| 212 | kuid_t uid, kgid_t gid, | 224 | kuid_t uid, kgid_t gid, |
| 213 | const struct cred *cred, | 225 | const struct cred *cred, |
| 214 | key_perm_t perm, | 226 | key_perm_t perm, |
| 215 | unsigned long flags); | 227 | unsigned long flags, |
| 228 | int (*restrict_link)(struct key *, | ||
| 229 | const struct key_type *, | ||
| 230 | const union key_payload *)); | ||
| 216 | 231 | ||
| 217 | 232 | ||
| 218 | #define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */ | 233 | #define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */ |
| 219 | #define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */ | 234 | #define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */ |
| 220 | #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ | 235 | #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ |
| 221 | #define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */ | 236 | #define KEY_ALLOC_BUILT_IN 0x0004 /* Key is built into kernel */ |
| 222 | #define KEY_ALLOC_BUILT_IN 0x0008 /* Key is built into kernel */ | 237 | #define KEY_ALLOC_BYPASS_RESTRICTION 0x0008 /* Override the check on restricted keyrings */ |
| 223 | 238 | ||
| 224 | extern void key_revoke(struct key *key); | 239 | extern void key_revoke(struct key *key); |
| 225 | extern void key_invalidate(struct key *key); | 240 | extern void key_invalidate(struct key *key); |
| @@ -288,8 +303,15 @@ extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid | |||
| 288 | const struct cred *cred, | 303 | const struct cred *cred, |
| 289 | key_perm_t perm, | 304 | key_perm_t perm, |
| 290 | unsigned long flags, | 305 | unsigned long flags, |
| 306 | int (*restrict_link)(struct key *, | ||
| 307 | const struct key_type *, | ||
| 308 | const union key_payload *), | ||
| 291 | struct key *dest); | 309 | struct key *dest); |
| 292 | 310 | ||
| 311 | extern int restrict_link_reject(struct key *keyring, | ||
| 312 | const struct key_type *type, | ||
| 313 | const union key_payload *payload); | ||
| 314 | |||
| 293 | extern int keyring_clear(struct key *keyring); | 315 | extern int keyring_clear(struct key *keyring); |
| 294 | 316 | ||
| 295 | extern key_ref_t keyring_search(key_ref_t keyring, | 317 | extern key_ref_t keyring_search(key_ref_t keyring, |
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 512fd000562b..7ae397669d8b 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h | |||
| @@ -1805,7 +1805,6 @@ struct security_hook_heads { | |||
| 1805 | struct list_head tun_dev_attach_queue; | 1805 | struct list_head tun_dev_attach_queue; |
| 1806 | struct list_head tun_dev_attach; | 1806 | struct list_head tun_dev_attach; |
| 1807 | struct list_head tun_dev_open; | 1807 | struct list_head tun_dev_open; |
| 1808 | struct list_head skb_owned_by; | ||
| 1809 | #endif /* CONFIG_SECURITY_NETWORK */ | 1808 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 1810 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1809 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| 1811 | struct list_head xfrm_policy_alloc_security; | 1810 | struct list_head xfrm_policy_alloc_security; |
| @@ -1894,5 +1893,10 @@ extern void __init yama_add_hooks(void); | |||
| 1894 | #else | 1893 | #else |
| 1895 | static inline void __init yama_add_hooks(void) { } | 1894 | static inline void __init yama_add_hooks(void) { } |
| 1896 | #endif | 1895 | #endif |
| 1896 | #ifdef CONFIG_SECURITY_LOADPIN | ||
| 1897 | void __init loadpin_add_hooks(void); | ||
| 1898 | #else | ||
| 1899 | static inline void loadpin_add_hooks(void) { }; | ||
| 1900 | #endif | ||
| 1897 | 1901 | ||
| 1898 | #endif /* ! __LINUX_LSM_HOOKS_H */ | 1902 | #endif /* ! __LINUX_LSM_HOOKS_H */ |
diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h index dabe643eb5fa..5ce9538f290e 100644 --- a/include/linux/string_helpers.h +++ b/include/linux/string_helpers.h | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | 5 | ||
| 6 | struct file; | ||
| 7 | |||
| 6 | /* Descriptions of the types of units to | 8 | /* Descriptions of the types of units to |
| 7 | * print in */ | 9 | * print in */ |
| 8 | enum string_size_units { | 10 | enum string_size_units { |
| @@ -68,4 +70,8 @@ static inline int string_escape_str_any_np(const char *src, char *dst, | |||
| 68 | return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, only); | 70 | return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, only); |
| 69 | } | 71 | } |
| 70 | 72 | ||
| 73 | char *kstrdup_quotable(const char *src, gfp_t gfp); | ||
| 74 | char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp); | ||
| 75 | char *kstrdup_quotable_file(struct file *file, gfp_t gfp); | ||
| 76 | |||
| 71 | #endif | 77 | #endif |
diff --git a/include/linux/verification.h b/include/linux/verification.h new file mode 100644 index 000000000000..a10549a6c7cd --- /dev/null +++ b/include/linux/verification.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* Signature verification | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 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 | #ifndef _LINUX_VERIFICATION_H | ||
| 13 | #define _LINUX_VERIFICATION_H | ||
| 14 | |||
| 15 | /* | ||
| 16 | * The use to which an asymmetric key is being put. | ||
| 17 | */ | ||
| 18 | enum key_being_used_for { | ||
| 19 | VERIFYING_MODULE_SIGNATURE, | ||
| 20 | VERIFYING_FIRMWARE_SIGNATURE, | ||
| 21 | VERIFYING_KEXEC_PE_SIGNATURE, | ||
| 22 | VERIFYING_KEY_SIGNATURE, | ||
| 23 | VERIFYING_KEY_SELF_SIGNATURE, | ||
| 24 | VERIFYING_UNSPECIFIED_SIGNATURE, | ||
| 25 | NR__KEY_BEING_USED_FOR | ||
| 26 | }; | ||
| 27 | extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; | ||
| 28 | |||
| 29 | #ifdef CONFIG_SYSTEM_DATA_VERIFICATION | ||
| 30 | |||
| 31 | struct key; | ||
| 32 | |||
| 33 | extern int verify_pkcs7_signature(const void *data, size_t len, | ||
| 34 | const void *raw_pkcs7, size_t pkcs7_len, | ||
| 35 | struct key *trusted_keys, | ||
| 36 | enum key_being_used_for usage, | ||
| 37 | int (*view_content)(void *ctx, | ||
| 38 | const void *data, size_t len, | ||
| 39 | size_t asn1hdrlen), | ||
| 40 | void *ctx); | ||
| 41 | |||
| 42 | #ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION | ||
| 43 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, | ||
| 44 | struct key *trusted_keys, | ||
| 45 | enum key_being_used_for usage); | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ | ||
| 49 | #endif /* _LINUX_VERIFY_PEFILE_H */ | ||
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h deleted file mode 100644 index da2049b5161c..000000000000 --- a/include/linux/verify_pefile.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | /* Signed PE file verification | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 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 | #ifndef _LINUX_VERIFY_PEFILE_H | ||
| 13 | #define _LINUX_VERIFY_PEFILE_H | ||
| 14 | |||
| 15 | #include <crypto/public_key.h> | ||
| 16 | |||
| 17 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, | ||
| 18 | struct key *trusted_keyring, | ||
| 19 | enum key_being_used_for usage, | ||
| 20 | bool *_trusted); | ||
| 21 | |||
| 22 | #endif /* _LINUX_VERIFY_PEFILE_H */ | ||
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h index 840cb990abe2..86eddd6241f3 100644 --- a/include/uapi/linux/keyctl.h +++ b/include/uapi/linux/keyctl.h | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | #ifndef _LINUX_KEYCTL_H | 12 | #ifndef _LINUX_KEYCTL_H |
| 13 | #define _LINUX_KEYCTL_H | 13 | #define _LINUX_KEYCTL_H |
| 14 | 14 | ||
| 15 | #include <linux/types.h> | ||
| 16 | |||
| 15 | /* special process keyring shortcut IDs */ | 17 | /* special process keyring shortcut IDs */ |
| 16 | #define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */ | 18 | #define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */ |
| 17 | #define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */ | 19 | #define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */ |
| @@ -57,5 +59,13 @@ | |||
| 57 | #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ | 59 | #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ |
| 58 | #define KEYCTL_INVALIDATE 21 /* invalidate a key */ | 60 | #define KEYCTL_INVALIDATE 21 /* invalidate a key */ |
| 59 | #define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ | 61 | #define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ |
| 62 | #define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */ | ||
| 63 | |||
| 64 | /* keyctl structures */ | ||
| 65 | struct keyctl_dh_params { | ||
| 66 | __s32 private; | ||
| 67 | __s32 prime; | ||
| 68 | __s32 base; | ||
| 69 | }; | ||
| 60 | 70 | ||
| 61 | #endif /* _LINUX_KEYCTL_H */ | 71 | #endif /* _LINUX_KEYCTL_H */ |
diff --git a/kernel/module_signing.c b/kernel/module_signing.c index 64b9dead4a07..937c844bee4a 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
| 14 | #include <linux/string.h> | 14 | #include <linux/string.h> |
| 15 | #include <keys/system_keyring.h> | 15 | #include <linux/verification.h> |
| 16 | #include <crypto/public_key.h> | 16 | #include <crypto/public_key.h> |
| 17 | #include "module-internal.h" | 17 | #include "module-internal.h" |
| 18 | 18 | ||
| @@ -80,6 +80,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) | |||
| 80 | return -EBADMSG; | 80 | return -EBADMSG; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | return system_verify_data(mod, modlen, mod + modlen, sig_len, | 83 | return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len, |
| 84 | VERIFYING_MODULE_SIGNATURE); | 84 | NULL, VERIFYING_MODULE_SIGNATURE, |
| 85 | NULL, NULL); | ||
| 85 | } | 86 | } |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index e1e5a354854e..6c9bb62ed046 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
| @@ -915,7 +915,7 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off, | |||
| 915 | 915 | ||
| 916 | fprog = filter->prog->orig_prog; | 916 | fprog = filter->prog->orig_prog; |
| 917 | if (!fprog) { | 917 | if (!fprog) { |
| 918 | /* This must be a new non-cBPF filter, since we save every | 918 | /* This must be a new non-cBPF filter, since we save |
| 919 | * every cBPF filter's orig_prog above when | 919 | * every cBPF filter's orig_prog above when |
| 920 | * CONFIG_CHECKPOINT_RESTORE is enabled. | 920 | * CONFIG_CHECKPOINT_RESTORE is enabled. |
| 921 | */ | 921 | */ |
diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 5c88204b6f1f..ecaac2c0526f 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c | |||
| @@ -10,6 +10,10 @@ | |||
| 10 | #include <linux/export.h> | 10 | #include <linux/export.h> |
| 11 | #include <linux/ctype.h> | 11 | #include <linux/ctype.h> |
| 12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
| 13 | #include <linux/fs.h> | ||
| 14 | #include <linux/limits.h> | ||
| 15 | #include <linux/mm.h> | ||
| 16 | #include <linux/slab.h> | ||
| 13 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 14 | #include <linux/string_helpers.h> | 18 | #include <linux/string_helpers.h> |
| 15 | 19 | ||
| @@ -534,3 +538,91 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, | |||
| 534 | return p - dst; | 538 | return p - dst; |
| 535 | } | 539 | } |
| 536 | EXPORT_SYMBOL(string_escape_mem); | 540 | EXPORT_SYMBOL(string_escape_mem); |
| 541 | |||
| 542 | /* | ||
| 543 | * Return an allocated string that has been escaped of special characters | ||
| 544 | * and double quotes, making it safe to log in quotes. | ||
| 545 | */ | ||
| 546 | char *kstrdup_quotable(const char *src, gfp_t gfp) | ||
| 547 | { | ||
| 548 | size_t slen, dlen; | ||
| 549 | char *dst; | ||
| 550 | const int flags = ESCAPE_HEX; | ||
| 551 | const char esc[] = "\f\n\r\t\v\a\e\\\""; | ||
| 552 | |||
| 553 | if (!src) | ||
| 554 | return NULL; | ||
| 555 | slen = strlen(src); | ||
| 556 | |||
| 557 | dlen = string_escape_mem(src, slen, NULL, 0, flags, esc); | ||
| 558 | dst = kmalloc(dlen + 1, gfp); | ||
| 559 | if (!dst) | ||
| 560 | return NULL; | ||
| 561 | |||
| 562 | WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen); | ||
| 563 | dst[dlen] = '\0'; | ||
| 564 | |||
| 565 | return dst; | ||
| 566 | } | ||
| 567 | EXPORT_SYMBOL_GPL(kstrdup_quotable); | ||
| 568 | |||
| 569 | /* | ||
| 570 | * Returns allocated NULL-terminated string containing process | ||
| 571 | * command line, with inter-argument NULLs replaced with spaces, | ||
| 572 | * and other special characters escaped. | ||
| 573 | */ | ||
| 574 | char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp) | ||
| 575 | { | ||
| 576 | char *buffer, *quoted; | ||
| 577 | int i, res; | ||
| 578 | |||
| 579 | buffer = kmalloc(PAGE_SIZE, GFP_TEMPORARY); | ||
| 580 | if (!buffer) | ||
| 581 | return NULL; | ||
| 582 | |||
| 583 | res = get_cmdline(task, buffer, PAGE_SIZE - 1); | ||
| 584 | buffer[res] = '\0'; | ||
| 585 | |||
| 586 | /* Collapse trailing NULLs, leave res pointing to last non-NULL. */ | ||
| 587 | while (--res >= 0 && buffer[res] == '\0') | ||
| 588 | ; | ||
| 589 | |||
| 590 | /* Replace inter-argument NULLs. */ | ||
| 591 | for (i = 0; i <= res; i++) | ||
| 592 | if (buffer[i] == '\0') | ||
| 593 | buffer[i] = ' '; | ||
| 594 | |||
| 595 | /* Make sure result is printable. */ | ||
| 596 | quoted = kstrdup_quotable(buffer, gfp); | ||
| 597 | kfree(buffer); | ||
| 598 | return quoted; | ||
| 599 | } | ||
| 600 | EXPORT_SYMBOL_GPL(kstrdup_quotable_cmdline); | ||
| 601 | |||
| 602 | /* | ||
| 603 | * Returns allocated NULL-terminated string containing pathname, | ||
| 604 | * with special characters escaped, able to be safely logged. If | ||
| 605 | * there is an error, the leading character will be "<". | ||
| 606 | */ | ||
| 607 | char *kstrdup_quotable_file(struct file *file, gfp_t gfp) | ||
| 608 | { | ||
| 609 | char *temp, *pathname; | ||
| 610 | |||
| 611 | if (!file) | ||
| 612 | return kstrdup("<unknown>", gfp); | ||
| 613 | |||
| 614 | /* We add 11 spaces for ' (deleted)' to be appended */ | ||
| 615 | temp = kmalloc(PATH_MAX + 11, GFP_TEMPORARY); | ||
| 616 | if (!temp) | ||
| 617 | return kstrdup("<no_memory>", gfp); | ||
| 618 | |||
| 619 | pathname = file_path(file, temp, PATH_MAX + 11); | ||
| 620 | if (IS_ERR(pathname)) | ||
| 621 | pathname = kstrdup("<too_long>", gfp); | ||
| 622 | else | ||
| 623 | pathname = kstrdup_quotable(pathname, gfp); | ||
| 624 | |||
| 625 | kfree(temp); | ||
| 626 | return pathname; | ||
| 627 | } | ||
| 628 | EXPORT_SYMBOL_GPL(kstrdup_quotable_file); | ||
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index c79b85eb4d4c..8737412c7b27 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
| @@ -281,7 +281,7 @@ static int __init init_dns_resolver(void) | |||
| 281 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, | 281 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, |
| 282 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 282 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 283 | KEY_USR_VIEW | KEY_USR_READ, | 283 | KEY_USR_VIEW | KEY_USR_READ, |
| 284 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | 284 | KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); |
| 285 | if (IS_ERR(keyring)) { | 285 | if (IS_ERR(keyring)) { |
| 286 | ret = PTR_ERR(keyring); | 286 | ret = PTR_ERR(keyring); |
| 287 | goto failed_put_cred; | 287 | goto failed_put_cred; |
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 28cddc85b700..1325776daa27 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
| @@ -677,7 +677,7 @@ int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, | |||
| 677 | u32 spot = start; | 677 | u32 spot = start; |
| 678 | 678 | ||
| 679 | while (rc == 0 && spot <= end) { | 679 | while (rc == 0 && spot <= end) { |
| 680 | if (((spot & (BITS_PER_LONG - 1)) != 0) && | 680 | if (((spot & (BITS_PER_LONG - 1)) == 0) && |
| 681 | ((end - spot) > BITS_PER_LONG)) { | 681 | ((end - spot) > BITS_PER_LONG)) { |
| 682 | rc = netlbl_catmap_setlong(catmap, | 682 | rc = netlbl_catmap_setlong(catmap, |
| 683 | spot, | 683 | spot, |
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 3fb492eedeb9..1021b4c0bdd2 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c | |||
| @@ -965,7 +965,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn, | |||
| 965 | 965 | ||
| 966 | key = key_alloc(&key_type_rxrpc, "x", | 966 | key = key_alloc(&key_type_rxrpc, "x", |
| 967 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0, | 967 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0, |
| 968 | KEY_ALLOC_NOT_IN_QUOTA); | 968 | KEY_ALLOC_NOT_IN_QUOTA, NULL); |
| 969 | if (IS_ERR(key)) { | 969 | if (IS_ERR(key)) { |
| 970 | _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key)); | 970 | _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key)); |
| 971 | return -ENOMEM; | 971 | return -ENOMEM; |
| @@ -1012,7 +1012,7 @@ struct key *rxrpc_get_null_key(const char *keyname) | |||
| 1012 | 1012 | ||
| 1013 | key = key_alloc(&key_type_rxrpc, keyname, | 1013 | key = key_alloc(&key_type_rxrpc, keyname, |
| 1014 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, | 1014 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, |
| 1015 | KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA); | 1015 | KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL); |
| 1016 | if (IS_ERR(key)) | 1016 | if (IS_ERR(key)) |
| 1017 | return key; | 1017 | return key; |
| 1018 | 1018 | ||
diff --git a/security/Kconfig b/security/Kconfig index e45237897b43..176758cdfa57 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
| @@ -122,6 +122,7 @@ source security/selinux/Kconfig | |||
| 122 | source security/smack/Kconfig | 122 | source security/smack/Kconfig |
| 123 | source security/tomoyo/Kconfig | 123 | source security/tomoyo/Kconfig |
| 124 | source security/apparmor/Kconfig | 124 | source security/apparmor/Kconfig |
| 125 | source security/loadpin/Kconfig | ||
| 125 | source security/yama/Kconfig | 126 | source security/yama/Kconfig |
| 126 | 127 | ||
| 127 | source security/integrity/Kconfig | 128 | source security/integrity/Kconfig |
diff --git a/security/Makefile b/security/Makefile index c9bfbc84ff50..f2d71cdb8e19 100644 --- a/security/Makefile +++ b/security/Makefile | |||
| @@ -8,6 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack | |||
| 8 | subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo | 8 | subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo |
| 9 | subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor | 9 | subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor |
| 10 | subdir-$(CONFIG_SECURITY_YAMA) += yama | 10 | subdir-$(CONFIG_SECURITY_YAMA) += yama |
| 11 | subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin | ||
| 11 | 12 | ||
| 12 | # always enable default capabilities | 13 | # always enable default capabilities |
| 13 | obj-y += commoncap.o | 14 | obj-y += commoncap.o |
| @@ -22,6 +23,7 @@ obj-$(CONFIG_AUDIT) += lsm_audit.o | |||
| 22 | obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ | 23 | obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ |
| 23 | obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ | 24 | obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ |
| 24 | obj-$(CONFIG_SECURITY_YAMA) += yama/ | 25 | obj-$(CONFIG_SECURITY_YAMA) += yama/ |
| 26 | obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ | ||
| 25 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | 27 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o |
| 26 | 28 | ||
| 27 | # Object integrity file lists | 29 | # Object integrity file lists |
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 979be65d22c4..da9565891738 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig | |||
| @@ -35,7 +35,6 @@ config INTEGRITY_ASYMMETRIC_KEYS | |||
| 35 | default n | 35 | default n |
| 36 | select ASYMMETRIC_KEY_TYPE | 36 | select ASYMMETRIC_KEY_TYPE |
| 37 | select ASYMMETRIC_PUBLIC_KEY_SUBTYPE | 37 | select ASYMMETRIC_PUBLIC_KEY_SUBTYPE |
| 38 | select PUBLIC_KEY_ALGO_RSA | ||
| 39 | select CRYPTO_RSA | 38 | select CRYPTO_RSA |
| 40 | select X509_CERTIFICATE_PARSER | 39 | select X509_CERTIFICATE_PARSER |
| 41 | help | 40 | help |
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 8ef15118cc78..4304372b323f 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <linux/cred.h> | 18 | #include <linux/cred.h> |
| 19 | #include <linux/key-type.h> | 19 | #include <linux/key-type.h> |
| 20 | #include <linux/digsig.h> | 20 | #include <linux/digsig.h> |
| 21 | #include <crypto/public_key.h> | ||
| 22 | #include <keys/system_keyring.h> | ||
| 21 | 23 | ||
| 22 | #include "integrity.h" | 24 | #include "integrity.h" |
| 23 | 25 | ||
| @@ -40,6 +42,12 @@ static bool init_keyring __initdata = true; | |||
| 40 | static bool init_keyring __initdata; | 42 | static bool init_keyring __initdata; |
| 41 | #endif | 43 | #endif |
| 42 | 44 | ||
| 45 | #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY | ||
| 46 | #define restrict_link_to_ima restrict_link_by_builtin_and_secondary_trusted | ||
| 47 | #else | ||
| 48 | #define restrict_link_to_ima restrict_link_by_builtin_trusted | ||
| 49 | #endif | ||
| 50 | |||
| 43 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 51 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
| 44 | const char *digest, int digestlen) | 52 | const char *digest, int digestlen) |
| 45 | { | 53 | { |
| @@ -83,10 +91,9 @@ int __init integrity_init_keyring(const unsigned int id) | |||
| 83 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | 91 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 84 | KEY_USR_VIEW | KEY_USR_READ | | 92 | KEY_USR_VIEW | KEY_USR_READ | |
| 85 | KEY_USR_WRITE | KEY_USR_SEARCH), | 93 | KEY_USR_WRITE | KEY_USR_SEARCH), |
| 86 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | 94 | KEY_ALLOC_NOT_IN_QUOTA, |
| 87 | if (!IS_ERR(keyring[id])) | 95 | restrict_link_to_ima, NULL); |
| 88 | set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags); | 96 | if (IS_ERR(keyring[id])) { |
| 89 | else { | ||
| 90 | err = PTR_ERR(keyring[id]); | 97 | err = PTR_ERR(keyring[id]); |
| 91 | pr_info("Can't allocate %s keyring (%d)\n", | 98 | pr_info("Can't allocate %s keyring (%d)\n", |
| 92 | keyring_name[id], err); | 99 | keyring_name[id], err); |
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index e54a8a8dae94..5487827fa86c 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
| @@ -155,23 +155,33 @@ config IMA_TRUSTED_KEYRING | |||
| 155 | 155 | ||
| 156 | This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING | 156 | This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING |
| 157 | 157 | ||
| 158 | config IMA_MOK_KEYRING | 158 | config IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY |
| 159 | bool "Create IMA machine owner keys (MOK) and blacklist keyrings" | 159 | bool "Permit keys validly signed by a built-in or secondary CA cert (EXPERIMENTAL)" |
| 160 | depends on SYSTEM_TRUSTED_KEYRING | ||
| 161 | depends on SECONDARY_TRUSTED_KEYRING | ||
| 162 | depends on INTEGRITY_ASYMMETRIC_KEYS | ||
| 163 | select INTEGRITY_TRUSTED_KEYRING | ||
| 164 | default n | ||
| 165 | help | ||
| 166 | Keys may be added to the IMA or IMA blacklist keyrings, if the | ||
| 167 | key is validly signed by a CA cert in the system built-in or | ||
| 168 | secondary trusted keyrings. | ||
| 169 | |||
| 170 | Intermediate keys between those the kernel has compiled in and the | ||
| 171 | IMA keys to be added may be added to the system secondary keyring, | ||
| 172 | provided they are validly signed by a key already resident in the | ||
| 173 | built-in or secondary trusted keyrings. | ||
| 174 | |||
| 175 | config IMA_BLACKLIST_KEYRING | ||
| 176 | bool "Create IMA machine owner blacklist keyrings (EXPERIMENTAL)" | ||
| 160 | depends on SYSTEM_TRUSTED_KEYRING | 177 | depends on SYSTEM_TRUSTED_KEYRING |
| 161 | depends on IMA_TRUSTED_KEYRING | 178 | depends on IMA_TRUSTED_KEYRING |
| 162 | default n | 179 | default n |
| 163 | help | 180 | help |
| 164 | This option creates IMA MOK and blacklist keyrings. IMA MOK is an | 181 | This option creates an IMA blacklist keyring, which contains all |
| 165 | intermediate keyring that sits between .system and .ima keyrings, | 182 | revoked IMA keys. It is consulted before any other keyring. If |
| 166 | effectively forming a simple CA hierarchy. To successfully import a | 183 | the search is successful the requested operation is rejected and |
| 167 | key into .ima_mok it must be signed by a key which CA is in .system | 184 | an error is returned to the caller. |
| 168 | keyring. On turn any key that needs to go in .ima keyring must be | ||
| 169 | signed by CA in either .system or .ima_mok keyrings. IMA MOK is empty | ||
| 170 | at kernel boot. | ||
| 171 | |||
| 172 | IMA blacklist keyring contains all revoked IMA keys. It is consulted | ||
| 173 | before any other keyring. If the search is successful the requested | ||
| 174 | operation is rejected and error is returned to the caller. | ||
| 175 | 185 | ||
| 176 | config IMA_LOAD_X509 | 186 | config IMA_LOAD_X509 |
| 177 | bool "Load X509 certificate onto the '.ima' trusted keyring" | 187 | bool "Load X509 certificate onto the '.ima' trusted keyring" |
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index a8539f9e060f..9aeaedad1e2b 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile | |||
| @@ -8,4 +8,4 @@ obj-$(CONFIG_IMA) += ima.o | |||
| 8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ | 8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ |
| 9 | ima_policy.o ima_template.o ima_template_lib.o | 9 | ima_policy.o ima_template.o ima_template_lib.o |
| 10 | ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o | 10 | ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o |
| 11 | obj-$(CONFIG_IMA_MOK_KEYRING) += ima_mok.o | 11 | obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 6b4694aedae8..1bcbc12e03d9 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
| @@ -275,6 +275,11 @@ out: | |||
| 275 | xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { | 275 | xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { |
| 276 | if (!ima_fix_xattr(dentry, iint)) | 276 | if (!ima_fix_xattr(dentry, iint)) |
| 277 | status = INTEGRITY_PASS; | 277 | status = INTEGRITY_PASS; |
| 278 | } else if ((inode->i_size == 0) && | ||
| 279 | (iint->flags & IMA_NEW_FILE) && | ||
| 280 | (xattr_value && | ||
| 281 | xattr_value->type == EVM_IMA_XATTR_DIGSIG)) { | ||
| 282 | status = INTEGRITY_PASS; | ||
| 278 | } | 283 | } |
| 279 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, | 284 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, |
| 280 | op, cause, rc, 0); | 285 | op, cause, rc, 0); |
| @@ -328,7 +333,7 @@ void ima_inode_post_setattr(struct dentry *dentry) | |||
| 328 | if (iint) { | 333 | if (iint) { |
| 329 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | | 334 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | |
| 330 | IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | | 335 | IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | |
| 331 | IMA_ACTION_FLAGS); | 336 | IMA_ACTION_RULE_FLAGS); |
| 332 | if (must_appraise) | 337 | if (must_appraise) |
| 333 | iint->flags |= IMA_APPRAISE; | 338 | iint->flags |= IMA_APPRAISE; |
| 334 | } | 339 | } |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 391f41751021..68b26c340acd 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -246,7 +246,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size, | |||
| 246 | ima_audit_measurement(iint, pathname); | 246 | ima_audit_measurement(iint, pathname); |
| 247 | 247 | ||
| 248 | out_digsig: | 248 | out_digsig: |
| 249 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) | 249 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) && |
| 250 | !(iint->flags & IMA_NEW_FILE)) | ||
| 250 | rc = -EACCES; | 251 | rc = -EACCES; |
| 251 | kfree(xattr_value); | 252 | kfree(xattr_value); |
| 252 | out_free: | 253 | out_free: |
| @@ -316,6 +317,28 @@ int ima_file_check(struct file *file, int mask, int opened) | |||
| 316 | EXPORT_SYMBOL_GPL(ima_file_check); | 317 | EXPORT_SYMBOL_GPL(ima_file_check); |
| 317 | 318 | ||
| 318 | /** | 319 | /** |
| 320 | * ima_post_path_mknod - mark as a new inode | ||
| 321 | * @dentry: newly created dentry | ||
| 322 | * | ||
| 323 | * Mark files created via the mknodat syscall as new, so that the | ||
| 324 | * file data can be written later. | ||
| 325 | */ | ||
| 326 | void ima_post_path_mknod(struct dentry *dentry) | ||
| 327 | { | ||
| 328 | struct integrity_iint_cache *iint; | ||
| 329 | struct inode *inode = dentry->d_inode; | ||
| 330 | int must_appraise; | ||
| 331 | |||
| 332 | must_appraise = ima_must_appraise(inode, MAY_ACCESS, FILE_CHECK); | ||
| 333 | if (!must_appraise) | ||
| 334 | return; | ||
| 335 | |||
| 336 | iint = integrity_inode_get(inode); | ||
| 337 | if (iint) | ||
| 338 | iint->flags |= IMA_NEW_FILE; | ||
| 339 | } | ||
| 340 | |||
| 341 | /** | ||
| 319 | * ima_read_file - pre-measure/appraise hook decision based on policy | 342 | * ima_read_file - pre-measure/appraise hook decision based on policy |
| 320 | * @file: pointer to the file to be measured/appraised/audit | 343 | * @file: pointer to the file to be measured/appraised/audit |
| 321 | * @read_id: caller identifier | 344 | * @read_id: caller identifier |
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c index 676885e4320e..74a279957464 100644 --- a/security/integrity/ima/ima_mok.c +++ b/security/integrity/ima/ima_mok.c | |||
| @@ -17,38 +17,29 @@ | |||
| 17 | #include <linux/cred.h> | 17 | #include <linux/cred.h> |
| 18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <keys/asymmetric-type.h> | 20 | #include <keys/system_keyring.h> |
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | struct key *ima_mok_keyring; | ||
| 24 | struct key *ima_blacklist_keyring; | 23 | struct key *ima_blacklist_keyring; |
| 25 | 24 | ||
| 26 | /* | 25 | /* |
| 27 | * Allocate the IMA MOK and blacklist keyrings | 26 | * Allocate the IMA blacklist keyring |
| 28 | */ | 27 | */ |
| 29 | __init int ima_mok_init(void) | 28 | __init int ima_mok_init(void) |
| 30 | { | 29 | { |
| 31 | pr_notice("Allocating IMA MOK and blacklist keyrings.\n"); | 30 | pr_notice("Allocating IMA blacklist keyring.\n"); |
| 32 | |||
| 33 | ima_mok_keyring = keyring_alloc(".ima_mok", | ||
| 34 | KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), | ||
| 35 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
| 36 | KEY_USR_VIEW | KEY_USR_READ | | ||
| 37 | KEY_USR_WRITE | KEY_USR_SEARCH, | ||
| 38 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | ||
| 39 | 31 | ||
| 40 | ima_blacklist_keyring = keyring_alloc(".ima_blacklist", | 32 | ima_blacklist_keyring = keyring_alloc(".ima_blacklist", |
| 41 | KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), | 33 | KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), |
| 42 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 34 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 43 | KEY_USR_VIEW | KEY_USR_READ | | 35 | KEY_USR_VIEW | KEY_USR_READ | |
| 44 | KEY_USR_WRITE | KEY_USR_SEARCH, | 36 | KEY_USR_WRITE | KEY_USR_SEARCH, |
| 45 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | 37 | KEY_ALLOC_NOT_IN_QUOTA, |
| 38 | restrict_link_by_builtin_trusted, NULL); | ||
| 46 | 39 | ||
| 47 | if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring)) | 40 | if (IS_ERR(ima_blacklist_keyring)) |
| 48 | panic("Can't allocate IMA MOK or blacklist keyrings."); | 41 | panic("Can't allocate IMA blacklist keyring."); |
| 49 | set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags); | ||
| 50 | 42 | ||
| 51 | set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags); | ||
| 52 | set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags); | 43 | set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags); |
| 53 | return 0; | 44 | return 0; |
| 54 | } | 45 | } |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index e08935cf343f..90bc57d796ec 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | /* iint cache flags */ | 29 | /* iint cache flags */ |
| 30 | #define IMA_ACTION_FLAGS 0xff000000 | 30 | #define IMA_ACTION_FLAGS 0xff000000 |
| 31 | #define IMA_ACTION_RULE_FLAGS 0x06000000 | ||
| 31 | #define IMA_DIGSIG 0x01000000 | 32 | #define IMA_DIGSIG 0x01000000 |
| 32 | #define IMA_DIGSIG_REQUIRED 0x02000000 | 33 | #define IMA_DIGSIG_REQUIRED 0x02000000 |
| 33 | #define IMA_PERMIT_DIRECTIO 0x04000000 | 34 | #define IMA_PERMIT_DIRECTIO 0x04000000 |
diff --git a/security/keys/Kconfig b/security/keys/Kconfig index fe4d74e126a7..f826e8739023 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig | |||
| @@ -41,6 +41,10 @@ config BIG_KEYS | |||
| 41 | bool "Large payload keys" | 41 | bool "Large payload keys" |
| 42 | depends on KEYS | 42 | depends on KEYS |
| 43 | depends on TMPFS | 43 | depends on TMPFS |
| 44 | select CRYPTO | ||
| 45 | select CRYPTO_AES | ||
| 46 | select CRYPTO_ECB | ||
| 47 | select CRYPTO_RNG | ||
| 44 | help | 48 | help |
| 45 | This option provides support for holding large keys within the kernel | 49 | This option provides support for holding large keys within the kernel |
| 46 | (for example Kerberos ticket caches). The data may be stored out to | 50 | (for example Kerberos ticket caches). The data may be stored out to |
| @@ -81,3 +85,14 @@ config ENCRYPTED_KEYS | |||
| 81 | Userspace only ever sees/stores encrypted blobs. | 85 | Userspace only ever sees/stores encrypted blobs. |
| 82 | 86 | ||
| 83 | If you are unsure as to whether this is required, answer N. | 87 | If you are unsure as to whether this is required, answer N. |
| 88 | |||
| 89 | config KEY_DH_OPERATIONS | ||
| 90 | bool "Diffie-Hellman operations on retained keys" | ||
| 91 | depends on KEYS | ||
| 92 | select MPILIB | ||
| 93 | help | ||
| 94 | This option provides support for calculating Diffie-Hellman | ||
| 95 | public keys and shared secrets using values stored as keys | ||
| 96 | in the kernel. | ||
| 97 | |||
| 98 | If you are unsure as to whether this is required, answer N. | ||
diff --git a/security/keys/Makefile b/security/keys/Makefile index dfb3a7bededf..1fd4a16e6daf 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
| @@ -19,6 +19,7 @@ obj-$(CONFIG_KEYS_COMPAT) += compat.o | |||
| 19 | obj-$(CONFIG_PROC_FS) += proc.o | 19 | obj-$(CONFIG_PROC_FS) += proc.o |
| 20 | obj-$(CONFIG_SYSCTL) += sysctl.o | 20 | obj-$(CONFIG_SYSCTL) += sysctl.o |
| 21 | obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o | 21 | obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o |
| 22 | obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.o | ||
| 22 | 23 | ||
| 23 | # | 24 | # |
| 24 | # Key types | 25 | # Key types |
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index c721e398893a..9e443fccad4c 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
| @@ -14,8 +14,10 @@ | |||
| 14 | #include <linux/file.h> | 14 | #include <linux/file.h> |
| 15 | #include <linux/shmem_fs.h> | 15 | #include <linux/shmem_fs.h> |
| 16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 17 | #include <linux/scatterlist.h> | ||
| 17 | #include <keys/user-type.h> | 18 | #include <keys/user-type.h> |
| 18 | #include <keys/big_key-type.h> | 19 | #include <keys/big_key-type.h> |
| 20 | #include <crypto/rng.h> | ||
| 19 | 21 | ||
| 20 | /* | 22 | /* |
| 21 | * Layout of key payload words. | 23 | * Layout of key payload words. |
| @@ -28,6 +30,14 @@ enum { | |||
| 28 | }; | 30 | }; |
| 29 | 31 | ||
| 30 | /* | 32 | /* |
| 33 | * Crypto operation with big_key data | ||
| 34 | */ | ||
| 35 | enum big_key_op { | ||
| 36 | BIG_KEY_ENC, | ||
| 37 | BIG_KEY_DEC, | ||
| 38 | }; | ||
| 39 | |||
| 40 | /* | ||
| 31 | * If the data is under this limit, there's no point creating a shm file to | 41 | * If the data is under this limit, there's no point creating a shm file to |
| 32 | * hold it as the permanently resident metadata for the shmem fs will be at | 42 | * hold it as the permanently resident metadata for the shmem fs will be at |
| 33 | * least as large as the data. | 43 | * least as large as the data. |
| @@ -35,6 +45,11 @@ enum { | |||
| 35 | #define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry)) | 45 | #define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry)) |
| 36 | 46 | ||
| 37 | /* | 47 | /* |
| 48 | * Key size for big_key data encryption | ||
| 49 | */ | ||
| 50 | #define ENC_KEY_SIZE 16 | ||
| 51 | |||
| 52 | /* | ||
| 38 | * big_key defined keys take an arbitrary string as the description and an | 53 | * big_key defined keys take an arbitrary string as the description and an |
| 39 | * arbitrary blob of data as the payload | 54 | * arbitrary blob of data as the payload |
| 40 | */ | 55 | */ |
| @@ -50,12 +65,62 @@ struct key_type key_type_big_key = { | |||
| 50 | }; | 65 | }; |
| 51 | 66 | ||
| 52 | /* | 67 | /* |
| 68 | * Crypto names for big_key data encryption | ||
| 69 | */ | ||
| 70 | static const char big_key_rng_name[] = "stdrng"; | ||
| 71 | static const char big_key_alg_name[] = "ecb(aes)"; | ||
| 72 | |||
| 73 | /* | ||
| 74 | * Crypto algorithms for big_key data encryption | ||
| 75 | */ | ||
| 76 | static struct crypto_rng *big_key_rng; | ||
| 77 | static struct crypto_blkcipher *big_key_blkcipher; | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Generate random key to encrypt big_key data | ||
| 81 | */ | ||
| 82 | static inline int big_key_gen_enckey(u8 *key) | ||
| 83 | { | ||
| 84 | return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE); | ||
| 85 | } | ||
| 86 | |||
| 87 | /* | ||
| 88 | * Encrypt/decrypt big_key data | ||
| 89 | */ | ||
| 90 | static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) | ||
| 91 | { | ||
| 92 | int ret = -EINVAL; | ||
| 93 | struct scatterlist sgio; | ||
| 94 | struct blkcipher_desc desc; | ||
| 95 | |||
| 96 | if (crypto_blkcipher_setkey(big_key_blkcipher, key, ENC_KEY_SIZE)) { | ||
| 97 | ret = -EAGAIN; | ||
| 98 | goto error; | ||
| 99 | } | ||
| 100 | |||
| 101 | desc.flags = 0; | ||
| 102 | desc.tfm = big_key_blkcipher; | ||
| 103 | |||
| 104 | sg_init_one(&sgio, data, datalen); | ||
| 105 | |||
| 106 | if (op == BIG_KEY_ENC) | ||
| 107 | ret = crypto_blkcipher_encrypt(&desc, &sgio, &sgio, datalen); | ||
| 108 | else | ||
| 109 | ret = crypto_blkcipher_decrypt(&desc, &sgio, &sgio, datalen); | ||
| 110 | |||
| 111 | error: | ||
| 112 | return ret; | ||
| 113 | } | ||
| 114 | |||
| 115 | /* | ||
| 53 | * Preparse a big key | 116 | * Preparse a big key |
| 54 | */ | 117 | */ |
| 55 | int big_key_preparse(struct key_preparsed_payload *prep) | 118 | int big_key_preparse(struct key_preparsed_payload *prep) |
| 56 | { | 119 | { |
| 57 | struct path *path = (struct path *)&prep->payload.data[big_key_path]; | 120 | struct path *path = (struct path *)&prep->payload.data[big_key_path]; |
| 58 | struct file *file; | 121 | struct file *file; |
| 122 | u8 *enckey; | ||
| 123 | u8 *data = NULL; | ||
| 59 | ssize_t written; | 124 | ssize_t written; |
| 60 | size_t datalen = prep->datalen; | 125 | size_t datalen = prep->datalen; |
| 61 | int ret; | 126 | int ret; |
| @@ -73,16 +138,43 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
| 73 | /* Create a shmem file to store the data in. This will permit the data | 138 | /* Create a shmem file to store the data in. This will permit the data |
| 74 | * to be swapped out if needed. | 139 | * to be swapped out if needed. |
| 75 | * | 140 | * |
| 76 | * TODO: Encrypt the stored data with a temporary key. | 141 | * File content is stored encrypted with randomly generated key. |
| 77 | */ | 142 | */ |
| 78 | file = shmem_kernel_file_setup("", datalen, 0); | 143 | size_t enclen = ALIGN(datalen, crypto_blkcipher_blocksize(big_key_blkcipher)); |
| 144 | |||
| 145 | /* prepare aligned data to encrypt */ | ||
| 146 | data = kmalloc(enclen, GFP_KERNEL); | ||
| 147 | if (!data) | ||
| 148 | return -ENOMEM; | ||
| 149 | |||
| 150 | memcpy(data, prep->data, datalen); | ||
| 151 | memset(data + datalen, 0x00, enclen - datalen); | ||
| 152 | |||
| 153 | /* generate random key */ | ||
| 154 | enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); | ||
| 155 | if (!enckey) { | ||
| 156 | ret = -ENOMEM; | ||
| 157 | goto error; | ||
| 158 | } | ||
| 159 | |||
| 160 | ret = big_key_gen_enckey(enckey); | ||
| 161 | if (ret) | ||
| 162 | goto err_enckey; | ||
| 163 | |||
| 164 | /* encrypt aligned data */ | ||
| 165 | ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey); | ||
| 166 | if (ret) | ||
| 167 | goto err_enckey; | ||
| 168 | |||
| 169 | /* save aligned data to file */ | ||
| 170 | file = shmem_kernel_file_setup("", enclen, 0); | ||
| 79 | if (IS_ERR(file)) { | 171 | if (IS_ERR(file)) { |
| 80 | ret = PTR_ERR(file); | 172 | ret = PTR_ERR(file); |
| 81 | goto error; | 173 | goto err_enckey; |
| 82 | } | 174 | } |
| 83 | 175 | ||
| 84 | written = kernel_write(file, prep->data, prep->datalen, 0); | 176 | written = kernel_write(file, data, enclen, 0); |
| 85 | if (written != datalen) { | 177 | if (written != enclen) { |
| 86 | ret = written; | 178 | ret = written; |
| 87 | if (written >= 0) | 179 | if (written >= 0) |
| 88 | ret = -ENOMEM; | 180 | ret = -ENOMEM; |
| @@ -92,12 +184,15 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
| 92 | /* Pin the mount and dentry to the key so that we can open it again | 184 | /* Pin the mount and dentry to the key so that we can open it again |
| 93 | * later | 185 | * later |
| 94 | */ | 186 | */ |
| 187 | prep->payload.data[big_key_data] = enckey; | ||
| 95 | *path = file->f_path; | 188 | *path = file->f_path; |
| 96 | path_get(path); | 189 | path_get(path); |
| 97 | fput(file); | 190 | fput(file); |
| 191 | kfree(data); | ||
| 98 | } else { | 192 | } else { |
| 99 | /* Just store the data in a buffer */ | 193 | /* Just store the data in a buffer */ |
| 100 | void *data = kmalloc(datalen, GFP_KERNEL); | 194 | void *data = kmalloc(datalen, GFP_KERNEL); |
| 195 | |||
| 101 | if (!data) | 196 | if (!data) |
| 102 | return -ENOMEM; | 197 | return -ENOMEM; |
| 103 | 198 | ||
| @@ -108,7 +203,10 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
| 108 | 203 | ||
| 109 | err_fput: | 204 | err_fput: |
| 110 | fput(file); | 205 | fput(file); |
| 206 | err_enckey: | ||
| 207 | kfree(enckey); | ||
| 111 | error: | 208 | error: |
| 209 | kfree(data); | ||
| 112 | return ret; | 210 | return ret; |
| 113 | } | 211 | } |
| 114 | 212 | ||
| @@ -119,10 +217,10 @@ void big_key_free_preparse(struct key_preparsed_payload *prep) | |||
| 119 | { | 217 | { |
| 120 | if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { | 218 | if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { |
| 121 | struct path *path = (struct path *)&prep->payload.data[big_key_path]; | 219 | struct path *path = (struct path *)&prep->payload.data[big_key_path]; |
| 220 | |||
| 122 | path_put(path); | 221 | path_put(path); |
| 123 | } else { | ||
| 124 | kfree(prep->payload.data[big_key_data]); | ||
| 125 | } | 222 | } |
| 223 | kfree(prep->payload.data[big_key_data]); | ||
| 126 | } | 224 | } |
| 127 | 225 | ||
| 128 | /* | 226 | /* |
| @@ -147,15 +245,15 @@ void big_key_destroy(struct key *key) | |||
| 147 | { | 245 | { |
| 148 | size_t datalen = (size_t)key->payload.data[big_key_len]; | 246 | size_t datalen = (size_t)key->payload.data[big_key_len]; |
| 149 | 247 | ||
| 150 | if (datalen) { | 248 | if (datalen > BIG_KEY_FILE_THRESHOLD) { |
| 151 | struct path *path = (struct path *)&key->payload.data[big_key_path]; | 249 | struct path *path = (struct path *)&key->payload.data[big_key_path]; |
| 250 | |||
| 152 | path_put(path); | 251 | path_put(path); |
| 153 | path->mnt = NULL; | 252 | path->mnt = NULL; |
| 154 | path->dentry = NULL; | 253 | path->dentry = NULL; |
| 155 | } else { | ||
| 156 | kfree(key->payload.data[big_key_data]); | ||
| 157 | key->payload.data[big_key_data] = NULL; | ||
| 158 | } | 254 | } |
| 255 | kfree(key->payload.data[big_key_data]); | ||
| 256 | key->payload.data[big_key_data] = NULL; | ||
| 159 | } | 257 | } |
| 160 | 258 | ||
| 161 | /* | 259 | /* |
| @@ -188,17 +286,41 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) | |||
| 188 | if (datalen > BIG_KEY_FILE_THRESHOLD) { | 286 | if (datalen > BIG_KEY_FILE_THRESHOLD) { |
| 189 | struct path *path = (struct path *)&key->payload.data[big_key_path]; | 287 | struct path *path = (struct path *)&key->payload.data[big_key_path]; |
| 190 | struct file *file; | 288 | struct file *file; |
| 191 | loff_t pos; | 289 | u8 *data; |
| 290 | u8 *enckey = (u8 *)key->payload.data[big_key_data]; | ||
| 291 | size_t enclen = ALIGN(datalen, crypto_blkcipher_blocksize(big_key_blkcipher)); | ||
| 292 | |||
| 293 | data = kmalloc(enclen, GFP_KERNEL); | ||
| 294 | if (!data) | ||
| 295 | return -ENOMEM; | ||
| 192 | 296 | ||
| 193 | file = dentry_open(path, O_RDONLY, current_cred()); | 297 | file = dentry_open(path, O_RDONLY, current_cred()); |
| 194 | if (IS_ERR(file)) | 298 | if (IS_ERR(file)) { |
| 195 | return PTR_ERR(file); | 299 | ret = PTR_ERR(file); |
| 300 | goto error; | ||
| 301 | } | ||
| 196 | 302 | ||
| 197 | pos = 0; | 303 | /* read file to kernel and decrypt */ |
| 198 | ret = vfs_read(file, buffer, datalen, &pos); | 304 | ret = kernel_read(file, 0, data, enclen); |
| 199 | fput(file); | 305 | if (ret >= 0 && ret != enclen) { |
| 200 | if (ret >= 0 && ret != datalen) | ||
| 201 | ret = -EIO; | 306 | ret = -EIO; |
| 307 | goto err_fput; | ||
| 308 | } | ||
| 309 | |||
| 310 | ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey); | ||
| 311 | if (ret) | ||
| 312 | goto err_fput; | ||
| 313 | |||
| 314 | ret = datalen; | ||
| 315 | |||
| 316 | /* copy decrypted data to user */ | ||
| 317 | if (copy_to_user(buffer, data, datalen) != 0) | ||
| 318 | ret = -EFAULT; | ||
| 319 | |||
| 320 | err_fput: | ||
| 321 | fput(file); | ||
| 322 | error: | ||
| 323 | kfree(data); | ||
| 202 | } else { | 324 | } else { |
| 203 | ret = datalen; | 325 | ret = datalen; |
| 204 | if (copy_to_user(buffer, key->payload.data[big_key_data], | 326 | if (copy_to_user(buffer, key->payload.data[big_key_data], |
| @@ -209,8 +331,48 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) | |||
| 209 | return ret; | 331 | return ret; |
| 210 | } | 332 | } |
| 211 | 333 | ||
| 334 | /* | ||
| 335 | * Register key type | ||
| 336 | */ | ||
| 212 | static int __init big_key_init(void) | 337 | static int __init big_key_init(void) |
| 213 | { | 338 | { |
| 214 | return register_key_type(&key_type_big_key); | 339 | return register_key_type(&key_type_big_key); |
| 215 | } | 340 | } |
| 341 | |||
| 342 | /* | ||
| 343 | * Initialize big_key crypto and RNG algorithms | ||
| 344 | */ | ||
| 345 | static int __init big_key_crypto_init(void) | ||
| 346 | { | ||
| 347 | int ret = -EINVAL; | ||
| 348 | |||
| 349 | /* init RNG */ | ||
| 350 | big_key_rng = crypto_alloc_rng(big_key_rng_name, 0, 0); | ||
| 351 | if (IS_ERR(big_key_rng)) { | ||
| 352 | big_key_rng = NULL; | ||
| 353 | return -EFAULT; | ||
| 354 | } | ||
| 355 | |||
| 356 | /* seed RNG */ | ||
| 357 | ret = crypto_rng_reset(big_key_rng, NULL, crypto_rng_seedsize(big_key_rng)); | ||
| 358 | if (ret) | ||
| 359 | goto error; | ||
| 360 | |||
| 361 | /* init block cipher */ | ||
| 362 | big_key_blkcipher = crypto_alloc_blkcipher(big_key_alg_name, 0, 0); | ||
| 363 | if (IS_ERR(big_key_blkcipher)) { | ||
| 364 | big_key_blkcipher = NULL; | ||
| 365 | ret = -EFAULT; | ||
| 366 | goto error; | ||
| 367 | } | ||
| 368 | |||
| 369 | return 0; | ||
| 370 | |||
| 371 | error: | ||
| 372 | crypto_free_rng(big_key_rng); | ||
| 373 | big_key_rng = NULL; | ||
| 374 | return ret; | ||
| 375 | } | ||
| 376 | |||
| 216 | device_initcall(big_key_init); | 377 | device_initcall(big_key_init); |
| 378 | late_initcall(big_key_crypto_init); | ||
diff --git a/security/keys/compat.c b/security/keys/compat.c index 25430a3aa7f7..c8783b3b628c 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
| @@ -132,6 +132,10 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, | |||
| 132 | case KEYCTL_GET_PERSISTENT: | 132 | case KEYCTL_GET_PERSISTENT: |
| 133 | return keyctl_get_persistent(arg2, arg3); | 133 | return keyctl_get_persistent(arg2, arg3); |
| 134 | 134 | ||
| 135 | case KEYCTL_DH_COMPUTE: | ||
| 136 | return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3), | ||
| 137 | arg4); | ||
| 138 | |||
| 135 | default: | 139 | default: |
| 136 | return -EOPNOTSUPP; | 140 | return -EOPNOTSUPP; |
| 137 | } | 141 | } |
diff --git a/security/keys/dh.c b/security/keys/dh.c new file mode 100644 index 000000000000..880505a4b9f1 --- /dev/null +++ b/security/keys/dh.c | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | /* Crypto operations using stored keys | ||
| 2 | * | ||
| 3 | * Copyright (c) 2016, Intel Corporation | ||
| 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/mpi.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/uaccess.h> | ||
| 14 | #include <keys/user-type.h> | ||
| 15 | #include "internal.h" | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Public key or shared secret generation function [RFC2631 sec 2.1.1] | ||
| 19 | * | ||
| 20 | * ya = g^xa mod p; | ||
| 21 | * or | ||
| 22 | * ZZ = yb^xa mod p; | ||
| 23 | * | ||
| 24 | * where xa is the local private key, ya is the local public key, g is | ||
| 25 | * the generator, p is the prime, yb is the remote public key, and ZZ | ||
| 26 | * is the shared secret. | ||
| 27 | * | ||
| 28 | * Both are the same calculation, so g or yb are the "base" and ya or | ||
| 29 | * ZZ are the "result". | ||
| 30 | */ | ||
| 31 | static int do_dh(MPI result, MPI base, MPI xa, MPI p) | ||
| 32 | { | ||
| 33 | return mpi_powm(result, base, xa, p); | ||
| 34 | } | ||
| 35 | |||
| 36 | static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi) | ||
| 37 | { | ||
| 38 | struct key *key; | ||
| 39 | key_ref_t key_ref; | ||
| 40 | long status; | ||
| 41 | ssize_t ret; | ||
| 42 | |||
| 43 | key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ); | ||
| 44 | if (IS_ERR(key_ref)) { | ||
| 45 | ret = -ENOKEY; | ||
| 46 | goto error; | ||
| 47 | } | ||
| 48 | |||
| 49 | key = key_ref_to_ptr(key_ref); | ||
| 50 | |||
| 51 | ret = -EOPNOTSUPP; | ||
| 52 | if (key->type == &key_type_user) { | ||
| 53 | down_read(&key->sem); | ||
| 54 | status = key_validate(key); | ||
| 55 | if (status == 0) { | ||
| 56 | const struct user_key_payload *payload; | ||
| 57 | |||
| 58 | payload = user_key_payload(key); | ||
| 59 | |||
| 60 | if (maxlen == 0) { | ||
| 61 | *mpi = NULL; | ||
| 62 | ret = payload->datalen; | ||
| 63 | } else if (payload->datalen <= maxlen) { | ||
| 64 | *mpi = mpi_read_raw_data(payload->data, | ||
| 65 | payload->datalen); | ||
| 66 | if (*mpi) | ||
| 67 | ret = payload->datalen; | ||
| 68 | } else { | ||
| 69 | ret = -EINVAL; | ||
| 70 | } | ||
| 71 | } | ||
| 72 | up_read(&key->sem); | ||
| 73 | } | ||
| 74 | |||
| 75 | key_put(key); | ||
| 76 | error: | ||
| 77 | return ret; | ||
| 78 | } | ||
| 79 | |||
| 80 | long keyctl_dh_compute(struct keyctl_dh_params __user *params, | ||
| 81 | char __user *buffer, size_t buflen) | ||
| 82 | { | ||
| 83 | long ret; | ||
| 84 | MPI base, private, prime, result; | ||
| 85 | unsigned nbytes; | ||
| 86 | struct keyctl_dh_params pcopy; | ||
| 87 | uint8_t *kbuf; | ||
| 88 | ssize_t keylen; | ||
| 89 | size_t resultlen; | ||
| 90 | |||
| 91 | if (!params || (!buffer && buflen)) { | ||
| 92 | ret = -EINVAL; | ||
| 93 | goto out; | ||
| 94 | } | ||
| 95 | if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) { | ||
| 96 | ret = -EFAULT; | ||
| 97 | goto out; | ||
| 98 | } | ||
| 99 | |||
| 100 | keylen = mpi_from_key(pcopy.prime, buflen, &prime); | ||
| 101 | if (keylen < 0 || !prime) { | ||
| 102 | /* buflen == 0 may be used to query the required buffer size, | ||
| 103 | * which is the prime key length. | ||
| 104 | */ | ||
| 105 | ret = keylen; | ||
| 106 | goto out; | ||
| 107 | } | ||
| 108 | |||
| 109 | /* The result is never longer than the prime */ | ||
| 110 | resultlen = keylen; | ||
| 111 | |||
| 112 | keylen = mpi_from_key(pcopy.base, SIZE_MAX, &base); | ||
| 113 | if (keylen < 0 || !base) { | ||
| 114 | ret = keylen; | ||
| 115 | goto error1; | ||
| 116 | } | ||
| 117 | |||
| 118 | keylen = mpi_from_key(pcopy.private, SIZE_MAX, &private); | ||
| 119 | if (keylen < 0 || !private) { | ||
| 120 | ret = keylen; | ||
| 121 | goto error2; | ||
| 122 | } | ||
| 123 | |||
| 124 | result = mpi_alloc(0); | ||
| 125 | if (!result) { | ||
| 126 | ret = -ENOMEM; | ||
| 127 | goto error3; | ||
| 128 | } | ||
| 129 | |||
| 130 | kbuf = kmalloc(resultlen, GFP_KERNEL); | ||
| 131 | if (!kbuf) { | ||
| 132 | ret = -ENOMEM; | ||
| 133 | goto error4; | ||
| 134 | } | ||
| 135 | |||
| 136 | ret = do_dh(result, base, private, prime); | ||
| 137 | if (ret) | ||
| 138 | goto error5; | ||
| 139 | |||
| 140 | ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL); | ||
| 141 | if (ret != 0) | ||
| 142 | goto error5; | ||
| 143 | |||
| 144 | ret = nbytes; | ||
| 145 | if (copy_to_user(buffer, kbuf, nbytes) != 0) | ||
| 146 | ret = -EFAULT; | ||
| 147 | |||
| 148 | error5: | ||
| 149 | kfree(kbuf); | ||
| 150 | error4: | ||
| 151 | mpi_free(result); | ||
| 152 | error3: | ||
| 153 | mpi_free(private); | ||
| 154 | error2: | ||
| 155 | mpi_free(base); | ||
| 156 | error1: | ||
| 157 | mpi_free(prime); | ||
| 158 | out: | ||
| 159 | return ret; | ||
| 160 | } | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 5105c2c2da75..8ec7a528365d 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
| 16 | #include <linux/key-type.h> | 16 | #include <linux/key-type.h> |
| 17 | #include <linux/task_work.h> | 17 | #include <linux/task_work.h> |
| 18 | #include <linux/keyctl.h> | ||
| 18 | 19 | ||
| 19 | struct iovec; | 20 | struct iovec; |
| 20 | 21 | ||
| @@ -257,6 +258,17 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring) | |||
| 257 | } | 258 | } |
| 258 | #endif | 259 | #endif |
| 259 | 260 | ||
| 261 | #ifdef CONFIG_KEY_DH_OPERATIONS | ||
| 262 | extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *, | ||
| 263 | size_t); | ||
| 264 | #else | ||
| 265 | static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params, | ||
| 266 | char __user *buffer, size_t buflen) | ||
| 267 | { | ||
| 268 | return -EOPNOTSUPP; | ||
| 269 | } | ||
| 270 | #endif | ||
| 271 | |||
| 260 | /* | 272 | /* |
| 261 | * Debugging key validation | 273 | * Debugging key validation |
| 262 | */ | 274 | */ |
diff --git a/security/keys/key.c b/security/keys/key.c index b28755131687..bd5a272f28a6 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -201,6 +201,7 @@ serial_exists: | |||
| 201 | * @cred: The credentials specifying UID namespace. | 201 | * @cred: The credentials specifying UID namespace. |
| 202 | * @perm: The permissions mask of the new key. | 202 | * @perm: The permissions mask of the new key. |
| 203 | * @flags: Flags specifying quota properties. | 203 | * @flags: Flags specifying quota properties. |
| 204 | * @restrict_link: Optional link restriction method for new keyrings. | ||
| 204 | * | 205 | * |
| 205 | * Allocate a key of the specified type with the attributes given. The key is | 206 | * Allocate a key of the specified type with the attributes given. The key is |
| 206 | * returned in an uninstantiated state and the caller needs to instantiate the | 207 | * returned in an uninstantiated state and the caller needs to instantiate the |
| @@ -223,7 +224,10 @@ serial_exists: | |||
| 223 | */ | 224 | */ |
| 224 | struct key *key_alloc(struct key_type *type, const char *desc, | 225 | struct key *key_alloc(struct key_type *type, const char *desc, |
| 225 | kuid_t uid, kgid_t gid, const struct cred *cred, | 226 | kuid_t uid, kgid_t gid, const struct cred *cred, |
| 226 | key_perm_t perm, unsigned long flags) | 227 | key_perm_t perm, unsigned long flags, |
| 228 | int (*restrict_link)(struct key *, | ||
| 229 | const struct key_type *, | ||
| 230 | const union key_payload *)) | ||
| 227 | { | 231 | { |
| 228 | struct key_user *user = NULL; | 232 | struct key_user *user = NULL; |
| 229 | struct key *key; | 233 | struct key *key; |
| @@ -291,11 +295,10 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
| 291 | key->uid = uid; | 295 | key->uid = uid; |
| 292 | key->gid = gid; | 296 | key->gid = gid; |
| 293 | key->perm = perm; | 297 | key->perm = perm; |
| 298 | key->restrict_link = restrict_link; | ||
| 294 | 299 | ||
| 295 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) | 300 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) |
| 296 | key->flags |= 1 << KEY_FLAG_IN_QUOTA; | 301 | key->flags |= 1 << KEY_FLAG_IN_QUOTA; |
| 297 | if (flags & KEY_ALLOC_TRUSTED) | ||
| 298 | key->flags |= 1 << KEY_FLAG_TRUSTED; | ||
| 299 | if (flags & KEY_ALLOC_BUILT_IN) | 302 | if (flags & KEY_ALLOC_BUILT_IN) |
| 300 | key->flags |= 1 << KEY_FLAG_BUILTIN; | 303 | key->flags |= 1 << KEY_FLAG_BUILTIN; |
| 301 | 304 | ||
| @@ -496,6 +499,12 @@ int key_instantiate_and_link(struct key *key, | |||
| 496 | } | 499 | } |
| 497 | 500 | ||
| 498 | if (keyring) { | 501 | 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 | } | ||
| 499 | ret = __key_link_begin(keyring, &key->index_key, &edit); | 508 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
| 500 | if (ret < 0) | 509 | if (ret < 0) |
| 501 | goto error; | 510 | goto error; |
| @@ -551,8 +560,12 @@ int key_reject_and_link(struct key *key, | |||
| 551 | awaken = 0; | 560 | awaken = 0; |
| 552 | ret = -EBUSY; | 561 | ret = -EBUSY; |
| 553 | 562 | ||
| 554 | if (keyring) | 563 | if (keyring) { |
| 564 | if (keyring->restrict_link) | ||
| 565 | return -EPERM; | ||
| 566 | |||
| 555 | link_ret = __key_link_begin(keyring, &key->index_key, &edit); | 567 | link_ret = __key_link_begin(keyring, &key->index_key, &edit); |
| 568 | } | ||
| 556 | 569 | ||
| 557 | mutex_lock(&key_construction_mutex); | 570 | mutex_lock(&key_construction_mutex); |
| 558 | 571 | ||
| @@ -793,6 +806,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 793 | struct key *keyring, *key = NULL; | 806 | struct key *keyring, *key = NULL; |
| 794 | key_ref_t key_ref; | 807 | key_ref_t key_ref; |
| 795 | int ret; | 808 | int ret; |
| 809 | int (*restrict_link)(struct key *, | ||
| 810 | const struct key_type *, | ||
| 811 | const union key_payload *) = NULL; | ||
| 796 | 812 | ||
| 797 | /* look up the key type to see if it's one of the registered kernel | 813 | /* look up the key type to see if it's one of the registered kernel |
| 798 | * types */ | 814 | * types */ |
| @@ -811,6 +827,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 811 | 827 | ||
| 812 | key_check(keyring); | 828 | key_check(keyring); |
| 813 | 829 | ||
| 830 | key_ref = ERR_PTR(-EPERM); | ||
| 831 | if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION)) | ||
| 832 | restrict_link = keyring->restrict_link; | ||
| 833 | |||
| 814 | key_ref = ERR_PTR(-ENOTDIR); | 834 | key_ref = ERR_PTR(-ENOTDIR); |
| 815 | if (keyring->type != &key_type_keyring) | 835 | if (keyring->type != &key_type_keyring) |
| 816 | goto error_put_type; | 836 | goto error_put_type; |
| @@ -819,7 +839,6 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 819 | prep.data = payload; | 839 | prep.data = payload; |
| 820 | prep.datalen = plen; | 840 | prep.datalen = plen; |
| 821 | prep.quotalen = index_key.type->def_datalen; | 841 | prep.quotalen = index_key.type->def_datalen; |
| 822 | prep.trusted = flags & KEY_ALLOC_TRUSTED; | ||
| 823 | prep.expiry = TIME_T_MAX; | 842 | prep.expiry = TIME_T_MAX; |
| 824 | if (index_key.type->preparse) { | 843 | if (index_key.type->preparse) { |
| 825 | ret = index_key.type->preparse(&prep); | 844 | ret = index_key.type->preparse(&prep); |
| @@ -835,10 +854,13 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 835 | } | 854 | } |
| 836 | index_key.desc_len = strlen(index_key.description); | 855 | index_key.desc_len = strlen(index_key.description); |
| 837 | 856 | ||
| 838 | key_ref = ERR_PTR(-EPERM); | 857 | if (restrict_link) { |
| 839 | if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags)) | 858 | ret = restrict_link(keyring, index_key.type, &prep.payload); |
| 840 | goto error_free_prep; | 859 | if (ret < 0) { |
| 841 | flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0; | 860 | key_ref = ERR_PTR(ret); |
| 861 | goto error_free_prep; | ||
| 862 | } | ||
| 863 | } | ||
| 842 | 864 | ||
| 843 | ret = __key_link_begin(keyring, &index_key, &edit); | 865 | ret = __key_link_begin(keyring, &index_key, &edit); |
| 844 | if (ret < 0) { | 866 | if (ret < 0) { |
| @@ -879,7 +901,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 879 | 901 | ||
| 880 | /* allocate a new key */ | 902 | /* allocate a new key */ |
| 881 | key = key_alloc(index_key.type, index_key.description, | 903 | key = key_alloc(index_key.type, index_key.description, |
| 882 | cred->fsuid, cred->fsgid, cred, perm, flags); | 904 | cred->fsuid, cred->fsgid, cred, perm, flags, NULL); |
| 883 | if (IS_ERR(key)) { | 905 | if (IS_ERR(key)) { |
| 884 | key_ref = ERR_CAST(key); | 906 | key_ref = ERR_CAST(key); |
| 885 | goto error_link_end; | 907 | goto error_link_end; |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index ed73c6c1c326..3b135a0af344 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -1686,6 +1686,11 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
| 1686 | case KEYCTL_GET_PERSISTENT: | 1686 | case KEYCTL_GET_PERSISTENT: |
| 1687 | return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3); | 1687 | return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3); |
| 1688 | 1688 | ||
| 1689 | case KEYCTL_DH_COMPUTE: | ||
| 1690 | return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2, | ||
| 1691 | (char __user *) arg3, | ||
| 1692 | (size_t) arg4); | ||
| 1693 | |||
| 1689 | default: | 1694 | default: |
| 1690 | return -EOPNOTSUPP; | 1695 | return -EOPNOTSUPP; |
| 1691 | } | 1696 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index f931ccfeefb0..c91e4e0cea08 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -491,13 +491,17 @@ static long keyring_read(const struct key *keyring, | |||
| 491 | */ | 491 | */ |
| 492 | struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | 492 | struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, |
| 493 | const struct cred *cred, key_perm_t perm, | 493 | const struct cred *cred, key_perm_t perm, |
| 494 | unsigned long flags, struct key *dest) | 494 | unsigned long flags, |
| 495 | int (*restrict_link)(struct key *, | ||
| 496 | const struct key_type *, | ||
| 497 | const union key_payload *), | ||
| 498 | struct key *dest) | ||
| 495 | { | 499 | { |
| 496 | struct key *keyring; | 500 | struct key *keyring; |
| 497 | int ret; | 501 | int ret; |
| 498 | 502 | ||
| 499 | keyring = key_alloc(&key_type_keyring, description, | 503 | keyring = key_alloc(&key_type_keyring, description, |
| 500 | uid, gid, cred, perm, flags); | 504 | uid, gid, cred, perm, flags, restrict_link); |
| 501 | if (!IS_ERR(keyring)) { | 505 | if (!IS_ERR(keyring)) { |
| 502 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); | 506 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); |
| 503 | if (ret < 0) { | 507 | if (ret < 0) { |
| @@ -510,6 +514,26 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | |||
| 510 | } | 514 | } |
| 511 | EXPORT_SYMBOL(keyring_alloc); | 515 | EXPORT_SYMBOL(keyring_alloc); |
| 512 | 516 | ||
| 517 | /** | ||
| 518 | * restrict_link_reject - Give -EPERM to restrict link | ||
| 519 | * @keyring: The keyring being added to. | ||
| 520 | * @type: The type of key being added. | ||
| 521 | * @payload: The payload of the key intended to be added. | ||
| 522 | * | ||
| 523 | * Reject the addition of any links to a keyring. It can be overridden by | ||
| 524 | * passing KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when | ||
| 525 | * adding a key to a keyring. | ||
| 526 | * | ||
| 527 | * This is meant to be passed as the restrict_link parameter to | ||
| 528 | * keyring_alloc(). | ||
| 529 | */ | ||
| 530 | int restrict_link_reject(struct key *keyring, | ||
| 531 | const struct key_type *type, | ||
| 532 | const union key_payload *payload) | ||
| 533 | { | ||
| 534 | return -EPERM; | ||
| 535 | } | ||
| 536 | |||
| 513 | /* | 537 | /* |
| 514 | * By default, we keys found by getting an exact match on their descriptions. | 538 | * By default, we keys found by getting an exact match on their descriptions. |
| 515 | */ | 539 | */ |
| @@ -1191,6 +1215,16 @@ void __key_link_end(struct key *keyring, | |||
| 1191 | up_write(&keyring->sem); | 1215 | up_write(&keyring->sem); |
| 1192 | } | 1216 | } |
| 1193 | 1217 | ||
| 1218 | /* | ||
| 1219 | * Check addition of keys to restricted keyrings. | ||
| 1220 | */ | ||
| 1221 | static int __key_link_check_restriction(struct key *keyring, struct key *key) | ||
| 1222 | { | ||
| 1223 | if (!keyring->restrict_link) | ||
| 1224 | return 0; | ||
| 1225 | return keyring->restrict_link(keyring, key->type, &key->payload); | ||
| 1226 | } | ||
| 1227 | |||
| 1194 | /** | 1228 | /** |
| 1195 | * key_link - Link a key to a keyring | 1229 | * key_link - Link a key to a keyring |
| 1196 | * @keyring: The keyring to make the link in. | 1230 | * @keyring: The keyring to make the link in. |
| @@ -1221,14 +1255,12 @@ int key_link(struct key *keyring, struct key *key) | |||
| 1221 | key_check(keyring); | 1255 | key_check(keyring); |
| 1222 | key_check(key); | 1256 | key_check(key); |
| 1223 | 1257 | ||
| 1224 | if (test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags) && | ||
| 1225 | !test_bit(KEY_FLAG_TRUSTED, &key->flags)) | ||
| 1226 | return -EPERM; | ||
| 1227 | |||
| 1228 | ret = __key_link_begin(keyring, &key->index_key, &edit); | 1258 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
| 1229 | if (ret == 0) { | 1259 | if (ret == 0) { |
| 1230 | kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage)); | 1260 | kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage)); |
| 1231 | ret = __key_link_check_live_key(keyring, key); | 1261 | ret = __key_link_check_restriction(keyring, key); |
| 1262 | if (ret == 0) | ||
| 1263 | ret = __key_link_check_live_key(keyring, key); | ||
| 1232 | if (ret == 0) | 1264 | if (ret == 0) |
| 1233 | __key_link(key, &edit); | 1265 | __key_link(key, &edit); |
| 1234 | __key_link_end(keyring, &key->index_key, edit); | 1266 | __key_link_end(keyring, &key->index_key, edit); |
diff --git a/security/keys/persistent.c b/security/keys/persistent.c index c9fae5ea89fe..2ef45b319dd9 100644 --- a/security/keys/persistent.c +++ b/security/keys/persistent.c | |||
| @@ -26,7 +26,7 @@ static int key_create_persistent_register(struct user_namespace *ns) | |||
| 26 | current_cred(), | 26 | current_cred(), |
| 27 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | 27 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 28 | KEY_USR_VIEW | KEY_USR_READ), | 28 | KEY_USR_VIEW | KEY_USR_READ), |
| 29 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | 29 | KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); |
| 30 | if (IS_ERR(reg)) | 30 | if (IS_ERR(reg)) |
| 31 | return PTR_ERR(reg); | 31 | return PTR_ERR(reg); |
| 32 | 32 | ||
| @@ -60,7 +60,7 @@ static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid, | |||
| 60 | uid, INVALID_GID, current_cred(), | 60 | uid, INVALID_GID, current_cred(), |
| 61 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | 61 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | |
| 62 | KEY_USR_VIEW | KEY_USR_READ), | 62 | KEY_USR_VIEW | KEY_USR_READ), |
| 63 | KEY_ALLOC_NOT_IN_QUOTA, | 63 | KEY_ALLOC_NOT_IN_QUOTA, NULL, |
| 64 | ns->persistent_keyring_register); | 64 | ns->persistent_keyring_register); |
| 65 | if (IS_ERR(persistent)) | 65 | if (IS_ERR(persistent)) |
| 66 | return ERR_CAST(persistent); | 66 | return ERR_CAST(persistent); |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index e6d50172872f..40a885239782 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -76,7 +76,8 @@ int install_user_keyrings(void) | |||
| 76 | if (IS_ERR(uid_keyring)) { | 76 | if (IS_ERR(uid_keyring)) { |
| 77 | uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, | 77 | uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, |
| 78 | cred, user_keyring_perm, | 78 | cred, user_keyring_perm, |
| 79 | KEY_ALLOC_IN_QUOTA, NULL); | 79 | KEY_ALLOC_IN_QUOTA, |
| 80 | NULL, NULL); | ||
| 80 | if (IS_ERR(uid_keyring)) { | 81 | if (IS_ERR(uid_keyring)) { |
| 81 | ret = PTR_ERR(uid_keyring); | 82 | ret = PTR_ERR(uid_keyring); |
| 82 | goto error; | 83 | goto error; |
| @@ -92,7 +93,8 @@ int install_user_keyrings(void) | |||
| 92 | session_keyring = | 93 | session_keyring = |
| 93 | keyring_alloc(buf, user->uid, INVALID_GID, | 94 | keyring_alloc(buf, user->uid, INVALID_GID, |
| 94 | cred, user_keyring_perm, | 95 | cred, user_keyring_perm, |
| 95 | KEY_ALLOC_IN_QUOTA, NULL); | 96 | KEY_ALLOC_IN_QUOTA, |
| 97 | NULL, NULL); | ||
| 96 | if (IS_ERR(session_keyring)) { | 98 | if (IS_ERR(session_keyring)) { |
| 97 | ret = PTR_ERR(session_keyring); | 99 | ret = PTR_ERR(session_keyring); |
| 98 | goto error_release; | 100 | goto error_release; |
| @@ -134,7 +136,8 @@ int install_thread_keyring_to_cred(struct cred *new) | |||
| 134 | 136 | ||
| 135 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, | 137 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, |
| 136 | KEY_POS_ALL | KEY_USR_VIEW, | 138 | KEY_POS_ALL | KEY_USR_VIEW, |
| 137 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 139 | KEY_ALLOC_QUOTA_OVERRUN, |
| 140 | NULL, NULL); | ||
| 138 | if (IS_ERR(keyring)) | 141 | if (IS_ERR(keyring)) |
| 139 | return PTR_ERR(keyring); | 142 | return PTR_ERR(keyring); |
| 140 | 143 | ||
| @@ -180,7 +183,8 @@ int install_process_keyring_to_cred(struct cred *new) | |||
| 180 | 183 | ||
| 181 | keyring = keyring_alloc("_pid", new->uid, new->gid, new, | 184 | keyring = keyring_alloc("_pid", new->uid, new->gid, new, |
| 182 | KEY_POS_ALL | KEY_USR_VIEW, | 185 | KEY_POS_ALL | KEY_USR_VIEW, |
| 183 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 186 | KEY_ALLOC_QUOTA_OVERRUN, |
| 187 | NULL, NULL); | ||
| 184 | if (IS_ERR(keyring)) | 188 | if (IS_ERR(keyring)) |
| 185 | return PTR_ERR(keyring); | 189 | return PTR_ERR(keyring); |
| 186 | 190 | ||
| @@ -231,7 +235,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
| 231 | 235 | ||
| 232 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, | 236 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, |
| 233 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, | 237 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, |
| 234 | flags, NULL); | 238 | flags, NULL, NULL); |
| 235 | if (IS_ERR(keyring)) | 239 | if (IS_ERR(keyring)) |
| 236 | return PTR_ERR(keyring); | 240 | return PTR_ERR(keyring); |
| 237 | } else { | 241 | } else { |
| @@ -785,7 +789,7 @@ long join_session_keyring(const char *name) | |||
| 785 | keyring = keyring_alloc( | 789 | keyring = keyring_alloc( |
| 786 | name, old->uid, old->gid, old, | 790 | name, old->uid, old->gid, old, |
| 787 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, | 791 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, |
| 788 | KEY_ALLOC_IN_QUOTA, NULL); | 792 | KEY_ALLOC_IN_QUOTA, NULL, NULL); |
| 789 | if (IS_ERR(keyring)) { | 793 | if (IS_ERR(keyring)) { |
| 790 | ret = PTR_ERR(keyring); | 794 | ret = PTR_ERR(keyring); |
| 791 | goto error2; | 795 | goto error2; |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index c7a117c9a8f3..a29e3554751e 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
| @@ -116,7 +116,7 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
| 116 | cred = get_current_cred(); | 116 | cred = get_current_cred(); |
| 117 | keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, | 117 | keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, |
| 118 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, | 118 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, |
| 119 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 119 | KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); |
| 120 | put_cred(cred); | 120 | put_cred(cred); |
| 121 | if (IS_ERR(keyring)) { | 121 | if (IS_ERR(keyring)) { |
| 122 | ret = PTR_ERR(keyring); | 122 | ret = PTR_ERR(keyring); |
| @@ -355,7 +355,7 @@ static int construct_alloc_key(struct keyring_search_context *ctx, | |||
| 355 | 355 | ||
| 356 | key = key_alloc(ctx->index_key.type, ctx->index_key.description, | 356 | key = key_alloc(ctx->index_key.type, ctx->index_key.description, |
| 357 | ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred, | 357 | ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred, |
| 358 | perm, flags); | 358 | perm, flags, NULL); |
| 359 | if (IS_ERR(key)) | 359 | if (IS_ERR(key)) |
| 360 | goto alloc_failed; | 360 | goto alloc_failed; |
| 361 | 361 | ||
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 4f0f112fe276..9db8b4a82787 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
| @@ -202,7 +202,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, | |||
| 202 | authkey = key_alloc(&key_type_request_key_auth, desc, | 202 | authkey = key_alloc(&key_type_request_key_auth, desc, |
| 203 | cred->fsuid, cred->fsgid, cred, | 203 | cred->fsuid, cred->fsgid, cred, |
| 204 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | | 204 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | |
| 205 | KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA); | 205 | KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL); |
| 206 | if (IS_ERR(authkey)) { | 206 | if (IS_ERR(authkey)) { |
| 207 | ret = PTR_ERR(authkey); | 207 | ret = PTR_ERR(authkey); |
| 208 | goto error_alloc; | 208 | goto error_alloc; |
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 8705d79b2c6f..66b1840b4110 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c | |||
| @@ -96,45 +96,25 @@ EXPORT_SYMBOL_GPL(user_free_preparse); | |||
| 96 | */ | 96 | */ |
| 97 | int user_update(struct key *key, struct key_preparsed_payload *prep) | 97 | int user_update(struct key *key, struct key_preparsed_payload *prep) |
| 98 | { | 98 | { |
| 99 | struct user_key_payload *upayload, *zap; | 99 | struct user_key_payload *zap = NULL; |
| 100 | size_t datalen = prep->datalen; | ||
| 101 | int ret; | 100 | int ret; |
| 102 | 101 | ||
| 103 | ret = -EINVAL; | ||
| 104 | if (datalen <= 0 || datalen > 32767 || !prep->data) | ||
| 105 | goto error; | ||
| 106 | |||
| 107 | /* construct a replacement payload */ | ||
| 108 | ret = -ENOMEM; | ||
| 109 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); | ||
| 110 | if (!upayload) | ||
| 111 | goto error; | ||
| 112 | |||
| 113 | upayload->datalen = datalen; | ||
| 114 | memcpy(upayload->data, prep->data, datalen); | ||
| 115 | |||
| 116 | /* check the quota and attach the new data */ | 102 | /* check the quota and attach the new data */ |
| 117 | zap = upayload; | 103 | ret = key_payload_reserve(key, prep->datalen); |
| 118 | 104 | if (ret < 0) | |
| 119 | ret = key_payload_reserve(key, datalen); | 105 | return ret; |
| 120 | 106 | ||
| 121 | if (ret == 0) { | 107 | /* attach the new data, displacing the old */ |
| 122 | /* attach the new data, displacing the old */ | 108 | key->expiry = prep->expiry; |
| 123 | if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags)) | 109 | if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags)) |
| 124 | zap = key->payload.data[0]; | 110 | zap = rcu_dereference_key(key); |
| 125 | else | 111 | rcu_assign_keypointer(key, prep->payload.data[0]); |
| 126 | zap = NULL; | 112 | prep->payload.data[0] = NULL; |
| 127 | rcu_assign_keypointer(key, upayload); | ||
| 128 | key->expiry = 0; | ||
| 129 | } | ||
| 130 | 113 | ||
| 131 | if (zap) | 114 | if (zap) |
| 132 | kfree_rcu(zap, rcu); | 115 | kfree_rcu(zap, rcu); |
| 133 | |||
| 134 | error: | ||
| 135 | return ret; | 116 | return ret; |
| 136 | } | 117 | } |
| 137 | |||
| 138 | EXPORT_SYMBOL_GPL(user_update); | 118 | EXPORT_SYMBOL_GPL(user_update); |
| 139 | 119 | ||
| 140 | /* | 120 | /* |
diff --git a/security/loadpin/Kconfig b/security/loadpin/Kconfig new file mode 100644 index 000000000000..dd01aa91e521 --- /dev/null +++ b/security/loadpin/Kconfig | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | config SECURITY_LOADPIN | ||
| 2 | bool "Pin load of kernel files (modules, fw, etc) to one filesystem" | ||
| 3 | depends on SECURITY && BLOCK | ||
| 4 | help | ||
| 5 | Any files read through the kernel file reading interface | ||
| 6 | (kernel modules, firmware, kexec images, security policy) | ||
| 7 | can be pinned to the first filesystem used for loading. When | ||
| 8 | enabled, any files that come from other filesystems will be | ||
| 9 | rejected. This is best used on systems without an initrd that | ||
| 10 | have a root filesystem backed by a read-only device such as | ||
| 11 | dm-verity or a CDROM. | ||
| 12 | |||
| 13 | config SECURITY_LOADPIN_ENABLED | ||
| 14 | bool "Enforce LoadPin at boot" | ||
| 15 | depends on SECURITY_LOADPIN | ||
| 16 | help | ||
| 17 | If selected, LoadPin will enforce pinning at boot. If not | ||
| 18 | selected, it can be enabled at boot with the kernel parameter | ||
| 19 | "loadpin.enabled=1". | ||
diff --git a/security/loadpin/Makefile b/security/loadpin/Makefile new file mode 100644 index 000000000000..c2d77f83037b --- /dev/null +++ b/security/loadpin/Makefile | |||
| @@ -0,0 +1 @@ | |||
| obj-$(CONFIG_SECURITY_LOADPIN) += loadpin.o | |||
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c new file mode 100644 index 000000000000..89a46f10b8a7 --- /dev/null +++ b/security/loadpin/loadpin.c | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | /* | ||
| 2 | * Module and Firmware Pinning Security Module | ||
| 3 | * | ||
| 4 | * Copyright 2011-2016 Google Inc. | ||
| 5 | * | ||
| 6 | * Author: Kees Cook <keescook@chromium.org> | ||
| 7 | * | ||
| 8 | * This software is licensed under the terms of the GNU General Public | ||
| 9 | * License version 2, as published by the Free Software Foundation, and | ||
| 10 | * may be copied, distributed, and modified under those terms. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #define pr_fmt(fmt) "LoadPin: " fmt | ||
| 19 | |||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/fs.h> | ||
| 22 | #include <linux/fs_struct.h> | ||
| 23 | #include <linux/lsm_hooks.h> | ||
| 24 | #include <linux/mount.h> | ||
| 25 | #include <linux/path.h> | ||
| 26 | #include <linux/sched.h> /* current */ | ||
| 27 | #include <linux/string_helpers.h> | ||
| 28 | |||
| 29 | static void report_load(const char *origin, struct file *file, char *operation) | ||
| 30 | { | ||
| 31 | char *cmdline, *pathname; | ||
| 32 | |||
| 33 | pathname = kstrdup_quotable_file(file, GFP_KERNEL); | ||
| 34 | cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); | ||
| 35 | |||
| 36 | pr_notice("%s %s obj=%s%s%s pid=%d cmdline=%s%s%s\n", | ||
| 37 | origin, operation, | ||
| 38 | (pathname && pathname[0] != '<') ? "\"" : "", | ||
| 39 | pathname, | ||
| 40 | (pathname && pathname[0] != '<') ? "\"" : "", | ||
| 41 | task_pid_nr(current), | ||
| 42 | cmdline ? "\"" : "", cmdline, cmdline ? "\"" : ""); | ||
| 43 | |||
| 44 | kfree(cmdline); | ||
| 45 | kfree(pathname); | ||
| 46 | } | ||
| 47 | |||
| 48 | static int enabled = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENABLED); | ||
| 49 | static struct super_block *pinned_root; | ||
| 50 | static DEFINE_SPINLOCK(pinned_root_spinlock); | ||
| 51 | |||
| 52 | #ifdef CONFIG_SYSCTL | ||
| 53 | static int zero; | ||
| 54 | static int one = 1; | ||
| 55 | |||
| 56 | static struct ctl_path loadpin_sysctl_path[] = { | ||
| 57 | { .procname = "kernel", }, | ||
| 58 | { .procname = "loadpin", }, | ||
| 59 | { } | ||
| 60 | }; | ||
| 61 | |||
| 62 | static struct ctl_table loadpin_sysctl_table[] = { | ||
| 63 | { | ||
| 64 | .procname = "enabled", | ||
| 65 | .data = &enabled, | ||
| 66 | .maxlen = sizeof(int), | ||
| 67 | .mode = 0644, | ||
| 68 | .proc_handler = proc_dointvec_minmax, | ||
| 69 | .extra1 = &zero, | ||
| 70 | .extra2 = &one, | ||
| 71 | }, | ||
| 72 | { } | ||
| 73 | }; | ||
| 74 | |||
| 75 | /* | ||
| 76 | * This must be called after early kernel init, since then the rootdev | ||
| 77 | * is available. | ||
| 78 | */ | ||
| 79 | static void check_pinning_enforcement(struct super_block *mnt_sb) | ||
| 80 | { | ||
| 81 | bool ro = false; | ||
| 82 | |||
| 83 | /* | ||
| 84 | * If load pinning is not enforced via a read-only block | ||
| 85 | * device, allow sysctl to change modes for testing. | ||
| 86 | */ | ||
| 87 | if (mnt_sb->s_bdev) { | ||
| 88 | ro = bdev_read_only(mnt_sb->s_bdev); | ||
| 89 | pr_info("dev(%u,%u): %s\n", | ||
| 90 | MAJOR(mnt_sb->s_bdev->bd_dev), | ||
| 91 | MINOR(mnt_sb->s_bdev->bd_dev), | ||
| 92 | ro ? "read-only" : "writable"); | ||
| 93 | } else | ||
| 94 | pr_info("mnt_sb lacks block device, treating as: writable\n"); | ||
| 95 | |||
| 96 | if (!ro) { | ||
| 97 | if (!register_sysctl_paths(loadpin_sysctl_path, | ||
| 98 | loadpin_sysctl_table)) | ||
| 99 | pr_notice("sysctl registration failed!\n"); | ||
| 100 | else | ||
| 101 | pr_info("load pinning can be disabled.\n"); | ||
| 102 | } else | ||
| 103 | pr_info("load pinning engaged.\n"); | ||
| 104 | } | ||
| 105 | #else | ||
| 106 | static void check_pinning_enforcement(struct super_block *mnt_sb) | ||
| 107 | { | ||
| 108 | pr_info("load pinning engaged.\n"); | ||
| 109 | } | ||
| 110 | #endif | ||
| 111 | |||
| 112 | static void loadpin_sb_free_security(struct super_block *mnt_sb) | ||
| 113 | { | ||
| 114 | /* | ||
| 115 | * When unmounting the filesystem we were using for load | ||
| 116 | * pinning, we acknowledge the superblock release, but make sure | ||
| 117 | * no other modules or firmware can be loaded. | ||
| 118 | */ | ||
| 119 | if (!IS_ERR_OR_NULL(pinned_root) && mnt_sb == pinned_root) { | ||
| 120 | pinned_root = ERR_PTR(-EIO); | ||
| 121 | pr_info("umount pinned fs: refusing further loads\n"); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) | ||
| 126 | { | ||
| 127 | struct super_block *load_root; | ||
| 128 | const char *origin = kernel_read_file_id_str(id); | ||
| 129 | |||
| 130 | /* This handles the older init_module API that has a NULL file. */ | ||
| 131 | if (!file) { | ||
| 132 | if (!enabled) { | ||
| 133 | report_load(origin, NULL, "old-api-pinning-ignored"); | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | report_load(origin, NULL, "old-api-denied"); | ||
| 138 | return -EPERM; | ||
| 139 | } | ||
| 140 | |||
| 141 | load_root = file->f_path.mnt->mnt_sb; | ||
| 142 | |||
| 143 | /* First loaded module/firmware defines the root for all others. */ | ||
| 144 | spin_lock(&pinned_root_spinlock); | ||
| 145 | /* | ||
| 146 | * pinned_root is only NULL at startup. Otherwise, it is either | ||
| 147 | * a valid reference, or an ERR_PTR. | ||
| 148 | */ | ||
| 149 | if (!pinned_root) { | ||
| 150 | pinned_root = load_root; | ||
| 151 | /* | ||
| 152 | * Unlock now since it's only pinned_root we care about. | ||
| 153 | * In the worst case, we will (correctly) report pinning | ||
| 154 | * failures before we have announced that pinning is | ||
| 155 | * enabled. This would be purely cosmetic. | ||
| 156 | */ | ||
| 157 | spin_unlock(&pinned_root_spinlock); | ||
| 158 | check_pinning_enforcement(pinned_root); | ||
| 159 | report_load(origin, file, "pinned"); | ||
| 160 | } else { | ||
| 161 | spin_unlock(&pinned_root_spinlock); | ||
| 162 | } | ||
| 163 | |||
| 164 | if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) { | ||
| 165 | if (unlikely(!enabled)) { | ||
| 166 | report_load(origin, file, "pinning-ignored"); | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | report_load(origin, file, "denied"); | ||
| 171 | return -EPERM; | ||
| 172 | } | ||
| 173 | |||
| 174 | return 0; | ||
| 175 | } | ||
| 176 | |||
| 177 | static struct security_hook_list loadpin_hooks[] = { | ||
| 178 | LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security), | ||
| 179 | LSM_HOOK_INIT(kernel_read_file, loadpin_read_file), | ||
| 180 | }; | ||
| 181 | |||
| 182 | void __init loadpin_add_hooks(void) | ||
| 183 | { | ||
| 184 | pr_info("ready to pin (currently %sabled)", enabled ? "en" : "dis"); | ||
| 185 | security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks)); | ||
| 186 | } | ||
| 187 | |||
| 188 | /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */ | ||
| 189 | module_param(enabled, int, 0); | ||
| 190 | MODULE_PARM_DESC(enabled, "Pin module/firmware loading (default: true)"); | ||
diff --git a/security/security.c b/security/security.c index d17e4a6d269c..709569305d32 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -60,6 +60,7 @@ int __init security_init(void) | |||
| 60 | */ | 60 | */ |
| 61 | capability_add_hooks(); | 61 | capability_add_hooks(); |
| 62 | yama_add_hooks(); | 62 | yama_add_hooks(); |
| 63 | loadpin_add_hooks(); | ||
| 63 | 64 | ||
| 64 | /* | 65 | /* |
| 65 | * Load all the remaining security modules. | 66 | * Load all the remaining security modules. |
| @@ -1848,7 +1849,6 @@ struct security_hook_heads security_hook_heads = { | |||
| 1848 | .tun_dev_attach = | 1849 | .tun_dev_attach = |
| 1849 | LIST_HEAD_INIT(security_hook_heads.tun_dev_attach), | 1850 | LIST_HEAD_INIT(security_hook_heads.tun_dev_attach), |
| 1850 | .tun_dev_open = LIST_HEAD_INIT(security_hook_heads.tun_dev_open), | 1851 | .tun_dev_open = LIST_HEAD_INIT(security_hook_heads.tun_dev_open), |
| 1851 | .skb_owned_by = LIST_HEAD_INIT(security_hook_heads.skb_owned_by), | ||
| 1852 | #endif /* CONFIG_SECURITY_NETWORK */ | 1852 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 1853 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1853 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| 1854 | .xfrm_policy_alloc_security = | 1854 | .xfrm_policy_alloc_security = |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3140efa76a75..a86d537eb79b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -259,7 +259,7 @@ static int __inode_security_revalidate(struct inode *inode, | |||
| 259 | 259 | ||
| 260 | might_sleep_if(may_sleep); | 260 | might_sleep_if(may_sleep); |
| 261 | 261 | ||
| 262 | if (isec->initialized == LABEL_INVALID) { | 262 | if (ss_initialized && isec->initialized != LABEL_INITIALIZED) { |
| 263 | if (!may_sleep) | 263 | if (!may_sleep) |
| 264 | return -ECHILD; | 264 | return -ECHILD; |
| 265 | 265 | ||
| @@ -297,6 +297,13 @@ static struct inode_security_struct *inode_security(struct inode *inode) | |||
| 297 | return inode->i_security; | 297 | return inode->i_security; |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry) | ||
| 301 | { | ||
| 302 | struct inode *inode = d_backing_inode(dentry); | ||
| 303 | |||
| 304 | return inode->i_security; | ||
| 305 | } | ||
| 306 | |||
| 300 | /* | 307 | /* |
| 301 | * Get the security label of a dentry's backing inode. | 308 | * Get the security label of a dentry's backing inode. |
| 302 | */ | 309 | */ |
| @@ -687,7 +694,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
| 687 | struct superblock_security_struct *sbsec = sb->s_security; | 694 | struct superblock_security_struct *sbsec = sb->s_security; |
| 688 | const char *name = sb->s_type->name; | 695 | const char *name = sb->s_type->name; |
| 689 | struct dentry *root = sbsec->sb->s_root; | 696 | struct dentry *root = sbsec->sb->s_root; |
| 690 | struct inode_security_struct *root_isec = backing_inode_security(root); | 697 | struct inode_security_struct *root_isec; |
| 691 | u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; | 698 | u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; |
| 692 | u32 defcontext_sid = 0; | 699 | u32 defcontext_sid = 0; |
| 693 | char **mount_options = opts->mnt_opts; | 700 | char **mount_options = opts->mnt_opts; |
| @@ -730,6 +737,8 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
| 730 | && (num_opts == 0)) | 737 | && (num_opts == 0)) |
| 731 | goto out; | 738 | goto out; |
| 732 | 739 | ||
| 740 | root_isec = backing_inode_security_novalidate(root); | ||
| 741 | |||
| 733 | /* | 742 | /* |
| 734 | * parse the mount options, check if they are valid sids. | 743 | * parse the mount options, check if they are valid sids. |
| 735 | * also check if someone is trying to mount the same sb more | 744 | * also check if someone is trying to mount the same sb more |
| @@ -1623,7 +1632,7 @@ static int current_has_perm(const struct task_struct *tsk, | |||
| 1623 | 1632 | ||
| 1624 | /* Check whether a task is allowed to use a capability. */ | 1633 | /* Check whether a task is allowed to use a capability. */ |
| 1625 | static int cred_has_capability(const struct cred *cred, | 1634 | static int cred_has_capability(const struct cred *cred, |
| 1626 | int cap, int audit) | 1635 | int cap, int audit, bool initns) |
| 1627 | { | 1636 | { |
| 1628 | struct common_audit_data ad; | 1637 | struct common_audit_data ad; |
| 1629 | struct av_decision avd; | 1638 | struct av_decision avd; |
| @@ -1637,10 +1646,10 @@ static int cred_has_capability(const struct cred *cred, | |||
| 1637 | 1646 | ||
| 1638 | switch (CAP_TO_INDEX(cap)) { | 1647 | switch (CAP_TO_INDEX(cap)) { |
| 1639 | case 0: | 1648 | case 0: |
| 1640 | sclass = SECCLASS_CAPABILITY; | 1649 | sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS; |
| 1641 | break; | 1650 | break; |
| 1642 | case 1: | 1651 | case 1: |
| 1643 | sclass = SECCLASS_CAPABILITY2; | 1652 | sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS; |
| 1644 | break; | 1653 | break; |
| 1645 | default: | 1654 | default: |
| 1646 | printk(KERN_ERR | 1655 | printk(KERN_ERR |
| @@ -1782,7 +1791,6 @@ static int selinux_determine_inode_label(struct inode *dir, | |||
| 1782 | u32 *_new_isid) | 1791 | u32 *_new_isid) |
| 1783 | { | 1792 | { |
| 1784 | const struct superblock_security_struct *sbsec = dir->i_sb->s_security; | 1793 | const struct superblock_security_struct *sbsec = dir->i_sb->s_security; |
| 1785 | const struct inode_security_struct *dsec = inode_security(dir); | ||
| 1786 | const struct task_security_struct *tsec = current_security(); | 1794 | const struct task_security_struct *tsec = current_security(); |
| 1787 | 1795 | ||
| 1788 | if ((sbsec->flags & SE_SBINITIALIZED) && | 1796 | if ((sbsec->flags & SE_SBINITIALIZED) && |
| @@ -1792,6 +1800,7 @@ static int selinux_determine_inode_label(struct inode *dir, | |||
| 1792 | tsec->create_sid) { | 1800 | tsec->create_sid) { |
| 1793 | *_new_isid = tsec->create_sid; | 1801 | *_new_isid = tsec->create_sid; |
| 1794 | } else { | 1802 | } else { |
| 1803 | const struct inode_security_struct *dsec = inode_security(dir); | ||
| 1795 | return security_transition_sid(tsec->sid, dsec->sid, tclass, | 1804 | return security_transition_sid(tsec->sid, dsec->sid, tclass, |
| 1796 | name, _new_isid); | 1805 | name, _new_isid); |
| 1797 | } | 1806 | } |
| @@ -2076,7 +2085,7 @@ static int selinux_binder_transfer_file(struct task_struct *from, | |||
| 2076 | u32 sid = task_sid(to); | 2085 | u32 sid = task_sid(to); |
| 2077 | struct file_security_struct *fsec = file->f_security; | 2086 | struct file_security_struct *fsec = file->f_security; |
| 2078 | struct dentry *dentry = file->f_path.dentry; | 2087 | struct dentry *dentry = file->f_path.dentry; |
| 2079 | struct inode_security_struct *isec = backing_inode_security(dentry); | 2088 | struct inode_security_struct *isec; |
| 2080 | struct common_audit_data ad; | 2089 | struct common_audit_data ad; |
| 2081 | int rc; | 2090 | int rc; |
| 2082 | 2091 | ||
| @@ -2095,6 +2104,7 @@ static int selinux_binder_transfer_file(struct task_struct *from, | |||
| 2095 | if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) | 2104 | if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) |
| 2096 | return 0; | 2105 | return 0; |
| 2097 | 2106 | ||
| 2107 | isec = backing_inode_security(dentry); | ||
| 2098 | return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), | 2108 | return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), |
| 2099 | &ad); | 2109 | &ad); |
| 2100 | } | 2110 | } |
| @@ -2143,7 +2153,7 @@ static int selinux_capset(struct cred *new, const struct cred *old, | |||
| 2143 | static int selinux_capable(const struct cred *cred, struct user_namespace *ns, | 2153 | static int selinux_capable(const struct cred *cred, struct user_namespace *ns, |
| 2144 | int cap, int audit) | 2154 | int cap, int audit) |
| 2145 | { | 2155 | { |
| 2146 | return cred_has_capability(cred, cap, audit); | 2156 | return cred_has_capability(cred, cap, audit, ns == &init_user_ns); |
| 2147 | } | 2157 | } |
| 2148 | 2158 | ||
| 2149 | static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) | 2159 | static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) |
| @@ -2221,7 +2231,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
| 2221 | int rc, cap_sys_admin = 0; | 2231 | int rc, cap_sys_admin = 0; |
| 2222 | 2232 | ||
| 2223 | rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, | 2233 | rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, |
| 2224 | SECURITY_CAP_NOAUDIT); | 2234 | SECURITY_CAP_NOAUDIT, true); |
| 2225 | if (rc == 0) | 2235 | if (rc == 0) |
| 2226 | cap_sys_admin = 1; | 2236 | cap_sys_admin = 1; |
| 2227 | 2237 | ||
| @@ -2230,6 +2240,20 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
| 2230 | 2240 | ||
| 2231 | /* binprm security operations */ | 2241 | /* binprm security operations */ |
| 2232 | 2242 | ||
| 2243 | static u32 ptrace_parent_sid(struct task_struct *task) | ||
| 2244 | { | ||
| 2245 | u32 sid = 0; | ||
| 2246 | struct task_struct *tracer; | ||
| 2247 | |||
| 2248 | rcu_read_lock(); | ||
| 2249 | tracer = ptrace_parent(task); | ||
| 2250 | if (tracer) | ||
| 2251 | sid = task_sid(tracer); | ||
| 2252 | rcu_read_unlock(); | ||
| 2253 | |||
| 2254 | return sid; | ||
| 2255 | } | ||
| 2256 | |||
| 2233 | static int check_nnp_nosuid(const struct linux_binprm *bprm, | 2257 | static int check_nnp_nosuid(const struct linux_binprm *bprm, |
| 2234 | const struct task_security_struct *old_tsec, | 2258 | const struct task_security_struct *old_tsec, |
| 2235 | const struct task_security_struct *new_tsec) | 2259 | const struct task_security_struct *new_tsec) |
| @@ -2351,18 +2375,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
| 2351 | * changes its SID has the appropriate permit */ | 2375 | * changes its SID has the appropriate permit */ |
| 2352 | if (bprm->unsafe & | 2376 | if (bprm->unsafe & |
| 2353 | (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { | 2377 | (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { |
| 2354 | struct task_struct *tracer; | 2378 | u32 ptsid = ptrace_parent_sid(current); |
| 2355 | struct task_security_struct *sec; | ||
| 2356 | u32 ptsid = 0; | ||
| 2357 | |||
| 2358 | rcu_read_lock(); | ||
| 2359 | tracer = ptrace_parent(current); | ||
| 2360 | if (likely(tracer != NULL)) { | ||
| 2361 | sec = __task_cred(tracer)->security; | ||
| 2362 | ptsid = sec->sid; | ||
| 2363 | } | ||
| 2364 | rcu_read_unlock(); | ||
| 2365 | |||
| 2366 | if (ptsid != 0) { | 2379 | if (ptsid != 0) { |
| 2367 | rc = avc_has_perm(ptsid, new_tsec->sid, | 2380 | rc = avc_has_perm(ptsid, new_tsec->sid, |
| 2368 | SECCLASS_PROCESS, | 2381 | SECCLASS_PROCESS, |
| @@ -3046,7 +3059,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 3046 | const void *value, size_t size, int flags) | 3059 | const void *value, size_t size, int flags) |
| 3047 | { | 3060 | { |
| 3048 | struct inode *inode = d_backing_inode(dentry); | 3061 | struct inode *inode = d_backing_inode(dentry); |
| 3049 | struct inode_security_struct *isec = backing_inode_security(dentry); | 3062 | struct inode_security_struct *isec; |
| 3050 | struct superblock_security_struct *sbsec; | 3063 | struct superblock_security_struct *sbsec; |
| 3051 | struct common_audit_data ad; | 3064 | struct common_audit_data ad; |
| 3052 | u32 newsid, sid = current_sid(); | 3065 | u32 newsid, sid = current_sid(); |
| @@ -3065,6 +3078,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 3065 | ad.type = LSM_AUDIT_DATA_DENTRY; | 3078 | ad.type = LSM_AUDIT_DATA_DENTRY; |
| 3066 | ad.u.dentry = dentry; | 3079 | ad.u.dentry = dentry; |
| 3067 | 3080 | ||
| 3081 | isec = backing_inode_security(dentry); | ||
| 3068 | rc = avc_has_perm(sid, isec->sid, isec->sclass, | 3082 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
| 3069 | FILE__RELABELFROM, &ad); | 3083 | FILE__RELABELFROM, &ad); |
| 3070 | if (rc) | 3084 | if (rc) |
| @@ -3123,7 +3137,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, | |||
| 3123 | int flags) | 3137 | int flags) |
| 3124 | { | 3138 | { |
| 3125 | struct inode *inode = d_backing_inode(dentry); | 3139 | struct inode *inode = d_backing_inode(dentry); |
| 3126 | struct inode_security_struct *isec = backing_inode_security(dentry); | 3140 | struct inode_security_struct *isec; |
| 3127 | u32 newsid; | 3141 | u32 newsid; |
| 3128 | int rc; | 3142 | int rc; |
| 3129 | 3143 | ||
| @@ -3140,6 +3154,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, | |||
| 3140 | return; | 3154 | return; |
| 3141 | } | 3155 | } |
| 3142 | 3156 | ||
| 3157 | isec = backing_inode_security(dentry); | ||
| 3143 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 3158 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
| 3144 | isec->sid = newsid; | 3159 | isec->sid = newsid; |
| 3145 | isec->initialized = LABEL_INITIALIZED; | 3160 | isec->initialized = LABEL_INITIALIZED; |
| @@ -3181,7 +3196,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void | |||
| 3181 | u32 size; | 3196 | u32 size; |
| 3182 | int error; | 3197 | int error; |
| 3183 | char *context = NULL; | 3198 | char *context = NULL; |
| 3184 | struct inode_security_struct *isec = inode_security(inode); | 3199 | struct inode_security_struct *isec; |
| 3185 | 3200 | ||
| 3186 | if (strcmp(name, XATTR_SELINUX_SUFFIX)) | 3201 | if (strcmp(name, XATTR_SELINUX_SUFFIX)) |
| 3187 | return -EOPNOTSUPP; | 3202 | return -EOPNOTSUPP; |
| @@ -3199,7 +3214,8 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void | |||
| 3199 | SECURITY_CAP_NOAUDIT); | 3214 | SECURITY_CAP_NOAUDIT); |
| 3200 | if (!error) | 3215 | if (!error) |
| 3201 | error = cred_has_capability(current_cred(), CAP_MAC_ADMIN, | 3216 | error = cred_has_capability(current_cred(), CAP_MAC_ADMIN, |
| 3202 | SECURITY_CAP_NOAUDIT); | 3217 | SECURITY_CAP_NOAUDIT, true); |
| 3218 | isec = inode_security(inode); | ||
| 3203 | if (!error) | 3219 | if (!error) |
| 3204 | error = security_sid_to_context_force(isec->sid, &context, | 3220 | error = security_sid_to_context_force(isec->sid, &context, |
| 3205 | &size); | 3221 | &size); |
| @@ -3220,7 +3236,7 @@ out_nofree: | |||
| 3220 | static int selinux_inode_setsecurity(struct inode *inode, const char *name, | 3236 | static int selinux_inode_setsecurity(struct inode *inode, const char *name, |
| 3221 | const void *value, size_t size, int flags) | 3237 | const void *value, size_t size, int flags) |
| 3222 | { | 3238 | { |
| 3223 | struct inode_security_struct *isec = inode_security(inode); | 3239 | struct inode_security_struct *isec = inode_security_novalidate(inode); |
| 3224 | u32 newsid; | 3240 | u32 newsid; |
| 3225 | int rc; | 3241 | int rc; |
| 3226 | 3242 | ||
| @@ -3309,7 +3325,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, | |||
| 3309 | struct common_audit_data ad; | 3325 | struct common_audit_data ad; |
| 3310 | struct file_security_struct *fsec = file->f_security; | 3326 | struct file_security_struct *fsec = file->f_security; |
| 3311 | struct inode *inode = file_inode(file); | 3327 | struct inode *inode = file_inode(file); |
| 3312 | struct inode_security_struct *isec = inode_security(inode); | 3328 | struct inode_security_struct *isec; |
| 3313 | struct lsm_ioctlop_audit ioctl; | 3329 | struct lsm_ioctlop_audit ioctl; |
| 3314 | u32 ssid = cred_sid(cred); | 3330 | u32 ssid = cred_sid(cred); |
| 3315 | int rc; | 3331 | int rc; |
| @@ -3333,6 +3349,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, | |||
| 3333 | if (unlikely(IS_PRIVATE(inode))) | 3349 | if (unlikely(IS_PRIVATE(inode))) |
| 3334 | return 0; | 3350 | return 0; |
| 3335 | 3351 | ||
| 3352 | isec = inode_security(inode); | ||
| 3336 | rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, | 3353 | rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, |
| 3337 | requested, driver, xperm, &ad); | 3354 | requested, driver, xperm, &ad); |
| 3338 | out: | 3355 | out: |
| @@ -3374,7 +3391,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
| 3374 | case KDSKBENT: | 3391 | case KDSKBENT: |
| 3375 | case KDSKBSENT: | 3392 | case KDSKBSENT: |
| 3376 | error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, | 3393 | error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, |
| 3377 | SECURITY_CAP_AUDIT); | 3394 | SECURITY_CAP_AUDIT, true); |
| 3378 | break; | 3395 | break; |
| 3379 | 3396 | ||
| 3380 | /* default case assumes that the command will go | 3397 | /* default case assumes that the command will go |
| @@ -3463,8 +3480,9 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, | |||
| 3463 | vma->vm_end <= vma->vm_mm->brk) { | 3480 | vma->vm_end <= vma->vm_mm->brk) { |
| 3464 | rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); | 3481 | rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); |
| 3465 | } else if (!vma->vm_file && | 3482 | } else if (!vma->vm_file && |
| 3466 | vma->vm_start <= vma->vm_mm->start_stack && | 3483 | ((vma->vm_start <= vma->vm_mm->start_stack && |
| 3467 | vma->vm_end >= vma->vm_mm->start_stack) { | 3484 | vma->vm_end >= vma->vm_mm->start_stack) || |
| 3485 | vma_is_stack_for_task(vma, current))) { | ||
| 3468 | rc = current_has_perm(current, PROCESS__EXECSTACK); | 3486 | rc = current_has_perm(current, PROCESS__EXECSTACK); |
| 3469 | } else if (vma->vm_file && vma->anon_vma) { | 3487 | } else if (vma->vm_file && vma->anon_vma) { |
| 3470 | /* | 3488 | /* |
| @@ -3720,6 +3738,52 @@ static int selinux_kernel_module_request(char *kmod_name) | |||
| 3720 | SYSTEM__MODULE_REQUEST, &ad); | 3738 | SYSTEM__MODULE_REQUEST, &ad); |
| 3721 | } | 3739 | } |
| 3722 | 3740 | ||
| 3741 | static int selinux_kernel_module_from_file(struct file *file) | ||
| 3742 | { | ||
| 3743 | struct common_audit_data ad; | ||
| 3744 | struct inode_security_struct *isec; | ||
| 3745 | struct file_security_struct *fsec; | ||
| 3746 | u32 sid = current_sid(); | ||
| 3747 | int rc; | ||
| 3748 | |||
| 3749 | /* init_module */ | ||
| 3750 | if (file == NULL) | ||
| 3751 | return avc_has_perm(sid, sid, SECCLASS_SYSTEM, | ||
| 3752 | SYSTEM__MODULE_LOAD, NULL); | ||
| 3753 | |||
| 3754 | /* finit_module */ | ||
| 3755 | |||
| 3756 | ad.type = LSM_AUDIT_DATA_PATH; | ||
| 3757 | ad.u.path = file->f_path; | ||
| 3758 | |||
| 3759 | fsec = file->f_security; | ||
| 3760 | if (sid != fsec->sid) { | ||
| 3761 | rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); | ||
| 3762 | if (rc) | ||
| 3763 | return rc; | ||
| 3764 | } | ||
| 3765 | |||
| 3766 | isec = inode_security(file_inode(file)); | ||
| 3767 | return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM, | ||
| 3768 | SYSTEM__MODULE_LOAD, &ad); | ||
| 3769 | } | ||
| 3770 | |||
| 3771 | static int selinux_kernel_read_file(struct file *file, | ||
| 3772 | enum kernel_read_file_id id) | ||
| 3773 | { | ||
| 3774 | int rc = 0; | ||
| 3775 | |||
| 3776 | switch (id) { | ||
| 3777 | case READING_MODULE: | ||
| 3778 | rc = selinux_kernel_module_from_file(file); | ||
| 3779 | break; | ||
| 3780 | default: | ||
| 3781 | break; | ||
| 3782 | } | ||
| 3783 | |||
| 3784 | return rc; | ||
| 3785 | } | ||
| 3786 | |||
| 3723 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) | 3787 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) |
| 3724 | { | 3788 | { |
| 3725 | return current_has_perm(p, PROCESS__SETPGID); | 3789 | return current_has_perm(p, PROCESS__SETPGID); |
| @@ -4599,6 +4663,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
| 4599 | { | 4663 | { |
| 4600 | u32 peer_secid = SECSID_NULL; | 4664 | u32 peer_secid = SECSID_NULL; |
| 4601 | u16 family; | 4665 | u16 family; |
| 4666 | struct inode_security_struct *isec; | ||
| 4602 | 4667 | ||
| 4603 | if (skb && skb->protocol == htons(ETH_P_IP)) | 4668 | if (skb && skb->protocol == htons(ETH_P_IP)) |
| 4604 | family = PF_INET; | 4669 | family = PF_INET; |
| @@ -4609,9 +4674,10 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
| 4609 | else | 4674 | else |
| 4610 | goto out; | 4675 | goto out; |
| 4611 | 4676 | ||
| 4612 | if (sock && family == PF_UNIX) | 4677 | if (sock && family == PF_UNIX) { |
| 4613 | selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid); | 4678 | isec = inode_security_novalidate(SOCK_INODE(sock)); |
| 4614 | else if (skb) | 4679 | peer_secid = isec->sid; |
| 4680 | } else if (skb) | ||
| 4615 | selinux_skb_peerlbl_sid(skb, family, &peer_secid); | 4681 | selinux_skb_peerlbl_sid(skb, family, &peer_secid); |
| 4616 | 4682 | ||
| 4617 | out: | 4683 | out: |
| @@ -5676,7 +5742,6 @@ static int selinux_setprocattr(struct task_struct *p, | |||
| 5676 | char *name, void *value, size_t size) | 5742 | char *name, void *value, size_t size) |
| 5677 | { | 5743 | { |
| 5678 | struct task_security_struct *tsec; | 5744 | struct task_security_struct *tsec; |
| 5679 | struct task_struct *tracer; | ||
| 5680 | struct cred *new; | 5745 | struct cred *new; |
| 5681 | u32 sid = 0, ptsid; | 5746 | u32 sid = 0, ptsid; |
| 5682 | int error; | 5747 | int error; |
| @@ -5783,14 +5848,8 @@ static int selinux_setprocattr(struct task_struct *p, | |||
| 5783 | 5848 | ||
| 5784 | /* Check for ptracing, and update the task SID if ok. | 5849 | /* Check for ptracing, and update the task SID if ok. |
| 5785 | Otherwise, leave SID unchanged and fail. */ | 5850 | Otherwise, leave SID unchanged and fail. */ |
| 5786 | ptsid = 0; | 5851 | ptsid = ptrace_parent_sid(p); |
| 5787 | rcu_read_lock(); | 5852 | if (ptsid != 0) { |
| 5788 | tracer = ptrace_parent(p); | ||
| 5789 | if (tracer) | ||
| 5790 | ptsid = task_sid(tracer); | ||
| 5791 | rcu_read_unlock(); | ||
| 5792 | |||
| 5793 | if (tracer) { | ||
| 5794 | error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, | 5853 | error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, |
| 5795 | PROCESS__PTRACE, NULL); | 5854 | PROCESS__PTRACE, NULL); |
| 5796 | if (error) | 5855 | if (error) |
| @@ -6021,6 +6080,7 @@ static struct security_hook_list selinux_hooks[] = { | |||
| 6021 | LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as), | 6080 | LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as), |
| 6022 | LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as), | 6081 | LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as), |
| 6023 | LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request), | 6082 | LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request), |
| 6083 | LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file), | ||
| 6024 | LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid), | 6084 | LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid), |
| 6025 | LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid), | 6085 | LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid), |
| 6026 | LSM_HOOK_INIT(task_getsid, selinux_task_getsid), | 6086 | LSM_HOOK_INIT(task_getsid, selinux_task_getsid), |
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index ef83c4b85a33..1f1f4b2f6018 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h | |||
| @@ -12,6 +12,18 @@ | |||
| 12 | #define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \ | 12 | #define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \ |
| 13 | "write", "associate", "unix_read", "unix_write" | 13 | "write", "associate", "unix_read", "unix_write" |
| 14 | 14 | ||
| 15 | #define COMMON_CAP_PERMS "chown", "dac_override", "dac_read_search", \ | ||
| 16 | "fowner", "fsetid", "kill", "setgid", "setuid", "setpcap", \ | ||
| 17 | "linux_immutable", "net_bind_service", "net_broadcast", \ | ||
| 18 | "net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module", \ | ||
| 19 | "sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin", \ | ||
| 20 | "sys_boot", "sys_nice", "sys_resource", "sys_time", \ | ||
| 21 | "sys_tty_config", "mknod", "lease", "audit_write", \ | ||
| 22 | "audit_control", "setfcap" | ||
| 23 | |||
| 24 | #define COMMON_CAP2_PERMS "mac_override", "mac_admin", "syslog", \ | ||
| 25 | "wake_alarm", "block_suspend", "audit_read" | ||
| 26 | |||
| 15 | /* | 27 | /* |
| 16 | * Note: The name for any socket class should be suffixed by "socket", | 28 | * Note: The name for any socket class should be suffixed by "socket", |
| 17 | * and doesn't contain more than one substr of "socket". | 29 | * and doesn't contain more than one substr of "socket". |
| @@ -32,16 +44,9 @@ struct security_class_mapping secclass_map[] = { | |||
| 32 | "setsockcreate", NULL } }, | 44 | "setsockcreate", NULL } }, |
| 33 | { "system", | 45 | { "system", |
| 34 | { "ipc_info", "syslog_read", "syslog_mod", | 46 | { "ipc_info", "syslog_read", "syslog_mod", |
| 35 | "syslog_console", "module_request", NULL } }, | 47 | "syslog_console", "module_request", "module_load", NULL } }, |
| 36 | { "capability", | 48 | { "capability", |
| 37 | { "chown", "dac_override", "dac_read_search", | 49 | { COMMON_CAP_PERMS, NULL } }, |
| 38 | "fowner", "fsetid", "kill", "setgid", "setuid", "setpcap", | ||
| 39 | "linux_immutable", "net_bind_service", "net_broadcast", | ||
| 40 | "net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module", | ||
| 41 | "sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin", | ||
| 42 | "sys_boot", "sys_nice", "sys_resource", "sys_time", | ||
| 43 | "sys_tty_config", "mknod", "lease", "audit_write", | ||
| 44 | "audit_control", "setfcap", NULL } }, | ||
| 45 | { "filesystem", | 50 | { "filesystem", |
| 46 | { "mount", "remount", "unmount", "getattr", | 51 | { "mount", "remount", "unmount", "getattr", |
| 47 | "relabelfrom", "relabelto", "associate", "quotamod", | 52 | "relabelfrom", "relabelto", "associate", "quotamod", |
| @@ -150,12 +155,15 @@ struct security_class_mapping secclass_map[] = { | |||
| 150 | { "memprotect", { "mmap_zero", NULL } }, | 155 | { "memprotect", { "mmap_zero", NULL } }, |
| 151 | { "peer", { "recv", NULL } }, | 156 | { "peer", { "recv", NULL } }, |
| 152 | { "capability2", | 157 | { "capability2", |
| 153 | { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", | 158 | { COMMON_CAP2_PERMS, NULL } }, |
| 154 | "audit_read", NULL } }, | ||
| 155 | { "kernel_service", { "use_as_override", "create_files_as", NULL } }, | 159 | { "kernel_service", { "use_as_override", "create_files_as", NULL } }, |
| 156 | { "tun_socket", | 160 | { "tun_socket", |
| 157 | { COMMON_SOCK_PERMS, "attach_queue", NULL } }, | 161 | { COMMON_SOCK_PERMS, "attach_queue", NULL } }, |
| 158 | { "binder", { "impersonate", "call", "set_context_mgr", "transfer", | 162 | { "binder", { "impersonate", "call", "set_context_mgr", "transfer", |
| 159 | NULL } }, | 163 | NULL } }, |
| 164 | { "cap_userns", | ||
| 165 | { COMMON_CAP_PERMS, NULL } }, | ||
| 166 | { "cap2_userns", | ||
| 167 | { COMMON_CAP2_PERMS, NULL } }, | ||
| 160 | { NULL } | 168 | { NULL } |
| 161 | }; | 169 | }; |
diff --git a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h index 67ce7a8d8301..ff4fddca9050 100644 --- a/security/selinux/include/conditional.h +++ b/security/selinux/include/conditional.h | |||
| @@ -17,6 +17,6 @@ int security_get_bools(int *len, char ***names, int **values); | |||
| 17 | 17 | ||
| 18 | int security_set_bools(int len, int *values); | 18 | int security_set_bools(int len, int *values); |
| 19 | 19 | ||
| 20 | int security_get_bool_value(int bool); | 20 | int security_get_bool_value(int index); |
| 21 | 21 | ||
| 22 | #endif | 22 | #endif |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index a2ae05414ba1..c21e135460a5 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -38,9 +38,8 @@ struct task_security_struct { | |||
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | enum label_initialized { | 40 | enum label_initialized { |
| 41 | LABEL_MISSING, /* not initialized */ | 41 | LABEL_INVALID, /* invalid or not initialized */ |
| 42 | LABEL_INITIALIZED, /* inizialized */ | 42 | LABEL_INITIALIZED /* initialized */ |
| 43 | LABEL_INVALID /* invalid */ | ||
| 44 | }; | 43 | }; |
| 45 | 44 | ||
| 46 | struct inode_security_struct { | 45 | struct inode_security_struct { |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index ebda97333f1b..89df64672b89 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -2696,7 +2696,7 @@ out: | |||
| 2696 | return rc; | 2696 | return rc; |
| 2697 | } | 2697 | } |
| 2698 | 2698 | ||
| 2699 | int security_get_bool_value(int bool) | 2699 | int security_get_bool_value(int index) |
| 2700 | { | 2700 | { |
| 2701 | int rc; | 2701 | int rc; |
| 2702 | int len; | 2702 | int len; |
| @@ -2705,10 +2705,10 @@ int security_get_bool_value(int bool) | |||
| 2705 | 2705 | ||
| 2706 | rc = -EFAULT; | 2706 | rc = -EFAULT; |
| 2707 | len = policydb.p_bools.nprim; | 2707 | len = policydb.p_bools.nprim; |
| 2708 | if (bool >= len) | 2708 | if (index >= len) |
| 2709 | goto out; | 2709 | goto out; |
| 2710 | 2710 | ||
| 2711 | rc = policydb.bool_val_to_struct[bool]->state; | 2711 | rc = policydb.bool_val_to_struct[index]->state; |
| 2712 | out: | 2712 | out: |
| 2713 | read_unlock(&policy_rwlock); | 2713 | read_unlock(&policy_rwlock); |
| 2714 | return rc; | 2714 | return rc; |
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index cb6ed10816d4..9b756b1f3dc5 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/prctl.h> | 18 | #include <linux/prctl.h> |
| 19 | #include <linux/ratelimit.h> | 19 | #include <linux/ratelimit.h> |
| 20 | #include <linux/workqueue.h> | 20 | #include <linux/workqueue.h> |
| 21 | #include <linux/string_helpers.h> | ||
| 21 | 22 | ||
| 22 | #define YAMA_SCOPE_DISABLED 0 | 23 | #define YAMA_SCOPE_DISABLED 0 |
| 23 | #define YAMA_SCOPE_RELATIONAL 1 | 24 | #define YAMA_SCOPE_RELATIONAL 1 |
| @@ -41,6 +42,22 @@ static DEFINE_SPINLOCK(ptracer_relations_lock); | |||
| 41 | static void yama_relation_cleanup(struct work_struct *work); | 42 | static void yama_relation_cleanup(struct work_struct *work); |
| 42 | static DECLARE_WORK(yama_relation_work, yama_relation_cleanup); | 43 | static DECLARE_WORK(yama_relation_work, yama_relation_cleanup); |
| 43 | 44 | ||
| 45 | static void report_access(const char *access, struct task_struct *target, | ||
| 46 | struct task_struct *agent) | ||
| 47 | { | ||
| 48 | char *target_cmd, *agent_cmd; | ||
| 49 | |||
| 50 | target_cmd = kstrdup_quotable_cmdline(target, GFP_ATOMIC); | ||
| 51 | agent_cmd = kstrdup_quotable_cmdline(agent, GFP_ATOMIC); | ||
| 52 | |||
| 53 | pr_notice_ratelimited( | ||
| 54 | "ptrace %s of \"%s\"[%d] was attempted by \"%s\"[%d]\n", | ||
| 55 | access, target_cmd, target->pid, agent_cmd, agent->pid); | ||
| 56 | |||
| 57 | kfree(agent_cmd); | ||
| 58 | kfree(target_cmd); | ||
| 59 | } | ||
| 60 | |||
| 44 | /** | 61 | /** |
| 45 | * yama_relation_cleanup - remove invalid entries from the relation list | 62 | * yama_relation_cleanup - remove invalid entries from the relation list |
| 46 | * | 63 | * |
| @@ -307,11 +324,8 @@ static int yama_ptrace_access_check(struct task_struct *child, | |||
| 307 | } | 324 | } |
| 308 | } | 325 | } |
| 309 | 326 | ||
| 310 | if (rc && (mode & PTRACE_MODE_NOAUDIT) == 0) { | 327 | if (rc && (mode & PTRACE_MODE_NOAUDIT) == 0) |
| 311 | printk_ratelimited(KERN_NOTICE | 328 | report_access("attach", child, current); |
| 312 | "ptrace of pid %d was attempted by: %s (pid %d)\n", | ||
| 313 | child->pid, current->comm, current->pid); | ||
| 314 | } | ||
| 315 | 329 | ||
| 316 | return rc; | 330 | return rc; |
| 317 | } | 331 | } |
| @@ -337,11 +351,8 @@ int yama_ptrace_traceme(struct task_struct *parent) | |||
| 337 | break; | 351 | break; |
| 338 | } | 352 | } |
| 339 | 353 | ||
| 340 | if (rc) { | 354 | if (rc) |
| 341 | printk_ratelimited(KERN_NOTICE | 355 | report_access("traceme", current, parent); |
| 342 | "ptraceme of pid %d was attempted by: %s (pid %d)\n", | ||
| 343 | current->pid, parent->comm, parent->pid); | ||
| 344 | } | ||
| 345 | 356 | ||
| 346 | return rc; | 357 | return rc; |
| 347 | } | 358 | } |
