From patchwork Fri Mar 16 20:38:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thiago Jung Bauermann X-Patchwork-Id: 887155 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 402yZq28Rcz9sPk for ; Sat, 17 Mar 2018 08:02:27 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 402yZq0ZnGzDr7s for ; Sat, 17 Mar 2018 08:02:27 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=bauerman@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 402y5K23nmzF1ZS for ; Sat, 17 Mar 2018 07:40:21 +1100 (AEDT) Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w2GKdaS5001971 for ; Fri, 16 Mar 2018 16:40:18 -0400 Received: from e34.co.us.ibm.com (e34.co.us.ibm.com [32.97.110.152]) by mx0b-001b2d01.pphosted.com with ESMTP id 2grmb9sq7k-1 (version=TLSv1.2 cipher=AES256-SHA256 bits=256 verify=NOT) for ; Fri, 16 Mar 2018 16:40:18 -0400 Received: from localhost by e34.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 16 Mar 2018 14:40:17 -0600 Received: from b03cxnp07028.gho.boulder.ibm.com (9.17.130.15) by e34.co.us.ibm.com (192.168.1.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 16 Mar 2018 14:40:12 -0600 Received: from b03ledav004.gho.boulder.ibm.com (b03ledav004.gho.boulder.ibm.com [9.17.130.235]) by b03cxnp07028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w2GKeBs211534744; Fri, 16 Mar 2018 13:40:11 -0700 Received: from b03ledav004.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C412378047; Fri, 16 Mar 2018 14:40:11 -0600 (MDT) Received: from morokweng.localdomain.com (unknown [9.85.199.230]) by b03ledav004.gho.boulder.ibm.com (Postfix) with ESMTP id A6B4F78038; Fri, 16 Mar 2018 14:40:07 -0600 (MDT) From: Thiago Jung Bauermann To: linux-integrity@vger.kernel.org Subject: [PATCH v6 10/12] ima: Add functions to read and verify a modsig signature Date: Fri, 16 Mar 2018 17:38:35 -0300 X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180316203837.10174-1-bauerman@linux.vnet.ibm.com> References: <20180316203837.10174-1-bauerman@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18031620-0016-0000-0000-00000867DF4E X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008686; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000254; SDB=6.01004029; UDB=6.00511020; IPR=6.00783318; MB=3.00020079; MTD=3.00000008; XFM=3.00000015; UTC=2018-03-16 20:40:16 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18031620-0017-0000-0000-00003DDF26D0 Message-Id: <20180316203837.10174-11-bauerman@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2018-03-16_13:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=3 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1803160243 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Herbert Xu , "David S. Miller" , linuxppc-dev@lists.ozlabs.org, Jessica Yu , linux-kernel@vger.kernel.org, James Morris , David Howells , "AKASHI, Takahiro" , linux-security-module@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, Dmitry Kasatkin , Thiago Jung Bauermann , Mimi Zohar , David Woodhouse , "Serge E. Hallyn" Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" This is the code needed by IMA-appraise to work with modsig signatures. It will be used by the next two patches. Signed-off-by: Thiago Jung Bauermann --- security/integrity/ima/Kconfig | 3 + security/integrity/ima/ima.h | 41 ++++++++ security/integrity/ima/ima_modsig.c | 181 ++++++++++++++++++++++++++++++++++++ security/integrity/integrity.h | 1 + 4 files changed, 226 insertions(+) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index ee278189e0bb..306601d62f0b 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -167,6 +167,9 @@ config IMA_APPRAISE_BOOTPARAM config IMA_APPRAISE_MODSIG bool "Support module-style signatures for appraisal" depends on IMA_APPRAISE + depends on INTEGRITY_ASYMMETRIC_KEYS + select PKCS7_MESSAGE_PARSER + select MODULE_SIG_FORMAT default n help Adds support for signatures appended to files. The format of the diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c61d8fc5190d..49aef56dc96d 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -301,11 +301,52 @@ static inline int ima_read_xattr(struct dentry *dentry, #ifdef CONFIG_IMA_APPRAISE_MODSIG bool ima_hook_supports_modsig(enum ima_hooks func); +int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, + struct evm_ima_xattr_data **xattr_value, + int *xattr_len); +int ima_get_modsig_hash(struct evm_ima_xattr_data *hdr, enum hash_algo *algo, + const u8 **hash, u8 *len); +int ima_modsig_serialize_data(struct evm_ima_xattr_data **data, int *data_len); +int ima_modsig_verify(const unsigned int keyring_id, + struct evm_ima_xattr_data *hdr); +void ima_free_xattr_data(struct evm_ima_xattr_data *hdr); #else static inline bool ima_hook_supports_modsig(enum ima_hooks func) { return false; } + +static inline int ima_read_modsig(enum ima_hooks func, const void *buf, + loff_t buf_len, + struct evm_ima_xattr_data **xattr_value, + int *xattr_len) +{ + return -ENOTSUPP; +} + +static inline int ima_get_modsig_hash(struct evm_ima_xattr_data *hdr, + enum hash_algo *algo, const u8 **hash, + u8 *len) +{ + return -ENOTSUPP; +} + +static inline int ima_modsig_serialize_data(struct evm_ima_xattr_data **data, + int *data_len) +{ + return -ENOTSUPP; +} + +static inline int ima_modsig_verify(const unsigned int keyring_id, + struct evm_ima_xattr_data *hdr) +{ + return -ENOTSUPP; +} + +static inline void ima_free_xattr_data(struct evm_ima_xattr_data *hdr) +{ + kfree(hdr); +} #endif /* CONFIG_IMA_APPRAISE_MODSIG */ /* LSM based policy rules require audit */ diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c index d8ea811b6f74..105fd04d585e 100644 --- a/security/integrity/ima/ima_modsig.c +++ b/security/integrity/ima/ima_modsig.c @@ -8,8 +8,25 @@ * Thiago Jung Bauermann */ +#include +#include +#include +#include + #include "ima.h" +struct modsig_hdr { + uint8_t type; /* Should be IMA_MODSIG. */ + struct pkcs7_message *pkcs7_msg; + int raw_pkcs7_len; + + /* + * This is what will go to the measurement list if the template requires + * storing the signature. + */ + struct evm_ima_xattr_data raw_pkcs7; +}; + /** * ima_hook_supports_modsig - can the policy allow modsig for this hook? * @@ -29,3 +46,167 @@ bool ima_hook_supports_modsig(enum ima_hooks func) return false; } } + +static bool modsig_has_known_key(struct modsig_hdr *hdr) +{ + const struct public_key_signature *pks; + struct key *keyring; + struct key *key; + + keyring = integrity_keyring_from_id(INTEGRITY_KEYRING_IMA); + if (IS_ERR(keyring)) + return false; + + pks = pkcs7_get_message_sig(hdr->pkcs7_msg); + if (!pks) + return false; + + key = find_asymmetric_key(keyring, pks->auth_ids[0], NULL, false); + if (IS_ERR(key)) + return false; + + key_put(key); + + return true; +} + +int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, + struct evm_ima_xattr_data **xattr_value, + int *xattr_len) +{ + const size_t marker_len = sizeof(MODULE_SIG_STRING) - 1; + const struct module_signature *sig; + struct modsig_hdr *hdr; + size_t sig_len; + const void *p; + int rc; + + /* + * Not supposed to happen. Hooks that support modsig are whitelisted + * when parsing the policy using ima_hooks_supports_modsig(). + */ + if (!buf || !buf_len) { + WARN_ONCE(true, "%s doesn't support modsig\n", + func_tokens[func]); + return -ENOENT; + } else 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 = validate_module_sig(sig, buf_len); + 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 = kmalloc(sizeof(*hdr) + sig_len, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len); + if (IS_ERR(hdr->pkcs7_msg)) { + rc = PTR_ERR(hdr->pkcs7_msg); + goto err_no_msg; + } + + rc = pkcs7_supply_detached_data(hdr->pkcs7_msg, buf, buf_len); + if (rc) + goto err; + + if (!modsig_has_known_key(hdr)) { + rc = -ENOKEY; + goto err; + } + + memcpy(hdr->raw_pkcs7.data, buf + buf_len, sig_len); + hdr->raw_pkcs7_len = sig_len + 1; + hdr->raw_pkcs7.type = IMA_MODSIG; + + hdr->type = IMA_MODSIG; + + *xattr_value = (typeof(*xattr_value)) hdr; + *xattr_len = sizeof(*hdr); + + return 0; + + err: + pkcs7_free_message(hdr->pkcs7_msg); + err_no_msg: + kfree(hdr); + return rc; +} + +int ima_get_modsig_hash(struct evm_ima_xattr_data *hdr, enum hash_algo *algo, + const u8 **hash, u8 *len) +{ + struct modsig_hdr *modsig = (typeof(modsig)) hdr; + const struct public_key_signature *pks; + int i; + + if (!hdr || hdr->type != IMA_MODSIG) + return -EINVAL; + + pks = pkcs7_get_message_sig(modsig->pkcs7_msg); + if (!pks) + return -EBADMSG; + + for (i = 0; i < HASH_ALGO__LAST; i++) + if (!strcmp(hash_algo_name[i], pks->hash_algo)) + break; + + *algo = i; + + return pkcs7_get_digest(modsig->pkcs7_msg, hash, len); +} + +int ima_modsig_serialize_data(struct evm_ima_xattr_data **data, int *data_len) +{ + struct modsig_hdr *modsig = (struct modsig_hdr *) *data; + + if (!*data || (*data)->type != IMA_MODSIG) + return -EINVAL; + + *data = &modsig->raw_pkcs7; + *data_len = modsig->raw_pkcs7_len; + + return 0; +} + +int ima_modsig_verify(const unsigned int keyring_id, + struct evm_ima_xattr_data *hdr) +{ + struct modsig_hdr *modsig = (struct modsig_hdr *) hdr; + struct key *keyring; + + if (!hdr || hdr->type != IMA_MODSIG) + return -EINVAL; + + keyring = integrity_keyring_from_id(keyring_id); + if (IS_ERR(keyring)) + return PTR_ERR(keyring); + + return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring, + VERIFYING_MODULE_SIGNATURE, NULL, NULL); +} + +void ima_free_xattr_data(struct evm_ima_xattr_data *hdr) +{ + if (!hdr) + return; + + if (hdr->type == IMA_MODSIG) { + struct modsig_hdr *modsig = (struct modsig_hdr *) hdr; + + pkcs7_free_message(modsig->pkcs7_msg); + } + + kfree(hdr); +} diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 6643c6550787..4acb1fb86b3b 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -74,6 +74,7 @@ enum evm_ima_xattr_type { EVM_IMA_XATTR_DIGSIG, IMA_XATTR_DIGEST_NG, EVM_XATTR_PORTABLE_DIGSIG, + IMA_MODSIG, IMA_XATTR_LAST };