diff options
Diffstat (limited to 'security')
33 files changed, 1332 insertions, 532 deletions
diff --git a/security/Kconfig b/security/Kconfig index d9aa521b5206..e4fe2f3c2c65 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | menu "Security options" | 5 | menu "Security options" |
| 6 | 6 | ||
| 7 | source security/keys/Kconfig | 7 | source "security/keys/Kconfig" |
| 8 | 8 | ||
| 9 | config SECURITY_DMESG_RESTRICT | 9 | config SECURITY_DMESG_RESTRICT |
| 10 | bool "Restrict unprivileged access to the kernel syslog" | 10 | bool "Restrict unprivileged access to the kernel syslog" |
| @@ -230,14 +230,14 @@ config STATIC_USERMODEHELPER_PATH | |||
| 230 | If you wish for all usermode helper programs to be disabled, | 230 | If you wish for all usermode helper programs to be disabled, |
| 231 | specify an empty string here (i.e. ""). | 231 | specify an empty string here (i.e. ""). |
| 232 | 232 | ||
| 233 | source security/selinux/Kconfig | 233 | source "security/selinux/Kconfig" |
| 234 | source security/smack/Kconfig | 234 | source "security/smack/Kconfig" |
| 235 | source security/tomoyo/Kconfig | 235 | source "security/tomoyo/Kconfig" |
| 236 | source security/apparmor/Kconfig | 236 | source "security/apparmor/Kconfig" |
| 237 | source security/loadpin/Kconfig | 237 | source "security/loadpin/Kconfig" |
| 238 | source security/yama/Kconfig | 238 | source "security/yama/Kconfig" |
| 239 | 239 | ||
| 240 | source security/integrity/Kconfig | 240 | source "security/integrity/Kconfig" |
| 241 | 241 | ||
| 242 | choice | 242 | choice |
| 243 | prompt "Default security module" | 243 | prompt "Default security module" |
diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c index 136f2a047836..af03d98c7552 100644 --- a/security/apparmor/crypto.c +++ b/security/apparmor/crypto.c | |||
| @@ -112,7 +112,7 @@ static int __init init_profile_hash(void) | |||
| 112 | if (!apparmor_initialized) | 112 | if (!apparmor_initialized) |
| 113 | return 0; | 113 | return 0; |
| 114 | 114 | ||
| 115 | tfm = crypto_alloc_shash("sha1", 0, CRYPTO_ALG_ASYNC); | 115 | tfm = crypto_alloc_shash("sha1", 0, 0); |
| 116 | if (IS_ERR(tfm)) { | 116 | if (IS_ERR(tfm)) { |
| 117 | int error = PTR_ERR(tfm); | 117 | int error = PTR_ERR(tfm); |
| 118 | AA_ERROR("failed to setup profile sha1 hashing: %d\n", error); | 118 | AA_ERROR("failed to setup profile sha1 hashing: %d\n", error); |
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index da9565891738..2ea4ec9991d5 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig | |||
| @@ -51,6 +51,17 @@ config INTEGRITY_TRUSTED_KEYRING | |||
| 51 | .evm keyrings be signed by a key on the system trusted | 51 | .evm keyrings be signed by a key on the system trusted |
| 52 | keyring. | 52 | keyring. |
| 53 | 53 | ||
| 54 | config INTEGRITY_PLATFORM_KEYRING | ||
| 55 | bool "Provide keyring for platform/firmware trusted keys" | ||
| 56 | depends on INTEGRITY_ASYMMETRIC_KEYS | ||
| 57 | depends on SYSTEM_BLACKLIST_KEYRING | ||
| 58 | depends on EFI | ||
| 59 | help | ||
| 60 | Provide a separate, distinct keyring for platform trusted keys, which | ||
| 61 | the kernel automatically populates during initialization from values | ||
| 62 | provided by the platform for verifying the kexec'ed kerned image | ||
| 63 | and, possibly, the initramfs signature. | ||
| 64 | |||
| 54 | config INTEGRITY_AUDIT | 65 | config INTEGRITY_AUDIT |
| 55 | bool "Enables integrity auditing support " | 66 | bool "Enables integrity auditing support " |
| 56 | depends on AUDIT | 67 | depends on AUDIT |
| @@ -66,7 +77,7 @@ config INTEGRITY_AUDIT | |||
| 66 | be enabled by specifying 'integrity_audit=1' on the kernel | 77 | be enabled by specifying 'integrity_audit=1' on the kernel |
| 67 | command line. | 78 | command line. |
| 68 | 79 | ||
| 69 | source security/integrity/ima/Kconfig | 80 | source "security/integrity/ima/Kconfig" |
| 70 | source security/integrity/evm/Kconfig | 81 | source "security/integrity/evm/Kconfig" |
| 71 | 82 | ||
| 72 | endif # if INTEGRITY | 83 | endif # if INTEGRITY |
diff --git a/security/integrity/Makefile b/security/integrity/Makefile index 04d6e462b079..86df9aba8c0f 100644 --- a/security/integrity/Makefile +++ b/security/integrity/Makefile | |||
| @@ -9,6 +9,11 @@ integrity-y := iint.o | |||
| 9 | integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o | 9 | integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o |
| 10 | integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o | 10 | integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o |
| 11 | integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o | 11 | integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o |
| 12 | integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o \ | ||
| 13 | platform_certs/efi_parser.o \ | ||
| 14 | platform_certs/load_uefi.o | ||
| 15 | obj-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/load_uefi.o | ||
| 16 | $(obj)/load_uefi.o: KBUILD_CFLAGS += -fshort-wchar | ||
| 12 | 17 | ||
| 13 | subdir-$(CONFIG_IMA) += ima | 18 | subdir-$(CONFIG_IMA) += ima |
| 14 | obj-$(CONFIG_IMA) += ima/ | 19 | obj-$(CONFIG_IMA) += ima/ |
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 5eacba858e4b..f45d6edecf99 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
| @@ -34,7 +34,7 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = { | |||
| 34 | ".evm", | 34 | ".evm", |
| 35 | ".ima", | 35 | ".ima", |
| 36 | #endif | 36 | #endif |
| 37 | "_module", | 37 | ".platform", |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY | 40 | #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY |
| @@ -73,12 +73,38 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | |||
| 73 | return -EOPNOTSUPP; | 73 | return -EOPNOTSUPP; |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | int __init integrity_init_keyring(const unsigned int id) | 76 | static int __integrity_init_keyring(const unsigned int id, key_perm_t perm, |
| 77 | struct key_restriction *restriction) | ||
| 77 | { | 78 | { |
| 78 | const struct cred *cred = current_cred(); | 79 | const struct cred *cred = current_cred(); |
| 79 | struct key_restriction *restriction; | ||
| 80 | int err = 0; | 80 | int err = 0; |
| 81 | 81 | ||
| 82 | keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), | ||
| 83 | KGIDT_INIT(0), cred, perm, | ||
| 84 | KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL); | ||
| 85 | if (IS_ERR(keyring[id])) { | ||
| 86 | err = PTR_ERR(keyring[id]); | ||
| 87 | pr_info("Can't allocate %s keyring (%d)\n", | ||
| 88 | keyring_name[id], err); | ||
| 89 | keyring[id] = NULL; | ||
| 90 | } | ||
| 91 | |||
| 92 | return err; | ||
| 93 | } | ||
| 94 | |||
| 95 | int __init integrity_init_keyring(const unsigned int id) | ||
| 96 | { | ||
| 97 | struct key_restriction *restriction; | ||
| 98 | key_perm_t perm; | ||
| 99 | |||
| 100 | perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | ||
| 101 | | KEY_USR_READ | KEY_USR_SEARCH; | ||
| 102 | |||
| 103 | if (id == INTEGRITY_KEYRING_PLATFORM) { | ||
| 104 | restriction = NULL; | ||
| 105 | goto out; | ||
| 106 | } | ||
| 107 | |||
| 82 | if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING)) | 108 | if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING)) |
| 83 | return 0; | 109 | return 0; |
| 84 | 110 | ||
| @@ -87,32 +113,43 @@ int __init integrity_init_keyring(const unsigned int id) | |||
| 87 | return -ENOMEM; | 113 | return -ENOMEM; |
| 88 | 114 | ||
| 89 | restriction->check = restrict_link_to_ima; | 115 | restriction->check = restrict_link_to_ima; |
| 116 | perm |= KEY_USR_WRITE; | ||
| 90 | 117 | ||
| 91 | keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), | 118 | out: |
| 92 | KGIDT_INIT(0), cred, | 119 | return __integrity_init_keyring(id, perm, restriction); |
| 93 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | 120 | } |
| 94 | KEY_USR_VIEW | KEY_USR_READ | | 121 | |
| 95 | KEY_USR_WRITE | KEY_USR_SEARCH), | 122 | int __init integrity_add_key(const unsigned int id, const void *data, |
| 96 | KEY_ALLOC_NOT_IN_QUOTA, | 123 | off_t size, key_perm_t perm) |
| 97 | restriction, NULL); | 124 | { |
| 98 | if (IS_ERR(keyring[id])) { | 125 | key_ref_t key; |
| 99 | err = PTR_ERR(keyring[id]); | 126 | int rc = 0; |
| 100 | pr_info("Can't allocate %s keyring (%d)\n", | 127 | |
| 101 | keyring_name[id], err); | 128 | if (!keyring[id]) |
| 102 | keyring[id] = NULL; | 129 | return -EINVAL; |
| 130 | |||
| 131 | key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric", | ||
| 132 | NULL, data, size, perm, | ||
| 133 | KEY_ALLOC_NOT_IN_QUOTA); | ||
| 134 | if (IS_ERR(key)) { | ||
| 135 | rc = PTR_ERR(key); | ||
| 136 | pr_err("Problem loading X.509 certificate %d\n", rc); | ||
| 137 | } else { | ||
| 138 | pr_notice("Loaded X.509 cert '%s'\n", | ||
| 139 | key_ref_to_ptr(key)->description); | ||
| 140 | key_ref_put(key); | ||
| 103 | } | 141 | } |
| 104 | return err; | 142 | |
| 143 | return rc; | ||
| 144 | |||
| 105 | } | 145 | } |
| 106 | 146 | ||
| 107 | int __init integrity_load_x509(const unsigned int id, const char *path) | 147 | int __init integrity_load_x509(const unsigned int id, const char *path) |
| 108 | { | 148 | { |
| 109 | key_ref_t key; | ||
| 110 | void *data; | 149 | void *data; |
| 111 | loff_t size; | 150 | loff_t size; |
| 112 | int rc; | 151 | int rc; |
| 113 | 152 | key_perm_t perm; | |
| 114 | if (!keyring[id]) | ||
| 115 | return -EINVAL; | ||
| 116 | 153 | ||
| 117 | rc = kernel_read_file_from_path(path, &data, &size, 0, | 154 | rc = kernel_read_file_from_path(path, &data, &size, 0, |
| 118 | READING_X509_CERTIFICATE); | 155 | READING_X509_CERTIFICATE); |
| @@ -121,23 +158,21 @@ int __init integrity_load_x509(const unsigned int id, const char *path) | |||
| 121 | return rc; | 158 | return rc; |
| 122 | } | 159 | } |
| 123 | 160 | ||
| 124 | key = key_create_or_update(make_key_ref(keyring[id], 1), | 161 | perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ; |
| 125 | "asymmetric", | 162 | |
| 126 | NULL, | 163 | pr_info("Loading X.509 certificate: %s\n", path); |
| 127 | data, | 164 | rc = integrity_add_key(id, (const void *)data, size, perm); |
| 128 | size, | 165 | |
| 129 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
| 130 | KEY_USR_VIEW | KEY_USR_READ), | ||
| 131 | KEY_ALLOC_NOT_IN_QUOTA); | ||
| 132 | if (IS_ERR(key)) { | ||
| 133 | rc = PTR_ERR(key); | ||
| 134 | pr_err("Problem loading X.509 certificate (%d): %s\n", | ||
| 135 | rc, path); | ||
| 136 | } else { | ||
| 137 | pr_notice("Loaded X.509 cert '%s': %s\n", | ||
| 138 | key_ref_to_ptr(key)->description, path); | ||
| 139 | key_ref_put(key); | ||
| 140 | } | ||
| 141 | vfree(data); | 166 | vfree(data); |
| 142 | return 0; | 167 | return rc; |
| 168 | } | ||
| 169 | |||
| 170 | int __init integrity_load_cert(const unsigned int id, const char *source, | ||
| 171 | const void *data, size_t len, key_perm_t perm) | ||
| 172 | { | ||
| 173 | if (!data) | ||
| 174 | return -EINVAL; | ||
| 175 | |||
| 176 | pr_info("Loading X.509 certificate: %s\n", source); | ||
| 177 | return integrity_add_key(id, data, len, perm); | ||
| 143 | } | 178 | } |
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 6dc075144508..d775e03fbbcc 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c | |||
| @@ -106,6 +106,7 @@ int asymmetric_verify(struct key *keyring, const char *sig, | |||
| 106 | 106 | ||
| 107 | pks.pkey_algo = "rsa"; | 107 | pks.pkey_algo = "rsa"; |
| 108 | pks.hash_algo = hash_algo_name[hdr->hash_algo]; | 108 | pks.hash_algo = hash_algo_name[hdr->hash_algo]; |
| 109 | pks.encoding = "pkcs1"; | ||
| 109 | pks.digest = (u8 *)data; | 110 | pks.digest = (u8 *)data; |
| 110 | pks.digest_size = datalen; | 111 | pks.digest_size = datalen; |
| 111 | pks.s = hdr->sig; | 112 | pks.s = hdr->sig; |
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 77ef210a8a6b..43e2dc3a60d0 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c | |||
| @@ -97,8 +97,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo) | |||
| 97 | mutex_lock(&mutex); | 97 | mutex_lock(&mutex); |
| 98 | if (*tfm) | 98 | if (*tfm) |
| 99 | goto out; | 99 | goto out; |
| 100 | *tfm = crypto_alloc_shash(algo, 0, | 100 | *tfm = crypto_alloc_shash(algo, 0, CRYPTO_NOLOAD); |
| 101 | CRYPTO_ALG_ASYNC | CRYPTO_NOLOAD); | ||
| 102 | if (IS_ERR(*tfm)) { | 101 | if (IS_ERR(*tfm)) { |
| 103 | rc = PTR_ERR(*tfm); | 102 | rc = PTR_ERR(*tfm); |
| 104 | pr_err("Can not allocate %s (reason: %ld)\n", algo, rc); | 103 | pr_err("Can not allocate %s (reason: %ld)\n", algo, rc); |
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 13b446328dda..a18f8c6d13b5 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
| @@ -157,6 +157,14 @@ config IMA_APPRAISE | |||
| 157 | <http://linux-ima.sourceforge.net> | 157 | <http://linux-ima.sourceforge.net> |
| 158 | If unsure, say N. | 158 | If unsure, say N. |
| 159 | 159 | ||
| 160 | config IMA_ARCH_POLICY | ||
| 161 | bool "Enable loading an IMA architecture specific policy" | ||
| 162 | depends on KEXEC_VERIFY_SIG || IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS | ||
| 163 | default n | ||
| 164 | help | ||
| 165 | This option enables loading an IMA architecture specific policy | ||
| 166 | based on run time secure boot flags. | ||
| 167 | |||
| 160 | config IMA_APPRAISE_BUILD_POLICY | 168 | config IMA_APPRAISE_BUILD_POLICY |
| 161 | bool "IMA build time configured policy rules" | 169 | bool "IMA build time configured policy rules" |
| 162 | depends on IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS | 170 | depends on IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS |
| @@ -217,7 +225,7 @@ config IMA_APPRAISE_REQUIRE_POLICY_SIGS | |||
| 217 | 225 | ||
| 218 | config IMA_APPRAISE_BOOTPARAM | 226 | config IMA_APPRAISE_BOOTPARAM |
| 219 | bool "ima_appraise boot parameter" | 227 | bool "ima_appraise boot parameter" |
| 220 | depends on IMA_APPRAISE | 228 | depends on IMA_APPRAISE && !IMA_ARCH_POLICY |
| 221 | default y | 229 | default y |
| 222 | help | 230 | help |
| 223 | This option enables the different "ima_appraise=" modes | 231 | This option enables the different "ima_appraise=" modes |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 67dfbd1af3ca..c7505fb122d4 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
| @@ -335,7 +335,7 @@ void ima_audit_measurement(struct integrity_iint_cache *iint, | |||
| 335 | audit_log_untrustedstring(ab, filename); | 335 | audit_log_untrustedstring(ab, filename); |
| 336 | audit_log_format(ab, " hash=\"%s:%s\"", algo_name, hash); | 336 | audit_log_format(ab, " hash=\"%s:%s\"", algo_name, hash); |
| 337 | 337 | ||
| 338 | audit_log_task_info(ab, current); | 338 | audit_log_task_info(ab); |
| 339 | audit_log_end(ab); | 339 | audit_log_end(ab); |
| 340 | 340 | ||
| 341 | iint->flags |= IMA_AUDITED; | 341 | iint->flags |= IMA_AUDITED; |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 2e11e750a067..a2baa85ea2f5 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
| @@ -289,12 +289,22 @@ int ima_appraise_measurement(enum ima_hooks func, | |||
| 289 | case EVM_IMA_XATTR_DIGSIG: | 289 | case EVM_IMA_XATTR_DIGSIG: |
| 290 | set_bit(IMA_DIGSIG, &iint->atomic_flags); | 290 | set_bit(IMA_DIGSIG, &iint->atomic_flags); |
| 291 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, | 291 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, |
| 292 | (const char *)xattr_value, rc, | 292 | (const char *)xattr_value, |
| 293 | xattr_len, | ||
| 293 | iint->ima_hash->digest, | 294 | iint->ima_hash->digest, |
| 294 | iint->ima_hash->length); | 295 | iint->ima_hash->length); |
| 295 | if (rc == -EOPNOTSUPP) { | 296 | if (rc == -EOPNOTSUPP) { |
| 296 | status = INTEGRITY_UNKNOWN; | 297 | status = INTEGRITY_UNKNOWN; |
| 297 | } else if (rc) { | 298 | break; |
| 299 | } | ||
| 300 | if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc && | ||
| 301 | func == KEXEC_KERNEL_CHECK) | ||
| 302 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM, | ||
| 303 | (const char *)xattr_value, | ||
| 304 | xattr_len, | ||
| 305 | iint->ima_hash->digest, | ||
| 306 | iint->ima_hash->length); | ||
| 307 | if (rc) { | ||
| 298 | cause = "invalid-signature"; | 308 | cause = "invalid-signature"; |
| 299 | status = INTEGRITY_FAIL; | 309 | status = INTEGRITY_FAIL; |
| 300 | } else { | 310 | } else { |
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 16bd18747cfa..d6f32807b347 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c | |||
| @@ -106,7 +106,7 @@ void ima_add_kexec_buffer(struct kimage *image) | |||
| 106 | kexec_segment_size = ALIGN(ima_get_binary_runtime_size() + | 106 | kexec_segment_size = ALIGN(ima_get_binary_runtime_size() + |
| 107 | PAGE_SIZE / 2, PAGE_SIZE); | 107 | PAGE_SIZE / 2, PAGE_SIZE); |
| 108 | if ((kexec_segment_size == ULONG_MAX) || | 108 | if ((kexec_segment_size == ULONG_MAX) || |
| 109 | ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages / 2)) { | 109 | ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { |
| 110 | pr_err("Binary measurement list too large.\n"); | 110 | pr_err("Binary measurement list too large.\n"); |
| 111 | return; | 111 | return; |
| 112 | } | 112 | } |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index adaf96932237..4ffac4f5c647 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 23 | 23 | ||
| 24 | #include <linux/init.h> | 24 | #include <linux/module.h> |
| 25 | #include <linux/file.h> | 25 | #include <linux/file.h> |
| 26 | #include <linux/binfmts.h> | 26 | #include <linux/binfmts.h> |
| 27 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
| @@ -105,7 +105,7 @@ static void ima_rdwr_violation_check(struct file *file, | |||
| 105 | } else { | 105 | } else { |
| 106 | if (must_measure) | 106 | if (must_measure) |
| 107 | set_bit(IMA_MUST_MEASURE, &iint->atomic_flags); | 107 | set_bit(IMA_MUST_MEASURE, &iint->atomic_flags); |
| 108 | if ((atomic_read(&inode->i_writecount) > 0) && must_measure) | 108 | if (inode_is_open_for_write(inode) && must_measure) |
| 109 | send_writers = true; | 109 | send_writers = true; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| @@ -507,20 +507,26 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, | |||
| 507 | */ | 507 | */ |
| 508 | int ima_load_data(enum kernel_load_data_id id) | 508 | int ima_load_data(enum kernel_load_data_id id) |
| 509 | { | 509 | { |
| 510 | bool sig_enforce; | 510 | bool ima_enforce, sig_enforce; |
| 511 | 511 | ||
| 512 | if ((ima_appraise & IMA_APPRAISE_ENFORCE) != IMA_APPRAISE_ENFORCE) | 512 | ima_enforce = |
| 513 | return 0; | 513 | (ima_appraise & IMA_APPRAISE_ENFORCE) == IMA_APPRAISE_ENFORCE; |
| 514 | 514 | ||
| 515 | switch (id) { | 515 | switch (id) { |
| 516 | case LOADING_KEXEC_IMAGE: | 516 | case LOADING_KEXEC_IMAGE: |
| 517 | if (ima_appraise & IMA_APPRAISE_KEXEC) { | 517 | if (IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG) |
| 518 | && arch_ima_get_secureboot()) { | ||
| 519 | pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); | ||
| 520 | return -EACCES; | ||
| 521 | } | ||
| 522 | |||
| 523 | if (ima_enforce && (ima_appraise & IMA_APPRAISE_KEXEC)) { | ||
| 518 | pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); | 524 | pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); |
| 519 | return -EACCES; /* INTEGRITY_UNKNOWN */ | 525 | return -EACCES; /* INTEGRITY_UNKNOWN */ |
| 520 | } | 526 | } |
| 521 | break; | 527 | break; |
| 522 | case LOADING_FIRMWARE: | 528 | case LOADING_FIRMWARE: |
| 523 | if (ima_appraise & IMA_APPRAISE_FIRMWARE) { | 529 | if (ima_enforce && (ima_appraise & IMA_APPRAISE_FIRMWARE)) { |
| 524 | pr_err("Prevent firmware sysfs fallback loading.\n"); | 530 | pr_err("Prevent firmware sysfs fallback loading.\n"); |
| 525 | return -EACCES; /* INTEGRITY_UNKNOWN */ | 531 | return -EACCES; /* INTEGRITY_UNKNOWN */ |
| 526 | } | 532 | } |
| @@ -528,7 +534,8 @@ int ima_load_data(enum kernel_load_data_id id) | |||
| 528 | case LOADING_MODULE: | 534 | case LOADING_MODULE: |
| 529 | sig_enforce = is_module_sig_enforced(); | 535 | sig_enforce = is_module_sig_enforced(); |
| 530 | 536 | ||
| 531 | if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES)) { | 537 | if (ima_enforce && (!sig_enforce |
| 538 | && (ima_appraise & IMA_APPRAISE_MODULES))) { | ||
| 532 | pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n"); | 539 | pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n"); |
| 533 | return -EACCES; /* INTEGRITY_UNKNOWN */ | 540 | return -EACCES; /* INTEGRITY_UNKNOWN */ |
| 534 | } | 541 | } |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 3778dc396193..8bc8a1c8cb3f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/rculist.h> | 20 | #include <linux/rculist.h> |
| 21 | #include <linux/genhd.h> | 21 | #include <linux/genhd.h> |
| 22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
| 23 | #include <linux/ima.h> | ||
| 23 | 24 | ||
| 24 | #include "ima.h" | 25 | #include "ima.h" |
| 25 | 26 | ||
| @@ -58,6 +59,8 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | |||
| 58 | 59 | ||
| 59 | enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; | 60 | enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; |
| 60 | 61 | ||
| 62 | enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY }; | ||
| 63 | |||
| 61 | struct ima_rule_entry { | 64 | struct ima_rule_entry { |
| 62 | struct list_head list; | 65 | struct list_head list; |
| 63 | int action; | 66 | int action; |
| @@ -104,7 +107,8 @@ static struct ima_rule_entry dont_measure_rules[] __ro_after_init = { | |||
| 104 | .flags = IMA_FSMAGIC}, | 107 | .flags = IMA_FSMAGIC}, |
| 105 | {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC, | 108 | {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC, |
| 106 | .flags = IMA_FSMAGIC}, | 109 | .flags = IMA_FSMAGIC}, |
| 107 | {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC} | 110 | {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, |
| 111 | {.action = DONT_MEASURE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC} | ||
| 108 | }; | 112 | }; |
| 109 | 113 | ||
| 110 | static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { | 114 | static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { |
| @@ -147,6 +151,7 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { | |||
| 147 | {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, | 151 | {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, |
| 148 | {.action = DONT_APPRAISE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, | 152 | {.action = DONT_APPRAISE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, |
| 149 | {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, | 153 | {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, |
| 154 | {.action = DONT_APPRAISE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC}, | ||
| 150 | {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, | 155 | {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
| 151 | {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC}, | 156 | {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
| 152 | #ifdef CONFIG_IMA_WRITE_POLICY | 157 | #ifdef CONFIG_IMA_WRITE_POLICY |
| @@ -193,6 +198,9 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { | |||
| 193 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | 198 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, |
| 194 | }; | 199 | }; |
| 195 | 200 | ||
| 201 | /* An array of architecture specific rules */ | ||
| 202 | struct ima_rule_entry *arch_policy_entry __ro_after_init; | ||
| 203 | |||
| 196 | static LIST_HEAD(ima_default_rules); | 204 | static LIST_HEAD(ima_default_rules); |
| 197 | static LIST_HEAD(ima_policy_rules); | 205 | static LIST_HEAD(ima_policy_rules); |
| 198 | static LIST_HEAD(ima_temp_rules); | 206 | static LIST_HEAD(ima_temp_rules); |
| @@ -473,6 +481,75 @@ static int ima_appraise_flag(enum ima_hooks func) | |||
| 473 | return 0; | 481 | return 0; |
| 474 | } | 482 | } |
| 475 | 483 | ||
| 484 | static void add_rules(struct ima_rule_entry *entries, int count, | ||
| 485 | enum policy_rule_list policy_rule) | ||
| 486 | { | ||
| 487 | int i = 0; | ||
| 488 | |||
| 489 | for (i = 0; i < count; i++) { | ||
| 490 | struct ima_rule_entry *entry; | ||
| 491 | |||
| 492 | if (policy_rule & IMA_DEFAULT_POLICY) | ||
| 493 | list_add_tail(&entries[i].list, &ima_default_rules); | ||
| 494 | |||
| 495 | if (policy_rule & IMA_CUSTOM_POLICY) { | ||
| 496 | entry = kmemdup(&entries[i], sizeof(*entry), | ||
| 497 | GFP_KERNEL); | ||
| 498 | if (!entry) | ||
| 499 | continue; | ||
| 500 | |||
| 501 | list_add_tail(&entry->list, &ima_policy_rules); | ||
| 502 | } | ||
| 503 | if (entries[i].action == APPRAISE) | ||
| 504 | temp_ima_appraise |= ima_appraise_flag(entries[i].func); | ||
| 505 | if (entries[i].func == POLICY_CHECK) | ||
| 506 | temp_ima_appraise |= IMA_APPRAISE_POLICY; | ||
| 507 | } | ||
| 508 | } | ||
| 509 | |||
| 510 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry); | ||
| 511 | |||
| 512 | static int __init ima_init_arch_policy(void) | ||
| 513 | { | ||
| 514 | const char * const *arch_rules; | ||
| 515 | const char * const *rules; | ||
| 516 | int arch_entries = 0; | ||
| 517 | int i = 0; | ||
| 518 | |||
| 519 | arch_rules = arch_get_ima_policy(); | ||
| 520 | if (!arch_rules) | ||
| 521 | return arch_entries; | ||
| 522 | |||
| 523 | /* Get number of rules */ | ||
| 524 | for (rules = arch_rules; *rules != NULL; rules++) | ||
| 525 | arch_entries++; | ||
| 526 | |||
| 527 | arch_policy_entry = kcalloc(arch_entries + 1, | ||
| 528 | sizeof(*arch_policy_entry), GFP_KERNEL); | ||
| 529 | if (!arch_policy_entry) | ||
| 530 | return 0; | ||
| 531 | |||
| 532 | /* Convert each policy string rules to struct ima_rule_entry format */ | ||
| 533 | for (rules = arch_rules, i = 0; *rules != NULL; rules++) { | ||
| 534 | char rule[255]; | ||
| 535 | int result; | ||
| 536 | |||
| 537 | result = strlcpy(rule, *rules, sizeof(rule)); | ||
| 538 | |||
| 539 | INIT_LIST_HEAD(&arch_policy_entry[i].list); | ||
| 540 | result = ima_parse_rule(rule, &arch_policy_entry[i]); | ||
| 541 | if (result) { | ||
| 542 | pr_warn("Skipping unknown architecture policy rule: %s\n", | ||
| 543 | rule); | ||
| 544 | memset(&arch_policy_entry[i], 0, | ||
| 545 | sizeof(*arch_policy_entry)); | ||
| 546 | continue; | ||
| 547 | } | ||
| 548 | i++; | ||
| 549 | } | ||
| 550 | return i; | ||
| 551 | } | ||
| 552 | |||
| 476 | /** | 553 | /** |
| 477 | * ima_init_policy - initialize the default measure rules. | 554 | * ima_init_policy - initialize the default measure rules. |
| 478 | * | 555 | * |
| @@ -481,68 +558,68 @@ static int ima_appraise_flag(enum ima_hooks func) | |||
| 481 | */ | 558 | */ |
| 482 | void __init ima_init_policy(void) | 559 | void __init ima_init_policy(void) |
| 483 | { | 560 | { |
| 484 | int i, measure_entries, appraise_entries, secure_boot_entries; | 561 | int build_appraise_entries, arch_entries; |
| 485 | 562 | ||
| 486 | /* if !ima_policy set entries = 0 so we load NO default rules */ | 563 | /* if !ima_policy, we load NO default rules */ |
| 487 | measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0; | 564 | if (ima_policy) |
| 488 | appraise_entries = ima_use_appraise_tcb ? | 565 | add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules), |
| 489 | ARRAY_SIZE(default_appraise_rules) : 0; | 566 | IMA_DEFAULT_POLICY); |
| 490 | secure_boot_entries = ima_use_secure_boot ? | ||
| 491 | ARRAY_SIZE(secure_boot_rules) : 0; | ||
| 492 | |||
| 493 | for (i = 0; i < measure_entries; i++) | ||
| 494 | list_add_tail(&dont_measure_rules[i].list, &ima_default_rules); | ||
| 495 | 567 | ||
| 496 | switch (ima_policy) { | 568 | switch (ima_policy) { |
| 497 | case ORIGINAL_TCB: | 569 | case ORIGINAL_TCB: |
| 498 | for (i = 0; i < ARRAY_SIZE(original_measurement_rules); i++) | 570 | add_rules(original_measurement_rules, |
| 499 | list_add_tail(&original_measurement_rules[i].list, | 571 | ARRAY_SIZE(original_measurement_rules), |
| 500 | &ima_default_rules); | 572 | IMA_DEFAULT_POLICY); |
| 501 | break; | 573 | break; |
| 502 | case DEFAULT_TCB: | 574 | case DEFAULT_TCB: |
| 503 | for (i = 0; i < ARRAY_SIZE(default_measurement_rules); i++) | 575 | add_rules(default_measurement_rules, |
| 504 | list_add_tail(&default_measurement_rules[i].list, | 576 | ARRAY_SIZE(default_measurement_rules), |
| 505 | &ima_default_rules); | 577 | IMA_DEFAULT_POLICY); |
| 506 | default: | 578 | default: |
| 507 | break; | 579 | break; |
| 508 | } | 580 | } |
| 509 | 581 | ||
| 510 | /* | 582 | /* |
| 583 | * Based on runtime secure boot flags, insert arch specific measurement | ||
| 584 | * and appraise rules requiring file signatures for both the initial | ||
| 585 | * and custom policies, prior to other appraise rules. | ||
| 586 | * (Highest priority) | ||
| 587 | */ | ||
| 588 | arch_entries = ima_init_arch_policy(); | ||
| 589 | if (!arch_entries) | ||
| 590 | pr_info("No architecture policies found\n"); | ||
| 591 | else | ||
| 592 | add_rules(arch_policy_entry, arch_entries, | ||
| 593 | IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); | ||
| 594 | |||
| 595 | /* | ||
| 511 | * Insert the builtin "secure_boot" policy rules requiring file | 596 | * Insert the builtin "secure_boot" policy rules requiring file |
| 512 | * signatures, prior to any other appraise rules. | 597 | * signatures, prior to other appraise rules. |
| 513 | */ | 598 | */ |
| 514 | for (i = 0; i < secure_boot_entries; i++) { | 599 | if (ima_use_secure_boot) |
| 515 | list_add_tail(&secure_boot_rules[i].list, &ima_default_rules); | 600 | add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules), |
| 516 | temp_ima_appraise |= | 601 | IMA_DEFAULT_POLICY); |
| 517 | ima_appraise_flag(secure_boot_rules[i].func); | ||
| 518 | } | ||
| 519 | 602 | ||
| 520 | /* | 603 | /* |
| 521 | * Insert the build time appraise rules requiring file signatures | 604 | * Insert the build time appraise rules requiring file signatures |
| 522 | * for both the initial and custom policies, prior to other appraise | 605 | * for both the initial and custom policies, prior to other appraise |
| 523 | * rules. | 606 | * rules. As the secure boot rules includes all of the build time |
| 607 | * rules, include either one or the other set of rules, but not both. | ||
| 524 | */ | 608 | */ |
| 525 | for (i = 0; i < ARRAY_SIZE(build_appraise_rules); i++) { | 609 | build_appraise_entries = ARRAY_SIZE(build_appraise_rules); |
| 526 | struct ima_rule_entry *entry; | 610 | if (build_appraise_entries) { |
| 527 | 611 | if (ima_use_secure_boot) | |
| 528 | if (!secure_boot_entries) | 612 | add_rules(build_appraise_rules, build_appraise_entries, |
| 529 | list_add_tail(&build_appraise_rules[i].list, | 613 | IMA_CUSTOM_POLICY); |
| 530 | &ima_default_rules); | 614 | else |
| 531 | 615 | add_rules(build_appraise_rules, build_appraise_entries, | |
| 532 | entry = kmemdup(&build_appraise_rules[i], sizeof(*entry), | 616 | IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); |
| 533 | GFP_KERNEL); | ||
| 534 | if (entry) | ||
| 535 | list_add_tail(&entry->list, &ima_policy_rules); | ||
| 536 | build_ima_appraise |= | ||
| 537 | ima_appraise_flag(build_appraise_rules[i].func); | ||
| 538 | } | 617 | } |
| 539 | 618 | ||
| 540 | for (i = 0; i < appraise_entries; i++) { | 619 | if (ima_use_appraise_tcb) |
| 541 | list_add_tail(&default_appraise_rules[i].list, | 620 | add_rules(default_appraise_rules, |
| 542 | &ima_default_rules); | 621 | ARRAY_SIZE(default_appraise_rules), |
| 543 | if (default_appraise_rules[i].func == POLICY_CHECK) | 622 | IMA_DEFAULT_POLICY); |
| 544 | temp_ima_appraise |= IMA_APPRAISE_POLICY; | ||
| 545 | } | ||
| 546 | 623 | ||
| 547 | ima_rules = &ima_default_rules; | 624 | ima_rules = &ima_default_rules; |
| 548 | ima_update_policy_flag(); | 625 | ima_update_policy_flag(); |
| @@ -576,13 +653,21 @@ void ima_update_policy(void) | |||
| 576 | if (ima_rules != policy) { | 653 | if (ima_rules != policy) { |
| 577 | ima_policy_flag = 0; | 654 | ima_policy_flag = 0; |
| 578 | ima_rules = policy; | 655 | ima_rules = policy; |
| 656 | |||
| 657 | /* | ||
| 658 | * IMA architecture specific policy rules are specified | ||
| 659 | * as strings and converted to an array of ima_entry_rules | ||
| 660 | * on boot. After loading a custom policy, free the | ||
| 661 | * architecture specific rules stored as an array. | ||
| 662 | */ | ||
| 663 | kfree(arch_policy_entry); | ||
| 579 | } | 664 | } |
| 580 | ima_update_policy_flag(); | 665 | ima_update_policy_flag(); |
| 581 | } | 666 | } |
| 582 | 667 | ||
| 668 | /* Keep the enumeration in sync with the policy_tokens! */ | ||
| 583 | enum { | 669 | enum { |
| 584 | Opt_err = -1, | 670 | Opt_measure, Opt_dont_measure, |
| 585 | Opt_measure = 1, Opt_dont_measure, | ||
| 586 | Opt_appraise, Opt_dont_appraise, | 671 | Opt_appraise, Opt_dont_appraise, |
| 587 | Opt_audit, Opt_hash, Opt_dont_hash, | 672 | Opt_audit, Opt_hash, Opt_dont_hash, |
| 588 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | 673 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
| @@ -592,10 +677,10 @@ enum { | |||
| 592 | Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, | 677 | Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, |
| 593 | Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, | 678 | Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, |
| 594 | Opt_appraise_type, Opt_permit_directio, | 679 | Opt_appraise_type, Opt_permit_directio, |
| 595 | Opt_pcr | 680 | Opt_pcr, Opt_err |
| 596 | }; | 681 | }; |
| 597 | 682 | ||
| 598 | static match_table_t policy_tokens = { | 683 | static const match_table_t policy_tokens = { |
| 599 | {Opt_measure, "measure"}, | 684 | {Opt_measure, "measure"}, |
| 600 | {Opt_dont_measure, "dont_measure"}, | 685 | {Opt_dont_measure, "dont_measure"}, |
| 601 | {Opt_appraise, "appraise"}, | 686 | {Opt_appraise, "appraise"}, |
| @@ -1103,7 +1188,7 @@ void ima_policy_stop(struct seq_file *m, void *v) | |||
| 1103 | { | 1188 | { |
| 1104 | } | 1189 | } |
| 1105 | 1190 | ||
| 1106 | #define pt(token) policy_tokens[token + Opt_err].pattern | 1191 | #define pt(token) policy_tokens[token].pattern |
| 1107 | #define mt(token) mask_tokens[token] | 1192 | #define mt(token) mask_tokens[token] |
| 1108 | 1193 | ||
| 1109 | /* | 1194 | /* |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index e60473b13a8d..7de59f44cba3 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
| @@ -141,7 +141,7 @@ int integrity_kernel_read(struct file *file, loff_t offset, | |||
| 141 | 141 | ||
| 142 | #define INTEGRITY_KEYRING_EVM 0 | 142 | #define INTEGRITY_KEYRING_EVM 0 |
| 143 | #define INTEGRITY_KEYRING_IMA 1 | 143 | #define INTEGRITY_KEYRING_IMA 1 |
| 144 | #define INTEGRITY_KEYRING_MODULE 2 | 144 | #define INTEGRITY_KEYRING_PLATFORM 2 |
| 145 | #define INTEGRITY_KEYRING_MAX 3 | 145 | #define INTEGRITY_KEYRING_MAX 3 |
| 146 | 146 | ||
| 147 | extern struct dentry *integrity_dir; | 147 | extern struct dentry *integrity_dir; |
| @@ -153,6 +153,8 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | |||
| 153 | 153 | ||
| 154 | int __init integrity_init_keyring(const unsigned int id); | 154 | int __init integrity_init_keyring(const unsigned int id); |
| 155 | int __init integrity_load_x509(const unsigned int id, const char *path); | 155 | int __init integrity_load_x509(const unsigned int id, const char *path); |
| 156 | int __init integrity_load_cert(const unsigned int id, const char *source, | ||
| 157 | const void *data, size_t len, key_perm_t perm); | ||
| 156 | #else | 158 | #else |
| 157 | 159 | ||
| 158 | static inline int integrity_digsig_verify(const unsigned int id, | 160 | static inline int integrity_digsig_verify(const unsigned int id, |
| @@ -166,6 +168,14 @@ static inline int integrity_init_keyring(const unsigned int id) | |||
| 166 | { | 168 | { |
| 167 | return 0; | 169 | return 0; |
| 168 | } | 170 | } |
| 171 | |||
| 172 | static inline int __init integrity_load_cert(const unsigned int id, | ||
| 173 | const char *source, | ||
| 174 | const void *data, size_t len, | ||
| 175 | key_perm_t perm) | ||
| 176 | { | ||
| 177 | return 0; | ||
| 178 | } | ||
| 169 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ | 179 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ |
| 170 | 180 | ||
| 171 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS | 181 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS |
| @@ -222,3 +232,13 @@ integrity_audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type) | |||
| 222 | } | 232 | } |
| 223 | 233 | ||
| 224 | #endif | 234 | #endif |
| 235 | |||
| 236 | #ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING | ||
| 237 | void __init add_to_platform_keyring(const char *source, const void *data, | ||
| 238 | size_t len); | ||
| 239 | #else | ||
| 240 | static inline void __init add_to_platform_keyring(const char *source, | ||
| 241 | const void *data, size_t len) | ||
| 242 | { | ||
| 243 | } | ||
| 244 | #endif | ||
diff --git a/security/integrity/platform_certs/efi_parser.c b/security/integrity/platform_certs/efi_parser.c new file mode 100644 index 000000000000..18f01f36fe6a --- /dev/null +++ b/security/integrity/platform_certs/efi_parser.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* EFI signature/key/certificate list parser | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved. | ||
| 5 | * Written by David Howells (dhowells@redhat.com) | ||
| 6 | */ | ||
| 7 | |||
| 8 | #define pr_fmt(fmt) "EFI: "fmt | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/printk.h> | ||
| 11 | #include <linux/err.h> | ||
| 12 | #include <linux/efi.h> | ||
| 13 | |||
| 14 | /** | ||
| 15 | * parse_efi_signature_list - Parse an EFI signature list for certificates | ||
| 16 | * @source: The source of the key | ||
| 17 | * @data: The data blob to parse | ||
| 18 | * @size: The size of the data blob | ||
| 19 | * @get_handler_for_guid: Get the handler func for the sig type (or NULL) | ||
| 20 | * | ||
| 21 | * Parse an EFI signature list looking for elements of interest. A list is | ||
| 22 | * made up of a series of sublists, where all the elements in a sublist are of | ||
| 23 | * the same type, but sublists can be of different types. | ||
| 24 | * | ||
| 25 | * For each sublist encountered, the @get_handler_for_guid function is called | ||
| 26 | * with the type specifier GUID and returns either a pointer to a function to | ||
| 27 | * handle elements of that type or NULL if the type is not of interest. | ||
| 28 | * | ||
| 29 | * If the sublist is of interest, each element is passed to the handler | ||
| 30 | * function in turn. | ||
| 31 | * | ||
| 32 | * Error EBADMSG is returned if the list doesn't parse correctly and 0 is | ||
| 33 | * returned if the list was parsed correctly. No error can be returned from | ||
| 34 | * the @get_handler_for_guid function or the element handler function it | ||
| 35 | * returns. | ||
| 36 | */ | ||
| 37 | int __init parse_efi_signature_list( | ||
| 38 | const char *source, | ||
| 39 | const void *data, size_t size, | ||
| 40 | efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *)) | ||
| 41 | { | ||
| 42 | efi_element_handler_t handler; | ||
| 43 | unsigned int offs = 0; | ||
| 44 | |||
| 45 | pr_devel("-->%s(,%zu)\n", __func__, size); | ||
| 46 | |||
| 47 | while (size > 0) { | ||
| 48 | const efi_signature_data_t *elem; | ||
| 49 | efi_signature_list_t list; | ||
| 50 | size_t lsize, esize, hsize, elsize; | ||
| 51 | |||
| 52 | if (size < sizeof(list)) | ||
| 53 | return -EBADMSG; | ||
| 54 | |||
| 55 | memcpy(&list, data, sizeof(list)); | ||
| 56 | pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n", | ||
| 57 | offs, | ||
| 58 | list.signature_type.b, list.signature_list_size, | ||
| 59 | list.signature_header_size, list.signature_size); | ||
| 60 | |||
| 61 | lsize = list.signature_list_size; | ||
| 62 | hsize = list.signature_header_size; | ||
| 63 | esize = list.signature_size; | ||
| 64 | elsize = lsize - sizeof(list) - hsize; | ||
| 65 | |||
| 66 | if (lsize > size) { | ||
| 67 | pr_devel("<--%s() = -EBADMSG [overrun @%x]\n", | ||
| 68 | __func__, offs); | ||
| 69 | return -EBADMSG; | ||
| 70 | } | ||
| 71 | |||
| 72 | if (lsize < sizeof(list) || | ||
| 73 | lsize - sizeof(list) < hsize || | ||
| 74 | esize < sizeof(*elem) || | ||
| 75 | elsize < esize || | ||
| 76 | elsize % esize != 0) { | ||
| 77 | pr_devel("- bad size combo @%x\n", offs); | ||
| 78 | return -EBADMSG; | ||
| 79 | } | ||
| 80 | |||
| 81 | handler = get_handler_for_guid(&list.signature_type); | ||
| 82 | if (!handler) { | ||
| 83 | data += lsize; | ||
| 84 | size -= lsize; | ||
| 85 | offs += lsize; | ||
| 86 | continue; | ||
| 87 | } | ||
| 88 | |||
| 89 | data += sizeof(list) + hsize; | ||
| 90 | size -= sizeof(list) + hsize; | ||
| 91 | offs += sizeof(list) + hsize; | ||
| 92 | |||
| 93 | for (; elsize > 0; elsize -= esize) { | ||
| 94 | elem = data; | ||
| 95 | |||
| 96 | pr_devel("ELEM[%04x]\n", offs); | ||
| 97 | handler(source, | ||
| 98 | &elem->signature_data, | ||
| 99 | esize - sizeof(*elem)); | ||
| 100 | |||
| 101 | data += esize; | ||
| 102 | size -= esize; | ||
| 103 | offs += esize; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c new file mode 100644 index 000000000000..81b19c52832b --- /dev/null +++ b/security/integrity/platform_certs/load_uefi.c | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | #include <linux/kernel.h> | ||
| 4 | #include <linux/sched.h> | ||
| 5 | #include <linux/cred.h> | ||
| 6 | #include <linux/err.h> | ||
| 7 | #include <linux/efi.h> | ||
| 8 | #include <linux/slab.h> | ||
| 9 | #include <keys/asymmetric-type.h> | ||
| 10 | #include <keys/system_keyring.h> | ||
| 11 | #include "../integrity.h" | ||
| 12 | |||
| 13 | static efi_guid_t efi_cert_x509_guid __initdata = EFI_CERT_X509_GUID; | ||
| 14 | static efi_guid_t efi_cert_x509_sha256_guid __initdata = | ||
| 15 | EFI_CERT_X509_SHA256_GUID; | ||
| 16 | static efi_guid_t efi_cert_sha256_guid __initdata = EFI_CERT_SHA256_GUID; | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Look to see if a UEFI variable called MokIgnoreDB exists and return true if | ||
| 20 | * it does. | ||
| 21 | * | ||
| 22 | * This UEFI variable is set by the shim if a user tells the shim to not use | ||
| 23 | * the certs/hashes in the UEFI db variable for verification purposes. If it | ||
| 24 | * is set, we should ignore the db variable also and the true return indicates | ||
| 25 | * this. | ||
| 26 | */ | ||
| 27 | static __init bool uefi_check_ignore_db(void) | ||
| 28 | { | ||
| 29 | efi_status_t status; | ||
| 30 | unsigned int db = 0; | ||
| 31 | unsigned long size = sizeof(db); | ||
| 32 | efi_guid_t guid = EFI_SHIM_LOCK_GUID; | ||
| 33 | |||
| 34 | status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db); | ||
| 35 | return status == EFI_SUCCESS; | ||
| 36 | } | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Get a certificate list blob from the named EFI variable. | ||
| 40 | */ | ||
| 41 | static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, | ||
| 42 | unsigned long *size) | ||
| 43 | { | ||
| 44 | efi_status_t status; | ||
| 45 | unsigned long lsize = 4; | ||
| 46 | unsigned long tmpdb[4]; | ||
| 47 | void *db; | ||
| 48 | |||
| 49 | status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb); | ||
| 50 | if (status != EFI_BUFFER_TOO_SMALL) { | ||
| 51 | pr_err("Couldn't get size: 0x%lx\n", status); | ||
| 52 | return NULL; | ||
| 53 | } | ||
| 54 | |||
| 55 | db = kmalloc(lsize, GFP_KERNEL); | ||
| 56 | if (!db) | ||
| 57 | return NULL; | ||
| 58 | |||
| 59 | status = efi.get_variable(name, guid, NULL, &lsize, db); | ||
| 60 | if (status != EFI_SUCCESS) { | ||
| 61 | kfree(db); | ||
| 62 | pr_err("Error reading db var: 0x%lx\n", status); | ||
| 63 | return NULL; | ||
| 64 | } | ||
| 65 | |||
| 66 | *size = lsize; | ||
| 67 | return db; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Blacklist a hash. | ||
| 72 | */ | ||
| 73 | static __init void uefi_blacklist_hash(const char *source, const void *data, | ||
| 74 | size_t len, const char *type, | ||
| 75 | size_t type_len) | ||
| 76 | { | ||
| 77 | char *hash, *p; | ||
| 78 | |||
| 79 | hash = kmalloc(type_len + len * 2 + 1, GFP_KERNEL); | ||
| 80 | if (!hash) | ||
| 81 | return; | ||
| 82 | p = memcpy(hash, type, type_len); | ||
| 83 | p += type_len; | ||
| 84 | bin2hex(p, data, len); | ||
| 85 | p += len * 2; | ||
| 86 | *p = 0; | ||
| 87 | |||
| 88 | mark_hash_blacklisted(hash); | ||
| 89 | kfree(hash); | ||
| 90 | } | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Blacklist an X509 TBS hash. | ||
| 94 | */ | ||
| 95 | static __init void uefi_blacklist_x509_tbs(const char *source, | ||
| 96 | const void *data, size_t len) | ||
| 97 | { | ||
| 98 | uefi_blacklist_hash(source, data, len, "tbs:", 4); | ||
| 99 | } | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Blacklist the hash of an executable. | ||
| 103 | */ | ||
| 104 | static __init void uefi_blacklist_binary(const char *source, | ||
| 105 | const void *data, size_t len) | ||
| 106 | { | ||
| 107 | uefi_blacklist_hash(source, data, len, "bin:", 4); | ||
| 108 | } | ||
| 109 | |||
| 110 | /* | ||
| 111 | * Return the appropriate handler for particular signature list types found in | ||
| 112 | * the UEFI db and MokListRT tables. | ||
| 113 | */ | ||
| 114 | static __init efi_element_handler_t get_handler_for_db(const efi_guid_t * | ||
| 115 | sig_type) | ||
| 116 | { | ||
| 117 | if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) | ||
| 118 | return add_to_platform_keyring; | ||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* | ||
| 123 | * Return the appropriate handler for particular signature list types found in | ||
| 124 | * the UEFI dbx and MokListXRT tables. | ||
| 125 | */ | ||
| 126 | static __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t * | ||
| 127 | sig_type) | ||
| 128 | { | ||
| 129 | if (efi_guidcmp(*sig_type, efi_cert_x509_sha256_guid) == 0) | ||
| 130 | return uefi_blacklist_x509_tbs; | ||
| 131 | if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0) | ||
| 132 | return uefi_blacklist_binary; | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Load the certs contained in the UEFI databases into the platform trusted | ||
| 138 | * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist | ||
| 139 | * keyring. | ||
| 140 | */ | ||
| 141 | static int __init load_uefi_certs(void) | ||
| 142 | { | ||
| 143 | efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID; | ||
| 144 | efi_guid_t mok_var = EFI_SHIM_LOCK_GUID; | ||
| 145 | void *db = NULL, *dbx = NULL, *mok = NULL; | ||
| 146 | unsigned long dbsize = 0, dbxsize = 0, moksize = 0; | ||
| 147 | int rc = 0; | ||
| 148 | |||
| 149 | if (!efi.get_variable) | ||
| 150 | return false; | ||
| 151 | |||
| 152 | /* Get db, MokListRT, and dbx. They might not exist, so it isn't | ||
| 153 | * an error if we can't get them. | ||
| 154 | */ | ||
| 155 | if (!uefi_check_ignore_db()) { | ||
| 156 | db = get_cert_list(L"db", &secure_var, &dbsize); | ||
| 157 | if (!db) { | ||
| 158 | pr_err("MODSIGN: Couldn't get UEFI db list\n"); | ||
| 159 | } else { | ||
| 160 | rc = parse_efi_signature_list("UEFI:db", | ||
| 161 | db, dbsize, get_handler_for_db); | ||
| 162 | if (rc) | ||
| 163 | pr_err("Couldn't parse db signatures: %d\n", | ||
| 164 | rc); | ||
| 165 | kfree(db); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | mok = get_cert_list(L"MokListRT", &mok_var, &moksize); | ||
| 170 | if (!mok) { | ||
| 171 | pr_info("Couldn't get UEFI MokListRT\n"); | ||
| 172 | } else { | ||
| 173 | rc = parse_efi_signature_list("UEFI:MokListRT", | ||
| 174 | mok, moksize, get_handler_for_db); | ||
| 175 | if (rc) | ||
| 176 | pr_err("Couldn't parse MokListRT signatures: %d\n", rc); | ||
| 177 | kfree(mok); | ||
| 178 | } | ||
| 179 | |||
| 180 | dbx = get_cert_list(L"dbx", &secure_var, &dbxsize); | ||
| 181 | if (!dbx) { | ||
| 182 | pr_info("Couldn't get UEFI dbx list\n"); | ||
| 183 | } else { | ||
| 184 | rc = parse_efi_signature_list("UEFI:dbx", | ||
| 185 | dbx, dbxsize, | ||
| 186 | get_handler_for_dbx); | ||
| 187 | if (rc) | ||
| 188 | pr_err("Couldn't parse dbx signatures: %d\n", rc); | ||
| 189 | kfree(dbx); | ||
| 190 | } | ||
| 191 | |||
| 192 | return rc; | ||
| 193 | } | ||
| 194 | late_initcall(load_uefi_certs); | ||
diff --git a/security/integrity/platform_certs/platform_keyring.c b/security/integrity/platform_certs/platform_keyring.c new file mode 100644 index 000000000000..bcafd7387729 --- /dev/null +++ b/security/integrity/platform_certs/platform_keyring.c | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Platform keyring for firmware/platform keys | ||
| 4 | * | ||
| 5 | * Copyright IBM Corporation, 2018 | ||
| 6 | * Author(s): Nayna Jain <nayna@linux.ibm.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/export.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/sched.h> | ||
| 12 | #include <linux/cred.h> | ||
| 13 | #include <linux/err.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include "../integrity.h" | ||
| 16 | |||
| 17 | /** | ||
| 18 | * add_to_platform_keyring - Add to platform keyring without validation. | ||
| 19 | * @source: Source of key | ||
| 20 | * @data: The blob holding the key | ||
| 21 | * @len: The length of the data blob | ||
| 22 | * | ||
| 23 | * Add a key to the platform keyring without checking its trust chain. This | ||
| 24 | * is available only during kernel initialisation. | ||
| 25 | */ | ||
| 26 | void __init add_to_platform_keyring(const char *source, const void *data, | ||
| 27 | size_t len) | ||
| 28 | { | ||
| 29 | key_perm_t perm; | ||
| 30 | int rc; | ||
| 31 | |||
| 32 | perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW; | ||
| 33 | |||
| 34 | rc = integrity_load_cert(INTEGRITY_KEYRING_PLATFORM, source, data, len, | ||
| 35 | perm); | ||
| 36 | if (rc) | ||
| 37 | pr_info("Error adding keys to platform keyring %s\n", source); | ||
| 38 | } | ||
| 39 | |||
| 40 | /* | ||
| 41 | * Create the trusted keyrings. | ||
| 42 | */ | ||
| 43 | static __init int platform_keyring_init(void) | ||
| 44 | { | ||
| 45 | int rc; | ||
| 46 | |||
| 47 | rc = integrity_init_keyring(INTEGRITY_KEYRING_PLATFORM); | ||
| 48 | if (rc) | ||
| 49 | return rc; | ||
| 50 | |||
| 51 | pr_notice("Platform Keyring initialized\n"); | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Must be initialised before we try and load the keys into the keyring. | ||
| 57 | */ | ||
| 58 | device_initcall(platform_keyring_init); | ||
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index d92cbf9687c3..389a298274d3 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c | |||
| @@ -45,6 +45,7 @@ static const char hmac_alg[] = "hmac(sha256)"; | |||
| 45 | static const char blkcipher_alg[] = "cbc(aes)"; | 45 | static const char blkcipher_alg[] = "cbc(aes)"; |
| 46 | static const char key_format_default[] = "default"; | 46 | static const char key_format_default[] = "default"; |
| 47 | static const char key_format_ecryptfs[] = "ecryptfs"; | 47 | static const char key_format_ecryptfs[] = "ecryptfs"; |
| 48 | static const char key_format_enc32[] = "enc32"; | ||
| 48 | static unsigned int ivsize; | 49 | static unsigned int ivsize; |
| 49 | static int blksize; | 50 | static int blksize; |
| 50 | 51 | ||
| @@ -54,6 +55,7 @@ static int blksize; | |||
| 54 | #define HASH_SIZE SHA256_DIGEST_SIZE | 55 | #define HASH_SIZE SHA256_DIGEST_SIZE |
| 55 | #define MAX_DATA_SIZE 4096 | 56 | #define MAX_DATA_SIZE 4096 |
| 56 | #define MIN_DATA_SIZE 20 | 57 | #define MIN_DATA_SIZE 20 |
| 58 | #define KEY_ENC32_PAYLOAD_LEN 32 | ||
| 57 | 59 | ||
| 58 | static struct crypto_shash *hash_tfm; | 60 | static struct crypto_shash *hash_tfm; |
| 59 | 61 | ||
| @@ -62,12 +64,13 @@ enum { | |||
| 62 | }; | 64 | }; |
| 63 | 65 | ||
| 64 | enum { | 66 | enum { |
| 65 | Opt_error = -1, Opt_default, Opt_ecryptfs | 67 | Opt_error = -1, Opt_default, Opt_ecryptfs, Opt_enc32 |
| 66 | }; | 68 | }; |
| 67 | 69 | ||
| 68 | static const match_table_t key_format_tokens = { | 70 | static const match_table_t key_format_tokens = { |
| 69 | {Opt_default, "default"}, | 71 | {Opt_default, "default"}, |
| 70 | {Opt_ecryptfs, "ecryptfs"}, | 72 | {Opt_ecryptfs, "ecryptfs"}, |
| 73 | {Opt_enc32, "enc32"}, | ||
| 71 | {Opt_error, NULL} | 74 | {Opt_error, NULL} |
| 72 | }; | 75 | }; |
| 73 | 76 | ||
| @@ -195,6 +198,7 @@ static int datablob_parse(char *datablob, const char **format, | |||
| 195 | key_format = match_token(p, key_format_tokens, args); | 198 | key_format = match_token(p, key_format_tokens, args); |
| 196 | switch (key_format) { | 199 | switch (key_format) { |
| 197 | case Opt_ecryptfs: | 200 | case Opt_ecryptfs: |
| 201 | case Opt_enc32: | ||
| 198 | case Opt_default: | 202 | case Opt_default: |
| 199 | *format = p; | 203 | *format = p; |
| 200 | *master_desc = strsep(&datablob, " \t"); | 204 | *master_desc = strsep(&datablob, " \t"); |
| @@ -342,7 +346,7 @@ static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen, | |||
| 342 | struct crypto_shash *tfm; | 346 | struct crypto_shash *tfm; |
| 343 | int err; | 347 | int err; |
| 344 | 348 | ||
| 345 | tfm = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); | 349 | tfm = crypto_alloc_shash(hmac_alg, 0, 0); |
| 346 | if (IS_ERR(tfm)) { | 350 | if (IS_ERR(tfm)) { |
| 347 | pr_err("encrypted_key: can't alloc %s transform: %ld\n", | 351 | pr_err("encrypted_key: can't alloc %s transform: %ld\n", |
| 348 | hmac_alg, PTR_ERR(tfm)); | 352 | hmac_alg, PTR_ERR(tfm)); |
| @@ -625,15 +629,22 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, | |||
| 625 | format_len = (!format) ? strlen(key_format_default) : strlen(format); | 629 | format_len = (!format) ? strlen(key_format_default) : strlen(format); |
| 626 | decrypted_datalen = dlen; | 630 | decrypted_datalen = dlen; |
| 627 | payload_datalen = decrypted_datalen; | 631 | payload_datalen = decrypted_datalen; |
| 628 | if (format && !strcmp(format, key_format_ecryptfs)) { | 632 | if (format) { |
| 629 | if (dlen != ECRYPTFS_MAX_KEY_BYTES) { | 633 | if (!strcmp(format, key_format_ecryptfs)) { |
| 630 | pr_err("encrypted_key: keylen for the ecryptfs format " | 634 | if (dlen != ECRYPTFS_MAX_KEY_BYTES) { |
| 631 | "must be equal to %d bytes\n", | 635 | pr_err("encrypted_key: keylen for the ecryptfs format must be equal to %d bytes\n", |
| 632 | ECRYPTFS_MAX_KEY_BYTES); | 636 | ECRYPTFS_MAX_KEY_BYTES); |
| 633 | return ERR_PTR(-EINVAL); | 637 | return ERR_PTR(-EINVAL); |
| 638 | } | ||
| 639 | decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES; | ||
| 640 | payload_datalen = sizeof(struct ecryptfs_auth_tok); | ||
| 641 | } else if (!strcmp(format, key_format_enc32)) { | ||
| 642 | if (decrypted_datalen != KEY_ENC32_PAYLOAD_LEN) { | ||
| 643 | pr_err("encrypted_key: enc32 key payload incorrect length: %d\n", | ||
| 644 | decrypted_datalen); | ||
| 645 | return ERR_PTR(-EINVAL); | ||
| 646 | } | ||
| 634 | } | 647 | } |
| 635 | decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES; | ||
| 636 | payload_datalen = sizeof(struct ecryptfs_auth_tok); | ||
| 637 | } | 648 | } |
| 638 | 649 | ||
| 639 | encrypted_datalen = roundup(decrypted_datalen, blksize); | 650 | encrypted_datalen = roundup(decrypted_datalen, blksize); |
| @@ -984,7 +995,7 @@ static int __init init_encrypted(void) | |||
| 984 | { | 995 | { |
| 985 | int ret; | 996 | int ret; |
| 986 | 997 | ||
| 987 | hash_tfm = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); | 998 | hash_tfm = crypto_alloc_shash(hash_alg, 0, 0); |
| 988 | if (IS_ERR(hash_tfm)) { | 999 | if (IS_ERR(hash_tfm)) { |
| 989 | pr_err("encrypted_key: can't allocate %s transform: %ld\n", | 1000 | pr_err("encrypted_key: can't allocate %s transform: %ld\n", |
| 990 | hash_alg, PTR_ERR(hash_tfm)); | 1001 | hash_alg, PTR_ERR(hash_tfm)); |
diff --git a/security/keys/internal.h b/security/keys/internal.h index 74cb0ff42fed..479909b858c7 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -158,8 +158,6 @@ extern struct key *request_key_and_link(struct key_type *type, | |||
| 158 | 158 | ||
| 159 | extern bool lookup_user_key_possessed(const struct key *key, | 159 | extern bool lookup_user_key_possessed(const struct key *key, |
| 160 | const struct key_match_data *match_data); | 160 | const struct key_match_data *match_data); |
| 161 | extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, | ||
| 162 | key_perm_t perm); | ||
| 163 | #define KEY_LOOKUP_CREATE 0x01 | 161 | #define KEY_LOOKUP_CREATE 0x01 |
| 164 | #define KEY_LOOKUP_PARTIAL 0x02 | 162 | #define KEY_LOOKUP_PARTIAL 0x02 |
| 165 | #define KEY_LOOKUP_FOR_UNLINK 0x04 | 163 | #define KEY_LOOKUP_FOR_UNLINK 0x04 |
diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c index 783978842f13..8bdea5abad11 100644 --- a/security/keys/keyctl_pkey.c +++ b/security/keys/keyctl_pkey.c | |||
| @@ -25,7 +25,7 @@ static void keyctl_pkey_params_free(struct kernel_pkey_params *params) | |||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | enum { | 27 | enum { |
| 28 | Opt_err = -1, | 28 | Opt_err, |
| 29 | Opt_enc, /* "enc=<encoding>" eg. "enc=oaep" */ | 29 | Opt_enc, /* "enc=<encoding>" eg. "enc=oaep" */ |
| 30 | Opt_hash, /* "hash=<digest-name>" eg. "hash=sha1" */ | 30 | Opt_hash, /* "hash=<digest-name>" eg. "hash=sha1" */ |
| 31 | }; | 31 | }; |
| @@ -50,6 +50,8 @@ static int keyctl_pkey_params_parse(struct kernel_pkey_params *params) | |||
| 50 | if (*p == '\0' || *p == ' ' || *p == '\t') | 50 | if (*p == '\0' || *p == ' ' || *p == '\t') |
| 51 | continue; | 51 | continue; |
| 52 | token = match_token(p, param_keys, args); | 52 | token = match_token(p, param_keys, args); |
| 53 | if (token == Opt_err) | ||
| 54 | return -EINVAL; | ||
| 53 | if (__test_and_set_bit(token, &token_mask)) | 55 | if (__test_and_set_bit(token, &token_mask)) |
| 54 | return -EINVAL; | 56 | return -EINVAL; |
| 55 | q = args[0].from; | 57 | q = args[0].from; |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 8b8994920620..02c77e928f68 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -754,6 +754,7 @@ reget_creds: | |||
| 754 | put_cred(ctx.cred); | 754 | put_cred(ctx.cred); |
| 755 | goto try_again; | 755 | goto try_again; |
| 756 | } | 756 | } |
| 757 | EXPORT_SYMBOL(lookup_user_key); | ||
| 757 | 758 | ||
| 758 | /* | 759 | /* |
| 759 | * Join the named keyring as the session keyring if possible else attempt to | 760 | * Join the named keyring as the session keyring if possible else attempt to |
diff --git a/security/keys/trusted.c b/security/keys/trusted.c index ff6789365a12..4d98f4f87236 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c | |||
| @@ -711,7 +711,7 @@ static int key_unseal(struct trusted_key_payload *p, | |||
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | enum { | 713 | enum { |
| 714 | Opt_err = -1, | 714 | Opt_err, |
| 715 | Opt_new, Opt_load, Opt_update, | 715 | Opt_new, Opt_load, Opt_update, |
| 716 | Opt_keyhandle, Opt_keyauth, Opt_blobauth, | 716 | Opt_keyhandle, Opt_keyauth, Opt_blobauth, |
| 717 | Opt_pcrinfo, Opt_pcrlock, Opt_migratable, | 717 | Opt_pcrinfo, Opt_pcrlock, Opt_migratable, |
| @@ -1199,14 +1199,14 @@ static int __init trusted_shash_alloc(void) | |||
| 1199 | { | 1199 | { |
| 1200 | int ret; | 1200 | int ret; |
| 1201 | 1201 | ||
| 1202 | hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); | 1202 | hmacalg = crypto_alloc_shash(hmac_alg, 0, 0); |
| 1203 | if (IS_ERR(hmacalg)) { | 1203 | if (IS_ERR(hmacalg)) { |
| 1204 | pr_info("trusted_key: could not allocate crypto %s\n", | 1204 | pr_info("trusted_key: could not allocate crypto %s\n", |
| 1205 | hmac_alg); | 1205 | hmac_alg); |
| 1206 | return PTR_ERR(hmacalg); | 1206 | return PTR_ERR(hmacalg); |
| 1207 | } | 1207 | } |
| 1208 | 1208 | ||
| 1209 | hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); | 1209 | hashalg = crypto_alloc_shash(hash_alg, 0, 0); |
| 1210 | if (IS_ERR(hashalg)) { | 1210 | if (IS_ERR(hashalg)) { |
| 1211 | pr_info("trusted_key: could not allocate crypto %s\n", | 1211 | pr_info("trusted_key: could not allocate crypto %s\n", |
| 1212 | hash_alg); | 1212 | hash_alg); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7ce683259357..0f27db6d94a9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -2934,7 +2934,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 2934 | return rc; | 2934 | return rc; |
| 2935 | 2935 | ||
| 2936 | /* Allow all mounts performed by the kernel */ | 2936 | /* Allow all mounts performed by the kernel */ |
| 2937 | if (flags & MS_KERNMOUNT) | 2937 | if (flags & (MS_KERNMOUNT | MS_SUBMOUNT)) |
| 2938 | return 0; | 2938 | return 0; |
| 2939 | 2939 | ||
| 2940 | ad.type = LSM_AUDIT_DATA_DENTRY; | 2940 | ad.type = LSM_AUDIT_DATA_DENTRY; |
| @@ -5318,6 +5318,9 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname, | |||
| 5318 | addr_buf = address; | 5318 | addr_buf = address; |
| 5319 | 5319 | ||
| 5320 | while (walk_size < addrlen) { | 5320 | while (walk_size < addrlen) { |
| 5321 | if (walk_size + sizeof(sa_family_t) > addrlen) | ||
| 5322 | return -EINVAL; | ||
| 5323 | |||
| 5321 | addr = addr_buf; | 5324 | addr = addr_buf; |
| 5322 | switch (addr->sa_family) { | 5325 | switch (addr->sa_family) { |
| 5323 | case AF_UNSPEC: | 5326 | case AF_UNSPEC: |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 23e762d529fa..ba8eedf42b90 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
| @@ -81,7 +81,7 @@ enum { | |||
| 81 | }; | 81 | }; |
| 82 | #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) | 82 | #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) |
| 83 | 83 | ||
| 84 | extern char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX]; | 84 | extern const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX]; |
| 85 | 85 | ||
| 86 | /* | 86 | /* |
| 87 | * type_datum properties | 87 | * type_datum properties |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 74b951f55608..9cec81209617 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -80,6 +80,9 @@ static const struct nlmsg_perm nlmsg_route_perms[] = | |||
| 80 | { RTM_NEWSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | 80 | { RTM_NEWSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
| 81 | { RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | 81 | { RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
| 82 | { RTM_NEWCACHEREPORT, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | 82 | { RTM_NEWCACHEREPORT, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
| 83 | { RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | ||
| 84 | { RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | ||
| 85 | { RTM_GETCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | ||
| 83 | }; | 86 | }; |
| 84 | 87 | ||
| 85 | static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = | 88 | static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = |
| @@ -158,7 +161,11 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) | |||
| 158 | 161 | ||
| 159 | switch (sclass) { | 162 | switch (sclass) { |
| 160 | case SECCLASS_NETLINK_ROUTE_SOCKET: | 163 | case SECCLASS_NETLINK_ROUTE_SOCKET: |
| 161 | /* RTM_MAX always point to RTM_SETxxxx, ie RTM_NEWxxx + 3 */ | 164 | /* RTM_MAX always points to RTM_SETxxxx, ie RTM_NEWxxx + 3. |
| 165 | * If the BUILD_BUG_ON() below fails you must update the | ||
| 166 | * structures at the top of this file with the new mappings | ||
| 167 | * before updating the BUILD_BUG_ON() macro! | ||
| 168 | */ | ||
| 162 | BUILD_BUG_ON(RTM_MAX != (RTM_NEWCHAIN + 3)); | 169 | BUILD_BUG_ON(RTM_MAX != (RTM_NEWCHAIN + 3)); |
| 163 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, | 170 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, |
| 164 | sizeof(nlmsg_route_perms)); | 171 | sizeof(nlmsg_route_perms)); |
| @@ -170,6 +177,10 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) | |||
| 170 | break; | 177 | break; |
| 171 | 178 | ||
| 172 | case SECCLASS_NETLINK_XFRM_SOCKET: | 179 | case SECCLASS_NETLINK_XFRM_SOCKET: |
| 180 | /* If the BUILD_BUG_ON() below fails you must update the | ||
| 181 | * structures at the top of this file with the new mappings | ||
| 182 | * before updating the BUILD_BUG_ON() macro! | ||
| 183 | */ | ||
| 173 | BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_MAPPING); | 184 | BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_MAPPING); |
| 174 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms, | 185 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms, |
| 175 | sizeof(nlmsg_xfrm_perms)); | 186 | sizeof(nlmsg_xfrm_perms)); |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 2fe459df3c85..5e05f5b902d7 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
| @@ -245,9 +245,13 @@ int mls_context_to_sid(struct policydb *pol, | |||
| 245 | char *rangep[2]; | 245 | char *rangep[2]; |
| 246 | 246 | ||
| 247 | if (!pol->mls_enabled) { | 247 | if (!pol->mls_enabled) { |
| 248 | if ((def_sid != SECSID_NULL && oldc) || (*scontext) == '\0') | 248 | /* |
| 249 | return 0; | 249 | * With no MLS, only return -EINVAL if there is a MLS field |
| 250 | return -EINVAL; | 250 | * and it did not come from an xattr. |
| 251 | */ | ||
| 252 | if (oldc && def_sid == SECSID_NULL) | ||
| 253 | return -EINVAL; | ||
| 254 | return 0; | ||
| 251 | } | 255 | } |
| 252 | 256 | ||
| 253 | /* | 257 | /* |
| @@ -436,16 +440,17 @@ int mls_setup_user_range(struct policydb *p, | |||
| 436 | 440 | ||
| 437 | /* | 441 | /* |
| 438 | * Convert the MLS fields in the security context | 442 | * Convert the MLS fields in the security context |
| 439 | * structure `c' from the values specified in the | 443 | * structure `oldc' from the values specified in the |
| 440 | * policy `oldp' to the values specified in the policy `newp'. | 444 | * policy `oldp' to the values specified in the policy `newp', |
| 445 | * storing the resulting context in `newc'. | ||
| 441 | */ | 446 | */ |
| 442 | int mls_convert_context(struct policydb *oldp, | 447 | int mls_convert_context(struct policydb *oldp, |
| 443 | struct policydb *newp, | 448 | struct policydb *newp, |
| 444 | struct context *c) | 449 | struct context *oldc, |
| 450 | struct context *newc) | ||
| 445 | { | 451 | { |
| 446 | struct level_datum *levdatum; | 452 | struct level_datum *levdatum; |
| 447 | struct cat_datum *catdatum; | 453 | struct cat_datum *catdatum; |
| 448 | struct ebitmap bitmap; | ||
| 449 | struct ebitmap_node *node; | 454 | struct ebitmap_node *node; |
| 450 | int l, i; | 455 | int l, i; |
| 451 | 456 | ||
| @@ -455,28 +460,25 @@ int mls_convert_context(struct policydb *oldp, | |||
| 455 | for (l = 0; l < 2; l++) { | 460 | for (l = 0; l < 2; l++) { |
| 456 | levdatum = hashtab_search(newp->p_levels.table, | 461 | levdatum = hashtab_search(newp->p_levels.table, |
| 457 | sym_name(oldp, SYM_LEVELS, | 462 | sym_name(oldp, SYM_LEVELS, |
| 458 | c->range.level[l].sens - 1)); | 463 | oldc->range.level[l].sens - 1)); |
| 459 | 464 | ||
| 460 | if (!levdatum) | 465 | if (!levdatum) |
| 461 | return -EINVAL; | 466 | return -EINVAL; |
| 462 | c->range.level[l].sens = levdatum->level->sens; | 467 | newc->range.level[l].sens = levdatum->level->sens; |
| 463 | 468 | ||
| 464 | ebitmap_init(&bitmap); | 469 | ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, |
| 465 | ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) { | 470 | node, i) { |
| 466 | int rc; | 471 | int rc; |
| 467 | 472 | ||
| 468 | catdatum = hashtab_search(newp->p_cats.table, | 473 | catdatum = hashtab_search(newp->p_cats.table, |
| 469 | sym_name(oldp, SYM_CATS, i)); | 474 | sym_name(oldp, SYM_CATS, i)); |
| 470 | if (!catdatum) | 475 | if (!catdatum) |
| 471 | return -EINVAL; | 476 | return -EINVAL; |
| 472 | rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); | 477 | rc = ebitmap_set_bit(&newc->range.level[l].cat, |
| 478 | catdatum->value - 1, 1); | ||
| 473 | if (rc) | 479 | if (rc) |
| 474 | return rc; | 480 | return rc; |
| 475 | |||
| 476 | cond_resched(); | ||
| 477 | } | 481 | } |
| 478 | ebitmap_destroy(&c->range.level[l].cat); | ||
| 479 | c->range.level[l].cat = bitmap; | ||
| 480 | } | 482 | } |
| 481 | 483 | ||
| 482 | return 0; | 484 | return 0; |
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 67093647576d..7954b1e60b64 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h | |||
| @@ -46,7 +46,8 @@ int mls_range_set(struct context *context, struct mls_range *range); | |||
| 46 | 46 | ||
| 47 | int mls_convert_context(struct policydb *oldp, | 47 | int mls_convert_context(struct policydb *oldp, |
| 48 | struct policydb *newp, | 48 | struct policydb *newp, |
| 49 | struct context *context); | 49 | struct context *oldc, |
| 50 | struct context *newc); | ||
| 50 | 51 | ||
| 51 | int mls_compute_sid(struct policydb *p, | 52 | int mls_compute_sid(struct policydb *p, |
| 52 | struct context *scontext, | 53 | struct context *scontext, |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f4eadd3f7350..a50d625e7946 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -909,13 +909,21 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s) | |||
| 909 | if (!c->context[0].user) { | 909 | if (!c->context[0].user) { |
| 910 | pr_err("SELinux: SID %s was never defined.\n", | 910 | pr_err("SELinux: SID %s was never defined.\n", |
| 911 | c->u.name); | 911 | c->u.name); |
| 912 | sidtab_destroy(s); | ||
| 913 | goto out; | ||
| 914 | } | ||
| 915 | if (c->sid[0] == SECSID_NULL || c->sid[0] > SECINITSID_NUM) { | ||
| 916 | pr_err("SELinux: Initial SID %s out of range.\n", | ||
| 917 | c->u.name); | ||
| 918 | sidtab_destroy(s); | ||
| 912 | goto out; | 919 | goto out; |
| 913 | } | 920 | } |
| 914 | 921 | ||
| 915 | rc = sidtab_insert(s, c->sid[0], &c->context[0]); | 922 | rc = sidtab_set_initial(s, c->sid[0], &c->context[0]); |
| 916 | if (rc) { | 923 | if (rc) { |
| 917 | pr_err("SELinux: unable to load initial SID %s.\n", | 924 | pr_err("SELinux: unable to load initial SID %s.\n", |
| 918 | c->u.name); | 925 | c->u.name); |
| 926 | sidtab_destroy(s); | ||
| 919 | goto out; | 927 | goto out; |
| 920 | } | 928 | } |
| 921 | } | 929 | } |
| @@ -2108,6 +2116,7 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
| 2108 | { | 2116 | { |
| 2109 | int i, j, rc; | 2117 | int i, j, rc; |
| 2110 | u32 nel, len; | 2118 | u32 nel, len; |
| 2119 | __be64 prefixbuf[1]; | ||
| 2111 | __le32 buf[3]; | 2120 | __le32 buf[3]; |
| 2112 | struct ocontext *l, *c; | 2121 | struct ocontext *l, *c; |
| 2113 | u32 nodebuf[8]; | 2122 | u32 nodebuf[8]; |
| @@ -2217,21 +2226,30 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
| 2217 | goto out; | 2226 | goto out; |
| 2218 | break; | 2227 | break; |
| 2219 | } | 2228 | } |
| 2220 | case OCON_IBPKEY: | 2229 | case OCON_IBPKEY: { |
| 2221 | rc = next_entry(nodebuf, fp, sizeof(u32) * 4); | 2230 | u32 pkey_lo, pkey_hi; |
| 2231 | |||
| 2232 | rc = next_entry(prefixbuf, fp, sizeof(u64)); | ||
| 2233 | if (rc) | ||
| 2234 | goto out; | ||
| 2235 | |||
| 2236 | /* we need to have subnet_prefix in CPU order */ | ||
| 2237 | c->u.ibpkey.subnet_prefix = be64_to_cpu(prefixbuf[0]); | ||
| 2238 | |||
| 2239 | rc = next_entry(buf, fp, sizeof(u32) * 2); | ||
| 2222 | if (rc) | 2240 | if (rc) |
| 2223 | goto out; | 2241 | goto out; |
| 2224 | 2242 | ||
| 2225 | c->u.ibpkey.subnet_prefix = be64_to_cpu(*((__be64 *)nodebuf)); | 2243 | pkey_lo = le32_to_cpu(buf[0]); |
| 2244 | pkey_hi = le32_to_cpu(buf[1]); | ||
| 2226 | 2245 | ||
| 2227 | if (nodebuf[2] > 0xffff || | 2246 | if (pkey_lo > U16_MAX || pkey_hi > U16_MAX) { |
| 2228 | nodebuf[3] > 0xffff) { | ||
| 2229 | rc = -EINVAL; | 2247 | rc = -EINVAL; |
| 2230 | goto out; | 2248 | goto out; |
| 2231 | } | 2249 | } |
| 2232 | 2250 | ||
| 2233 | c->u.ibpkey.low_pkey = le32_to_cpu(nodebuf[2]); | 2251 | c->u.ibpkey.low_pkey = pkey_lo; |
| 2234 | c->u.ibpkey.high_pkey = le32_to_cpu(nodebuf[3]); | 2252 | c->u.ibpkey.high_pkey = pkey_hi; |
| 2235 | 2253 | ||
| 2236 | rc = context_read_and_validate(&c->context[0], | 2254 | rc = context_read_and_validate(&c->context[0], |
| 2237 | p, | 2255 | p, |
| @@ -2239,7 +2257,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
| 2239 | if (rc) | 2257 | if (rc) |
| 2240 | goto out; | 2258 | goto out; |
| 2241 | break; | 2259 | break; |
| 2242 | case OCON_IBENDPORT: | 2260 | } |
| 2261 | case OCON_IBENDPORT: { | ||
| 2262 | u32 port; | ||
| 2263 | |||
| 2243 | rc = next_entry(buf, fp, sizeof(u32) * 2); | 2264 | rc = next_entry(buf, fp, sizeof(u32) * 2); |
| 2244 | if (rc) | 2265 | if (rc) |
| 2245 | goto out; | 2266 | goto out; |
| @@ -2249,12 +2270,13 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
| 2249 | if (rc) | 2270 | if (rc) |
| 2250 | goto out; | 2271 | goto out; |
| 2251 | 2272 | ||
| 2252 | if (buf[1] > 0xff || buf[1] == 0) { | 2273 | port = le32_to_cpu(buf[1]); |
| 2274 | if (port > U8_MAX || port == 0) { | ||
| 2253 | rc = -EINVAL; | 2275 | rc = -EINVAL; |
| 2254 | goto out; | 2276 | goto out; |
| 2255 | } | 2277 | } |
| 2256 | 2278 | ||
| 2257 | c->u.ibendport.port = le32_to_cpu(buf[1]); | 2279 | c->u.ibendport.port = port; |
| 2258 | 2280 | ||
| 2259 | rc = context_read_and_validate(&c->context[0], | 2281 | rc = context_read_and_validate(&c->context[0], |
| 2260 | p, | 2282 | p, |
| @@ -2262,7 +2284,8 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
| 2262 | if (rc) | 2284 | if (rc) |
| 2263 | goto out; | 2285 | goto out; |
| 2264 | break; | 2286 | break; |
| 2265 | } | 2287 | } /* end case */ |
| 2288 | } /* end switch */ | ||
| 2266 | } | 2289 | } |
| 2267 | } | 2290 | } |
| 2268 | rc = 0; | 2291 | rc = 0; |
| @@ -3105,6 +3128,7 @@ static int ocontext_write(struct policydb *p, struct policydb_compat_info *info, | |||
| 3105 | { | 3128 | { |
| 3106 | unsigned int i, j, rc; | 3129 | unsigned int i, j, rc; |
| 3107 | size_t nel, len; | 3130 | size_t nel, len; |
| 3131 | __be64 prefixbuf[1]; | ||
| 3108 | __le32 buf[3]; | 3132 | __le32 buf[3]; |
| 3109 | u32 nodebuf[8]; | 3133 | u32 nodebuf[8]; |
| 3110 | struct ocontext *c; | 3134 | struct ocontext *c; |
| @@ -3192,12 +3216,17 @@ static int ocontext_write(struct policydb *p, struct policydb_compat_info *info, | |||
| 3192 | return rc; | 3216 | return rc; |
| 3193 | break; | 3217 | break; |
| 3194 | case OCON_IBPKEY: | 3218 | case OCON_IBPKEY: |
| 3195 | *((__be64 *)nodebuf) = cpu_to_be64(c->u.ibpkey.subnet_prefix); | 3219 | /* subnet_prefix is in CPU order */ |
| 3220 | prefixbuf[0] = cpu_to_be64(c->u.ibpkey.subnet_prefix); | ||
| 3196 | 3221 | ||
| 3197 | nodebuf[2] = cpu_to_le32(c->u.ibpkey.low_pkey); | 3222 | rc = put_entry(prefixbuf, sizeof(u64), 1, fp); |
| 3198 | nodebuf[3] = cpu_to_le32(c->u.ibpkey.high_pkey); | 3223 | if (rc) |
| 3224 | return rc; | ||
| 3199 | 3225 | ||
| 3200 | rc = put_entry(nodebuf, sizeof(u32), 4, fp); | 3226 | buf[0] = cpu_to_le32(c->u.ibpkey.low_pkey); |
| 3227 | buf[1] = cpu_to_le32(c->u.ibpkey.high_pkey); | ||
| 3228 | |||
| 3229 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
| 3201 | if (rc) | 3230 | if (rc) |
| 3202 | return rc; | 3231 | return rc; |
| 3203 | rc = context_write(p, &c->context[0], fp); | 3232 | rc = context_write(p, &c->context[0], fp); |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 12e414394530..dd44126c8d14 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -71,7 +71,7 @@ | |||
| 71 | #include "audit.h" | 71 | #include "audit.h" |
| 72 | 72 | ||
| 73 | /* Policy capability names */ | 73 | /* Policy capability names */ |
| 74 | char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { | 74 | const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { |
| 75 | "network_peer_controls", | 75 | "network_peer_controls", |
| 76 | "open_perms", | 76 | "open_perms", |
| 77 | "extended_socket_class", | 77 | "extended_socket_class", |
| @@ -776,7 +776,7 @@ static int security_compute_validatetrans(struct selinux_state *state, | |||
| 776 | read_lock(&state->ss->policy_rwlock); | 776 | read_lock(&state->ss->policy_rwlock); |
| 777 | 777 | ||
| 778 | policydb = &state->ss->policydb; | 778 | policydb = &state->ss->policydb; |
| 779 | sidtab = &state->ss->sidtab; | 779 | sidtab = state->ss->sidtab; |
| 780 | 780 | ||
| 781 | if (!user) | 781 | if (!user) |
| 782 | tclass = unmap_class(&state->ss->map, orig_tclass); | 782 | tclass = unmap_class(&state->ss->map, orig_tclass); |
| @@ -876,7 +876,7 @@ int security_bounded_transition(struct selinux_state *state, | |||
| 876 | read_lock(&state->ss->policy_rwlock); | 876 | read_lock(&state->ss->policy_rwlock); |
| 877 | 877 | ||
| 878 | policydb = &state->ss->policydb; | 878 | policydb = &state->ss->policydb; |
| 879 | sidtab = &state->ss->sidtab; | 879 | sidtab = state->ss->sidtab; |
| 880 | 880 | ||
| 881 | rc = -EINVAL; | 881 | rc = -EINVAL; |
| 882 | old_context = sidtab_search(sidtab, old_sid); | 882 | old_context = sidtab_search(sidtab, old_sid); |
| @@ -1034,7 +1034,7 @@ void security_compute_xperms_decision(struct selinux_state *state, | |||
| 1034 | goto allow; | 1034 | goto allow; |
| 1035 | 1035 | ||
| 1036 | policydb = &state->ss->policydb; | 1036 | policydb = &state->ss->policydb; |
| 1037 | sidtab = &state->ss->sidtab; | 1037 | sidtab = state->ss->sidtab; |
| 1038 | 1038 | ||
| 1039 | scontext = sidtab_search(sidtab, ssid); | 1039 | scontext = sidtab_search(sidtab, ssid); |
| 1040 | if (!scontext) { | 1040 | if (!scontext) { |
| @@ -1123,7 +1123,7 @@ void security_compute_av(struct selinux_state *state, | |||
| 1123 | goto allow; | 1123 | goto allow; |
| 1124 | 1124 | ||
| 1125 | policydb = &state->ss->policydb; | 1125 | policydb = &state->ss->policydb; |
| 1126 | sidtab = &state->ss->sidtab; | 1126 | sidtab = state->ss->sidtab; |
| 1127 | 1127 | ||
| 1128 | scontext = sidtab_search(sidtab, ssid); | 1128 | scontext = sidtab_search(sidtab, ssid); |
| 1129 | if (!scontext) { | 1129 | if (!scontext) { |
| @@ -1177,7 +1177,7 @@ void security_compute_av_user(struct selinux_state *state, | |||
| 1177 | goto allow; | 1177 | goto allow; |
| 1178 | 1178 | ||
| 1179 | policydb = &state->ss->policydb; | 1179 | policydb = &state->ss->policydb; |
| 1180 | sidtab = &state->ss->sidtab; | 1180 | sidtab = state->ss->sidtab; |
| 1181 | 1181 | ||
| 1182 | scontext = sidtab_search(sidtab, ssid); | 1182 | scontext = sidtab_search(sidtab, ssid); |
| 1183 | if (!scontext) { | 1183 | if (!scontext) { |
| @@ -1315,7 +1315,7 @@ static int security_sid_to_context_core(struct selinux_state *state, | |||
| 1315 | } | 1315 | } |
| 1316 | read_lock(&state->ss->policy_rwlock); | 1316 | read_lock(&state->ss->policy_rwlock); |
| 1317 | policydb = &state->ss->policydb; | 1317 | policydb = &state->ss->policydb; |
| 1318 | sidtab = &state->ss->sidtab; | 1318 | sidtab = state->ss->sidtab; |
| 1319 | if (force) | 1319 | if (force) |
| 1320 | context = sidtab_search_force(sidtab, sid); | 1320 | context = sidtab_search_force(sidtab, sid); |
| 1321 | else | 1321 | else |
| @@ -1483,7 +1483,7 @@ static int security_context_to_sid_core(struct selinux_state *state, | |||
| 1483 | } | 1483 | } |
| 1484 | read_lock(&state->ss->policy_rwlock); | 1484 | read_lock(&state->ss->policy_rwlock); |
| 1485 | policydb = &state->ss->policydb; | 1485 | policydb = &state->ss->policydb; |
| 1486 | sidtab = &state->ss->sidtab; | 1486 | sidtab = state->ss->sidtab; |
| 1487 | rc = string_to_context_struct(policydb, sidtab, scontext2, | 1487 | rc = string_to_context_struct(policydb, sidtab, scontext2, |
| 1488 | &context, def_sid); | 1488 | &context, def_sid); |
| 1489 | if (rc == -EINVAL && force) { | 1489 | if (rc == -EINVAL && force) { |
| @@ -1668,7 +1668,7 @@ static int security_compute_sid(struct selinux_state *state, | |||
| 1668 | } | 1668 | } |
| 1669 | 1669 | ||
| 1670 | policydb = &state->ss->policydb; | 1670 | policydb = &state->ss->policydb; |
| 1671 | sidtab = &state->ss->sidtab; | 1671 | sidtab = state->ss->sidtab; |
| 1672 | 1672 | ||
| 1673 | scontext = sidtab_search(sidtab, ssid); | 1673 | scontext = sidtab_search(sidtab, ssid); |
| 1674 | if (!scontext) { | 1674 | if (!scontext) { |
| @@ -1880,19 +1880,6 @@ int security_change_sid(struct selinux_state *state, | |||
| 1880 | out_sid, false); | 1880 | out_sid, false); |
| 1881 | } | 1881 | } |
| 1882 | 1882 | ||
| 1883 | /* Clone the SID into the new SID table. */ | ||
| 1884 | static int clone_sid(u32 sid, | ||
| 1885 | struct context *context, | ||
| 1886 | void *arg) | ||
| 1887 | { | ||
| 1888 | struct sidtab *s = arg; | ||
| 1889 | |||
| 1890 | if (sid > SECINITSID_NUM) | ||
| 1891 | return sidtab_insert(s, sid, context); | ||
| 1892 | else | ||
| 1893 | return 0; | ||
| 1894 | } | ||
| 1895 | |||
| 1896 | static inline int convert_context_handle_invalid_context( | 1883 | static inline int convert_context_handle_invalid_context( |
| 1897 | struct selinux_state *state, | 1884 | struct selinux_state *state, |
| 1898 | struct context *context) | 1885 | struct context *context) |
| @@ -1920,101 +1907,84 @@ struct convert_context_args { | |||
| 1920 | 1907 | ||
| 1921 | /* | 1908 | /* |
| 1922 | * Convert the values in the security context | 1909 | * Convert the values in the security context |
| 1923 | * structure `c' from the values specified | 1910 | * structure `oldc' from the values specified |
| 1924 | * in the policy `p->oldp' to the values specified | 1911 | * in the policy `p->oldp' to the values specified |
| 1925 | * in the policy `p->newp'. Verify that the | 1912 | * in the policy `p->newp', storing the new context |
| 1926 | * context is valid under the new policy. | 1913 | * in `newc'. Verify that the context is valid |
| 1914 | * under the new policy. | ||
| 1927 | */ | 1915 | */ |
| 1928 | static int convert_context(u32 key, | 1916 | static int convert_context(struct context *oldc, struct context *newc, void *p) |
| 1929 | struct context *c, | ||
| 1930 | void *p) | ||
| 1931 | { | 1917 | { |
| 1932 | struct convert_context_args *args; | 1918 | struct convert_context_args *args; |
| 1933 | struct context oldc; | ||
| 1934 | struct ocontext *oc; | 1919 | struct ocontext *oc; |
| 1935 | struct mls_range *range; | ||
| 1936 | struct role_datum *role; | 1920 | struct role_datum *role; |
| 1937 | struct type_datum *typdatum; | 1921 | struct type_datum *typdatum; |
| 1938 | struct user_datum *usrdatum; | 1922 | struct user_datum *usrdatum; |
| 1939 | char *s; | 1923 | char *s; |
| 1940 | u32 len; | 1924 | u32 len; |
| 1941 | int rc = 0; | 1925 | int rc; |
| 1942 | |||
| 1943 | if (key <= SECINITSID_NUM) | ||
| 1944 | goto out; | ||
| 1945 | 1926 | ||
| 1946 | args = p; | 1927 | args = p; |
| 1947 | 1928 | ||
| 1948 | if (c->str) { | 1929 | if (oldc->str) { |
| 1949 | struct context ctx; | 1930 | s = kstrdup(oldc->str, GFP_KERNEL); |
| 1950 | |||
| 1951 | rc = -ENOMEM; | ||
| 1952 | s = kstrdup(c->str, GFP_KERNEL); | ||
| 1953 | if (!s) | 1931 | if (!s) |
| 1954 | goto out; | 1932 | return -ENOMEM; |
| 1955 | 1933 | ||
| 1956 | rc = string_to_context_struct(args->newp, NULL, s, | 1934 | rc = string_to_context_struct(args->newp, NULL, s, |
| 1957 | &ctx, SECSID_NULL); | 1935 | newc, SECSID_NULL); |
| 1958 | kfree(s); | 1936 | if (rc == -EINVAL) { |
| 1959 | if (!rc) { | ||
| 1960 | pr_info("SELinux: Context %s became valid (mapped).\n", | ||
| 1961 | c->str); | ||
| 1962 | /* Replace string with mapped representation. */ | ||
| 1963 | kfree(c->str); | ||
| 1964 | memcpy(c, &ctx, sizeof(*c)); | ||
| 1965 | goto out; | ||
| 1966 | } else if (rc == -EINVAL) { | ||
| 1967 | /* Retain string representation for later mapping. */ | 1937 | /* Retain string representation for later mapping. */ |
| 1968 | rc = 0; | 1938 | context_init(newc); |
| 1969 | goto out; | 1939 | newc->str = s; |
| 1970 | } else { | 1940 | newc->len = oldc->len; |
| 1941 | return 0; | ||
| 1942 | } | ||
| 1943 | kfree(s); | ||
| 1944 | if (rc) { | ||
| 1971 | /* Other error condition, e.g. ENOMEM. */ | 1945 | /* Other error condition, e.g. ENOMEM. */ |
| 1972 | pr_err("SELinux: Unable to map context %s, rc = %d.\n", | 1946 | pr_err("SELinux: Unable to map context %s, rc = %d.\n", |
| 1973 | c->str, -rc); | 1947 | oldc->str, -rc); |
| 1974 | goto out; | 1948 | return rc; |
| 1975 | } | 1949 | } |
| 1950 | pr_info("SELinux: Context %s became valid (mapped).\n", | ||
| 1951 | oldc->str); | ||
| 1952 | return 0; | ||
| 1976 | } | 1953 | } |
| 1977 | 1954 | ||
| 1978 | rc = context_cpy(&oldc, c); | 1955 | context_init(newc); |
| 1979 | if (rc) | ||
| 1980 | goto out; | ||
| 1981 | 1956 | ||
| 1982 | /* Convert the user. */ | 1957 | /* Convert the user. */ |
| 1983 | rc = -EINVAL; | 1958 | rc = -EINVAL; |
| 1984 | usrdatum = hashtab_search(args->newp->p_users.table, | 1959 | usrdatum = hashtab_search(args->newp->p_users.table, |
| 1985 | sym_name(args->oldp, SYM_USERS, c->user - 1)); | 1960 | sym_name(args->oldp, |
| 1961 | SYM_USERS, oldc->user - 1)); | ||
| 1986 | if (!usrdatum) | 1962 | if (!usrdatum) |
| 1987 | goto bad; | 1963 | goto bad; |
| 1988 | c->user = usrdatum->value; | 1964 | newc->user = usrdatum->value; |
| 1989 | 1965 | ||
| 1990 | /* Convert the role. */ | 1966 | /* Convert the role. */ |
| 1991 | rc = -EINVAL; | 1967 | rc = -EINVAL; |
| 1992 | role = hashtab_search(args->newp->p_roles.table, | 1968 | role = hashtab_search(args->newp->p_roles.table, |
| 1993 | sym_name(args->oldp, SYM_ROLES, c->role - 1)); | 1969 | sym_name(args->oldp, SYM_ROLES, oldc->role - 1)); |
| 1994 | if (!role) | 1970 | if (!role) |
| 1995 | goto bad; | 1971 | goto bad; |
| 1996 | c->role = role->value; | 1972 | newc->role = role->value; |
| 1997 | 1973 | ||
| 1998 | /* Convert the type. */ | 1974 | /* Convert the type. */ |
| 1999 | rc = -EINVAL; | 1975 | rc = -EINVAL; |
| 2000 | typdatum = hashtab_search(args->newp->p_types.table, | 1976 | typdatum = hashtab_search(args->newp->p_types.table, |
| 2001 | sym_name(args->oldp, SYM_TYPES, c->type - 1)); | 1977 | sym_name(args->oldp, |
| 1978 | SYM_TYPES, oldc->type - 1)); | ||
| 2002 | if (!typdatum) | 1979 | if (!typdatum) |
| 2003 | goto bad; | 1980 | goto bad; |
| 2004 | c->type = typdatum->value; | 1981 | newc->type = typdatum->value; |
| 2005 | 1982 | ||
| 2006 | /* Convert the MLS fields if dealing with MLS policies */ | 1983 | /* Convert the MLS fields if dealing with MLS policies */ |
| 2007 | if (args->oldp->mls_enabled && args->newp->mls_enabled) { | 1984 | if (args->oldp->mls_enabled && args->newp->mls_enabled) { |
| 2008 | rc = mls_convert_context(args->oldp, args->newp, c); | 1985 | rc = mls_convert_context(args->oldp, args->newp, oldc, newc); |
| 2009 | if (rc) | 1986 | if (rc) |
| 2010 | goto bad; | 1987 | goto bad; |
| 2011 | } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { | ||
| 2012 | /* | ||
| 2013 | * Switching between MLS and non-MLS policy: | ||
| 2014 | * free any storage used by the MLS fields in the | ||
| 2015 | * context for all existing entries in the sidtab. | ||
| 2016 | */ | ||
| 2017 | mls_context_destroy(c); | ||
| 2018 | } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { | 1988 | } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { |
| 2019 | /* | 1989 | /* |
| 2020 | * Switching between non-MLS and MLS policy: | 1990 | * Switching between non-MLS and MLS policy: |
| @@ -2032,38 +2002,30 @@ static int convert_context(u32 key, | |||
| 2032 | " the initial SIDs list\n"); | 2002 | " the initial SIDs list\n"); |
| 2033 | goto bad; | 2003 | goto bad; |
| 2034 | } | 2004 | } |
| 2035 | range = &oc->context[0].range; | 2005 | rc = mls_range_set(newc, &oc->context[0].range); |
| 2036 | rc = mls_range_set(c, range); | ||
| 2037 | if (rc) | 2006 | if (rc) |
| 2038 | goto bad; | 2007 | goto bad; |
| 2039 | } | 2008 | } |
| 2040 | 2009 | ||
| 2041 | /* Check the validity of the new context. */ | 2010 | /* Check the validity of the new context. */ |
| 2042 | if (!policydb_context_isvalid(args->newp, c)) { | 2011 | if (!policydb_context_isvalid(args->newp, newc)) { |
| 2043 | rc = convert_context_handle_invalid_context(args->state, | 2012 | rc = convert_context_handle_invalid_context(args->state, oldc); |
| 2044 | &oldc); | ||
| 2045 | if (rc) | 2013 | if (rc) |
| 2046 | goto bad; | 2014 | goto bad; |
| 2047 | } | 2015 | } |
| 2048 | 2016 | ||
| 2049 | context_destroy(&oldc); | 2017 | return 0; |
| 2050 | |||
| 2051 | rc = 0; | ||
| 2052 | out: | ||
| 2053 | return rc; | ||
| 2054 | bad: | 2018 | bad: |
| 2055 | /* Map old representation to string and save it. */ | 2019 | /* Map old representation to string and save it. */ |
| 2056 | rc = context_struct_to_string(args->oldp, &oldc, &s, &len); | 2020 | rc = context_struct_to_string(args->oldp, oldc, &s, &len); |
| 2057 | if (rc) | 2021 | if (rc) |
| 2058 | return rc; | 2022 | return rc; |
| 2059 | context_destroy(&oldc); | 2023 | context_destroy(newc); |
| 2060 | context_destroy(c); | 2024 | newc->str = s; |
| 2061 | c->str = s; | 2025 | newc->len = len; |
| 2062 | c->len = len; | ||
| 2063 | pr_info("SELinux: Context %s became invalid (unmapped).\n", | 2026 | pr_info("SELinux: Context %s became invalid (unmapped).\n", |
| 2064 | c->str); | 2027 | newc->str); |
| 2065 | rc = 0; | 2028 | return 0; |
| 2066 | goto out; | ||
| 2067 | } | 2029 | } |
| 2068 | 2030 | ||
| 2069 | static void security_load_policycaps(struct selinux_state *state) | 2031 | static void security_load_policycaps(struct selinux_state *state) |
| @@ -2103,11 +2065,11 @@ static int security_preserve_bools(struct selinux_state *state, | |||
| 2103 | int security_load_policy(struct selinux_state *state, void *data, size_t len) | 2065 | int security_load_policy(struct selinux_state *state, void *data, size_t len) |
| 2104 | { | 2066 | { |
| 2105 | struct policydb *policydb; | 2067 | struct policydb *policydb; |
| 2106 | struct sidtab *sidtab; | 2068 | struct sidtab *oldsidtab, *newsidtab; |
| 2107 | struct policydb *oldpolicydb, *newpolicydb; | 2069 | struct policydb *oldpolicydb, *newpolicydb; |
| 2108 | struct sidtab oldsidtab, newsidtab; | ||
| 2109 | struct selinux_mapping *oldmapping; | 2070 | struct selinux_mapping *oldmapping; |
| 2110 | struct selinux_map newmap; | 2071 | struct selinux_map newmap; |
| 2072 | struct sidtab_convert_params convert_params; | ||
| 2111 | struct convert_context_args args; | 2073 | struct convert_context_args args; |
| 2112 | u32 seqno; | 2074 | u32 seqno; |
| 2113 | int rc = 0; | 2075 | int rc = 0; |
| @@ -2121,27 +2083,37 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) | |||
| 2121 | newpolicydb = oldpolicydb + 1; | 2083 | newpolicydb = oldpolicydb + 1; |
| 2122 | 2084 | ||
| 2123 | policydb = &state->ss->policydb; | 2085 | policydb = &state->ss->policydb; |
| 2124 | sidtab = &state->ss->sidtab; | 2086 | |
| 2087 | newsidtab = kmalloc(sizeof(*newsidtab), GFP_KERNEL); | ||
| 2088 | if (!newsidtab) { | ||
| 2089 | rc = -ENOMEM; | ||
| 2090 | goto out; | ||
| 2091 | } | ||
| 2125 | 2092 | ||
| 2126 | if (!state->initialized) { | 2093 | if (!state->initialized) { |
| 2127 | rc = policydb_read(policydb, fp); | 2094 | rc = policydb_read(policydb, fp); |
| 2128 | if (rc) | 2095 | if (rc) { |
| 2096 | kfree(newsidtab); | ||
| 2129 | goto out; | 2097 | goto out; |
| 2098 | } | ||
| 2130 | 2099 | ||
| 2131 | policydb->len = len; | 2100 | policydb->len = len; |
| 2132 | rc = selinux_set_mapping(policydb, secclass_map, | 2101 | rc = selinux_set_mapping(policydb, secclass_map, |
| 2133 | &state->ss->map); | 2102 | &state->ss->map); |
| 2134 | if (rc) { | 2103 | if (rc) { |
| 2104 | kfree(newsidtab); | ||
| 2135 | policydb_destroy(policydb); | 2105 | policydb_destroy(policydb); |
| 2136 | goto out; | 2106 | goto out; |
| 2137 | } | 2107 | } |
| 2138 | 2108 | ||
| 2139 | rc = policydb_load_isids(policydb, sidtab); | 2109 | rc = policydb_load_isids(policydb, newsidtab); |
| 2140 | if (rc) { | 2110 | if (rc) { |
| 2111 | kfree(newsidtab); | ||
| 2141 | policydb_destroy(policydb); | 2112 | policydb_destroy(policydb); |
| 2142 | goto out; | 2113 | goto out; |
| 2143 | } | 2114 | } |
| 2144 | 2115 | ||
| 2116 | state->ss->sidtab = newsidtab; | ||
| 2145 | security_load_policycaps(state); | 2117 | security_load_policycaps(state); |
| 2146 | state->initialized = 1; | 2118 | state->initialized = 1; |
| 2147 | seqno = ++state->ss->latest_granting; | 2119 | seqno = ++state->ss->latest_granting; |
| @@ -2154,13 +2126,11 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) | |||
| 2154 | goto out; | 2126 | goto out; |
| 2155 | } | 2127 | } |
| 2156 | 2128 | ||
| 2157 | #if 0 | ||
| 2158 | sidtab_hash_eval(sidtab, "sids"); | ||
| 2159 | #endif | ||
| 2160 | |||
| 2161 | rc = policydb_read(newpolicydb, fp); | 2129 | rc = policydb_read(newpolicydb, fp); |
| 2162 | if (rc) | 2130 | if (rc) { |
| 2131 | kfree(newsidtab); | ||
| 2163 | goto out; | 2132 | goto out; |
| 2133 | } | ||
| 2164 | 2134 | ||
| 2165 | newpolicydb->len = len; | 2135 | newpolicydb->len = len; |
| 2166 | /* If switching between different policy types, log MLS status */ | 2136 | /* If switching between different policy types, log MLS status */ |
| @@ -2169,10 +2139,11 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) | |||
| 2169 | else if (!policydb->mls_enabled && newpolicydb->mls_enabled) | 2139 | else if (!policydb->mls_enabled && newpolicydb->mls_enabled) |
| 2170 | pr_info("SELinux: Enabling MLS support...\n"); | 2140 | pr_info("SELinux: Enabling MLS support...\n"); |
| 2171 | 2141 | ||
| 2172 | rc = policydb_load_isids(newpolicydb, &newsidtab); | 2142 | rc = policydb_load_isids(newpolicydb, newsidtab); |
| 2173 | if (rc) { | 2143 | if (rc) { |
| 2174 | pr_err("SELinux: unable to load the initial SIDs\n"); | 2144 | pr_err("SELinux: unable to load the initial SIDs\n"); |
| 2175 | policydb_destroy(newpolicydb); | 2145 | policydb_destroy(newpolicydb); |
| 2146 | kfree(newsidtab); | ||
| 2176 | goto out; | 2147 | goto out; |
| 2177 | } | 2148 | } |
| 2178 | 2149 | ||
| @@ -2186,12 +2157,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) | |||
| 2186 | goto err; | 2157 | goto err; |
| 2187 | } | 2158 | } |
| 2188 | 2159 | ||
| 2189 | /* Clone the SID table. */ | 2160 | oldsidtab = state->ss->sidtab; |
| 2190 | sidtab_shutdown(sidtab); | ||
| 2191 | |||
| 2192 | rc = sidtab_map(sidtab, clone_sid, &newsidtab); | ||
| 2193 | if (rc) | ||
| 2194 | goto err; | ||
| 2195 | 2161 | ||
| 2196 | /* | 2162 | /* |
| 2197 | * Convert the internal representations of contexts | 2163 | * Convert the internal representations of contexts |
| @@ -2200,7 +2166,12 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) | |||
| 2200 | args.state = state; | 2166 | args.state = state; |
| 2201 | args.oldp = policydb; | 2167 | args.oldp = policydb; |
| 2202 | args.newp = newpolicydb; | 2168 | args.newp = newpolicydb; |
| 2203 | rc = sidtab_map(&newsidtab, convert_context, &args); | 2169 | |
| 2170 | convert_params.func = convert_context; | ||
| 2171 | convert_params.args = &args; | ||
| 2172 | convert_params.target = newsidtab; | ||
| 2173 | |||
| 2174 | rc = sidtab_convert(oldsidtab, &convert_params); | ||
| 2204 | if (rc) { | 2175 | if (rc) { |
| 2205 | pr_err("SELinux: unable to convert the internal" | 2176 | pr_err("SELinux: unable to convert the internal" |
| 2206 | " representation of contexts in the new SID" | 2177 | " representation of contexts in the new SID" |
| @@ -2210,12 +2181,11 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) | |||
| 2210 | 2181 | ||
| 2211 | /* Save the old policydb and SID table to free later. */ | 2182 | /* Save the old policydb and SID table to free later. */ |
| 2212 | memcpy(oldpolicydb, policydb, sizeof(*policydb)); | 2183 | memcpy(oldpolicydb, policydb, sizeof(*policydb)); |
| 2213 | sidtab_set(&oldsidtab, sidtab); | ||
| 2214 | 2184 | ||
| 2215 | /* Install the new policydb and SID table. */ | 2185 | /* Install the new policydb and SID table. */ |
| 2216 | write_lock_irq(&state->ss->policy_rwlock); | 2186 | write_lock_irq(&state->ss->policy_rwlock); |
| 2217 | memcpy(policydb, newpolicydb, sizeof(*policydb)); | 2187 | memcpy(policydb, newpolicydb, sizeof(*policydb)); |
| 2218 | sidtab_set(sidtab, &newsidtab); | 2188 | state->ss->sidtab = newsidtab; |
| 2219 | security_load_policycaps(state); | 2189 | security_load_policycaps(state); |
| 2220 | oldmapping = state->ss->map.mapping; | 2190 | oldmapping = state->ss->map.mapping; |
| 2221 | state->ss->map.mapping = newmap.mapping; | 2191 | state->ss->map.mapping = newmap.mapping; |
| @@ -2225,7 +2195,8 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) | |||
| 2225 | 2195 | ||
| 2226 | /* Free the old policydb and SID table. */ | 2196 | /* Free the old policydb and SID table. */ |
| 2227 | policydb_destroy(oldpolicydb); | 2197 | policydb_destroy(oldpolicydb); |
| 2228 | sidtab_destroy(&oldsidtab); | 2198 | sidtab_destroy(oldsidtab); |
| 2199 | kfree(oldsidtab); | ||
| 2229 | kfree(oldmapping); | 2200 | kfree(oldmapping); |
| 2230 | 2201 | ||
| 2231 | avc_ss_reset(state->avc, seqno); | 2202 | avc_ss_reset(state->avc, seqno); |
| @@ -2239,7 +2210,8 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) | |||
| 2239 | 2210 | ||
| 2240 | err: | 2211 | err: |
| 2241 | kfree(newmap.mapping); | 2212 | kfree(newmap.mapping); |
| 2242 | sidtab_destroy(&newsidtab); | 2213 | sidtab_destroy(newsidtab); |
| 2214 | kfree(newsidtab); | ||
| 2243 | policydb_destroy(newpolicydb); | 2215 | policydb_destroy(newpolicydb); |
| 2244 | 2216 | ||
| 2245 | out: | 2217 | out: |
| @@ -2276,7 +2248,7 @@ int security_port_sid(struct selinux_state *state, | |||
| 2276 | read_lock(&state->ss->policy_rwlock); | 2248 | read_lock(&state->ss->policy_rwlock); |
| 2277 | 2249 | ||
| 2278 | policydb = &state->ss->policydb; | 2250 | policydb = &state->ss->policydb; |
| 2279 | sidtab = &state->ss->sidtab; | 2251 | sidtab = state->ss->sidtab; |
| 2280 | 2252 | ||
| 2281 | c = policydb->ocontexts[OCON_PORT]; | 2253 | c = policydb->ocontexts[OCON_PORT]; |
| 2282 | while (c) { | 2254 | while (c) { |
| @@ -2322,7 +2294,7 @@ int security_ib_pkey_sid(struct selinux_state *state, | |||
| 2322 | read_lock(&state->ss->policy_rwlock); | 2294 | read_lock(&state->ss->policy_rwlock); |
| 2323 | 2295 | ||
| 2324 | policydb = &state->ss->policydb; | 2296 | policydb = &state->ss->policydb; |
| 2325 | sidtab = &state->ss->sidtab; | 2297 | sidtab = state->ss->sidtab; |
| 2326 | 2298 | ||
| 2327 | c = policydb->ocontexts[OCON_IBPKEY]; | 2299 | c = policydb->ocontexts[OCON_IBPKEY]; |
| 2328 | while (c) { | 2300 | while (c) { |
| @@ -2368,7 +2340,7 @@ int security_ib_endport_sid(struct selinux_state *state, | |||
| 2368 | read_lock(&state->ss->policy_rwlock); | 2340 | read_lock(&state->ss->policy_rwlock); |
| 2369 | 2341 | ||
| 2370 | policydb = &state->ss->policydb; | 2342 | policydb = &state->ss->policydb; |
| 2371 | sidtab = &state->ss->sidtab; | 2343 | sidtab = state->ss->sidtab; |
| 2372 | 2344 | ||
| 2373 | c = policydb->ocontexts[OCON_IBENDPORT]; | 2345 | c = policydb->ocontexts[OCON_IBENDPORT]; |
| 2374 | while (c) { | 2346 | while (c) { |
| @@ -2414,7 +2386,7 @@ int security_netif_sid(struct selinux_state *state, | |||
| 2414 | read_lock(&state->ss->policy_rwlock); | 2386 | read_lock(&state->ss->policy_rwlock); |
| 2415 | 2387 | ||
| 2416 | policydb = &state->ss->policydb; | 2388 | policydb = &state->ss->policydb; |
| 2417 | sidtab = &state->ss->sidtab; | 2389 | sidtab = state->ss->sidtab; |
| 2418 | 2390 | ||
| 2419 | c = policydb->ocontexts[OCON_NETIF]; | 2391 | c = policydb->ocontexts[OCON_NETIF]; |
| 2420 | while (c) { | 2392 | while (c) { |
| @@ -2479,7 +2451,7 @@ int security_node_sid(struct selinux_state *state, | |||
| 2479 | read_lock(&state->ss->policy_rwlock); | 2451 | read_lock(&state->ss->policy_rwlock); |
| 2480 | 2452 | ||
| 2481 | policydb = &state->ss->policydb; | 2453 | policydb = &state->ss->policydb; |
| 2482 | sidtab = &state->ss->sidtab; | 2454 | sidtab = state->ss->sidtab; |
| 2483 | 2455 | ||
| 2484 | switch (domain) { | 2456 | switch (domain) { |
| 2485 | case AF_INET: { | 2457 | case AF_INET: { |
| @@ -2579,7 +2551,7 @@ int security_get_user_sids(struct selinux_state *state, | |||
| 2579 | read_lock(&state->ss->policy_rwlock); | 2551 | read_lock(&state->ss->policy_rwlock); |
| 2580 | 2552 | ||
| 2581 | policydb = &state->ss->policydb; | 2553 | policydb = &state->ss->policydb; |
| 2582 | sidtab = &state->ss->sidtab; | 2554 | sidtab = state->ss->sidtab; |
| 2583 | 2555 | ||
| 2584 | context_init(&usercon); | 2556 | context_init(&usercon); |
| 2585 | 2557 | ||
| @@ -2681,7 +2653,7 @@ static inline int __security_genfs_sid(struct selinux_state *state, | |||
| 2681 | u32 *sid) | 2653 | u32 *sid) |
| 2682 | { | 2654 | { |
| 2683 | struct policydb *policydb = &state->ss->policydb; | 2655 | struct policydb *policydb = &state->ss->policydb; |
| 2684 | struct sidtab *sidtab = &state->ss->sidtab; | 2656 | struct sidtab *sidtab = state->ss->sidtab; |
| 2685 | int len; | 2657 | int len; |
| 2686 | u16 sclass; | 2658 | u16 sclass; |
| 2687 | struct genfs *genfs; | 2659 | struct genfs *genfs; |
| @@ -2767,7 +2739,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) | |||
| 2767 | read_lock(&state->ss->policy_rwlock); | 2739 | read_lock(&state->ss->policy_rwlock); |
| 2768 | 2740 | ||
| 2769 | policydb = &state->ss->policydb; | 2741 | policydb = &state->ss->policydb; |
| 2770 | sidtab = &state->ss->sidtab; | 2742 | sidtab = state->ss->sidtab; |
| 2771 | 2743 | ||
| 2772 | c = policydb->ocontexts[OCON_FSUSE]; | 2744 | c = policydb->ocontexts[OCON_FSUSE]; |
| 2773 | while (c) { | 2745 | while (c) { |
| @@ -2973,7 +2945,7 @@ int security_sid_mls_copy(struct selinux_state *state, | |||
| 2973 | u32 sid, u32 mls_sid, u32 *new_sid) | 2945 | u32 sid, u32 mls_sid, u32 *new_sid) |
| 2974 | { | 2946 | { |
| 2975 | struct policydb *policydb = &state->ss->policydb; | 2947 | struct policydb *policydb = &state->ss->policydb; |
| 2976 | struct sidtab *sidtab = &state->ss->sidtab; | 2948 | struct sidtab *sidtab = state->ss->sidtab; |
| 2977 | struct context *context1; | 2949 | struct context *context1; |
| 2978 | struct context *context2; | 2950 | struct context *context2; |
| 2979 | struct context newcon; | 2951 | struct context newcon; |
| @@ -3064,7 +3036,7 @@ int security_net_peersid_resolve(struct selinux_state *state, | |||
| 3064 | u32 *peer_sid) | 3036 | u32 *peer_sid) |
| 3065 | { | 3037 | { |
| 3066 | struct policydb *policydb = &state->ss->policydb; | 3038 | struct policydb *policydb = &state->ss->policydb; |
| 3067 | struct sidtab *sidtab = &state->ss->sidtab; | 3039 | struct sidtab *sidtab = state->ss->sidtab; |
| 3068 | int rc; | 3040 | int rc; |
| 3069 | struct context *nlbl_ctx; | 3041 | struct context *nlbl_ctx; |
| 3070 | struct context *xfrm_ctx; | 3042 | struct context *xfrm_ctx; |
| @@ -3425,7 +3397,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, | |||
| 3425 | goto out; | 3397 | goto out; |
| 3426 | } | 3398 | } |
| 3427 | 3399 | ||
| 3428 | ctxt = sidtab_search(&state->ss->sidtab, sid); | 3400 | ctxt = sidtab_search(state->ss->sidtab, sid); |
| 3429 | if (unlikely(!ctxt)) { | 3401 | if (unlikely(!ctxt)) { |
| 3430 | WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", | 3402 | WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", |
| 3431 | sid); | 3403 | sid); |
| @@ -3588,7 +3560,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state, | |||
| 3588 | u32 *sid) | 3560 | u32 *sid) |
| 3589 | { | 3561 | { |
| 3590 | struct policydb *policydb = &state->ss->policydb; | 3562 | struct policydb *policydb = &state->ss->policydb; |
| 3591 | struct sidtab *sidtab = &state->ss->sidtab; | 3563 | struct sidtab *sidtab = state->ss->sidtab; |
| 3592 | int rc; | 3564 | int rc; |
| 3593 | struct context *ctx; | 3565 | struct context *ctx; |
| 3594 | struct context ctx_new; | 3566 | struct context ctx_new; |
| @@ -3666,7 +3638,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state, | |||
| 3666 | read_lock(&state->ss->policy_rwlock); | 3638 | read_lock(&state->ss->policy_rwlock); |
| 3667 | 3639 | ||
| 3668 | rc = -ENOENT; | 3640 | rc = -ENOENT; |
| 3669 | ctx = sidtab_search(&state->ss->sidtab, sid); | 3641 | ctx = sidtab_search(state->ss->sidtab, sid); |
| 3670 | if (ctx == NULL) | 3642 | if (ctx == NULL) |
| 3671 | goto out; | 3643 | goto out; |
| 3672 | 3644 | ||
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index 24c7bdcc8075..9a36de860368 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h | |||
| @@ -24,7 +24,7 @@ struct selinux_map { | |||
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | struct selinux_ss { | 26 | struct selinux_ss { |
| 27 | struct sidtab sidtab; | 27 | struct sidtab *sidtab; |
| 28 | struct policydb policydb; | 28 | struct policydb policydb; |
| 29 | rwlock_t policy_rwlock; | 29 | rwlock_t policy_rwlock; |
| 30 | u32 latest_granting; | 30 | u32 latest_granting; |
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index fd75a12fa8fc..e63a90ff2728 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c | |||
| @@ -2,108 +2,164 @@ | |||
| 2 | /* | 2 | /* |
| 3 | * Implementation of the SID table type. | 3 | * Implementation of the SID table type. |
| 4 | * | 4 | * |
| 5 | * Author : Stephen Smalley, <sds@tycho.nsa.gov> | 5 | * Original author: Stephen Smalley, <sds@tycho.nsa.gov> |
| 6 | * Author: Ondrej Mosnacek, <omosnacek@gmail.com> | ||
| 7 | * | ||
| 8 | * Copyright (C) 2018 Red Hat, Inc. | ||
| 6 | */ | 9 | */ |
| 10 | #include <linux/errno.h> | ||
| 7 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 8 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
| 13 | #include <linux/sched.h> | ||
| 9 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
| 10 | #include <linux/errno.h> | 15 | #include <linux/atomic.h> |
| 11 | #include "flask.h" | 16 | #include "flask.h" |
| 12 | #include "security.h" | 17 | #include "security.h" |
| 13 | #include "sidtab.h" | 18 | #include "sidtab.h" |
| 14 | 19 | ||
| 15 | #define SIDTAB_HASH(sid) \ | ||
| 16 | (sid & SIDTAB_HASH_MASK) | ||
| 17 | |||
| 18 | int sidtab_init(struct sidtab *s) | 20 | int sidtab_init(struct sidtab *s) |
| 19 | { | 21 | { |
| 20 | int i; | 22 | u32 i; |
| 21 | 23 | ||
| 22 | s->htable = kmalloc_array(SIDTAB_SIZE, sizeof(*s->htable), GFP_ATOMIC); | 24 | memset(s->roots, 0, sizeof(s->roots)); |
| 23 | if (!s->htable) | 25 | |
| 24 | return -ENOMEM; | 26 | for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) |
| 25 | for (i = 0; i < SIDTAB_SIZE; i++) | 27 | atomic_set(&s->rcache[i], -1); |
| 26 | s->htable[i] = NULL; | 28 | |
| 27 | s->nel = 0; | 29 | for (i = 0; i < SECINITSID_NUM; i++) |
| 28 | s->next_sid = 1; | 30 | s->isids[i].set = 0; |
| 29 | s->shutdown = 0; | 31 | |
| 32 | atomic_set(&s->count, 0); | ||
| 33 | |||
| 34 | s->convert = NULL; | ||
| 35 | |||
| 30 | spin_lock_init(&s->lock); | 36 | spin_lock_init(&s->lock); |
| 31 | return 0; | 37 | return 0; |
| 32 | } | 38 | } |
| 33 | 39 | ||
| 34 | int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) | 40 | int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context) |
| 35 | { | 41 | { |
| 36 | int hvalue; | 42 | struct sidtab_isid_entry *entry; |
| 37 | struct sidtab_node *prev, *cur, *newnode; | 43 | int rc; |
| 38 | |||
| 39 | if (!s) | ||
| 40 | return -ENOMEM; | ||
| 41 | |||
| 42 | hvalue = SIDTAB_HASH(sid); | ||
| 43 | prev = NULL; | ||
| 44 | cur = s->htable[hvalue]; | ||
| 45 | while (cur && sid > cur->sid) { | ||
| 46 | prev = cur; | ||
| 47 | cur = cur->next; | ||
| 48 | } | ||
| 49 | 44 | ||
| 50 | if (cur && sid == cur->sid) | 45 | if (sid == 0 || sid > SECINITSID_NUM) |
| 51 | return -EEXIST; | 46 | return -EINVAL; |
| 52 | 47 | ||
| 53 | newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC); | 48 | entry = &s->isids[sid - 1]; |
| 54 | if (!newnode) | ||
| 55 | return -ENOMEM; | ||
| 56 | 49 | ||
| 57 | newnode->sid = sid; | 50 | rc = context_cpy(&entry->context, context); |
| 58 | if (context_cpy(&newnode->context, context)) { | 51 | if (rc) |
| 59 | kfree(newnode); | 52 | return rc; |
| 60 | return -ENOMEM; | ||
| 61 | } | ||
| 62 | 53 | ||
| 63 | if (prev) { | 54 | entry->set = 1; |
| 64 | newnode->next = prev->next; | 55 | return 0; |
| 65 | wmb(); | 56 | } |
| 66 | prev->next = newnode; | 57 | |
| 67 | } else { | 58 | static u32 sidtab_level_from_count(u32 count) |
| 68 | newnode->next = s->htable[hvalue]; | 59 | { |
| 69 | wmb(); | 60 | u32 capacity = SIDTAB_LEAF_ENTRIES; |
| 70 | s->htable[hvalue] = newnode; | 61 | u32 level = 0; |
| 62 | |||
| 63 | while (count > capacity) { | ||
| 64 | capacity <<= SIDTAB_INNER_SHIFT; | ||
| 65 | ++level; | ||
| 71 | } | 66 | } |
| 67 | return level; | ||
| 68 | } | ||
| 72 | 69 | ||
| 73 | s->nel++; | 70 | static int sidtab_alloc_roots(struct sidtab *s, u32 level) |
| 74 | if (sid >= s->next_sid) | 71 | { |
| 75 | s->next_sid = sid + 1; | 72 | u32 l; |
| 73 | |||
| 74 | if (!s->roots[0].ptr_leaf) { | ||
| 75 | s->roots[0].ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, | ||
| 76 | GFP_ATOMIC); | ||
| 77 | if (!s->roots[0].ptr_leaf) | ||
| 78 | return -ENOMEM; | ||
| 79 | } | ||
| 80 | for (l = 1; l <= level; ++l) | ||
| 81 | if (!s->roots[l].ptr_inner) { | ||
| 82 | s->roots[l].ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, | ||
| 83 | GFP_ATOMIC); | ||
| 84 | if (!s->roots[l].ptr_inner) | ||
| 85 | return -ENOMEM; | ||
| 86 | s->roots[l].ptr_inner->entries[0] = s->roots[l - 1]; | ||
| 87 | } | ||
| 76 | return 0; | 88 | return 0; |
| 77 | } | 89 | } |
| 78 | 90 | ||
| 79 | static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) | 91 | static struct context *sidtab_do_lookup(struct sidtab *s, u32 index, int alloc) |
| 80 | { | 92 | { |
| 81 | int hvalue; | 93 | union sidtab_entry_inner *entry; |
| 82 | struct sidtab_node *cur; | 94 | u32 level, capacity_shift, leaf_index = index / SIDTAB_LEAF_ENTRIES; |
| 95 | |||
| 96 | /* find the level of the subtree we need */ | ||
| 97 | level = sidtab_level_from_count(index + 1); | ||
| 98 | capacity_shift = level * SIDTAB_INNER_SHIFT; | ||
| 83 | 99 | ||
| 84 | if (!s) | 100 | /* allocate roots if needed */ |
| 101 | if (alloc && sidtab_alloc_roots(s, level) != 0) | ||
| 85 | return NULL; | 102 | return NULL; |
| 86 | 103 | ||
| 87 | hvalue = SIDTAB_HASH(sid); | 104 | /* lookup inside the subtree */ |
| 88 | cur = s->htable[hvalue]; | 105 | entry = &s->roots[level]; |
| 89 | while (cur && sid > cur->sid) | 106 | while (level != 0) { |
| 90 | cur = cur->next; | 107 | capacity_shift -= SIDTAB_INNER_SHIFT; |
| 91 | 108 | --level; | |
| 92 | if (force && cur && sid == cur->sid && cur->context.len) | 109 | |
| 93 | return &cur->context; | 110 | entry = &entry->ptr_inner->entries[leaf_index >> capacity_shift]; |
| 94 | 111 | leaf_index &= ((u32)1 << capacity_shift) - 1; | |
| 95 | if (!cur || sid != cur->sid || cur->context.len) { | 112 | |
| 96 | /* Remap invalid SIDs to the unlabeled SID. */ | 113 | if (!entry->ptr_inner) { |
| 97 | sid = SECINITSID_UNLABELED; | 114 | if (alloc) |
| 98 | hvalue = SIDTAB_HASH(sid); | 115 | entry->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, |
| 99 | cur = s->htable[hvalue]; | 116 | GFP_ATOMIC); |
| 100 | while (cur && sid > cur->sid) | 117 | if (!entry->ptr_inner) |
| 101 | cur = cur->next; | 118 | return NULL; |
| 102 | if (!cur || sid != cur->sid) | 119 | } |
| 120 | } | ||
| 121 | if (!entry->ptr_leaf) { | ||
| 122 | if (alloc) | ||
| 123 | entry->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, | ||
| 124 | GFP_ATOMIC); | ||
| 125 | if (!entry->ptr_leaf) | ||
| 103 | return NULL; | 126 | return NULL; |
| 104 | } | 127 | } |
| 128 | return &entry->ptr_leaf->entries[index % SIDTAB_LEAF_ENTRIES].context; | ||
| 129 | } | ||
| 130 | |||
| 131 | static struct context *sidtab_lookup(struct sidtab *s, u32 index) | ||
| 132 | { | ||
| 133 | u32 count = (u32)atomic_read(&s->count); | ||
| 134 | |||
| 135 | if (index >= count) | ||
| 136 | return NULL; | ||
| 137 | |||
| 138 | /* read entries after reading count */ | ||
| 139 | smp_rmb(); | ||
| 140 | |||
| 141 | return sidtab_do_lookup(s, index, 0); | ||
| 142 | } | ||
| 143 | |||
| 144 | static struct context *sidtab_lookup_initial(struct sidtab *s, u32 sid) | ||
| 145 | { | ||
| 146 | return s->isids[sid - 1].set ? &s->isids[sid - 1].context : NULL; | ||
| 147 | } | ||
| 148 | |||
| 149 | static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) | ||
| 150 | { | ||
| 151 | struct context *context; | ||
| 152 | |||
| 153 | if (sid != 0) { | ||
| 154 | if (sid > SECINITSID_NUM) | ||
| 155 | context = sidtab_lookup(s, sid - (SECINITSID_NUM + 1)); | ||
| 156 | else | ||
| 157 | context = sidtab_lookup_initial(s, sid); | ||
| 158 | if (context && (!context->len || force)) | ||
| 159 | return context; | ||
| 160 | } | ||
| 105 | 161 | ||
| 106 | return &cur->context; | 162 | return sidtab_lookup_initial(s, SECINITSID_UNLABELED); |
| 107 | } | 163 | } |
| 108 | 164 | ||
| 109 | struct context *sidtab_search(struct sidtab *s, u32 sid) | 165 | struct context *sidtab_search(struct sidtab *s, u32 sid) |
| @@ -116,191 +172,324 @@ struct context *sidtab_search_force(struct sidtab *s, u32 sid) | |||
| 116 | return sidtab_search_core(s, sid, 1); | 172 | return sidtab_search_core(s, sid, 1); |
| 117 | } | 173 | } |
| 118 | 174 | ||
| 119 | int sidtab_map(struct sidtab *s, | 175 | static int sidtab_find_context(union sidtab_entry_inner entry, |
| 120 | int (*apply) (u32 sid, | 176 | u32 *pos, u32 count, u32 level, |
| 121 | struct context *context, | 177 | struct context *context, u32 *index) |
| 122 | void *args), | ||
| 123 | void *args) | ||
| 124 | { | 178 | { |
| 125 | int i, rc = 0; | 179 | int rc; |
| 126 | struct sidtab_node *cur; | 180 | u32 i; |
| 127 | 181 | ||
| 128 | if (!s) | 182 | if (level != 0) { |
| 129 | goto out; | 183 | struct sidtab_node_inner *node = entry.ptr_inner; |
| 184 | |||
| 185 | i = 0; | ||
| 186 | while (i < SIDTAB_INNER_ENTRIES && *pos < count) { | ||
| 187 | rc = sidtab_find_context(node->entries[i], | ||
| 188 | pos, count, level - 1, | ||
| 189 | context, index); | ||
| 190 | if (rc == 0) | ||
| 191 | return 0; | ||
| 192 | i++; | ||
| 193 | } | ||
| 194 | } else { | ||
| 195 | struct sidtab_node_leaf *node = entry.ptr_leaf; | ||
| 130 | 196 | ||
| 131 | for (i = 0; i < SIDTAB_SIZE; i++) { | 197 | i = 0; |
| 132 | cur = s->htable[i]; | 198 | while (i < SIDTAB_LEAF_ENTRIES && *pos < count) { |
| 133 | while (cur) { | 199 | if (context_cmp(&node->entries[i].context, context)) { |
| 134 | rc = apply(cur->sid, &cur->context, args); | 200 | *index = *pos; |
| 135 | if (rc) | 201 | return 0; |
| 136 | goto out; | 202 | } |
| 137 | cur = cur->next; | 203 | (*pos)++; |
| 204 | i++; | ||
| 138 | } | 205 | } |
| 139 | } | 206 | } |
| 140 | out: | 207 | return -ENOENT; |
| 141 | return rc; | ||
| 142 | } | 208 | } |
| 143 | 209 | ||
| 144 | static void sidtab_update_cache(struct sidtab *s, struct sidtab_node *n, int loc) | 210 | static void sidtab_rcache_update(struct sidtab *s, u32 index, u32 pos) |
| 145 | { | 211 | { |
| 146 | BUG_ON(loc >= SIDTAB_CACHE_LEN); | 212 | while (pos > 0) { |
| 147 | 213 | atomic_set(&s->rcache[pos], atomic_read(&s->rcache[pos - 1])); | |
| 148 | while (loc > 0) { | 214 | --pos; |
| 149 | s->cache[loc] = s->cache[loc - 1]; | ||
| 150 | loc--; | ||
| 151 | } | 215 | } |
| 152 | s->cache[0] = n; | 216 | atomic_set(&s->rcache[0], (int)index); |
| 153 | } | 217 | } |
| 154 | 218 | ||
| 155 | static inline u32 sidtab_search_context(struct sidtab *s, | 219 | static void sidtab_rcache_push(struct sidtab *s, u32 index) |
| 156 | struct context *context) | ||
| 157 | { | 220 | { |
| 158 | int i; | 221 | sidtab_rcache_update(s, index, SIDTAB_RCACHE_SIZE - 1); |
| 159 | struct sidtab_node *cur; | ||
| 160 | |||
| 161 | for (i = 0; i < SIDTAB_SIZE; i++) { | ||
| 162 | cur = s->htable[i]; | ||
| 163 | while (cur) { | ||
| 164 | if (context_cmp(&cur->context, context)) { | ||
| 165 | sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1); | ||
| 166 | return cur->sid; | ||
| 167 | } | ||
| 168 | cur = cur->next; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | return 0; | ||
| 172 | } | 222 | } |
| 173 | 223 | ||
| 174 | static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context) | 224 | static int sidtab_rcache_search(struct sidtab *s, struct context *context, |
| 225 | u32 *index) | ||
| 175 | { | 226 | { |
| 176 | int i; | 227 | u32 i; |
| 177 | struct sidtab_node *node; | ||
| 178 | 228 | ||
| 179 | for (i = 0; i < SIDTAB_CACHE_LEN; i++) { | 229 | for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) { |
| 180 | node = s->cache[i]; | 230 | int v = atomic_read(&s->rcache[i]); |
| 181 | if (unlikely(!node)) | 231 | |
| 232 | if (v < 0) | ||
| 233 | continue; | ||
| 234 | |||
| 235 | if (context_cmp(sidtab_do_lookup(s, (u32)v, 0), context)) { | ||
| 236 | sidtab_rcache_update(s, (u32)v, i); | ||
| 237 | *index = (u32)v; | ||
| 182 | return 0; | 238 | return 0; |
| 183 | if (context_cmp(&node->context, context)) { | ||
| 184 | sidtab_update_cache(s, node, i); | ||
| 185 | return node->sid; | ||
| 186 | } | 239 | } |
| 187 | } | 240 | } |
| 188 | return 0; | 241 | return -ENOENT; |
| 189 | } | 242 | } |
| 190 | 243 | ||
| 191 | int sidtab_context_to_sid(struct sidtab *s, | 244 | static int sidtab_reverse_lookup(struct sidtab *s, struct context *context, |
| 192 | struct context *context, | 245 | u32 *index) |
| 193 | u32 *out_sid) | ||
| 194 | { | 246 | { |
| 195 | u32 sid; | ||
| 196 | int ret = 0; | ||
| 197 | unsigned long flags; | 247 | unsigned long flags; |
| 248 | u32 count = (u32)atomic_read(&s->count); | ||
| 249 | u32 count_locked, level, pos; | ||
| 250 | struct sidtab_convert_params *convert; | ||
| 251 | struct context *dst, *dst_convert; | ||
| 252 | int rc; | ||
| 253 | |||
| 254 | rc = sidtab_rcache_search(s, context, index); | ||
| 255 | if (rc == 0) | ||
| 256 | return 0; | ||
| 257 | |||
| 258 | level = sidtab_level_from_count(count); | ||
| 259 | |||
| 260 | /* read entries after reading count */ | ||
| 261 | smp_rmb(); | ||
| 262 | |||
| 263 | pos = 0; | ||
| 264 | rc = sidtab_find_context(s->roots[level], &pos, count, level, | ||
| 265 | context, index); | ||
| 266 | if (rc == 0) { | ||
| 267 | sidtab_rcache_push(s, *index); | ||
| 268 | return 0; | ||
| 269 | } | ||
| 198 | 270 | ||
| 199 | *out_sid = SECSID_NULL; | 271 | /* lock-free search failed: lock, re-search, and insert if not found */ |
| 272 | spin_lock_irqsave(&s->lock, flags); | ||
| 200 | 273 | ||
| 201 | sid = sidtab_search_cache(s, context); | 274 | convert = s->convert; |
| 202 | if (!sid) | 275 | count_locked = (u32)atomic_read(&s->count); |
| 203 | sid = sidtab_search_context(s, context); | 276 | level = sidtab_level_from_count(count_locked); |
| 204 | if (!sid) { | 277 | |
| 205 | spin_lock_irqsave(&s->lock, flags); | 278 | /* if count has changed before we acquired the lock, then catch up */ |
| 206 | /* Rescan now that we hold the lock. */ | 279 | while (count < count_locked) { |
| 207 | sid = sidtab_search_context(s, context); | 280 | if (context_cmp(sidtab_do_lookup(s, count, 0), context)) { |
| 208 | if (sid) | 281 | sidtab_rcache_push(s, count); |
| 209 | goto unlock_out; | 282 | *index = count; |
| 210 | /* No SID exists for the context. Allocate a new one. */ | 283 | rc = 0; |
| 211 | if (s->next_sid == UINT_MAX || s->shutdown) { | 284 | goto out_unlock; |
| 212 | ret = -ENOMEM; | ||
| 213 | goto unlock_out; | ||
| 214 | } | 285 | } |
| 215 | sid = s->next_sid++; | 286 | ++count; |
| 216 | if (context->len) | ||
| 217 | pr_info("SELinux: Context %s is not valid (left unmapped).\n", | ||
| 218 | context->str); | ||
| 219 | ret = sidtab_insert(s, sid, context); | ||
| 220 | if (ret) | ||
| 221 | s->next_sid--; | ||
| 222 | unlock_out: | ||
| 223 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 224 | } | 287 | } |
| 225 | 288 | ||
| 226 | if (ret) | 289 | /* insert context into new entry */ |
| 227 | return ret; | 290 | rc = -ENOMEM; |
| 291 | dst = sidtab_do_lookup(s, count, 1); | ||
| 292 | if (!dst) | ||
| 293 | goto out_unlock; | ||
| 294 | |||
| 295 | rc = context_cpy(dst, context); | ||
| 296 | if (rc) | ||
| 297 | goto out_unlock; | ||
| 298 | |||
| 299 | /* | ||
| 300 | * if we are building a new sidtab, we need to convert the context | ||
| 301 | * and insert it there as well | ||
| 302 | */ | ||
| 303 | if (convert) { | ||
| 304 | rc = -ENOMEM; | ||
| 305 | dst_convert = sidtab_do_lookup(convert->target, count, 1); | ||
| 306 | if (!dst_convert) { | ||
| 307 | context_destroy(dst); | ||
| 308 | goto out_unlock; | ||
| 309 | } | ||
| 228 | 310 | ||
| 229 | *out_sid = sid; | 311 | rc = convert->func(context, dst_convert, convert->args); |
| 230 | return 0; | 312 | if (rc) { |
| 313 | context_destroy(dst); | ||
| 314 | goto out_unlock; | ||
| 315 | } | ||
| 316 | |||
| 317 | /* at this point we know the insert won't fail */ | ||
| 318 | atomic_set(&convert->target->count, count + 1); | ||
| 319 | } | ||
| 320 | |||
| 321 | if (context->len) | ||
| 322 | pr_info("SELinux: Context %s is not valid (left unmapped).\n", | ||
| 323 | context->str); | ||
| 324 | |||
| 325 | sidtab_rcache_push(s, count); | ||
| 326 | *index = count; | ||
| 327 | |||
| 328 | /* write entries before writing new count */ | ||
| 329 | smp_wmb(); | ||
| 330 | |||
| 331 | atomic_set(&s->count, count + 1); | ||
| 332 | |||
| 333 | rc = 0; | ||
| 334 | out_unlock: | ||
| 335 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 336 | return rc; | ||
| 231 | } | 337 | } |
| 232 | 338 | ||
| 233 | void sidtab_hash_eval(struct sidtab *h, char *tag) | 339 | int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid) |
| 234 | { | 340 | { |
| 235 | int i, chain_len, slots_used, max_chain_len; | 341 | int rc; |
| 236 | struct sidtab_node *cur; | 342 | u32 i; |
| 237 | 343 | ||
| 238 | slots_used = 0; | 344 | for (i = 0; i < SECINITSID_NUM; i++) { |
| 239 | max_chain_len = 0; | 345 | struct sidtab_isid_entry *entry = &s->isids[i]; |
| 240 | for (i = 0; i < SIDTAB_SIZE; i++) { | ||
| 241 | cur = h->htable[i]; | ||
| 242 | if (cur) { | ||
| 243 | slots_used++; | ||
| 244 | chain_len = 0; | ||
| 245 | while (cur) { | ||
| 246 | chain_len++; | ||
| 247 | cur = cur->next; | ||
| 248 | } | ||
| 249 | 346 | ||
| 250 | if (chain_len > max_chain_len) | 347 | if (entry->set && context_cmp(context, &entry->context)) { |
| 251 | max_chain_len = chain_len; | 348 | *sid = i + 1; |
| 349 | return 0; | ||
| 252 | } | 350 | } |
| 253 | } | 351 | } |
| 254 | 352 | ||
| 255 | pr_debug("%s: %d entries and %d/%d buckets used, longest " | 353 | rc = sidtab_reverse_lookup(s, context, sid); |
| 256 | "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE, | 354 | if (rc) |
| 257 | max_chain_len); | 355 | return rc; |
| 356 | *sid += SECINITSID_NUM + 1; | ||
| 357 | return 0; | ||
| 258 | } | 358 | } |
| 259 | 359 | ||
| 260 | void sidtab_destroy(struct sidtab *s) | 360 | static int sidtab_convert_tree(union sidtab_entry_inner *edst, |
| 361 | union sidtab_entry_inner *esrc, | ||
| 362 | u32 *pos, u32 count, u32 level, | ||
| 363 | struct sidtab_convert_params *convert) | ||
| 261 | { | 364 | { |
| 262 | int i; | 365 | int rc; |
| 263 | struct sidtab_node *cur, *temp; | 366 | u32 i; |
| 264 | 367 | ||
| 265 | if (!s) | 368 | if (level != 0) { |
| 266 | return; | 369 | if (!edst->ptr_inner) { |
| 267 | 370 | edst->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE, | |
| 268 | for (i = 0; i < SIDTAB_SIZE; i++) { | 371 | GFP_KERNEL); |
| 269 | cur = s->htable[i]; | 372 | if (!edst->ptr_inner) |
| 270 | while (cur) { | 373 | return -ENOMEM; |
| 271 | temp = cur; | 374 | } |
| 272 | cur = cur->next; | 375 | i = 0; |
| 273 | context_destroy(&temp->context); | 376 | while (i < SIDTAB_INNER_ENTRIES && *pos < count) { |
| 274 | kfree(temp); | 377 | rc = sidtab_convert_tree(&edst->ptr_inner->entries[i], |
| 378 | &esrc->ptr_inner->entries[i], | ||
| 379 | pos, count, level - 1, | ||
| 380 | convert); | ||
| 381 | if (rc) | ||
| 382 | return rc; | ||
| 383 | i++; | ||
| 384 | } | ||
| 385 | } else { | ||
| 386 | if (!edst->ptr_leaf) { | ||
| 387 | edst->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE, | ||
| 388 | GFP_KERNEL); | ||
| 389 | if (!edst->ptr_leaf) | ||
| 390 | return -ENOMEM; | ||
| 391 | } | ||
| 392 | i = 0; | ||
| 393 | while (i < SIDTAB_LEAF_ENTRIES && *pos < count) { | ||
| 394 | rc = convert->func(&esrc->ptr_leaf->entries[i].context, | ||
| 395 | &edst->ptr_leaf->entries[i].context, | ||
| 396 | convert->args); | ||
| 397 | if (rc) | ||
| 398 | return rc; | ||
| 399 | (*pos)++; | ||
| 400 | i++; | ||
| 275 | } | 401 | } |
| 276 | s->htable[i] = NULL; | 402 | cond_resched(); |
| 277 | } | 403 | } |
| 278 | kfree(s->htable); | 404 | return 0; |
| 279 | s->htable = NULL; | ||
| 280 | s->nel = 0; | ||
| 281 | s->next_sid = 1; | ||
| 282 | } | 405 | } |
| 283 | 406 | ||
| 284 | void sidtab_set(struct sidtab *dst, struct sidtab *src) | 407 | int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params) |
| 285 | { | 408 | { |
| 286 | unsigned long flags; | 409 | unsigned long flags; |
| 287 | int i; | 410 | u32 count, level, pos; |
| 288 | 411 | int rc; | |
| 289 | spin_lock_irqsave(&src->lock, flags); | 412 | |
| 290 | dst->htable = src->htable; | 413 | spin_lock_irqsave(&s->lock, flags); |
| 291 | dst->nel = src->nel; | 414 | |
| 292 | dst->next_sid = src->next_sid; | 415 | /* concurrent policy loads are not allowed */ |
| 293 | dst->shutdown = 0; | 416 | if (s->convert) { |
| 294 | for (i = 0; i < SIDTAB_CACHE_LEN; i++) | 417 | spin_unlock_irqrestore(&s->lock, flags); |
| 295 | dst->cache[i] = NULL; | 418 | return -EBUSY; |
| 296 | spin_unlock_irqrestore(&src->lock, flags); | 419 | } |
| 420 | |||
| 421 | count = (u32)atomic_read(&s->count); | ||
| 422 | level = sidtab_level_from_count(count); | ||
| 423 | |||
| 424 | /* allocate last leaf in the new sidtab (to avoid race with | ||
| 425 | * live convert) | ||
| 426 | */ | ||
| 427 | rc = sidtab_do_lookup(params->target, count - 1, 1) ? 0 : -ENOMEM; | ||
| 428 | if (rc) { | ||
| 429 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 430 | return rc; | ||
| 431 | } | ||
| 432 | |||
| 433 | /* set count in case no new entries are added during conversion */ | ||
| 434 | atomic_set(¶ms->target->count, count); | ||
| 435 | |||
| 436 | /* enable live convert of new entries */ | ||
| 437 | s->convert = params; | ||
| 438 | |||
| 439 | /* we can safely do the rest of the conversion outside the lock */ | ||
| 440 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 441 | |||
| 442 | pr_info("SELinux: Converting %u SID table entries...\n", count); | ||
| 443 | |||
| 444 | /* convert all entries not covered by live convert */ | ||
| 445 | pos = 0; | ||
| 446 | rc = sidtab_convert_tree(¶ms->target->roots[level], | ||
| 447 | &s->roots[level], &pos, count, level, params); | ||
| 448 | if (rc) { | ||
| 449 | /* we need to keep the old table - disable live convert */ | ||
| 450 | spin_lock_irqsave(&s->lock, flags); | ||
| 451 | s->convert = NULL; | ||
| 452 | spin_unlock_irqrestore(&s->lock, flags); | ||
| 453 | } | ||
| 454 | return rc; | ||
| 297 | } | 455 | } |
| 298 | 456 | ||
| 299 | void sidtab_shutdown(struct sidtab *s) | 457 | static void sidtab_destroy_tree(union sidtab_entry_inner entry, u32 level) |
| 300 | { | 458 | { |
| 301 | unsigned long flags; | 459 | u32 i; |
| 302 | 460 | ||
| 303 | spin_lock_irqsave(&s->lock, flags); | 461 | if (level != 0) { |
| 304 | s->shutdown = 1; | 462 | struct sidtab_node_inner *node = entry.ptr_inner; |
| 305 | spin_unlock_irqrestore(&s->lock, flags); | 463 | |
| 464 | if (!node) | ||
| 465 | return; | ||
| 466 | |||
| 467 | for (i = 0; i < SIDTAB_INNER_ENTRIES; i++) | ||
| 468 | sidtab_destroy_tree(node->entries[i], level - 1); | ||
| 469 | kfree(node); | ||
| 470 | } else { | ||
| 471 | struct sidtab_node_leaf *node = entry.ptr_leaf; | ||
| 472 | |||
| 473 | if (!node) | ||
| 474 | return; | ||
| 475 | |||
| 476 | for (i = 0; i < SIDTAB_LEAF_ENTRIES; i++) | ||
| 477 | context_destroy(&node->entries[i].context); | ||
| 478 | kfree(node); | ||
| 479 | } | ||
| 480 | } | ||
| 481 | |||
| 482 | void sidtab_destroy(struct sidtab *s) | ||
| 483 | { | ||
| 484 | u32 i, level; | ||
| 485 | |||
| 486 | for (i = 0; i < SECINITSID_NUM; i++) | ||
| 487 | if (s->isids[i].set) | ||
| 488 | context_destroy(&s->isids[i].context); | ||
| 489 | |||
| 490 | level = SIDTAB_MAX_LEVEL; | ||
| 491 | while (level && !s->roots[level].ptr_inner) | ||
| 492 | --level; | ||
| 493 | |||
| 494 | sidtab_destroy_tree(s->roots[level], level); | ||
| 306 | } | 495 | } |
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h index a1a1d2617b6f..bbd5c0d1f3bd 100644 --- a/security/selinux/ss/sidtab.h +++ b/security/selinux/ss/sidtab.h | |||
| @@ -1,56 +1,96 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* | 2 | /* |
| 3 | * A security identifier table (sidtab) is a hash table | 3 | * A security identifier table (sidtab) is a lookup table |
| 4 | * of security context structures indexed by SID value. | 4 | * of security context structures indexed by SID value. |
| 5 | * | 5 | * |
| 6 | * Author : Stephen Smalley, <sds@tycho.nsa.gov> | 6 | * Original author: Stephen Smalley, <sds@tycho.nsa.gov> |
| 7 | * Author: Ondrej Mosnacek, <omosnacek@gmail.com> | ||
| 8 | * | ||
| 9 | * Copyright (C) 2018 Red Hat, Inc. | ||
| 7 | */ | 10 | */ |
| 8 | #ifndef _SS_SIDTAB_H_ | 11 | #ifndef _SS_SIDTAB_H_ |
| 9 | #define _SS_SIDTAB_H_ | 12 | #define _SS_SIDTAB_H_ |
| 10 | 13 | ||
| 14 | #include <linux/spinlock_types.h> | ||
| 15 | #include <linux/log2.h> | ||
| 16 | |||
| 11 | #include "context.h" | 17 | #include "context.h" |
| 12 | 18 | ||
| 13 | struct sidtab_node { | 19 | struct sidtab_entry_leaf { |
| 14 | u32 sid; /* security identifier */ | 20 | struct context context; |
| 15 | struct context context; /* security context structure */ | 21 | }; |
| 16 | struct sidtab_node *next; | 22 | |
| 23 | struct sidtab_node_inner; | ||
| 24 | struct sidtab_node_leaf; | ||
| 25 | |||
| 26 | union sidtab_entry_inner { | ||
| 27 | struct sidtab_node_inner *ptr_inner; | ||
| 28 | struct sidtab_node_leaf *ptr_leaf; | ||
| 29 | }; | ||
| 30 | |||
| 31 | /* align node size to page boundary */ | ||
| 32 | #define SIDTAB_NODE_ALLOC_SHIFT PAGE_SHIFT | ||
| 33 | #define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE | ||
| 34 | |||
| 35 | #define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size) - 1) + 1)) | ||
| 36 | |||
| 37 | #define SIDTAB_INNER_SHIFT \ | ||
| 38 | (SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner))) | ||
| 39 | #define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT) | ||
| 40 | #define SIDTAB_LEAF_ENTRIES \ | ||
| 41 | (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry_leaf)) | ||
| 42 | |||
| 43 | #define SIDTAB_MAX_BITS 31 /* limited to INT_MAX due to atomic_t range */ | ||
| 44 | #define SIDTAB_MAX (((u32)1 << SIDTAB_MAX_BITS) - 1) | ||
| 45 | /* ensure enough tree levels for SIDTAB_MAX entries */ | ||
| 46 | #define SIDTAB_MAX_LEVEL \ | ||
| 47 | DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \ | ||
| 48 | SIDTAB_INNER_SHIFT) | ||
| 49 | |||
| 50 | struct sidtab_node_leaf { | ||
| 51 | struct sidtab_entry_leaf entries[SIDTAB_LEAF_ENTRIES]; | ||
| 17 | }; | 52 | }; |
| 18 | 53 | ||
| 19 | #define SIDTAB_HASH_BITS 7 | 54 | struct sidtab_node_inner { |
| 20 | #define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) | 55 | union sidtab_entry_inner entries[SIDTAB_INNER_ENTRIES]; |
| 21 | #define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1) | 56 | }; |
| 22 | 57 | ||
| 23 | #define SIDTAB_SIZE SIDTAB_HASH_BUCKETS | 58 | struct sidtab_isid_entry { |
| 59 | int set; | ||
| 60 | struct context context; | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct sidtab_convert_params { | ||
| 64 | int (*func)(struct context *oldc, struct context *newc, void *args); | ||
| 65 | void *args; | ||
| 66 | struct sidtab *target; | ||
| 67 | }; | ||
| 68 | |||
| 69 | #define SIDTAB_RCACHE_SIZE 3 | ||
| 24 | 70 | ||
| 25 | struct sidtab { | 71 | struct sidtab { |
| 26 | struct sidtab_node **htable; | 72 | union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1]; |
| 27 | unsigned int nel; /* number of elements */ | 73 | atomic_t count; |
| 28 | unsigned int next_sid; /* next SID to allocate */ | 74 | struct sidtab_convert_params *convert; |
| 29 | unsigned char shutdown; | ||
| 30 | #define SIDTAB_CACHE_LEN 3 | ||
| 31 | struct sidtab_node *cache[SIDTAB_CACHE_LEN]; | ||
| 32 | spinlock_t lock; | 75 | spinlock_t lock; |
| 76 | |||
| 77 | /* reverse lookup cache */ | ||
| 78 | atomic_t rcache[SIDTAB_RCACHE_SIZE]; | ||
| 79 | |||
| 80 | /* index == SID - 1 (no entry for SECSID_NULL) */ | ||
| 81 | struct sidtab_isid_entry isids[SECINITSID_NUM]; | ||
| 33 | }; | 82 | }; |
| 34 | 83 | ||
| 35 | int sidtab_init(struct sidtab *s); | 84 | int sidtab_init(struct sidtab *s); |
| 36 | int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); | 85 | int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context); |
| 37 | struct context *sidtab_search(struct sidtab *s, u32 sid); | 86 | struct context *sidtab_search(struct sidtab *s, u32 sid); |
| 38 | struct context *sidtab_search_force(struct sidtab *s, u32 sid); | 87 | struct context *sidtab_search_force(struct sidtab *s, u32 sid); |
| 39 | 88 | ||
| 40 | int sidtab_map(struct sidtab *s, | 89 | int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params); |
| 41 | int (*apply) (u32 sid, | ||
| 42 | struct context *context, | ||
| 43 | void *args), | ||
| 44 | void *args); | ||
| 45 | 90 | ||
| 46 | int sidtab_context_to_sid(struct sidtab *s, | 91 | int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid); |
| 47 | struct context *context, | ||
| 48 | u32 *sid); | ||
| 49 | 92 | ||
| 50 | void sidtab_hash_eval(struct sidtab *h, char *tag); | ||
| 51 | void sidtab_destroy(struct sidtab *s); | 93 | void sidtab_destroy(struct sidtab *s); |
| 52 | void sidtab_set(struct sidtab *dst, struct sidtab *src); | ||
| 53 | void sidtab_shutdown(struct sidtab *s); | ||
| 54 | 94 | ||
| 55 | #endif /* _SS_SIDTAB_H_ */ | 95 | #endif /* _SS_SIDTAB_H_ */ |
| 56 | 96 | ||
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 91dc3783ed94..bd7d18bdb147 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
| @@ -230,7 +230,7 @@ static int selinux_xfrm_skb_sid_ingress(struct sk_buff *skb, | |||
| 230 | u32 *sid, int ckall) | 230 | u32 *sid, int ckall) |
| 231 | { | 231 | { |
| 232 | u32 sid_session = SECSID_NULL; | 232 | u32 sid_session = SECSID_NULL; |
| 233 | struct sec_path *sp = skb->sp; | 233 | struct sec_path *sp = skb_sec_path(skb); |
| 234 | 234 | ||
| 235 | if (sp) { | 235 | if (sp) { |
| 236 | int i; | 236 | int i; |
| @@ -408,7 +408,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb, | |||
| 408 | struct common_audit_data *ad) | 408 | struct common_audit_data *ad) |
| 409 | { | 409 | { |
| 410 | int i; | 410 | int i; |
| 411 | struct sec_path *sp = skb->sp; | 411 | struct sec_path *sp = skb_sec_path(skb); |
| 412 | u32 peer_sid = SECINITSID_UNLABELED; | 412 | u32 peer_sid = SECINITSID_UNLABELED; |
| 413 | 413 | ||
| 414 | if (sp) { | 414 | if (sp) { |
