From patchwork Thu Jul 16 17:43:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lakshmi Ramasubramanian X-Patchwork-Id: 11668193 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 778FD1392 for ; Thu, 16 Jul 2020 17:44:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5B1142076A for ; Thu, 16 Jul 2020 17:44:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="apr1YUY8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729442AbgGPRoF (ORCPT ); Thu, 16 Jul 2020 13:44:05 -0400 Received: from linux.microsoft.com ([13.77.154.182]:54466 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728705AbgGPRoE (ORCPT ); Thu, 16 Jul 2020 13:44:04 -0400 Received: from localhost.localdomain (c-73-42-176-67.hsd1.wa.comcast.net [73.42.176.67]) by linux.microsoft.com (Postfix) with ESMTPSA id 0416720B490A; Thu, 16 Jul 2020 10:44:02 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 0416720B490A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1594921443; bh=JPlRumbOfvyOco8L8nkT1d2Rp+0/lx8FfGi5jva830E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=apr1YUY8lUr0p4AFF0sGw6AFS27S8wFf3xBss3qRcwYGv2VPW3FxF4nll3LQuhXog aacXn6a6kYy9vuvbncgTDkQl6RvcM6JAo9iiaSd3pIeveQIFFCI+haNN44PZwSRd2x +Z7/+7jLkmJo6IOgx6HmmnfCIvUBQNEIZgndodBM= From: Lakshmi Ramasubramanian To: zohar@linux.ibm.com, stephen.smalley.work@gmail.com, casey@schaufler-ca.com Cc: jmorris@namei.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/5] IMA: Add LSM_STATE func to measure LSM data Date: Thu, 16 Jul 2020 10:43:47 -0700 Message-Id: <20200716174351.20128-2-nramas@linux.microsoft.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200716174351.20128-1-nramas@linux.microsoft.com> References: <20200716174351.20128-1-nramas@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Critical data structures of security modules need to be measured to enable an attestation service to verify if the policies and configuration have been setup correctly and that they haven't been tampered with at runtime. A new IMA policy is required for handling this measurement. Define a new IMA policy func namely LSM_STATE to measure data provided by security modules. Update ima_match_rules() to check for LSM_STATE and ima_parse_rule() to handle LSM_STATE. Signed-off-by: Lakshmi Ramasubramanian --- Documentation/ABI/testing/ima_policy | 6 +++++- security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_api.c | 2 +- security/integrity/ima/ima_policy.c | 29 +++++++++++++++++++++++----- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index cd572912c593..355bc3eade33 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -29,7 +29,7 @@ Description: base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK] [FIRMWARE_CHECK] [KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK] - [KEXEC_CMDLINE] [KEY_CHECK] + [KEXEC_CMDLINE] [KEY_CHECK] [LSM_STATE] mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND] [[^]MAY_EXEC] fsmagic:= hex value @@ -125,3 +125,7 @@ Description: keys added to .builtin_trusted_keys or .ima keyring: measure func=KEY_CHECK keyrings=.builtin_trusted_keys|.ima + + Example of measure rule using LSM_STATE to measure LSM data: + + measure func=LSM_STATE diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 4515975cc540..880fda11a61b 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -200,6 +200,7 @@ static inline unsigned int ima_hash_key(u8 *digest) hook(POLICY_CHECK, policy) \ hook(KEXEC_CMDLINE, kexec_cmdline) \ hook(KEY_CHECK, key) \ + hook(LSM_STATE, lsm_state) \ hook(MAX_CHECK, none) #define __ima_hook_enumify(ENUM, str) ENUM, diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index bf22de8b7ce0..0cebd2404dcf 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -176,7 +176,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * subj=, obj=, type=, func=, mask=, fsmagic= * subj,obj, and type: are LSM specific. * func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK - * | KEXEC_CMDLINE | KEY_CHECK + * | KEXEC_CMDLINE | KEY_CHECK | LSM_STATE * mask: contains the permission mask * fsmagic: hex value * diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 66aa3e17a888..fc8457d9242b 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -417,15 +417,31 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, const char *keyring) { int i; + int funcmatch = 0; - if ((func == KEXEC_CMDLINE) || (func == KEY_CHECK)) { + switch (func) { + case KEXEC_CMDLINE: + case KEY_CHECK: + case LSM_STATE: if ((rule->flags & IMA_FUNC) && (rule->func == func)) { if (func == KEY_CHECK) - return ima_match_keyring(rule, keyring, cred); - return true; - } - return false; + funcmatch = ima_match_keyring(rule, keyring, + cred) ? 1 : -1; + else + funcmatch = 1; + } else + funcmatch = -1; + + break; + + default: + funcmatch = 0; + break; } + + if (funcmatch) + return (funcmatch == 1) ? true : false; + if ((rule->flags & IMA_FUNC) && (rule->func != func && func != POST_SETATTR)) return false; @@ -1068,6 +1084,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->func = KEXEC_CMDLINE; else if (strcmp(args[0].from, "KEY_CHECK") == 0) entry->func = KEY_CHECK; + else if (strcmp(args[0].from, "LSM_STATE") == 0) + entry->func = LSM_STATE; + else result = -EINVAL; if (!result) From patchwork Thu Jul 16 17:43:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lakshmi Ramasubramanian X-Patchwork-Id: 11668215 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C09B11510 for ; Thu, 16 Jul 2020 17:44:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A55EF207BC for ; Thu, 16 Jul 2020 17:44:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="dIjUJK4P" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729535AbgGPRoZ (ORCPT ); Thu, 16 Jul 2020 13:44:25 -0400 Received: from linux.microsoft.com ([13.77.154.182]:54476 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729415AbgGPRoE (ORCPT ); Thu, 16 Jul 2020 13:44:04 -0400 Received: from localhost.localdomain (c-73-42-176-67.hsd1.wa.comcast.net [73.42.176.67]) by linux.microsoft.com (Postfix) with ESMTPSA id 467EC20B490C; Thu, 16 Jul 2020 10:44:03 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 467EC20B490C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1594921443; bh=uMfFSH8BKWRMGn0Ob/aAF/poLIpxKXFWWoJsEWCn7j0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dIjUJK4PMD8yUDiTmHnKezBpnWOWLdnvWlPcbEvwaoPlheDB5Lf9uoT4UVTIYS99Z OjjKf6ICdE+C85mxymMBAUdhtHOjpH7pT3MGOY0ZWys/t8ptW5+pVuN5opJfIwi9lk DPQY3JzF3Hqqjzhu9/jJfCzlvUvmnidkYXGySyMU= From: Lakshmi Ramasubramanian To: zohar@linux.ibm.com, stephen.smalley.work@gmail.com, casey@schaufler-ca.com Cc: jmorris@namei.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/5] IMA: Define an IMA hook to measure LSM data Date: Thu, 16 Jul 2020 10:43:48 -0700 Message-Id: <20200716174351.20128-3-nramas@linux.microsoft.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200716174351.20128-1-nramas@linux.microsoft.com> References: <20200716174351.20128-1-nramas@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org IMA subsystem needs to define an IMA hook that the security modules can call to measure critical data of the security modules. Define a new IMA hook, namely ima_lsm_state(), that the security modules can call to measure data. Signed-off-by: Lakshmi Ramasubramanian --- include/linux/ima.h | 4 ++++ security/integrity/ima/ima_main.c | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/linux/ima.h b/include/linux/ima.h index 9164e1534ec9..7e2686f4953a 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -26,6 +26,7 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size, extern void ima_post_path_mknod(struct dentry *dentry); extern int ima_file_hash(struct file *file, char *buf, size_t buf_size); extern void ima_kexec_cmdline(const void *buf, int size); +extern void ima_lsm_state(const char *lsm_event_name, const void *buf, int size); #ifdef CONFIG_IMA_KEXEC extern void ima_add_kexec_buffer(struct kimage *image); @@ -104,6 +105,9 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size) } static inline void ima_kexec_cmdline(const void *buf, int size) {} + +static inline void ima_lsm_state(const char *lsm_event_name, + const void *buf, int size) {} #endif /* CONFIG_IMA */ #ifndef CONFIG_IMA_KEXEC diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 8351b2fd48e0..04d9a1d35300 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -835,6 +835,23 @@ void ima_kexec_cmdline(const void *buf, int size) KEXEC_CMDLINE, 0, NULL); } +/** + * ima_lsm_state - measure LSM specific state + * @lsm_event_name: LSM event + * @buf: pointer to buffer containing LSM specific state + * @size: Number of bytes in buf + * + * Buffers can only be measured, not appraised. + */ +void ima_lsm_state(const char *lsm_event_name, const void *buf, int size) +{ + if (!lsm_event_name || !buf || !size) + return; + + process_buffer_measurement(buf, size, lsm_event_name, + LSM_STATE, 0, NULL); +} + static int __init init_ima(void) { int error; From patchwork Thu Jul 16 17:43:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lakshmi Ramasubramanian X-Patchwork-Id: 11668201 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 947111392 for ; Thu, 16 Jul 2020 17:44:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 79B0F2076D for ; Thu, 16 Jul 2020 17:44:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="V2kfrWmU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729508AbgGPRoQ (ORCPT ); Thu, 16 Jul 2020 13:44:16 -0400 Received: from linux.microsoft.com ([13.77.154.182]:54484 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729416AbgGPRoE (ORCPT ); Thu, 16 Jul 2020 13:44:04 -0400 Received: from localhost.localdomain (c-73-42-176-67.hsd1.wa.comcast.net [73.42.176.67]) by linux.microsoft.com (Postfix) with ESMTPSA id 8BA4920B490D; Thu, 16 Jul 2020 10:44:03 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8BA4920B490D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1594921443; bh=RWokx6Gd27oCAJ3WfeSZo3rN7tWPRY28o2No3gTEX3A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=V2kfrWmU7YIfIqlbgLC/mi8r0ZWO2GiMiSjgSWF43XfOjVpq2lG7EXeViNital8Ba frJZ9rLF8E0IBRk9rJWbjQLzV5PIjL8EvwOYxywk2PiskVEa8NBn9UKmK+dGbdLmyn Rauqdot2l24h+eHytODFuglMFpsm9DGTt1szL3Gc= From: Lakshmi Ramasubramanian To: zohar@linux.ibm.com, stephen.smalley.work@gmail.com, casey@schaufler-ca.com Cc: jmorris@namei.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 3/5] LSM: Add security_measure_data in lsm_info struct Date: Thu, 16 Jul 2020 10:43:49 -0700 Message-Id: <20200716174351.20128-4-nramas@linux.microsoft.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200716174351.20128-1-nramas@linux.microsoft.com> References: <20200716174351.20128-1-nramas@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org The security modules that require their data to be measured using the IMA subsystem need to define a function that the LSM can call to trigger the measurement. Add a function pointer field namely security_measure_data in lsm_info structure. Update LSM to call this security module function, if defined, to measure the security module's data using the IMA subsystem. Signed-off-by: Lakshmi Ramasubramanian --- include/linux/lsm_hooks.h | 3 +++ security/security.c | 48 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 95b7c1d32062..56f0e524838c 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1591,6 +1591,9 @@ struct lsm_info { int *enabled; /* Optional: controlled by CONFIG_LSM */ int (*init)(void); /* Required. */ struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */ + int (*security_measure_data)(void); /* Optional: for measuring + * security module data. + */ }; extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; diff --git a/security/security.c b/security/security.c index 70a7ad357bc6..1afa2aebc3ac 100644 --- a/security/security.c +++ b/security/security.c @@ -86,6 +86,9 @@ static __initconst const char * const builtin_lsm_order = CONFIG_LSM; static __initdata struct lsm_info **ordered_lsms; static __initdata struct lsm_info *exclusive; +static struct lsm_info *security_state_lsms; +static int security_state_lsms_count; + static __initdata bool debug; #define init_debug(...) \ do { \ @@ -235,6 +238,45 @@ static void __init initialize_lsm(struct lsm_info *lsm) } } +static int measure_security_state(struct lsm_info *lsm) +{ + if (!lsm->security_measure_data) + return 0; + + return lsm->security_measure_data(); +} + +static void __init initialize_security_state_lsms(void) +{ + struct lsm_info **lsm; + int count = 0; + int inx; + + for (lsm = ordered_lsms; *lsm; lsm++) { + if ((*lsm)->security_measure_data) + count++; + } + + if (count == 0) + return; + + security_state_lsms = kcalloc(count, sizeof(struct lsm_info), + GFP_KERNEL); + if (!security_state_lsms) + return; + + inx = 0; + for (lsm = ordered_lsms; *lsm; lsm++) { + if ((*lsm)->security_measure_data) { + security_state_lsms[inx].security_measure_data = + (*lsm)->security_measure_data; + inx++; + } + } + + security_state_lsms_count = count; +} + /* Populate ordered LSMs list from comma-separated LSM name list. */ static void __init ordered_lsm_parse(const char *order, const char *origin) { @@ -352,8 +394,12 @@ static void __init ordered_lsm_init(void) lsm_early_cred((struct cred *) current->cred); lsm_early_task(current); - for (lsm = ordered_lsms; *lsm; lsm++) + for (lsm = ordered_lsms; *lsm; lsm++) { initialize_lsm(*lsm); + measure_security_state(*lsm); + } + + initialize_security_state_lsms(); kfree(ordered_lsms); } From patchwork Thu Jul 16 17:43:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lakshmi Ramasubramanian X-Patchwork-Id: 11668189 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 399706C1 for ; Thu, 16 Jul 2020 17:44:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 113422076D for ; Thu, 16 Jul 2020 17:44:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="CkdaOMyo" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729471AbgGPRoH (ORCPT ); Thu, 16 Jul 2020 13:44:07 -0400 Received: from linux.microsoft.com ([13.77.154.182]:54502 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729427AbgGPRoG (ORCPT ); Thu, 16 Jul 2020 13:44:06 -0400 Received: from localhost.localdomain (c-73-42-176-67.hsd1.wa.comcast.net [73.42.176.67]) by linux.microsoft.com (Postfix) with ESMTPSA id D786E20B490E; Thu, 16 Jul 2020 10:44:03 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com D786E20B490E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1594921444; bh=/fzFj/g8BpvBn9QTy27JmP5NXEAgLB6VRZyIXN1doC4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CkdaOMyooOGmsBVmT/Kczg1RSKLzNgxffuNSO+hLAPJcJmr9SePzFAEnDsPDZucxI 8fkR1MxujJlkjrT0HQe68R7fTQ5Znb04cRwmNQt//0ELofjAn3evTTZWO9Y6afIcDB jYT6lJbzfzwjKS1oMBUJL3s1N12rL5ab5asddmuY= From: Lakshmi Ramasubramanian To: zohar@linux.ibm.com, stephen.smalley.work@gmail.com, casey@schaufler-ca.com Cc: jmorris@namei.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 4/5] LSM: Define SELinux function to measure security state Date: Thu, 16 Jul 2020 10:43:50 -0700 Message-Id: <20200716174351.20128-5-nramas@linux.microsoft.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200716174351.20128-1-nramas@linux.microsoft.com> References: <20200716174351.20128-1-nramas@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org SELinux configuration and policy are some of the critical data for this security module that needs to be measured. To enable this measurement SELinux needs to implement the interface function, security_measure_data(), that the LSM can call. Define the security_state() function in SELinux to measure SELinux configuration and policy. Call this function to measure SELinux data when there is a change in the security module's state. Sample measurement of SELinux state and hash of the policy: 10 e32e...5ac3 ima-buf sha256:86e8...4594 selinux-state 656e61626c65643d313b656e666f7263696e673d303b636865636b72657170726f743d313b6e6574706565723d313b6f70656e7065726d3d313b657874736f636b636c6173733d313b616c776179736e6574776f726b3d303b6367726f75707365636c6162656c3d313b6e6e706e6f737569647472616e736974696f6e3d313b67656e66737365636c6162656c73796d6c696e6b3d303b 10 f4a7...9408 ima-buf sha256:4941...68fc selinux-policy-hash 8d1d...1834 The data for selinux-state in the above measurement is: enabled=1;enforcing=0;checkreqprot=1;network_peer_controls=1;open_perms=1;extended_socket_class=1;always_check_network=0;cgroup_seclabel=1;nnp_nosuid_transition=1;genfs_seclabel_symlinks=0; The data for selinux-policy-hash in the above measurement is the SHA256 hash of the SELinux policy. Signed-off-by: Lakshmi Ramasubramanian Suggested-by: Stephen Smalley --- security/selinux/Makefile | 2 + security/selinux/hooks.c | 4 + security/selinux/include/security.h | 26 +++++ security/selinux/measure.c | 158 ++++++++++++++++++++++++++++ security/selinux/selinuxfs.c | 1 + security/selinux/ss/services.c | 66 ++++++++++-- 6 files changed, 248 insertions(+), 9 deletions(-) create mode 100644 security/selinux/measure.c diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 4d8e0e8adf0b..83d512116341 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -16,6 +16,8 @@ selinux-$(CONFIG_NETLABEL) += netlabel.o selinux-$(CONFIG_SECURITY_INFINIBAND) += ibpkey.o +selinux-$(CONFIG_IMA) += measure.o + ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index efa6108b1ce9..cda1d328339f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -7259,6 +7259,8 @@ static __init int selinux_init(void) fs_validate_description("selinux", selinux_fs_parameters); + selinux_init_measurement(); + return 0; } @@ -7284,6 +7286,7 @@ DEFINE_LSM(selinux) = { .enabled = &selinux_enabled_boot, .blobs = &selinux_blob_sizes, .init = selinux_init, + .security_measure_data = selinux_measure_data, }; #if defined(CONFIG_NETFILTER) @@ -7394,6 +7397,7 @@ int selinux_disable(struct selinux_state *state) } selinux_mark_disabled(state); + selinux_measure_state(state); pr_info("SELinux: Disabled at runtime.\n"); diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index b0e02cfe3ce1..628062ff9bba 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -222,16 +222,42 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void) return state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]; } +static inline bool selinux_checkreqprot(const struct selinux_state *state) +{ + return READ_ONCE(state->checkreqprot); +} + int security_mls_enabled(struct selinux_state *state); int security_load_policy(struct selinux_state *state, void *data, size_t len); int security_read_policy(struct selinux_state *state, void **data, size_t *len); +int security_read_policy_kernel(struct selinux_state *state, + void **data, size_t *len); size_t security_policydb_len(struct selinux_state *state); int security_policycap_supported(struct selinux_state *state, unsigned int req_cap); +#ifdef CONFIG_IMA +extern void __init selinux_init_measurement(void); +extern int selinux_measure_data(void); +extern int selinux_measure_state(struct selinux_state *selinux_state); +#else +static inline void __init selinux_init_measurement(void) {} + +static inline int selinux_measure_data(void) +{ + return 0; +} + +static inline int selinux_measure_state( + struct selinux_state *selinux_state) +{ + return 0; +} +#endif + #define SEL_VEC_MAX 32 struct av_decision { u32 allowed; diff --git a/security/selinux/measure.c b/security/selinux/measure.c new file mode 100644 index 000000000000..27cbb309e926 --- /dev/null +++ b/security/selinux/measure.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Measure SELinux state using IMA subsystem. + */ +#include +#include "security.h" + +/* Pre-allocated buffer used for measuring state */ +static char *selinux_state_string; +static size_t selinux_state_string_len; +static char *selinux_state_string_fmt = + "%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;"; + +void __init selinux_init_measurement(void) +{ + selinux_state_string_len = + snprintf(NULL, 0, selinux_state_string_fmt, + "enabled", 0, + "enforcing", 0, + "checkreqprot", 0, + selinux_policycap_names[POLICYDB_CAPABILITY_NETPEER], 0, + selinux_policycap_names[POLICYDB_CAPABILITY_OPENPERM], 0, + selinux_policycap_names[POLICYDB_CAPABILITY_EXTSOCKCLASS], 0, + selinux_policycap_names[POLICYDB_CAPABILITY_ALWAYSNETWORK], 0, + selinux_policycap_names[POLICYDB_CAPABILITY_CGROUPSECLABEL], 0, + selinux_policycap_names[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION], 0, + selinux_policycap_names[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS], + 0); + + if (selinux_state_string_len < 0) + return; + + ++selinux_state_string_len; + + selinux_state_string = kzalloc(selinux_state_string_len, GFP_KERNEL); + if (!selinux_state_string) + selinux_state_string_len = 0; +} + +static int selinux_hash_policy(const char *hash_alg_name, + void *policy, size_t policy_len, + void **policy_hash, int *policy_hash_len) +{ + struct crypto_shash *tfm; + struct shash_desc *desc = NULL; + void *digest = NULL; + int desc_size; + int digest_size; + int ret = 0; + + tfm = crypto_alloc_shash(hash_alg_name, 0, 0); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); + digest_size = crypto_shash_digestsize(tfm); + + digest = kmalloc(digest_size, GFP_KERNEL); + if (!digest) { + ret = -ENOMEM; + goto error; + } + + desc = kzalloc(desc_size, GFP_KERNEL); + if (!desc) { + ret = -ENOMEM; + goto error; + } + + desc->tfm = tfm; + + ret = crypto_shash_digest(desc, policy, policy_len, digest); + if (ret < 0) + goto error; + + *policy_hash_len = digest_size; + *policy_hash = digest; + digest = NULL; + +error: + kfree(desc); + kfree(digest); + + crypto_free_shash(tfm); + + if (ret) + pr_err("%s: error %d\n", __func__, ret); + + return ret; +} + +int selinux_measure_state(struct selinux_state *selinux_state) +{ + void *policy = NULL; + void *policy_hash = NULL; + int count; + size_t buflen; + int policy_hash_len; + int rc = 0; + + if (!selinux_initialized(selinux_state)) + return -EOPNOTSUPP; + + if (!selinux_state_string) + return -ENOMEM; + + count = + snprintf( + selinux_state_string, selinux_state_string_len, + selinux_state_string_fmt, + "enabled", !selinux_disabled(selinux_state), + "enforcing", enforcing_enabled(selinux_state), + "checkreqprot", selinux_checkreqprot(selinux_state), + selinux_policycap_names[POLICYDB_CAPABILITY_NETPEER], + selinux_state->policycap[POLICYDB_CAPABILITY_NETPEER], + selinux_policycap_names[POLICYDB_CAPABILITY_OPENPERM], + selinux_state->policycap[POLICYDB_CAPABILITY_OPENPERM], + selinux_policycap_names[POLICYDB_CAPABILITY_EXTSOCKCLASS], + selinux_state->policycap[POLICYDB_CAPABILITY_EXTSOCKCLASS], + selinux_policycap_names[POLICYDB_CAPABILITY_ALWAYSNETWORK], + selinux_state->policycap[POLICYDB_CAPABILITY_ALWAYSNETWORK], + selinux_policycap_names[POLICYDB_CAPABILITY_CGROUPSECLABEL], + selinux_state->policycap[POLICYDB_CAPABILITY_CGROUPSECLABEL], + selinux_policycap_names[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION], + selinux_state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION], + selinux_policycap_names[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS], + selinux_state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]); + + if (count >= 0 && count < selinux_state_string_len) + ima_lsm_state("selinux-state", selinux_state_string, count); + else { + pr_err("selinux state error: %d\n", count); + rc = -EINVAL; + goto out; + } + + rc = security_read_policy_kernel(selinux_state, &policy, &buflen); + if (!rc) + rc = selinux_hash_policy("sha256", policy, buflen, + &policy_hash, &policy_hash_len); + if (!rc) + ima_lsm_state("selinux-policy-hash", policy_hash, + policy_hash_len); + +out: + vfree(policy); + kfree(policy_hash); + + if (rc) + pr_err("%s: error %d\n", __func__, rc); + + return rc; +} + +int selinux_measure_data(void) +{ + return selinux_measure_state(&selinux_state); +} diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 4781314c2510..b1f70739d709 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -173,6 +173,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); enforcing_set(state, new_value); + selinux_measure_state(&selinux_state); if (new_value) avc_ss_reset(state->avc, 0); selnl_notify_setenforce(new_value); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index ef0afd878bfc..79a6b462f1fe 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -3720,14 +3720,22 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state, } #endif /* CONFIG_NETLABEL */ +static int security_read_policy_len(struct selinux_state *state, size_t *len) +{ + if (!selinux_initialized(state)) + return -EINVAL; + + *len = security_policydb_len(state); + return 0; +} + /** * security_read_policy - read the policy. * @data: binary policy data * @len: length of data in bytes - * */ -int security_read_policy(struct selinux_state *state, - void **data, size_t *len) +int security_read_selinux_policy(struct selinux_state *state, + void **data, size_t *len) { struct policydb *policydb = &state->ss->policydb; int rc; @@ -3736,12 +3744,6 @@ int security_read_policy(struct selinux_state *state, if (!selinux_initialized(state)) return -EINVAL; - *len = security_policydb_len(state); - - *data = vmalloc_user(*len); - if (!*data) - return -ENOMEM; - fp.data = *data; fp.len = *len; @@ -3754,5 +3756,51 @@ int security_read_policy(struct selinux_state *state, *len = (unsigned long)fp.data - (unsigned long)*data; return 0; +} + +/** + * security_read_policy - read the policy. + * @data: binary policy data + * @len: length of data in bytes + * + */ +int security_read_policy(struct selinux_state *state, + void **data, size_t *len) +{ + int rc; + + rc = security_read_policy_len(state, len); + if (rc) + return rc; + + *data = vmalloc_user(*len); + if (!*data) + return -ENOMEM; + + return security_read_selinux_policy(state, data, len); +} + +/** + * security_read_policy_kernel - read the policy. + * @data: binary policy data + * @len: length of data in bytes + * + * Allocates kernel memory for reading SELinux policy. + * This function is for internal use only and should not + * be used for returning data to user space + */ +int security_read_policy_kernel(struct selinux_state *state, + void **data, size_t *len) +{ + int rc; + + rc = security_read_policy_len(state, len); + if (rc) + return rc; + + *data = vmalloc(*len); + if (!*data) + return -ENOMEM; + return security_read_selinux_policy(state, data, len); } From patchwork Thu Jul 16 17:43:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lakshmi Ramasubramanian X-Patchwork-Id: 11668207 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A2F876C1 for ; Thu, 16 Jul 2020 17:44:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7E569207BC for ; Thu, 16 Jul 2020 17:44:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="ZggH5bsH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729427AbgGPRoP (ORCPT ); Thu, 16 Jul 2020 13:44:15 -0400 Received: from linux.microsoft.com ([13.77.154.182]:54512 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729432AbgGPRoF (ORCPT ); Thu, 16 Jul 2020 13:44:05 -0400 Received: from localhost.localdomain (c-73-42-176-67.hsd1.wa.comcast.net [73.42.176.67]) by linux.microsoft.com (Postfix) with ESMTPSA id 33CC520B490F; Thu, 16 Jul 2020 10:44:04 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 33CC520B490F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1594921444; bh=mgND1QTe5Ztcv9Kvm/Chu/AhsMHOCtifBt1wUR59OJg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZggH5bsHm6of+unxW8oNu9IzB5aTHoePLY+eSifN8VHwiCCeD7Ka8cEwwjhykBIiN 6QkozYVnGvAPbLU1uqwZ818aya2br+V6So+XvMLY6mXV5kEpvbs9GKK7zqD8enFaPk 2Yzx9cDFJw2/skxXH2IrZH2DPnTqwk09RUbjLkXY= From: Lakshmi Ramasubramanian To: zohar@linux.ibm.com, stephen.smalley.work@gmail.com, casey@schaufler-ca.com Cc: jmorris@namei.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 5/5] LSM: Define workqueue for measuring security module state Date: Thu, 16 Jul 2020 10:43:51 -0700 Message-Id: <20200716174351.20128-6-nramas@linux.microsoft.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200716174351.20128-1-nramas@linux.microsoft.com> References: <20200716174351.20128-1-nramas@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Data structures critical to the functioning of a security module could be tampered with by malware or changed inadvertently at runtime thereby disabling or reducing the security guarantees provided by the security module. Such critical data need to be periodically checked and measured, if there is any change. This would enable an attestation service, for instance, to verify that the security modules are operating with the configuration and policy setup by the system administrator. Define a workqueue in the LSM and invoke the security modules in the workqueue handler to check their data and measure. Note that the data given by the security module would be measured by the IMA subsystem only if it has changed since the last time it was measured. Signed-off-by: Lakshmi Ramasubramanian --- security/security.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/security/security.c b/security/security.c index 1afa2aebc3ac..63b30da337d8 100644 --- a/security/security.c +++ b/security/security.c @@ -89,6 +89,11 @@ static __initdata struct lsm_info *exclusive; static struct lsm_info *security_state_lsms; static int security_state_lsms_count; +static long security_state_timeout = 300000; /* 5 Minutes */ +static void security_state_handler(struct work_struct *work); +static DECLARE_DELAYED_WORK(security_state_delayed_work, + security_state_handler); + static __initdata bool debug; #define init_debug(...) \ do { \ @@ -277,6 +282,26 @@ static void __init initialize_security_state_lsms(void) security_state_lsms_count = count; } +static void initialize_security_state_monitor(void) +{ + if (security_state_lsms_count == 0) + return; + + schedule_delayed_work(&security_state_delayed_work, + msecs_to_jiffies(security_state_timeout)); +} + +static void security_state_handler(struct work_struct *work) +{ + int inx; + + for (inx = 0; inx < security_state_lsms_count; inx++) + measure_security_state(&(security_state_lsms[inx])); + + schedule_delayed_work(&security_state_delayed_work, + msecs_to_jiffies(security_state_timeout)); +} + /* Populate ordered LSMs list from comma-separated LSM name list. */ static void __init ordered_lsm_parse(const char *order, const char *origin) { @@ -400,6 +425,7 @@ static void __init ordered_lsm_init(void) } initialize_security_state_lsms(); + initialize_security_state_monitor(); kfree(ordered_lsms); }