The logic to extract the signature bits from a module file are duplicated between the module core and IMA modsig appraisal.
Unify the implementation. Signed-off-by: Thomas Weißschuh <[email protected]> --- include/linux/module_signature.h | 4 +-- kernel/module/signing.c | 52 +++++++------------------------------ kernel/module_signature.c | 41 +++++++++++++++++++++++++++-- security/integrity/ima/ima_modsig.c | 24 ++++------------- 4 files changed, 56 insertions(+), 65 deletions(-) diff --git a/include/linux/module_signature.h b/include/linux/module_signature.h index 7eb4b00381ac..186a55effa30 100644 --- a/include/linux/module_signature.h +++ b/include/linux/module_signature.h @@ -40,7 +40,7 @@ struct module_signature { __be32 sig_len; /* Length of signature data */ }; -int mod_check_sig(const struct module_signature *ms, size_t file_len, - const char *name); +int mod_split_sig(const void *buf, size_t *buf_len, bool mangled, + size_t *sig_len, const u8 **sig, const char *name); #endif /* _LINUX_MODULE_SIGNATURE_H */ diff --git a/kernel/module/signing.c b/kernel/module/signing.c index fe3f51ac6199..6d64c0d18d0a 100644 --- a/kernel/module/signing.c +++ b/kernel/module/signing.c @@ -37,54 +37,22 @@ void set_module_sig_enforced(void) sig_enforce = true; } -/* - * Verify the signature on a module. - */ -static int mod_verify_sig(const void *mod, struct load_info *info) -{ - struct module_signature ms; - size_t sig_len, modlen = info->len; - int ret; - - pr_devel("==>%s(,%zu)\n", __func__, modlen); - - if (modlen <= sizeof(ms)) - return -EBADMSG; - - memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms)); - - ret = mod_check_sig(&ms, modlen, "module"); - if (ret) - return ret; - - sig_len = be32_to_cpu(ms.sig_len); - modlen -= sig_len + sizeof(ms); - info->len = modlen; - - return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len, - VERIFY_USE_SECONDARY_KEYRING, - VERIFYING_MODULE_SIGNATURE, - NULL, NULL); -} - int module_sig_check(struct load_info *info, int flags) { - int err = -ENODATA; - const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; + int err; const char *reason; const void *mod = info->hdr; + size_t sig_len; + const u8 *sig; bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS | MODULE_INIT_IGNORE_VERMAGIC); - /* - * Do not allow mangled modules as a module with version information - * removed is no longer the module that was signed. - */ - if (!mangled_module && - info->len > markerlen && - memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { - /* We truncate the module to discard the signature */ - info->len -= markerlen; - err = mod_verify_sig(mod, info); + + err = mod_split_sig(info->hdr, &info->len, mangled_module, &sig_len, &sig, "module"); + if (!err) { + err = verify_pkcs7_signature(mod, info->len, sig, sig_len, + VERIFY_USE_SECONDARY_KEYRING, + VERIFYING_MODULE_SIGNATURE, + NULL, NULL); if (!err) { info->sig_ok = true; return 0; diff --git a/kernel/module_signature.c b/kernel/module_signature.c index 00132d12487c..b2384a73524c 100644 --- a/kernel/module_signature.c +++ b/kernel/module_signature.c @@ -8,6 +8,7 @@ #include <linux/errno.h> #include <linux/printk.h> +#include <linux/string.h> #include <linux/module_signature.h> #include <asm/byteorder.h> @@ -18,8 +19,8 @@ * @file_len: Size of the file to which @ms is appended. * @name: What is being checked. Used for error messages. */ -int mod_check_sig(const struct module_signature *ms, size_t file_len, - const char *name) +static int mod_check_sig(const struct module_signature *ms, size_t file_len, + const char *name) { if (be32_to_cpu(ms->sig_len) >= file_len - sizeof(*ms)) return -EBADMSG; @@ -44,3 +45,39 @@ int mod_check_sig(const struct module_signature *ms, size_t file_len, return 0; } + +int mod_split_sig(const void *buf, size_t *buf_len, bool mangled, + size_t *sig_len, const u8 **sig, const char *name) +{ + const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; + struct module_signature ms; + size_t modlen = *buf_len; + int ret; + + /* + * Do not allow mangled modules as a module with version information + * removed is no longer the module that was signed. + */ + if (!mangled && + *buf_len > markerlen && + memcmp(buf + modlen - markerlen, MODULE_SIG_STRING, markerlen) == 0) { + /* We truncate the module to discard the signature */ + modlen -= markerlen; + } + + if (modlen <= sizeof(ms)) + return -EBADMSG; + + memcpy(&ms, buf + (modlen - sizeof(ms)), sizeof(ms)); + + ret = mod_check_sig(&ms, modlen, name); + if (ret) + return ret; + + *sig_len = be32_to_cpu(ms.sig_len); + modlen -= *sig_len + sizeof(ms); + *buf_len = modlen; + *sig = buf + modlen; + + return 0; +} diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c index 3265d744d5ce..a57342d39b07 100644 --- a/security/integrity/ima/ima_modsig.c +++ b/security/integrity/ima/ima_modsig.c @@ -40,44 +40,30 @@ struct modsig { int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, struct modsig **modsig) { - const size_t marker_len = strlen(MODULE_SIG_STRING); - const struct module_signature *sig; + size_t buf_len_sz = buf_len; struct modsig *hdr; size_t sig_len; - const void *p; + const u8 *sig; int rc; - if (buf_len <= marker_len + sizeof(*sig)) - return -ENOENT; - - p = buf + buf_len - marker_len; - if (memcmp(p, MODULE_SIG_STRING, marker_len)) - return -ENOENT; - - buf_len -= marker_len; - sig = (const struct module_signature *)(p - sizeof(*sig)); - - rc = mod_check_sig(sig, buf_len, func_tokens[func]); + rc = mod_split_sig(buf, &buf_len_sz, true, &sig_len, &sig, func_tokens[func]); if (rc) return rc; - sig_len = be32_to_cpu(sig->sig_len); - buf_len -= sig_len + sizeof(*sig); - /* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */ hdr = kzalloc(struct_size(hdr, raw_pkcs7, sig_len), GFP_KERNEL); if (!hdr) return -ENOMEM; hdr->raw_pkcs7_len = sig_len; - hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len); + hdr->pkcs7_msg = pkcs7_parse_message(sig, sig_len); if (IS_ERR(hdr->pkcs7_msg)) { rc = PTR_ERR(hdr->pkcs7_msg); kfree(hdr); return rc; } - memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len); + memcpy(hdr->raw_pkcs7, sig, sig_len); /* We don't know the hash algorithm yet. */ hdr->hash_algo = HASH_ALGO__LAST; -- 2.52.0
