diff options
author | Mikhail Kurinnoi <viewizard@viewizard.com> | 2018-06-27 09:33:42 -0400 |
---|---|---|
committer | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2018-07-18 07:27:22 -0400 |
commit | 6eb864c1d9dd1ef32b88e03c3f49d8be0dab7dcf (patch) | |
tree | 3484d390ade78e5dcdffdb67cb11b00ecefa10b9 | |
parent | 5feeb61183dde9d4f4026fd0d5801388c21d61a2 (diff) |
integrity: prevent deadlock during digsig verification.
This patch aimed to prevent deadlock during digsig verification.The point
of issue - user space utility modprobe and/or it's dependencies (ld-*.so,
libz.so.*, libc-*.so and /lib/modules/ files) that could be used for
kernel modules load during digsig verification and could be signed by
digsig in the same time.
First at all, look at crypto_alloc_tfm() work algorithm:
crypto_alloc_tfm() will first attempt to locate an already loaded
algorithm. If that fails and the kernel supports dynamically loadable
modules, it will then attempt to load a module of the same name or alias.
If that fails it will send a query to any loaded crypto manager to
construct an algorithm on the fly.
We have situation, when public_key_verify_signature() in case of RSA
algorithm use alg_name to store internal information in order to construct
an algorithm on the fly, but crypto_larval_lookup() will try to use
alg_name in order to load kernel module with same name.
1) we can't do anything with crypto module work, since it designed to work
exactly in this way;
2) we can't globally filter module requests for modprobe, since it
designed to work with any requests.
In this patch, I propose add an exception for "crypto-pkcs1pad(rsa,*)"
module requests only in case of enabled integrity asymmetric keys support.
Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules for
sure, we are safe to fail such module request from crypto_larval_lookup().
In this way we prevent modprobe execution during digsig verification and
avoid possible deadlock if modprobe and/or it's dependencies also signed
with digsig.
Requested "crypto-pkcs1pad(rsa,*)" kernel module name formed by:
1) "pkcs1pad(rsa,%s)" in public_key_verify_signature();
2) "crypto-%s" / "crypto-%s-all" in crypto_larval_lookup().
"crypto-pkcs1pad(rsa," part of request is a constant and unique and could
be used as filter.
Signed-off-by: Mikhail Kurinnoi <viewizard@viewizard.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
include/linux/integrity.h | 13 +++++++++++++
security/integrity/digsig_asymmetric.c | 23 +++++++++++++++++++++++
security/security.c | 7 ++++++-
3 files changed, 42 insertions(+), 1 deletion(-)
-rw-r--r-- | include/linux/integrity.h | 13 | ||||
-rw-r--r-- | security/integrity/digsig_asymmetric.c | 23 | ||||
-rw-r--r-- | security/security.c | 7 |
3 files changed, 42 insertions, 1 deletions
diff --git a/include/linux/integrity.h b/include/linux/integrity.h index 858d3f4a2241..54c853ec2fd1 100644 --- a/include/linux/integrity.h +++ b/include/linux/integrity.h | |||
@@ -44,4 +44,17 @@ static inline void integrity_load_keys(void) | |||
44 | } | 44 | } |
45 | #endif /* CONFIG_INTEGRITY */ | 45 | #endif /* CONFIG_INTEGRITY */ |
46 | 46 | ||
47 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS | ||
48 | |||
49 | extern int integrity_kernel_module_request(char *kmod_name); | ||
50 | |||
51 | #else | ||
52 | |||
53 | static inline int integrity_kernel_module_request(char *kmod_name) | ||
54 | { | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | #endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */ | ||
59 | |||
47 | #endif /* _LINUX_INTEGRITY_H */ | 60 | #endif /* _LINUX_INTEGRITY_H */ |
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index ab6a029062a1..6dc075144508 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c | |||
@@ -115,3 +115,26 @@ int asymmetric_verify(struct key *keyring, const char *sig, | |||
115 | pr_debug("%s() = %d\n", __func__, ret); | 115 | pr_debug("%s() = %d\n", __func__, ret); |
116 | return ret; | 116 | return ret; |
117 | } | 117 | } |
118 | |||
119 | /** | ||
120 | * integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests | ||
121 | * @kmod_name: kernel module name | ||
122 | * | ||
123 | * We have situation, when public_key_verify_signature() in case of RSA | ||
124 | * algorithm use alg_name to store internal information in order to | ||
125 | * construct an algorithm on the fly, but crypto_larval_lookup() will try | ||
126 | * to use alg_name in order to load kernel module with same name. | ||
127 | * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules, | ||
128 | * we are safe to fail such module request from crypto_larval_lookup(). | ||
129 | * | ||
130 | * In this way we prevent modprobe execution during digsig verification | ||
131 | * and avoid possible deadlock if modprobe and/or it's dependencies | ||
132 | * also signed with digsig. | ||
133 | */ | ||
134 | int integrity_kernel_module_request(char *kmod_name) | ||
135 | { | ||
136 | if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0) | ||
137 | return -EINVAL; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
diff --git a/security/security.c b/security/security.c index b49ee810371b..dbca03d3629b 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -1032,7 +1032,12 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
1032 | 1032 | ||
1033 | int security_kernel_module_request(char *kmod_name) | 1033 | int security_kernel_module_request(char *kmod_name) |
1034 | { | 1034 | { |
1035 | return call_int_hook(kernel_module_request, 0, kmod_name); | 1035 | int ret; |
1036 | |||
1037 | ret = call_int_hook(kernel_module_request, 0, kmod_name); | ||
1038 | if (ret) | ||
1039 | return ret; | ||
1040 | return integrity_kernel_module_request(kmod_name); | ||
1036 | } | 1041 | } |
1037 | 1042 | ||
1038 | int security_kernel_read_file(struct file *file, enum kernel_read_file_id id) | 1043 | int security_kernel_read_file(struct file *file, enum kernel_read_file_id id) |