From patchwork Wed Jun 22 13:35:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mimi Zohar X-Patchwork-Id: 9192943 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2AED5601C0 for ; Wed, 22 Jun 2016 13:35:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1AC972840D for ; Wed, 22 Jun 2016 13:35:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0EE6928406; Wed, 22 Jun 2016 13:35:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 041B62840D for ; Wed, 22 Jun 2016 13:35:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752470AbcFVNfx (ORCPT ); Wed, 22 Jun 2016 09:35:53 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:58415 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752272AbcFVNfc (ORCPT ); Wed, 22 Jun 2016 09:35:32 -0400 Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id u5MDTawS006530 for ; Wed, 22 Jun 2016 09:35:31 -0400 Received: from e23smtp03.au.ibm.com (e23smtp03.au.ibm.com [202.81.31.145]) by mx0a-001b2d01.pphosted.com with ESMTP id 23qcxeb8wn-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Wed, 22 Jun 2016 09:35:31 -0400 Received: from localhost by e23smtp03.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 22 Jun 2016 23:35:29 +1000 Received: from d23dlp01.au.ibm.com (202.81.31.203) by e23smtp03.au.ibm.com (202.81.31.209) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 22 Jun 2016 23:35:27 +1000 X-IBM-Helo: d23dlp01.au.ibm.com X-IBM-MailFrom: zohar@linux.vnet.ibm.com X-IBM-RcptTo: linux-kernel@vger.kernel.org; linux-security-module@vger.kernel.org Received: from d23relay06.au.ibm.com (d23relay06.au.ibm.com [9.185.63.219]) by d23dlp01.au.ibm.com (Postfix) with ESMTP id 7A7A62CE8056; Wed, 22 Jun 2016 23:35:26 +1000 (EST) Received: from d23av01.au.ibm.com (d23av01.au.ibm.com [9.190.234.96]) by d23relay06.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u5MDZQTO11600166; Wed, 22 Jun 2016 23:35:26 +1000 Received: from d23av01.au.ibm.com (localhost [127.0.0.1]) by d23av01.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u5MDZPFx001816; Wed, 22 Jun 2016 23:35:26 +1000 Received: from localhost.localdomain.localdomain ([9.80.83.79]) by d23av01.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u5MDZAsk001467; Wed, 22 Jun 2016 23:35:23 +1000 From: Mimi Zohar To: linux-security-module , linux-ima-devel Cc: Dave Young , kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Eric Biederman , Mimi Zohar Subject: [PATCH 3/3] ima: add pre-calculated measurements (experimental) Date: Wed, 22 Jun 2016 09:35:05 -0400 X-Mailer: git-send-email 2.1.0 In-Reply-To: <1466602505-21915-1-git-send-email-zohar@linux.vnet.ibm.com> References: <1466602505-21915-1-git-send-email-zohar@linux.vnet.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16062213-0008-0000-0000-0000009C4214 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16062213-0009-0000-0000-00000783DE5C Message-Id: <1466602505-21915-4-git-send-email-zohar@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-06-22_09:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=2 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1604210000 definitions=main-1606220145 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP This patch defines a new IMA hook named ima_add_measurement_check() for including pre-calculated measurements in the IMA measurement list. Signed-off-by: Mimi Zohar --- Documentation/ABI/testing/ima_policy | 2 +- include/linux/ima.h | 12 ++++ security/integrity/ima/Kconfig | 8 +++ security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_buffer.c | 116 +++++++++++++++++++++++++++++------ security/integrity/ima/ima_policy.c | 18 +++++- 6 files changed, 136 insertions(+), 21 deletions(-) diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 5a99c6f..e5a137e 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -28,7 +28,7 @@ Description: base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK] [FIRMWARE_CHECK] [KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK] - [KEXEC_CMDLINE_CHECK] + [KEXEC_CMDLINE_CHECK] [PRECALC_CHECK] mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND] [[^]MAY_EXEC] fsmagic:= hex value diff --git a/include/linux/ima.h b/include/linux/ima.h index 88203f9..797de51 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -15,6 +15,7 @@ struct linux_binprm; enum ima_buffer_id { MEASURING_KEXEC_CMDLINE, + MEASURING_PRECALC_DATA, MEASURING_MAX_BUFFER_ID }; @@ -29,6 +30,9 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size, extern void ima_post_path_mknod(struct dentry *dentry); extern void ima_buffer_check(void *buf, loff_t size, enum ima_buffer_id buffer_id); +extern void ima_add_measurement_check(const char *hashname, u8 *digest, + loff_t size, enum ima_buffer_id buffer_id, + char *hint); #else static inline int ima_bprm_check(struct linux_binprm *bprm) @@ -72,6 +76,14 @@ static inline void ima_buffer_check(void *buf, loff_t size, { return; } + +static inline void ima_add_measurement_check(const char *hashname, u8 *digest, + loff_t size, + enum ima_buffer_id buffer_id, + char *hint) +{ + return; +} #endif /* CONFIG_IMA */ #ifdef CONFIG_IMA_APPRAISE diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 5487827..0fb54d3 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -44,6 +44,14 @@ config IMA_LSM_RULES help Disabling this option will disregard LSM based policy rules. +config IMA_PRECALC_RULES + bool "Permit pre-calculated measurements (EXPERIMENTAL)" + depends on IMA + default n + help + Enabling this option will permit pre-calculated measurements + to be added to the IMA measurement list. + choice prompt "Default template" default IMA_NG_TEMPLATE diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 5f21a9a..ccad21d 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -152,6 +152,7 @@ enum ima_hooks { KEXEC_INITRAMFS_CHECK, KEXEC_CMDLINE_CHECK, POLICY_CHECK, + PRECALC_CHECK, MAX_CHECK }; diff --git a/security/integrity/ima/ima_buffer.c b/security/integrity/ima/ima_buffer.c index e74131b..ad49f6c 100644 --- a/security/integrity/ima/ima_buffer.c +++ b/security/integrity/ima/ima_buffer.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "ima.h" @@ -21,9 +23,37 @@ struct buffer_idmap { static struct buffer_idmap _idmap[MEASURING_MAX_BUFFER_ID] = { [MEASURING_KEXEC_CMDLINE].func = KEXEC_CMDLINE_CHECK, - [MEASURING_KEXEC_CMDLINE].buf = "boot-cmdline", + [MEASURING_KEXEC_CMDLINE].buf = "kexec-boot-cmdline", + [MEASURING_PRECALC_DATA].func = PRECALC_CHECK, + [MEASURING_PRECALC_DATA].buf = "precalc", }; +#define IMA_MAX_BUFFER_HINT_SIZE 255 + +static int store_buffer_measurement(struct ima_digest_data *hash, int pcr, + char *buffer_hint) +{ + struct ima_template_entry *entry; + struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; + struct ima_event_data event_data = {iint, NULL, NULL, NULL, 0, NULL}; + int violation = 0; + int result; + + iint->ima_hash = hash; + event_data.filename = buffer_hint; + + result = ima_alloc_init_template(&event_data, &entry); + if (result < 0) + return result; + + result = ima_store_template(entry, violation, NULL, + event_data.filename, pcr); + if (result < 0) + ima_free_template_entry(entry); + + return result; +} + static void process_buffer_measurement(void *buf, loff_t size, enum ima_buffer_id buffer_id, int pcr) { @@ -31,10 +61,6 @@ static void process_buffer_measurement(void *buf, loff_t size, struct ima_digest_data hdr; char digest[IMA_MAX_DIGEST_SIZE]; } hash; - struct ima_template_entry *entry; - struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; - struct ima_event_data event_data = {iint, NULL, NULL, NULL, 0, NULL}; - int violation = 0; int result; memset(&hash, 0, sizeof(hash)); @@ -45,20 +71,10 @@ static void process_buffer_measurement(void *buf, loff_t size, return; } - iint->ima_hash = &hash.hdr; - event_data.filename = _idmap[buffer_id].buf; - result = ima_alloc_init_template(&event_data, &entry); - if (result < 0) { - pr_debug("failed allocating template\n"); - return; - } - - result = ima_store_template(entry, violation, NULL, - event_data.filename, pcr); - if (result < 0) { + result = store_buffer_measurement(&hash.hdr, pcr, + _idmap[buffer_id].buf); + if (result < 0) pr_debug("failed storing buffer measurement\n"); - ima_free_template_entry(entry); - } } /** @@ -82,3 +98,67 @@ void ima_buffer_check(void *buf, loff_t size, enum ima_buffer_id buffer_id) process_buffer_measurement(buf, size, buffer_id, pcr); } EXPORT_SYMBOL_GPL(ima_buffer_check); + +/** + * ima_add_measurement_check - add pre-calculated hash measurement + * @hashname: pointer to hash algorithm name + * @digest: pointer to hash digest + * @size: hash digest size + * @buffer_id: caller identifier + * @hint: measurement identifier + * + * Include pre-calculated hash measurements in the IMA measurement list. + */ +void ima_add_measurement_check(const char *hashname, u8 *digest, loff_t size, + enum ima_buffer_id buffer_id, char *hint) +{ + struct { + struct ima_digest_data hdr; + char digest[IMA_MAX_DIGEST_SIZE]; + } hash; + int pcr = CONFIG_IMA_MEASURE_PCR_IDX; + char buffer_hint[IMA_MAX_BUFFER_HINT_SIZE]; + char *buf; + int result, i; + + if (buffer_id > MEASURING_MAX_BUFFER_ID) + return; + + if (!ima_match_buffer_id(_idmap[buffer_id].func, &pcr)) + return; + + if (!hint) { + pr_debug("missing buffer hint\n"); + return; + } + + buf = kstrdup_quotable(hint, GFP_KERNEL); + if (!buf) { + pr_debug("failed quoting buffer hint\n"); + return; + } + + /* Limit the total measurement hint to IMA_MAX_BUFFER_HINT_SIZE. */ + snprintf(buffer_hint, sizeof(buffer_hint), "(%s) %s", + _idmap[buffer_id].buf, buf); + kfree(buf); + + memset(&hash, 0, sizeof(hash)); + for (i = 1; i < HASH_ALGO__LAST; i++) { + if (strcmp(hashname, hash_algo_name[i]) != 0) + continue; + hash.hdr.algo = i; + break; + } + if (hash.hdr.algo == 0) { + pr_debug("invalid hash algorithm (%d)\n", hash.hdr.algo); + return; + } + + hash.hdr.length = size; + memcpy(&hash.hdr.digest, digest, size); + result = store_buffer_measurement(&hash.hdr, pcr, buffer_hint); + if (result < 0) + pr_debug("failed to store buffer measurement\n"); +} +EXPORT_SYMBOL_GPL(ima_add_measurement_check); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 8e53f84..4094dd7 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "ima.h" @@ -54,6 +55,12 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; +#ifdef CONFIG_MEASURING_PRECALC_RULES +static int permit_measuring_precalc_rules = 1; +#else +static int permit_measuring_precalc_rules; +#endif + struct ima_rule_entry { struct list_head list; int action; @@ -668,6 +675,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->func = KEXEC_CMDLINE_CHECK; else if (strcmp(args[0].from, "POLICY_CHECK") == 0) entry->func = POLICY_CHECK; + else if ((strcmp(args[0].from, "PRECALC_CHECK") == 0) + && permit_measuring_precalc_rules) + entry->func = PRECALC_CHECK; else result = -EINVAL; if (!result) @@ -929,7 +939,7 @@ enum { func_file = 0, func_mmap, func_bprm, func_module, func_firmware, func_post, func_kexec_kernel, func_kexec_initramfs, - func_kexec_cmdline, func_policy + func_kexec_cmdline, func_policy, func_precalc }; static char *func_tokens[] = { @@ -942,7 +952,8 @@ static char *func_tokens[] = { "KEXEC_KERNEL_CHECK", "KEXEC_INITRAMFS_CHECK", "KEXEC_CMDLINE_CHECK", - "POLICY_CHECK" + "POLICY_CHECK", + "PRECALC_CHECK" }; void *ima_policy_start(struct seq_file *m, loff_t *pos) @@ -1019,6 +1030,9 @@ static void policy_func_show(struct seq_file *m, enum ima_hooks func) case POLICY_CHECK: seq_printf(m, pt(Opt_func), ft(func_policy)); break; + case PRECALC_CHECK: + seq_printf(m, pt(Opt_func), ft(func_precalc)); + break; default: snprintf(tbuf, sizeof(tbuf), "%d", func); seq_printf(m, pt(Opt_func), tbuf);