2020-08-05 00:44:08

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: [PATCH v6 0/4] LSM: Measure security module data

Critical data structures of security modules are currently not measured.
Therefore an attestation service, for instance, would not be able to
attest whether the security modules are always operating with the policies
and configuration that the system administrator had setup. The policies
and configuration for the security modules could be tampered with by
malware by exploiting kernel vulnerabilities or modified through some
inadvertent actions on the system. Measuring such critical data would
enable an attestation service to better assess the state of the system.

IMA subsystem measures system files, command line arguments passed to
kexec, boot aggregate, keys, etc. It can be used to measure critical
data structures of security modules as well.

This change aims to address measuring critical data structures
of security modules when they are initialized and when they are
updated at runtime.

This series is based on commit 3db0d0c276a7 ("integrity: remove
redundant initialization of variable ret") in next-integrity

Change log:

v6:
=> Use kvmalloc for payload data for early boot data measurement
since payload size may exceed the limit supported by kmalloc.
=> Fixed IMA policy rule match error when checking for IMA hook
func LSM_STATE and LSM_POLICY.
=> Enable early boot data measurement and IMA hook func
LSM_STATE and LSM_POLICY when SELinux is enabled.

v5:
=> Append timestamp to "event name" string in the call to
the IMA hooks so that LSM data is always measured by IMA.
=> Removed workqueue patch that was handling periodic checking
of the LSM data. This change will be introduced as a separate
patch set while keeping this patch set focussed on measuring
the LSM data on initialization and on updates at runtime.
=> Handle early boot measurement of LSM data.

v4:
=> Added LSM_POLICY func and IMA hook to measure LSM policy.
=> Pass SELinux policy data, instead of the hash of the policy,
to the IMA hook to measure.
=> Include "initialized" flag in SELinux measurement.
Also, measure SELinux state even when initialization is not yet
completed. But measure SELinux policy only after initialization.

v3:
=> Loop through policy_capabilities to build the state data
to measure instead of hardcoding to current set of
policy capabilities.
=> Added error log messages for failure conditions.

v2:
=> Pass selinux_state struct as parameter to the function
that measures SELinux data.
=> Use strings from selinux_policycap_names array for SELinux
state measurement.
=> Refactored security_read_policy() to alloc kernel or user
virtual memory and then read the SELinux policy.

v1:
=> Per Stephen Smalley's suggestion added selinux_state booleans
and hash of SELinux policy in the measured data for SELinux.
=> Call IMA hook from the security module directly instead of
redirecting through the LSM.

Lakshmi Ramasubramanian (4):
IMA: Add func to measure LSM state and policy
IMA: Define IMA hooks to measure LSM state and policy
LSM: Define SELinux function to measure state and policy
IMA: Handle early boot data measurement

Documentation/ABI/testing/ima_policy | 9 +
include/linux/ima.h | 14 ++
security/integrity/ima/Kconfig | 5 +-
security/integrity/ima/Makefile | 2 +-
security/integrity/ima/ima.h | 45 +++--
security/integrity/ima/ima_api.c | 2 +-
security/integrity/ima/ima_asymmetric_keys.c | 6 +-
security/integrity/ima/ima_init.c | 2 +-
security/integrity/ima/ima_main.c | 64 ++++++-
security/integrity/ima/ima_policy.c | 36 +++-
security/integrity/ima/ima_queue_data.c | 190 +++++++++++++++++++
security/integrity/ima/ima_queue_keys.c | 174 -----------------
security/selinux/Makefile | 2 +
security/selinux/hooks.c | 1 +
security/selinux/include/security.h | 15 ++
security/selinux/measure.c | 150 +++++++++++++++
security/selinux/selinuxfs.c | 3 +
security/selinux/ss/services.c | 71 ++++++-
18 files changed, 569 insertions(+), 222 deletions(-)
create mode 100644 security/integrity/ima/ima_queue_data.c
delete mode 100644 security/integrity/ima/ima_queue_keys.c
create mode 100644 security/selinux/measure.c

--
2.27.0


2020-08-05 00:44:11

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

Critical data structures of security modules need to be measured to
enable an attestation service to verify if the configuration and
policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
measure the state and the policy provided by the security modules.
Update ima_match_rules() and ima_validate_rule() to check for
the new func and ima_parse_rule() to handle the new func.

Signed-off-by: Lakshmi Ramasubramanian <[email protected]>
---
Documentation/ABI/testing/ima_policy | 9 ++++++++
security/integrity/ima/ima.h | 2 ++
security/integrity/ima/ima_api.c | 2 +-
security/integrity/ima/ima_policy.c | 34 ++++++++++++++++++++++++----
4 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index cd572912c593..b7c7fb548c0c 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -30,6 +30,7 @@ Description:
[FIRMWARE_CHECK]
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
[KEXEC_CMDLINE] [KEY_CHECK]
+ [LSM_STATE] [LSM_POLICY]
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
[[^]MAY_EXEC]
fsmagic:= hex value
@@ -125,3 +126,11 @@ 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 state:
+
+ measure func=LSM_STATE template=ima-buf
+
+ Example of measure rule using LSM_POLICY to measure LSM policy:
+
+ measure func=LSM_POLICY template=ima-ng
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 38043074ce5e..1b5f4b2f17d0 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -200,6 +200,8 @@ 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(LSM_POLICY, lsm_policy) \
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 4f39fb93f278..8c8b4e4a6493 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 | LSM_POLICY
* 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 07f033634b27..e4de581442d5 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -442,13 +442,21 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
{
int i;

- if (func == KEY_CHECK) {
- return (rule->flags & IMA_FUNC) && (rule->func == func) &&
- ima_match_keyring(rule, keyring, cred);
- }
if ((rule->flags & IMA_FUNC) &&
(rule->func != func && func != POST_SETATTR))
return false;
+
+ switch (func) {
+ case KEY_CHECK:
+ return ((rule->func == func) &&
+ ima_match_keyring(rule, keyring, cred));
+ case LSM_STATE:
+ case LSM_POLICY:
+ return (rule->func == func);
+ default:
+ break;
+ }
+
if ((rule->flags & IMA_MASK) &&
(rule->mask != mask && func != POST_SETATTR))
return false;
@@ -1044,6 +1052,18 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
if (ima_rule_contains_lsm_cond(entry))
return false;

+ break;
+ case LSM_STATE:
+ case LSM_POLICY:
+ if (entry->action & ~(MEASURE | DONT_MEASURE))
+ return false;
+
+ if (entry->flags & ~(IMA_FUNC | IMA_PCR))
+ return false;
+
+ if (ima_rule_contains_lsm_cond(entry))
+ return false;
+
break;
default:
return false;
@@ -1176,6 +1196,12 @@ 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 (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
+ strcmp(args[0].from, "LSM_STATE") == 0)
+ entry->func = LSM_STATE;
+ else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
+ strcmp(args[0].from, "LSM_POLICY") == 0)
+ entry->func = LSM_POLICY;
else
result = -EINVAL;
if (!result)
--
2.27.0

2020-08-05 00:44:19

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: [PATCH v6 4/4] IMA: Handle early boot data measurement

The current implementation of early boot measurement in
the IMA subsystem is very specific to asymmetric keys. It does not
handle measurement of other data such as Linux Security Module (LSM)
data. Since most security modules are initialized very early in
the boot cycle, data provided by those modules are not measured
by IMA. Any other subsystem that initializes early in the boot cycle
and needs IMA to measure their data would suffer from the same issue.

Update the early boot key measurement to handle any early boot data.
Change the kernel configuration CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS to
CONFIG_IMA_QUEUE_EARLY_BOOT_DATA so it can be used for enabling
early boot data measurement. Change this new configuration to support
SECURITY_SELINUX subsystem in addition to KEYS subsystem, which is
currently supported. This can be extended to include more subsystems
in the future by updating this kernel configuration.

Update LSM hooks namely ima_measure_lsm_state() and ima_measure_lsm_policy
to utilize early boot measurement support.

Signed-off-by: Lakshmi Ramasubramanian <[email protected]>
---
security/integrity/ima/Kconfig | 5 +-
security/integrity/ima/Makefile | 2 +-
security/integrity/ima/ima.h | 37 ++--
security/integrity/ima/ima_asymmetric_keys.c | 6 +-
security/integrity/ima/ima_init.c | 2 +-
security/integrity/ima/ima_main.c | 22 ++-
security/integrity/ima/ima_policy.c | 2 +-
security/integrity/ima/ima_queue_data.c | 190 +++++++++++++++++++
security/integrity/ima/ima_queue_keys.c | 174 -----------------
9 files changed, 238 insertions(+), 202 deletions(-)
create mode 100644 security/integrity/ima/ima_queue_data.c
delete mode 100644 security/integrity/ima/ima_queue_keys.c

diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 080c53545ff0..e4fb1761d64a 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -322,10 +322,9 @@ config IMA_MEASURE_ASYMMETRIC_KEYS
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
default y

-config IMA_QUEUE_EARLY_BOOT_KEYS
+config IMA_QUEUE_EARLY_BOOT_DATA
bool
- depends on IMA_MEASURE_ASYMMETRIC_KEYS
- depends on SYSTEM_TRUSTED_KEYRING
+ depends on SECURITY_SELINUX || (IMA_MEASURE_ASYMMETRIC_KEYS && SYSTEM_TRUSTED_KEYRING)
default y

config IMA_SECURE_AND_OR_TRUSTED_BOOT
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index 67dabca670e2..cbbbc9848d2f 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -13,4 +13,4 @@ ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
ima-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
ima-$(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o
-ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o
+ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_DATA) += ima_queue_data.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 8ed9f5e1dd40..ebe4d9bb2f2b 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -229,29 +229,34 @@ extern const char *const func_tokens[];

struct modsig;

-#ifdef CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS
+#ifdef CONFIG_IMA_QUEUE_EARLY_BOOT_DATA
/*
- * To track keys that need to be measured.
+ * To track data that needs to be measured.
*/
-struct ima_key_entry {
+struct ima_data_entry {
struct list_head list;
void *payload;
size_t payload_len;
- char *keyring_name;
+ const char *event_name;
+ const char *event_data;
+ enum ima_hooks func;
};
-void ima_init_key_queue(void);
-bool ima_should_queue_key(void);
-bool ima_queue_key(struct key *keyring, const void *payload,
- size_t payload_len);
-void ima_process_queued_keys(void);
+void ima_init_data_queue(void);
+bool ima_should_queue_data(void);
+bool ima_queue_data(const char *event_name, const void *payload,
+ size_t payload_len, const char *event_data,
+ enum ima_hooks func);
+void ima_process_queued_data(void);
#else
-static inline void ima_init_key_queue(void) {}
-static inline bool ima_should_queue_key(void) { return false; }
-static inline bool ima_queue_key(struct key *keyring,
- const void *payload,
- size_t payload_len) { return false; }
-static inline void ima_process_queued_keys(void) {}
-#endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS */
+static inline void ima_init_data_queue(void) {}
+static inline bool ima_should_queue_data(void) { return false; }
+static inline bool ima_queue_data(const char *event_name,
+ const void *payload,
+ size_t payload_len,
+ const char *event_data,
+ enum ima_hooks func) { return false; }
+static inline void ima_process_queued_data(void) {}
+#endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_DATA */

/* LIM API function definitions */
int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c
index 1c68c500c26f..8f8431f8b096 100644
--- a/security/integrity/ima/ima_asymmetric_keys.c
+++ b/security/integrity/ima/ima_asymmetric_keys.c
@@ -37,8 +37,10 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
if (!payload || (payload_len == 0))
return;

- if (ima_should_queue_key())
- queued = ima_queue_key(keyring, payload, payload_len);
+ if (ima_should_queue_data())
+ queued = ima_queue_data(keyring->description, payload,
+ payload_len, keyring->description,
+ KEY_CHECK);

if (queued)
return;
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 4902fe7bd570..892894bf4af3 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -145,7 +145,7 @@ int __init ima_init(void)
if (rc != 0)
return rc;

- ima_init_key_queue();
+ ima_init_data_queue();

return rc;
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 74d421e40c8f..1c4e140964df 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -846,6 +846,22 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
fdput(f);
}

+static int ima_measure_lsm_data(const char *event_name,
+ const void *buf, int size,
+ enum ima_hooks func)
+{
+ bool queued = false;
+
+ if (ima_should_queue_data())
+ queued = ima_queue_data(event_name, buf, size, NULL, func);
+
+ if (queued)
+ return 0;
+
+ return process_buffer_measurement(NULL, buf, size, event_name, func,
+ 0, NULL);
+}
+
/**
* ima_measure_lsm_state - measure LSM specific state
* @lsm_event_name: LSM event
@@ -860,8 +876,7 @@ int ima_measure_lsm_state(const char *lsm_event_name, const void *buf,
if (!lsm_event_name || !buf || !size)
return -EINVAL;

- return process_buffer_measurement(NULL, buf, size, lsm_event_name,
- LSM_STATE, 0, NULL);
+ return ima_measure_lsm_data(lsm_event_name, buf, size, LSM_STATE);
}

/**
@@ -878,8 +893,7 @@ int ima_measure_lsm_policy(const char *lsm_event_name, const void *buf,
if (!lsm_event_name || !buf || !size)
return -EINVAL;

- return process_buffer_measurement(NULL, buf, size, lsm_event_name,
- LSM_POLICY, 0, NULL);
+ return ima_measure_lsm_data(lsm_event_name, buf, size, LSM_POLICY);
}

static int __init init_ima(void)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index e4de581442d5..196c427a79d1 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -837,7 +837,7 @@ void ima_update_policy(void)
ima_update_policy_flag();

/* Custom IMA policy has been loaded */
- ima_process_queued_keys();
+ ima_process_queued_data();
}

/* Keep the enumeration in sync with the policy_tokens! */
diff --git a/security/integrity/ima/ima_queue_data.c b/security/integrity/ima/ima_queue_data.c
new file mode 100644
index 000000000000..93420e7670b9
--- /dev/null
+++ b/security/integrity/ima/ima_queue_data.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Microsoft Corporation
+ *
+ * Author: Lakshmi Ramasubramanian ([email protected])
+ *
+ * File: ima_queue_data.c
+ * Enables deferred processing of data to be measured
+ */
+
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include "ima.h"
+
+/*
+ * Flag to indicate whether data can be processed
+ * right away or should be queued for processing later.
+ */
+static bool ima_process_data;
+
+/*
+ * To synchronize access to the list of data that need to be measured
+ */
+static DEFINE_MUTEX(ima_data_lock);
+static LIST_HEAD(ima_queued_data);
+
+/*
+ * If custom IMA policy is not loaded then data queued up
+ * for measurement should be freed. This worker is used
+ * for handling this scenario.
+ */
+static long ima_data_queue_timeout = 300000; /* 5 Minutes */
+static void ima_data_handler(struct work_struct *work);
+static DECLARE_DELAYED_WORK(ima_data_delayed_work, ima_data_handler);
+static bool timer_expired;
+
+/*
+ * This worker function frees data that may still be
+ * queued up in case custom IMA policy was not loaded.
+ */
+static void ima_data_handler(struct work_struct *work)
+{
+ timer_expired = true;
+ ima_process_queued_data();
+}
+
+/*
+ * This function sets up a worker to free queued data in case
+ * custom IMA policy was never loaded.
+ */
+void ima_init_data_queue(void)
+{
+ schedule_delayed_work(&ima_data_delayed_work,
+ msecs_to_jiffies(ima_data_queue_timeout));
+}
+
+static void ima_free_data_entry(struct ima_data_entry *entry)
+{
+ if (!entry)
+ return;
+
+ kvfree(entry->payload);
+ kfree(entry->event_name);
+ kfree(entry->event_data);
+ kfree(entry);
+}
+
+static void *ima_kvmemdup(const void *src, size_t len)
+{
+ void *p = kvmalloc(len, GFP_KERNEL);
+
+ if (p)
+ memcpy(p, src, len);
+ return p;
+}
+
+static struct ima_data_entry *ima_alloc_data_entry(const char *event_name,
+ const void *payload,
+ size_t payload_len,
+ const char *event_data,
+ enum ima_hooks func)
+{
+ struct ima_data_entry *entry;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ goto out;
+
+ /*
+ * Payload size may exceed the limit supported by kmalloc.
+ * So use kvmalloc instead.
+ */
+ entry->payload = ima_kvmemdup(payload, payload_len);
+ entry->event_name = kstrdup(event_name, GFP_KERNEL);
+ if (event_data)
+ entry->event_data = kstrdup(event_data, GFP_KERNEL);
+
+ entry->payload_len = payload_len;
+ entry->func = func;
+
+ if (!entry->payload || !entry->event_name ||
+ (event_data && !entry->event_data))
+ goto out;
+
+ INIT_LIST_HEAD(&entry->list);
+ return entry;
+
+out:
+ integrity_audit_message(AUDIT_INTEGRITY_PCR, NULL,
+ event_name, func_measure_str(func),
+ "ENOMEM", -ENOMEM, 0, -ENOMEM);
+ ima_free_data_entry(entry);
+ return NULL;
+}
+
+bool ima_queue_data(const char *event_name, const void *payload,
+ size_t payload_len, const char *event_data,
+ enum ima_hooks func)
+{
+ bool queued = false;
+ struct ima_data_entry *entry;
+
+ entry = ima_alloc_data_entry(event_name, payload, payload_len,
+ event_data, func);
+ if (!entry)
+ return false;
+
+ mutex_lock(&ima_data_lock);
+ if (!ima_process_data) {
+ list_add_tail(&entry->list, &ima_queued_data);
+ queued = true;
+ }
+ mutex_unlock(&ima_data_lock);
+
+ if (!queued)
+ ima_free_data_entry(entry);
+
+ return queued;
+}
+
+/*
+ * ima_process_queued_data() - process data queued for measurement
+ *
+ * This function sets ima_process_data to true and processes queued data.
+ * From here on data will be processed right away (not queued).
+ */
+void ima_process_queued_data(void)
+{
+ struct ima_data_entry *entry, *tmp;
+ bool process = false;
+
+ if (ima_process_data)
+ return;
+
+ /*
+ * Since ima_process_data is set to true, any new data will be
+ * processed immediately and not be queued to ima_queued_data list.
+ * First one setting the ima_process_data flag to true will
+ * process the queued data.
+ */
+ mutex_lock(&ima_data_lock);
+ if (!ima_process_data) {
+ ima_process_data = true;
+ process = true;
+ }
+ mutex_unlock(&ima_data_lock);
+
+ if (!process)
+ return;
+
+ if (!timer_expired)
+ cancel_delayed_work_sync(&ima_data_delayed_work);
+
+ list_for_each_entry_safe(entry, tmp, &ima_queued_data, list) {
+ if (!timer_expired)
+ process_buffer_measurement(NULL, entry->payload,
+ entry->payload_len,
+ entry->event_name,
+ entry->func, 0,
+ entry->event_data);
+ list_del(&entry->list);
+ ima_free_data_entry(entry);
+ }
+}
+
+inline bool ima_should_queue_data(void)
+{
+ return !ima_process_data;
+}
diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c
deleted file mode 100644
index 69a8626a35c0..000000000000
--- a/security/integrity/ima/ima_queue_keys.c
+++ /dev/null
@@ -1,174 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2019 Microsoft Corporation
- *
- * Author: Lakshmi Ramasubramanian ([email protected])
- *
- * File: ima_queue_keys.c
- * Enables deferred processing of keys
- */
-
-#include <linux/workqueue.h>
-#include <keys/asymmetric-type.h>
-#include "ima.h"
-
-/*
- * Flag to indicate whether a key can be processed
- * right away or should be queued for processing later.
- */
-static bool ima_process_keys;
-
-/*
- * To synchronize access to the list of keys that need to be measured
- */
-static DEFINE_MUTEX(ima_keys_lock);
-static LIST_HEAD(ima_keys);
-
-/*
- * If custom IMA policy is not loaded then keys queued up
- * for measurement should be freed. This worker is used
- * for handling this scenario.
- */
-static long ima_key_queue_timeout = 300000; /* 5 Minutes */
-static void ima_keys_handler(struct work_struct *work);
-static DECLARE_DELAYED_WORK(ima_keys_delayed_work, ima_keys_handler);
-static bool timer_expired;
-
-/*
- * This worker function frees keys that may still be
- * queued up in case custom IMA policy was not loaded.
- */
-static void ima_keys_handler(struct work_struct *work)
-{
- timer_expired = true;
- ima_process_queued_keys();
-}
-
-/*
- * This function sets up a worker to free queued keys in case
- * custom IMA policy was never loaded.
- */
-void ima_init_key_queue(void)
-{
- schedule_delayed_work(&ima_keys_delayed_work,
- msecs_to_jiffies(ima_key_queue_timeout));
-}
-
-static void ima_free_key_entry(struct ima_key_entry *entry)
-{
- if (entry) {
- kfree(entry->payload);
- kfree(entry->keyring_name);
- kfree(entry);
- }
-}
-
-static struct ima_key_entry *ima_alloc_key_entry(struct key *keyring,
- const void *payload,
- size_t payload_len)
-{
- int rc = 0;
- const char *audit_cause = "ENOMEM";
- struct ima_key_entry *entry;
-
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (entry) {
- entry->payload = kmemdup(payload, payload_len, GFP_KERNEL);
- entry->keyring_name = kstrdup(keyring->description,
- GFP_KERNEL);
- entry->payload_len = payload_len;
- }
-
- if ((entry == NULL) || (entry->payload == NULL) ||
- (entry->keyring_name == NULL)) {
- rc = -ENOMEM;
- goto out;
- }
-
- INIT_LIST_HEAD(&entry->list);
-
-out:
- if (rc) {
- integrity_audit_message(AUDIT_INTEGRITY_PCR, NULL,
- keyring->description,
- func_measure_str(KEY_CHECK),
- audit_cause, rc, 0, rc);
- ima_free_key_entry(entry);
- entry = NULL;
- }
-
- return entry;
-}
-
-bool ima_queue_key(struct key *keyring, const void *payload,
- size_t payload_len)
-{
- bool queued = false;
- struct ima_key_entry *entry;
-
- entry = ima_alloc_key_entry(keyring, payload, payload_len);
- if (!entry)
- return false;
-
- mutex_lock(&ima_keys_lock);
- if (!ima_process_keys) {
- list_add_tail(&entry->list, &ima_keys);
- queued = true;
- }
- mutex_unlock(&ima_keys_lock);
-
- if (!queued)
- ima_free_key_entry(entry);
-
- return queued;
-}
-
-/*
- * ima_process_queued_keys() - process keys queued for measurement
- *
- * This function sets ima_process_keys to true and processes queued keys.
- * From here on keys will be processed right away (not queued).
- */
-void ima_process_queued_keys(void)
-{
- struct ima_key_entry *entry, *tmp;
- bool process = false;
-
- if (ima_process_keys)
- return;
-
- /*
- * Since ima_process_keys is set to true, any new key will be
- * processed immediately and not be queued to ima_keys list.
- * First one setting the ima_process_keys flag to true will
- * process the queued keys.
- */
- mutex_lock(&ima_keys_lock);
- if (!ima_process_keys) {
- ima_process_keys = true;
- process = true;
- }
- mutex_unlock(&ima_keys_lock);
-
- if (!process)
- return;
-
- if (!timer_expired)
- cancel_delayed_work_sync(&ima_keys_delayed_work);
-
- list_for_each_entry_safe(entry, tmp, &ima_keys, list) {
- if (!timer_expired)
- process_buffer_measurement(NULL, entry->payload,
- entry->payload_len,
- entry->keyring_name,
- KEY_CHECK, 0,
- entry->keyring_name);
- list_del(&entry->list);
- ima_free_key_entry(entry);
- }
-}
-
-inline bool ima_should_queue_key(void)
-{
- return !ima_process_keys;
-}
--
2.27.0

2020-08-05 00:44:42

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: [PATCH v6 3/4] LSM: Define SELinux function to measure state and policy

SELinux configuration and policy are some of the critical data for this
security module that needs to be measured. This measurement can be used
by an attestation service, for instance, to verify if the configuration
and policies have been setup correctly and that they haven't been tampered
with at runtime.

Measure SELinux configuration, policy capabilities settings, and the
loaded policy by calling the IMA hooks ima_measure_lsm_state() and
ima_measure_lsm_policy() respectively.

Sample measurement of SELinux state and hash of the policy:

10 e32e...5ac3 ima-buf sha256:86e8...4594 selinux-state-1595389364:287899386 696e697469616c697a65643d313b656e61626c65643d313b656e666f7263696e673d303b636865636b72657170726f743d313b6e6574776f726b5f706565725f636f6e74726f6c733d313b6f70656e5f7065726d733d313b657874656e6465645f736f636b65745f636c6173733d313b616c776179735f636865636b5f6e6574776f726b3d303b6367726f75705f7365636c6162656c3d313b6e6e705f6e6f737569645f7472616e736974696f6e3d313b67656e66735f7365636c6162656c5f73796d6c696e6b733d303
10 f4a7...9408 ima-ng sha256:8d1d...1834 selinux-policy-hash-1595389353:863934271

To verify the measurement check the following:

Execute the following command to extract the measured data
from the IMA log for SELinux configuration (selinux-state).

grep -m 1 "selinux-state" /sys/kernel/security/integrity/ima/ascii_runtime_measurements | cut -d' ' -f 6 | xxd -r -p

The output should be the list of key-value pairs. For example,
initialized=1;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;

To verify the measured data with the current SELinux state:

=> enabled should be set to 1 if /sys/fs/selinux folder exists,
0 otherwise

For other entries, compare the integer value in the files
=> /sys/fs/selinux/enforce
=> /sys/fs/selinux/checkreqprot
And, each of the policy capabilities files under
=> /sys/fs/selinux/policy_capabilities

For selinux-policy-hash, the hash of SELinux policy is included
in the IMA log entry.

To verify the measured data with the current SELinux policy run
the following commands and verify the output hash values match.

sha256sum /sys/fs/selinux/policy | cut -d' ' -f 1

grep -m 1 "selinux-policy-hash" /sys/kernel/security/integrity/ima/ascii_runtime_measurements | cut -d' ' -f 4

Signed-off-by: Lakshmi Ramasubramanian <[email protected]>
Suggested-by: Stephen Smalley <[email protected]>
Reported-by: kernel test robot <[email protected]> # error: implicit declaration of function 'vfree'
Reported-by: kernel test robot <[email protected]> # error: implicit declaration of function 'crypto_alloc_shash'
Reported-by: kernel test robot <[email protected]> # sparse: symbol 'security_read_selinux_policy' was not declared. Should it be static?
---
security/selinux/Makefile | 2 +
security/selinux/hooks.c | 1 +
security/selinux/include/security.h | 15 +++
security/selinux/measure.c | 150 ++++++++++++++++++++++++++++
security/selinux/selinuxfs.c | 3 +
security/selinux/ss/services.c | 71 +++++++++++--
6 files changed, 233 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..5521dfc1900b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7394,6 +7394,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..77f42d9b544b 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -222,16 +222,31 @@ 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 selinux_measure_state(struct selinux_state *selinux_state);
+#else
+static inline void selinux_measure_state(struct selinux_state *selinux_state)
+{
+}
+#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..1583628d09d1
--- /dev/null
+++ b/security/selinux/measure.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Measure SELinux state using IMA subsystem.
+ */
+#include <linux/vmalloc.h>
+#include <linux/ktime.h>
+#include <linux/ima.h>
+#include "security.h"
+
+/*
+ * This function creates an unique name by appending the timestamp to
+ * the given string. This string is passed as "event name" to the IMA
+ * hook to measure the given SELinux data.
+ *
+ * The data provided by SELinux to the IMA subsystem for measuring may have
+ * already been measured (for instance the same state existed earlier).
+ * But for SELinux the current data represents a state change and hence
+ * needs to be measured again. To enable this, pass an unique "Event Name"
+ * to the IMA hook so that IMA subsystem will always measure the given data.
+ *
+ * For example,
+ * At time T0 SELinux data to be measured is "foo". IMA measures it.
+ * At time T1 the data is changed to "bar". IMA measures it.
+ * At time T2 the data is changed to "foo" again. IMA will not measure it
+ * (since it was already measured) unless the event name, for instance,
+ * is different in this call.
+ */
+static char *selinux_event_name(const char *name_prefix)
+{
+ char *event_name = NULL;
+ struct timespec64 curr_time;
+ int count;
+
+ ktime_get_real_ts64(&curr_time);
+ count = snprintf(NULL, 0, "%s-%lld:%09ld", name_prefix,
+ curr_time.tv_sec, curr_time.tv_nsec);
+ count++;
+ event_name = kzalloc(count, GFP_KERNEL);
+ if (!event_name) {
+ pr_warn("%s: event name not allocated.\n", __func__);
+ return NULL;
+ }
+
+ snprintf(event_name, count, "%s-%lld:%09ld", name_prefix,
+ curr_time.tv_sec, curr_time.tv_nsec);
+
+ return event_name;
+}
+
+static int read_selinux_state(char **state_str, int *state_str_len,
+ struct selinux_state *state)
+{
+ char *buf, *str_fmt = "%s=%d;";
+ int i, buf_len, curr;
+
+ buf_len = snprintf(NULL, 0, str_fmt, "initialized", 0);
+ buf_len += snprintf(NULL, 0, str_fmt, "enabled", 0);
+ buf_len += snprintf(NULL, 0, str_fmt, "enforcing", 0);
+ buf_len += snprintf(NULL, 0, str_fmt, "checkreqprot", 0);
+
+ for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++) {
+ buf_len += snprintf(NULL, 0, str_fmt,
+ selinux_policycap_names[i], 0);
+ }
+ ++buf_len;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ curr = snprintf(buf, buf_len, str_fmt,
+ "initialized", selinux_initialized(state));
+ curr += snprintf((buf + curr), (buf_len - curr), str_fmt,
+ "enabled", !selinux_disabled(state));
+ curr += snprintf((buf + curr), (buf_len - curr), str_fmt,
+ "enforcing", enforcing_enabled(state));
+ curr += snprintf((buf + curr), (buf_len - curr), str_fmt,
+ "checkreqprot", selinux_checkreqprot(state));
+
+ for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++) {
+ curr += snprintf((buf + curr), (buf_len - curr), str_fmt,
+ selinux_policycap_names[i],
+ state->policycap[i]);
+ }
+
+ *state_str = buf;
+ *state_str_len = curr;
+
+ return 0;
+}
+
+void selinux_measure_state(struct selinux_state *state)
+{
+ void *policy = NULL;
+ char *event_name = NULL;
+ char *state_str = NULL;
+ size_t policy_len;
+ int state_str_len, rc = 0;
+ bool initialized = selinux_initialized(state);
+
+ rc = read_selinux_state(&state_str, &state_str_len, state);
+ if (rc) {
+ pr_warn("%s: Failed to read selinux state.\n", __func__);
+ return;
+ }
+
+ /*
+ * Get an unique string for measuring the current SELinux state.
+ */
+ event_name = selinux_event_name("selinux-state");
+ if (!event_name) {
+ pr_warn("%s: Event name for state not allocated.\n",
+ __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = ima_measure_lsm_state(event_name, state_str, state_str_len);
+
+ kfree(event_name);
+ event_name = NULL;
+
+ if (rc)
+ goto out;
+
+ /*
+ * Measure SELinux policy only after initialization is completed.
+ */
+ if (!initialized)
+ goto out;
+
+ rc = security_read_policy_kernel(state, &policy, &policy_len);
+ if (rc)
+ goto out;
+
+ event_name = selinux_event_name("selinux-policy-hash");
+ if (!event_name) {
+ pr_warn("%s: Event name for policy not allocated.\n",
+ __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = ima_measure_lsm_policy(event_name, policy, policy_len);
+
+out:
+ kfree(event_name);
+ kfree(state_str);
+ vfree(policy);
+}
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 4781314c2510..6d46eaef5c92 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(state);
if (new_value)
avc_ss_reset(state->avc, 0);
selnl_notify_setenforce(new_value);
@@ -678,6 +679,8 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,

fsi->state->checkreqprot = new_value ? 1 : 0;
length = count;
+
+ selinux_measure_state(fsi->state);
out:
kfree(page);
return length;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index ef0afd878bfc..3978c804c361 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2182,6 +2182,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();
+ selinux_measure_state(state);
return 0;
}

@@ -2270,6 +2271,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();
+ selinux_measure_state(state);

rc = 0;
goto out;
@@ -2941,6 +2943,7 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values)
selnl_notify_policyload(seqno);
selinux_status_update_policyload(state, seqno);
selinux_xfrm_notify_policyload();
+ selinux_measure_state(state);
}
return rc;
}
@@ -3720,14 +3723,23 @@ 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.
+ * security_read_selinux_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)
+static int security_read_selinux_policy(struct selinux_state *state,
+ void **data, size_t *len)
{
struct policydb *policydb = &state->ss->policydb;
int rc;
@@ -3736,12 +3748,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 +3760,52 @@ 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);
}
--
2.27.0

2020-08-05 00:44:53

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: [PATCH v6 2/4] IMA: Define IMA hooks to measure LSM state and policy

IMA subsystem needs to define IMA hooks that the security modules can
call to measure state and policy data.

Define two new IMA hooks, namely ima_lsm_state() and ima_lsm_policy(),
that the security modules can call to measure LSM state and LSM policy
respectively. Return the status of the measurement operation from these
two IMA hooks.

Signed-off-by: Lakshmi Ramasubramanian <[email protected]>
Reviewed-by: Tyler Hicks <[email protected]>
---
include/linux/ima.h | 14 +++++++++
security/integrity/ima/ima.h | 6 ++--
security/integrity/ima/ima_main.c | 50 ++++++++++++++++++++++++++-----
3 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index d15100de6cdd..442ca0dce3c8 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -26,6 +26,10 @@ 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(int kernel_fd, const void *buf, int size);
+extern int ima_measure_lsm_state(const char *lsm_event_name, const void *buf,
+ int size);
+extern int ima_measure_lsm_policy(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 +108,16 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
}

static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
+static inline int ima_measure_lsm_state(const char *lsm_event_name,
+ const void *buf, int size)
+{
+ return -EOPNOTSUPP;
+}
+static inline int ima_measure_lsm_policy(const char *lsm_event_name,
+ const void *buf, int size)
+{
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_IMA */

#ifndef CONFIG_IMA_KEXEC
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 1b5f4b2f17d0..8ed9f5e1dd40 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -267,9 +267,9 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, const struct modsig *modsig, int pcr,
struct ima_template_desc *template_desc);
-void process_buffer_measurement(struct inode *inode, const void *buf, int size,
- const char *eventname, enum ima_hooks func,
- int pcr, const char *keyring);
+int process_buffer_measurement(struct inode *inode, const void *buf, int size,
+ const char *eventname, enum ima_hooks func,
+ int pcr, const char *keyring);
void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename);
int ima_alloc_init_template(struct ima_event_data *event_data,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 8a91711ca79b..74d421e40c8f 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -736,9 +736,9 @@ int ima_load_data(enum kernel_load_data_id id)
*
* Based on policy, the buffer is measured into the ima log.
*/
-void process_buffer_measurement(struct inode *inode, const void *buf, int size,
- const char *eventname, enum ima_hooks func,
- int pcr, const char *keyring)
+int process_buffer_measurement(struct inode *inode, const void *buf, int size,
+ const char *eventname, enum ima_hooks func,
+ int pcr, const char *keyring)
{
int ret = 0;
const char *audit_cause = "ENOMEM";
@@ -758,7 +758,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size,
u32 secid;

if (!ima_policy_flag)
- return;
+ return 0;

/*
* Both LSM hooks and auxilary based buffer measurements are
@@ -772,7 +772,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size,
action = ima_get_action(inode, current_cred(), secid, 0, func,
&pcr, &template, keyring);
if (!(action & IMA_MEASURE))
- return;
+ return 0;
}

if (!pcr)
@@ -787,7 +787,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size,
pr_err("template %s init failed, result: %d\n",
(strlen(template->name) ?
template->name : template->fmt), ret);
- return;
+ return ret;
}
}

@@ -819,7 +819,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size,
func_measure_str(func),
audit_cause, ret, 0, ret);

- return;
+ return ret;
}

/**
@@ -846,6 +846,42 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
fdput(f);
}

+/**
+ * ima_measure_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.
+ */
+int ima_measure_lsm_state(const char *lsm_event_name, const void *buf,
+ int size)
+{
+ if (!lsm_event_name || !buf || !size)
+ return -EINVAL;
+
+ return process_buffer_measurement(NULL, buf, size, lsm_event_name,
+ LSM_STATE, 0, NULL);
+}
+
+/**
+ * ima_measure_lsm_policy - measure LSM specific policy
+ * @lsm_event_name: LSM event
+ * @buf: pointer to buffer containing LSM specific policy
+ * @size: Number of bytes in buf
+ *
+ * Buffers can only be measured, not appraised.
+ */
+int ima_measure_lsm_policy(const char *lsm_event_name, const void *buf,
+ int size)
+{
+ if (!lsm_event_name || !buf || !size)
+ return -EINVAL;
+
+ return process_buffer_measurement(NULL, buf, size, lsm_event_name,
+ LSM_POLICY, 0, NULL);
+}
+
static int __init init_ima(void)
{
int error;
--
2.27.0

2020-08-05 01:05:26

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
> Critical data structures of security modules are currently not measured.
> Therefore an attestation service, for instance, would not be able to
> attest whether the security modules are always operating with the policies
> and configuration that the system administrator had setup. The policies
> and configuration for the security modules could be tampered with by
> malware by exploiting kernel vulnerabilities or modified through some
> inadvertent actions on the system. Measuring such critical data would
> enable an attestation service to better assess the state of the system.

I still wonder why you're calling this an LSM change/feature when
all the change is in IMA and SELinux. You're not putting anything
into the LSM infrastructure, not are you using the LSM infrastructure
to achieve your ends. Sure, you *could* support other security modules
using this scheme, but you have a configuration dependency on
SELinux, so that's at best going to be messy. If you want this to
be an LSM "feature" you need to use the LSM hooking mechanism.

I'm not objecting to the feature. It adds value. But as you've
implemented it it is either an IMA extension to SELinux, or an
SELiux extension to IMA. Could AppArmor add hooks for this without
changing the IMA code? It doesn't look like it to me.
 

2020-08-05 01:15:18

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/4/20 6:04 PM, Casey Schaufler wrote:
> On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
>> Critical data structures of security modules are currently not measured.
>> Therefore an attestation service, for instance, would not be able to
>> attest whether the security modules are always operating with the policies
>> and configuration that the system administrator had setup. The policies
>> and configuration for the security modules could be tampered with by
>> malware by exploiting kernel vulnerabilities or modified through some
>> inadvertent actions on the system. Measuring such critical data would
>> enable an attestation service to better assess the state of the system.
>
> I still wonder why you're calling this an LSM change/feature when
> all the change is in IMA and SELinux. You're not putting anything
> into the LSM infrastructure, not are you using the LSM infrastructure
> to achieve your ends. Sure, you *could* support other security modules
> using this scheme, but you have a configuration dependency on
> SELinux, so that's at best going to be messy. If you want this to
> be an LSM "feature" you need to use the LSM hooking mechanism.

>
> I'm not objecting to the feature. It adds value. But as you've
> implemented it it is either an IMA extension to SELinux, or an
> SELiux extension to IMA. Could AppArmor add hooks for this without
> changing the IMA code? It doesn't look like it to me.

The check in IMA to allow the new IMA hook func LSM_STATE and LSM_POLICY
when SELinux is enabled is just because SELinux is the only security
module using these hooks now.

To enable AppArmor, for instance, to use the new IMA hooks to measure
state and policy would just require adding the check for
CONFIG_SECURITY_APPARMOR. Other than that, there are no IMA changes
needed to support AppArmor or other such security modules.

Please see Patch 1/4

+ else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
+ strcmp(args[0].from, "LSM_STATE") == 0)
+ entry->func = LSM_STATE;
+ else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
+ strcmp(args[0].from, "LSM_POLICY") == 0)
+ entry->func = LSM_POLICY;

And, if early boot measurement is needed for AppArmor the following
change in IMA's Kconfig

Patch 4/4

+config IMA_QUEUE_EARLY_BOOT_DATA
bool
+ depends on SECURITY_SELINUX || (IMA_MEASURE_ASYMMETRIC_KEYS &&
SYSTEM_TRUSTED_KEYRING)
default y

If you think calling this an "LSM feature" is not appropriate, please
suggest a better phrase.

But like I said above, with minimal change in IMA other security modules
can be supported to measure STATE and POLICY data.

-lakshmi


2020-08-05 03:25:58

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

Hi Lakshmi,

There's still a number of other patch sets needing to be reviewed
before my getting to this one. The comment below is from a high level.

On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
> Critical data structures of security modules need to be measured to
> enable an attestation service to verify if the configuration and
> policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
> measure the state and the policy provided by the security modules.
> Update ima_match_rules() and ima_validate_rule() to check for
> the new func and ima_parse_rule() to handle the new func.

I can understand wanting to measure the in kernel LSM memory state to
make sure it hasn't changed, but policies are stored as files. Buffer
measurements should be limited to those things that are not files.

Changing how data is passed to the kernel has been happening for a
while. For example, instead of passing the kernel module or kernel
image in a buffer, the new syscalls - finit_module, kexec_file_load -
pass an open file descriptor. Similarly, instead of loading the IMA
policy data, a pathname may be provided.

Pre and post security hooks already exist for reading files. Instead
of adding IMA support for measuring the policy file data, update the
mechanism for loading the LSM policy. Then not only will you be able
to measure the policy, you'll also be able to require the policy be
signed.

Mimi

2020-08-05 16:07:05

by Tyler Hicks

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 2020-08-05 08:36:40, Casey Schaufler wrote:
> On 8/4/2020 6:14 PM, Lakshmi Ramasubramanian wrote:
> > On 8/4/20 6:04 PM, Casey Schaufler wrote:
> >> On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
> >>> Critical data structures of security modules are currently not measured.
> >>> Therefore an attestation service, for instance, would not be able to
> >>> attest whether the security modules are always operating with the policies
> >>> and configuration that the system administrator had setup. The policies
> >>> and configuration for the security modules could be tampered with by
> >>> malware by exploiting kernel vulnerabilities or modified through some
> >>> inadvertent actions on the system. Measuring such critical data would
> >>> enable an attestation service to better assess the state of the system.
> >>
> >> I still wonder why you're calling this an LSM change/feature when
> >> all the change is in IMA and SELinux. You're not putting anything
> >> into the LSM infrastructure, not are you using the LSM infrastructure
> >> to achieve your ends. Sure, you *could* support other security modules
> >> using this scheme, but you have a configuration dependency on
> >> SELinux, so that's at best going to be messy. If you want this to
> >> be an LSM "feature" you need to use the LSM hooking mechanism.
> >
> >>
> >> I'm not objecting to the feature. It adds value. But as you've
> >> implemented it it is either an IMA extension to SELinux, or an
> >> SELiux extension to IMA. Could AppArmor add hooks for this without
> >> changing the IMA code? It doesn't look like it to me.
> >
> > The check in IMA to allow the new IMA hook func LSM_STATE and LSM_POLICY when SELinux is enabled is just because SELinux is the only security module using these hooks now.
> >
> > To enable AppArmor, for instance, to use the new IMA hooks to measure state and policy would just require adding the check for CONFIG_SECURITY_APPARMOR. Other than that, there are no IMA changes needed to support AppArmor or other such security modules.
>
> This is exactly what I'm objecting to. What if a system has both SELinux
> and AppArmor compiled in? What if it has both enabled?

The SELinux state and policy would be measured but the AppArmor
state/policy would be silently ignored. This isn't ideal as the IMA
policy author would need to read the kernel code to figure out which
LSMs are going to be measured.

>
> >
> > Please see Patch 1/4
> >
> > +??????????? else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
> > +???????????????? strcmp(args[0].from, "LSM_STATE") == 0)
> > +??????????????? entry->func = LSM_STATE;
> > +??????????? else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
> > +???????????????? strcmp(args[0].from, "LSM_POLICY") == 0)
> > +??????????????? entry->func = LSM_POLICY;
> >
> > And, if early boot measurement is needed for AppArmor the following change in IMA's Kconfig
> >
> > Patch 4/4
> >
> > +config IMA_QUEUE_EARLY_BOOT_DATA
> > ???? bool
> > +??? depends on SECURITY_SELINUX || (IMA_MEASURE_ASYMMETRIC_KEYS && SYSTEM_TRUSTED_KEYRING)
> > ???? default y
> >
> > If you think calling this an "LSM feature" is not appropriate, please suggest a better phrase.
>
> In the code above you are under CONFIG_SECURITY_SELINUX.
> I would suggest that it's an SELinux feature, so you should
> be using SELINUX_STATE and SELINUX_POLICY, as I suggested
> before. Just because SELinux has state and policy to measure
> doesn't mean that a different module might not have other data,
> such as history, that should be covered as well.

In addition to SELINUX_STATE and SELINUX_POLICY, we should also consider
the proposed LSM_STATE and LSM_POLICY func values but require an "lsm"
rule conditional.

So the current proposed rules:

measure func=LSM_STATE
measure func=LSM_POLICY

Would become:

measure func=LSM_STATE lsm=selinux
measure func=LSM_POLICY lsm=selinux

The following rules would be rejected:

measure func=LSM_STATE
measure func=LSM_POLICY
measure func=LSM_STATE lsm=apparmor
measure func=LSM_POLICY lsm=smack

Of course, the apparmor and smack rules could/would be allowed when
proper support is in place.

Tyler

>
> I realize that IMA already has compile time dependencies to
> determine which xattrs to measure. There's no reason that
> the xattr list couldn't be determined at boot time, with
> each security module providing the XATTR_NAME values it
> uses.
>
> >
> > But like I said above, with minimal change in IMA other security modules can be supported to measure STATE and POLICY data.
> >
> > ?-lakshmi
> >
> >

2020-08-05 16:10:21

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
> Critical data structures of security modules are currently not measured.
> Therefore an attestation service, for instance, would not be able to
> attest whether the security modules are always operating with the policies
> and configuration that the system administrator had setup. The policies
> and configuration for the security modules could be tampered with by
> malware by exploiting kernel vulnerabilities or modified through some
> inadvertent actions on the system. Measuring such critical data would
> enable an attestation service to better assess the state of the system.

From a high level review, "Critical data structures" should be the
focus of this patch set. Measuring "critical data structures" should
be independent of measuring the "policy" being loaded. The in memory
policy hash could be an example of data included in the "critical data
structures".

Keep this patch set simple.

Mimi

2020-08-05 16:27:46

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/5/20 8:45 AM, Tyler Hicks wrote:
> On 2020-08-05 08:36:40, Casey Schaufler wrote:
>> On 8/4/2020 6:14 PM, Lakshmi Ramasubramanian wrote:
>>> On 8/4/20 6:04 PM, Casey Schaufler wrote:
>>>> On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
>>>>> Critical data structures of security modules are currently not measured.
>>>>> Therefore an attestation service, for instance, would not be able to
>>>>> attest whether the security modules are always operating with the policies
>>>>> and configuration that the system administrator had setup. The policies
>>>>> and configuration for the security modules could be tampered with by
>>>>> malware by exploiting kernel vulnerabilities or modified through some
>>>>> inadvertent actions on the system. Measuring such critical data would
>>>>> enable an attestation service to better assess the state of the system.
>>>>
>>>> I still wonder why you're calling this an LSM change/feature when
>>>> all the change is in IMA and SELinux. You're not putting anything
>>>> into the LSM infrastructure, not are you using the LSM infrastructure
>>>> to achieve your ends. Sure, you *could* support other security modules
>>>> using this scheme, but you have a configuration dependency on
>>>> SELinux, so that's at best going to be messy. If you want this to
>>>> be an LSM "feature" you need to use the LSM hooking mechanism.
>>>
>>>>
>>>> I'm not objecting to the feature. It adds value. But as you've
>>>> implemented it it is either an IMA extension to SELinux, or an
>>>> SELiux extension to IMA. Could AppArmor add hooks for this without
>>>> changing the IMA code? It doesn't look like it to me.
>>>
>>> The check in IMA to allow the new IMA hook func LSM_STATE and LSM_POLICY when SELinux is enabled is just because SELinux is the only security module using these hooks now.
>>>
>>> To enable AppArmor, for instance, to use the new IMA hooks to measure state and policy would just require adding the check for CONFIG_SECURITY_APPARMOR. Other than that, there are no IMA changes needed to support AppArmor or other such security modules.
>>
>> This is exactly what I'm objecting to. What if a system has both SELinux
>> and AppArmor compiled in? What if it has both enabled?
>
> The SELinux state and policy would be measured but the AppArmor
> state/policy would be silently ignored. This isn't ideal as the IMA
> policy author would need to read the kernel code to figure out which
> LSMs are going to be measured.

Tyler - I am not sure why AppArmor state\policy would be ignored when
both SELinux and AppArmor are enabled. Could you please clarify?

When both the security modules are enabled, IMA policy validator would
look like below:

if (IS_ENABLED(CONFIG_SECURITY_SELINUX) ||
IS_ENABLED(CONFIG_SECURITY_APPARMOR)) &&
strcmp(args[0].from, "LSM_STATE") == 0)
entry->func = LSM_STATE;

Similar one for LSM_POLICY validation.

Both SELinux and AppArmor can call ima_measure_lsm_state() and
ima_measure_lsm_policy() to measure state and policy respectively.

I don't think we should go the route of defining IMA hooks per security
module (i.e., SELINUX_STATE, APPARMOR_STATE, SELINUX_POLICY, etc.)
Instead keep the hook generic that any SM could use - which is what I
have tried to address in this patch series.

>>
>>>
>>> Please see Patch 1/4
>>>
>>> +            else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
>>> +                 strcmp(args[0].from, "LSM_STATE") == 0)
>>> +                entry->func = LSM_STATE;
>>> +            else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
>>> +                 strcmp(args[0].from, "LSM_POLICY") == 0)
>>> +                entry->func = LSM_POLICY;
>>>
>>> And, if early boot measurement is needed for AppArmor the following change in IMA's Kconfig
>>>
>>> Patch 4/4
>>>
>>> +config IMA_QUEUE_EARLY_BOOT_DATA
>>>      bool
>>> +    depends on SECURITY_SELINUX || (IMA_MEASURE_ASYMMETRIC_KEYS && SYSTEM_TRUSTED_KEYRING)
>>>      default y
>>>
>>> If you think calling this an "LSM feature" is not appropriate, please suggest a better phrase.
>>
>> In the code above you are under CONFIG_SECURITY_SELINUX.
>> I would suggest that it's an SELinux feature, so you should
>> be using SELINUX_STATE and SELINUX_POLICY, as I suggested
>> before. Just because SELinux has state and policy to measure
>> doesn't mean that a different module might not have other data,
>> such as history, that should be covered as well.

Good point - if other SMs have data besides state and policy, we can
define IMA hooks to measure that as well.

But I still think it is not the right approach to call this
SELINUX_STATE and SELINUX_POLICY - it will lead to unnecessary code
duplication in IMA as more SMs are onboarded, in my opinion. Correct me
if I am wrong.

-lakshmi

>
> In addition to SELINUX_STATE and SELINUX_POLICY, we should also consider
> the proposed LSM_STATE and LSM_POLICY func values but require an "lsm"
> rule conditional.
>
> So the current proposed rules:
>
> measure func=LSM_STATE
> measure func=LSM_POLICY
>
> Would become:
>
> measure func=LSM_STATE lsm=selinux
> measure func=LSM_POLICY lsm=selinux
>
> The following rules would be rejected:
>
> measure func=LSM_STATE
> measure func=LSM_POLICY
> measure func=LSM_STATE lsm=apparmor
> measure func=LSM_POLICY lsm=smack
>
> Of course, the apparmor and smack rules could/would be allowed when
> proper support is in place.
>

>
>>
>> I realize that IMA already has compile time dependencies to
>> determine which xattrs to measure. There's no reason that
>> the xattr list couldn't be determined at boot time, with
>> each security module providing the XATTR_NAME values it
>> uses.
>>
>>>
>>> But like I said above, with minimal change in IMA other security modules can be supported to measure STATE and POLICY data.
>>>
>>>  -lakshmi
>>>
>>>

2020-08-05 16:28:57

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On Wed, 2020-08-05 at 10:27 -0400, Stephen Smalley wrote:
> On Wed, Aug 5, 2020 at 9:20 AM Mimi Zohar <[email protected]> wrote:
> > On Wed, 2020-08-05 at 09:03 -0400, Stephen Smalley wrote:
> > > On Wed, Aug 5, 2020 at 8:57 AM Mimi Zohar <[email protected]> wrote:
> > > > On Wed, 2020-08-05 at 08:46 -0400, Stephen Smalley wrote:
> > > > > On 8/4/20 11:25 PM, Mimi Zohar wrote:
> > > > >
> > > > > > Hi Lakshmi,
> > > > > >
> > > > > > There's still a number of other patch sets needing to be reviewed
> > > > > > before my getting to this one. The comment below is from a high level.
> > > > > >
> > > > > > On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
> > > > > > > Critical data structures of security modules need to be measured to
> > > > > > > enable an attestation service to verify if the configuration and
> > > > > > > policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
> > > > > > > measure the state and the policy provided by the security modules.
> > > > > > > Update ima_match_rules() and ima_validate_rule() to check for
> > > > > > > the new func and ima_parse_rule() to handle the new func.
> > > > > > I can understand wanting to measure the in kernel LSM memory state to
> > > > > > make sure it hasn't changed, but policies are stored as files. Buffer
> > > > > > measurements should be limited to those things that are not files.
> > > > > >
> > > > > > Changing how data is passed to the kernel has been happening for a
> > > > > > while. For example, instead of passing the kernel module or kernel
> > > > > > image in a buffer, the new syscalls - finit_module, kexec_file_load -
> > > > > > pass an open file descriptor. Similarly, instead of loading the IMA
> > > > > > policy data, a pathname may be provided.
> > > > > >
> > > > > > Pre and post security hooks already exist for reading files. Instead
> > > > > > of adding IMA support for measuring the policy file data, update the
> > > > > > mechanism for loading the LSM policy. Then not only will you be able
> > > > > > to measure the policy, you'll also be able to require the policy be
> > > > > > signed.
> > > > >
> > > > > To clarify, the policy being measured by this patch series is a
> > > > > serialized representation of the in-memory policy data structures being
> > > > > enforced by SELinux. Not the file that was loaded. Hence, this
> > > > > measurement would detect tampering with the in-memory policy data
> > > > > structures after the policy has been loaded. In the case of SELinux,
> > > > > one can read this serialized representation via /sys/fs/selinux/policy.
> > > > > The result is not byte-for-byte identical to the policy file that was
> > > > > loaded but can be semantically compared via sediff and other tools to
> > > > > determine whether it is equivalent.
> > > >
> > > > Thank you for the clarification. Could the policy hash be included
> > > > with the other critical data? Does it really need to be measured
> > > > independently?
> > >
> > > They were split into two separate functions because we wanted to be
> > > able to support using different templates for them (ima-buf for the
> > > state variables so that the measurement includes the original buffer,
> > > which is small and relatively fixed-size, and ima-ng for the policy
> > > because it is large and we just want to capture the hash for later
> > > comparison against known-good). Also, the state variables are
> > > available for measurement always from early initialization, whereas
> > > the policy is only available for measurement once we have loaded an
> > > initial policy.
> >
> > Ok, measuring the policy separately from other critical data makes
> > sense. Instead of measuring the policy, which is large, measure the
> > policy hash.
>
> I think that was the original approach. However, I had concerns with
> adding code to SELinux to compute a hash over the policy versus
> leaving that to IMA's existing policy and mechanism. If that's
> preferred I guess we can do it that way but seems less flexible and
> duplicative.

Whether IMA or SELinux calculates the in memory policy hash, it should
not impact the original purpose of this patch set - measuring critical
state. It's unclear whether this patch set needs to be limited to LSM
critical state.

Measuring the in memory policy, if needed, should be a separate patch
set.

Mimi

2020-08-05 16:32:49

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/4/2020 6:14 PM, Lakshmi Ramasubramanian wrote:
> On 8/4/20 6:04 PM, Casey Schaufler wrote:
>> On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
>>> Critical data structures of security modules are currently not measured.
>>> Therefore an attestation service, for instance, would not be able to
>>> attest whether the security modules are always operating with the policies
>>> and configuration that the system administrator had setup. The policies
>>> and configuration for the security modules could be tampered with by
>>> malware by exploiting kernel vulnerabilities or modified through some
>>> inadvertent actions on the system. Measuring such critical data would
>>> enable an attestation service to better assess the state of the system.
>>
>> I still wonder why you're calling this an LSM change/feature when
>> all the change is in IMA and SELinux. You're not putting anything
>> into the LSM infrastructure, not are you using the LSM infrastructure
>> to achieve your ends. Sure, you *could* support other security modules
>> using this scheme, but you have a configuration dependency on
>> SELinux, so that's at best going to be messy. If you want this to
>> be an LSM "feature" you need to use the LSM hooking mechanism.
>
>>
>> I'm not objecting to the feature. It adds value. But as you've
>> implemented it it is either an IMA extension to SELinux, or an
>> SELiux extension to IMA. Could AppArmor add hooks for this without
>> changing the IMA code? It doesn't look like it to me.
>
> The check in IMA to allow the new IMA hook func LSM_STATE and LSM_POLICY when SELinux is enabled is just because SELinux is the only security module using these hooks now.
>
> To enable AppArmor, for instance, to use the new IMA hooks to measure state and policy would just require adding the check for CONFIG_SECURITY_APPARMOR. Other than that, there are no IMA changes needed to support AppArmor or other such security modules.

This is exactly what I'm objecting to. What if a system has both SELinux
and AppArmor compiled in? What if it has both enabled?

>
> Please see Patch 1/4
>
> +            else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
> +                 strcmp(args[0].from, "LSM_STATE") == 0)
> +                entry->func = LSM_STATE;
> +            else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
> +                 strcmp(args[0].from, "LSM_POLICY") == 0)
> +                entry->func = LSM_POLICY;
>
> And, if early boot measurement is needed for AppArmor the following change in IMA's Kconfig
>
> Patch 4/4
>
> +config IMA_QUEUE_EARLY_BOOT_DATA
>      bool
> +    depends on SECURITY_SELINUX || (IMA_MEASURE_ASYMMETRIC_KEYS && SYSTEM_TRUSTED_KEYRING)
>      default y
>
> If you think calling this an "LSM feature" is not appropriate, please suggest a better phrase.

In the code above you are under CONFIG_SECURITY_SELINUX.
I would suggest that it's an SELinux feature, so you should
be using SELINUX_STATE and SELINUX_POLICY, as I suggested
before. Just because SELinux has state and policy to measure
doesn't mean that a different module might not have other data,
such as history, that should be covered as well.

I realize that IMA already has compile time dependencies to
determine which xattrs to measure. There's no reason that
the xattr list couldn't be determined at boot time, with
each security module providing the XATTR_NAME values it
uses.

>
> But like I said above, with minimal change in IMA other security modules can be supported to measure STATE and POLICY data.
>
>  -lakshmi
>
>

2020-08-05 17:12:44

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On Tue, 2020-08-04 at 18:04 -0700, Casey Schaufler wrote:
> On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
> > Critical data structures of security modules are currently not measured.
> > Therefore an attestation service, for instance, would not be able to
> > attest whether the security modules are always operating with the policies
> > and configuration that the system administrator had setup. The policies
> > and configuration for the security modules could be tampered with by
> > malware by exploiting kernel vulnerabilities or modified through some
> > inadvertent actions on the system. Measuring such critical data would
> > enable an attestation service to better assess the state of the system.
>
> I still wonder why you're calling this an LSM change/feature when
> all the change is in IMA and SELinux. You're not putting anything
> into the LSM infrastructure, not are you using the LSM infrastructure
> to achieve your ends. Sure, you *could* support other security modules
> using this scheme, but you have a configuration dependency on
> SELinux, so that's at best going to be messy. If you want this to
> be an LSM "feature" you need to use the LSM hooking mechanism.
>
> I'm not objecting to the feature. It adds value. But as you've
> implemented it it is either an IMA extension to SELinux, or an
> SELiux extension to IMA. Could AppArmor add hooks for this without
> changing the IMA code? It doesn't look like it to me.

Agreed. Without reviewing the patch set in depth, I'm not quite sure
why this patch set needs to be limited to measuring just LSM critical
data and can't be generalized. The patch set could be titled "ima:
measuring critical data" or "ima: measuring critical kernel data".
Measuring SELinux critical data would be an example of its usage.

For an example, refer to the ima_file_check hook, which is an example
of IMA being called directly, not via an LSM hook.

Mimi

2020-08-05 17:13:25

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On Wed, 2020-08-05 at 10:45 -0500, Tyler Hicks wrote:

> In addition to SELINUX_STATE and SELINUX_POLICY, we should also consider
> the proposed LSM_STATE and LSM_POLICY func values but require an "lsm"
> rule conditional.
>
> So the current proposed rules:
>
> measure func=LSM_STATE
> measure func=LSM_POLICY
>
> Would become:
>
> measure func=LSM_STATE lsm=selinux
> measure func=LSM_POLICY lsm=selinux
>
> The following rules would be rejected:
>
> measure func=LSM_STATE
> measure func=LSM_POLICY
> measure func=LSM_STATE lsm=apparmor
> measure func=LSM_POLICY lsm=smack

Kees is cleaning up the firmware code which differentiated between how
firmware was loaded. There will be a single firmware enumeration.

Similarly, the new IMA hook to measure critical state may be placed in
multiple places. Is there really a need from a policy perspective for
differentiating the source of the critical state being measurind? The
data being measured should include some identifying information.

I think moving away from the idea that measuring "critical" data should
be limited to LSMs, will clarify this.

Mimi

2020-08-05 17:20:37

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On Wed, 2020-08-05 at 08:46 -0400, Stephen Smalley wrote:
> On 8/4/20 11:25 PM, Mimi Zohar wrote:
>
> > Hi Lakshmi,
> >
> > There's still a number of other patch sets needing to be reviewed
> > before my getting to this one. The comment below is from a high level.
> >
> > On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
> > > Critical data structures of security modules need to be measured to
> > > enable an attestation service to verify if the configuration and
> > > policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
> > > measure the state and the policy provided by the security modules.
> > > Update ima_match_rules() and ima_validate_rule() to check for
> > > the new func and ima_parse_rule() to handle the new func.
> > I can understand wanting to measure the in kernel LSM memory state to
> > make sure it hasn't changed, but policies are stored as files. Buffer
> > measurements should be limited to those things that are not files.
> >
> > Changing how data is passed to the kernel has been happening for a
> > while. For example, instead of passing the kernel module or kernel
> > image in a buffer, the new syscalls - finit_module, kexec_file_load -
> > pass an open file descriptor. Similarly, instead of loading the IMA
> > policy data, a pathname may be provided.
> >
> > Pre and post security hooks already exist for reading files. Instead
> > of adding IMA support for measuring the policy file data, update the
> > mechanism for loading the LSM policy. Then not only will you be able
> > to measure the policy, you'll also be able to require the policy be
> > signed.
>
> To clarify, the policy being measured by this patch series is a
> serialized representation of the in-memory policy data structures being
> enforced by SELinux. Not the file that was loaded. Hence, this
> measurement would detect tampering with the in-memory policy data
> structures after the policy has been loaded. In the case of SELinux,
> one can read this serialized representation via /sys/fs/selinux/policy.
> The result is not byte-for-byte identical to the policy file that was
> loaded but can be semantically compared via sediff and other tools to
> determine whether it is equivalent.

Thank you for the clarification. Could the policy hash be included
with the other critical data? Does it really need to be measured
independently?

Mimi

2020-08-05 17:31:55

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/5/20 10:03 AM, Mimi Zohar wrote:
> On Wed, 2020-08-05 at 10:45 -0500, Tyler Hicks wrote:
>
>> In addition to SELINUX_STATE and SELINUX_POLICY, we should also consider
>> the proposed LSM_STATE and LSM_POLICY func values but require an "lsm"
>> rule conditional.
>>
>> So the current proposed rules:
>>
>> measure func=LSM_STATE
>> measure func=LSM_POLICY
>>
>> Would become:
>>
>> measure func=LSM_STATE lsm=selinux
>> measure func=LSM_POLICY lsm=selinux
>>
>> The following rules would be rejected:
>>
>> measure func=LSM_STATE
>> measure func=LSM_POLICY
>> measure func=LSM_STATE lsm=apparmor
>> measure func=LSM_POLICY lsm=smack
>
> Kees is cleaning up the firmware code which differentiated between how
> firmware was loaded. There will be a single firmware enumeration.
>
> Similarly, the new IMA hook to measure critical state may be placed in
> multiple places. Is there really a need from a policy perspective for
> differentiating the source of the critical state being measurind? The
> data being measured should include some identifying information.

Yes Mimi - SELinux is including the identifying information in the
"event name" field. Please see a sample measurement of STATE and POLICY
for SELinux below:

10 e32e...5ac3 ima-buf sha256:86e8...4594
selinux-state-1595389364:287899386
696e697469616c697a65643d313b656e61626c65643d313b656e666f7263696e673d303b636865636b72657170726f743d313b6e6574776f726b5f706565725f636f6e74726f6c733d313b6f70656e5f7065726d733d313b657874656e6465645f736f636b65745f636c6173733d313b616c776179735f636865636b5f6e6574776f726b3d303b6367726f75705f7365636c6162656c3d313b6e6e705f6e6f737569645f7472616e736974696f6e3d313b67656e66735f7365636c6162656c5f73796d6c696e6b733d303

10 f4a7...9408 ima-ng sha256:8d1d...1834
selinux-policy-hash-1595389353:863934271

>
> I think moving away from the idea that measuring "critical" data should
> be limited to LSMs, will clarify this.
>

Are you suggesting that instead of calling the hooks LSM_STATE and
LSM_POLICY, we should keep it more generic so that it can be utilized by
any subsystem to measure their "critical data"?

I think that is a good idea.

-lakshmi

2020-08-05 19:14:07

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/5/2020 11:08 AM, Lakshmi Ramasubramanian wrote:
> On 8/5/20 10:57 AM, Casey Schaufler wrote:
>> On 8/5/2020 10:25 AM, Lakshmi Ramasubramanian wrote:
>>> On 8/5/20 10:03 AM, Mimi Zohar wrote:
>>>> On Wed, 2020-08-05 at 10:45 -0500, Tyler Hicks wrote:
>>>>
>>>>> In addition to SELINUX_STATE and SELINUX_POLICY, we should also consider
>>>>> the proposed LSM_STATE and LSM_POLICY func values but require an "lsm"
>>>>> rule conditional.
>>>>>
>>>>> So the current proposed rules:
>>>>>
>>>>> ? measure func=LSM_STATE
>>>>> ? measure func=LSM_POLICY
>>>>>
>>>>> Would become:
>>>>>
>>>>> ? measure func=LSM_STATE lsm=selinux
>>>>> ? measure func=LSM_POLICY lsm=selinux
>>>>>
>>>>> The following rules would be rejected:
>>>>>
>>>>> ? measure func=LSM_STATE
>>>>> ? measure func=LSM_POLICY
>>>>> ? measure func=LSM_STATE lsm=apparmor
>>>>> ? measure func=LSM_POLICY lsm=smack
>>>>
>>>> Kees is cleaning up the firmware code which differentiated between how
>>>> firmware was loaded.?? There will be a single firmware enumeration.
>>>>
>>>> Similarly, the new IMA hook to measure critical state may be placed in
>>>> multiple places.? Is there really a need from a policy perspective for
>>>> differentiating the source of the critical state being measurind??? The
>>>> data being measured should include some identifying information.
>>>
>>> Yes Mimi - SELinux is including the identifying information in the "event name" field. Please see a sample measurement of STATE and POLICY for SELinux below:
>>>
>>> 10 e32e...5ac3 ima-buf sha256:86e8...4594 selinux-state-1595389364:287899386 696e697469616c697a65643d313b656e61626c65643d313b656e666f7263696e673d303b636865636b72657170726f743d313b6e6574776f726b5f706565725f636f6e74726f6c733d313b6f70656e5f7065726d733d313b657874656e6465645f736f636b65745f636c6173733d313b616c776179735f636865636b5f6e6574776f726b3d303b6367726f75705f7365636c6162656c3d313b6e6e705f6e6f737569645f7472616e736974696f6e3d313b67656e66735f7365636c6162656c5f73796d6c696e6b733d303
>>>
>>> 10 f4a7...9408 ima-ng sha256:8d1d...1834 selinux-policy-hash-1595389353:863934271
>>>
>>>>
>>>> I think moving away from the idea that measuring "critical" data should
>>>> be limited to LSMs, will clarify this.
>>>>
>>>
>>> Are you suggesting that instead of calling the hooks LSM_STATE and LSM_POLICY, we should keep it more generic so that it can be utilized by any subsystem to measure their "critical data"?
>>
>> Policy, state, history or whim, it should be up to the security module
>> to determine what data it cares about, and how it should be measured.
>> Smack does not keep its policy in a single blob of data, it uses lists
>> which can be modified at will. Your definition of the behavior for
>> LSM_POLICY wouldn't work for Smack. That doesn't mean that there isn't
>> a viable way to measure the Smack policy, it just means that IMA isn't
>> the place for it. If SELinux wants its data measured, SELinux should be
>> providing the mechanism to do it.
>>
>> I guess that I'm agreeing with you in part. If you want a generic measurement
>> of "critical data", you don't need to assign a type to it, you have the
>> caller (a security module, a device driver or whatever) identify itself and
>> how it is going to deal with the data. That's very different from what you've
>> done to date.
>
> Agree.
>
> Like Stephen had stated earlier, the reason we kept separate hooks (STATE and POLICY) is because the data for state is usually small and therefore we measure the entire data. Whereas, policy data is usually quite large (a few MB) and hence we measure a hash of the policy.

SELinux should determine how it wants its data measured.
SELinux, not IMA, should determine if some "critical data"
be measured in total, by its hash or as a count of policy
rules. It would be handy for IMA to supply functions to do
data blobs and hashes, but it should be up to the caller to
decide if they meet their needs.

>
> If change to a generic measurement of "critical data", at the least IMA should provide a way to measure "data" and "hash(data)".
>
> And, with the caller providing the identifying information, there would be no need to call it "LSM_STATE" or "SELINUX_STATE" or such.
>
> ?-lakshmi
>
>

2020-08-05 19:15:01

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/5/20 10:57 AM, Casey Schaufler wrote:
> On 8/5/2020 10:25 AM, Lakshmi Ramasubramanian wrote:
>> On 8/5/20 10:03 AM, Mimi Zohar wrote:
>>> On Wed, 2020-08-05 at 10:45 -0500, Tyler Hicks wrote:
>>>
>>>> In addition to SELINUX_STATE and SELINUX_POLICY, we should also consider
>>>> the proposed LSM_STATE and LSM_POLICY func values but require an "lsm"
>>>> rule conditional.
>>>>
>>>> So the current proposed rules:
>>>>
>>>> ? measure func=LSM_STATE
>>>> ? measure func=LSM_POLICY
>>>>
>>>> Would become:
>>>>
>>>> ? measure func=LSM_STATE lsm=selinux
>>>> ? measure func=LSM_POLICY lsm=selinux
>>>>
>>>> The following rules would be rejected:
>>>>
>>>> ? measure func=LSM_STATE
>>>> ? measure func=LSM_POLICY
>>>> ? measure func=LSM_STATE lsm=apparmor
>>>> ? measure func=LSM_POLICY lsm=smack
>>>
>>> Kees is cleaning up the firmware code which differentiated between how
>>> firmware was loaded.?? There will be a single firmware enumeration.
>>>
>>> Similarly, the new IMA hook to measure critical state may be placed in
>>> multiple places.? Is there really a need from a policy perspective for
>>> differentiating the source of the critical state being measurind??? The
>>> data being measured should include some identifying information.
>>
>> Yes Mimi - SELinux is including the identifying information in the "event name" field. Please see a sample measurement of STATE and POLICY for SELinux below:
>>
>> 10 e32e...5ac3 ima-buf sha256:86e8...4594 selinux-state-1595389364:287899386 696e697469616c697a65643d313b656e61626c65643d313b656e666f7263696e673d303b636865636b72657170726f743d313b6e6574776f726b5f706565725f636f6e74726f6c733d313b6f70656e5f7065726d733d313b657874656e6465645f736f636b65745f636c6173733d313b616c776179735f636865636b5f6e6574776f726b3d303b6367726f75705f7365636c6162656c3d313b6e6e705f6e6f737569645f7472616e736974696f6e3d313b67656e66735f7365636c6162656c5f73796d6c696e6b733d303
>>
>> 10 f4a7...9408 ima-ng sha256:8d1d...1834 selinux-policy-hash-1595389353:863934271
>>
>>>
>>> I think moving away from the idea that measuring "critical" data should
>>> be limited to LSMs, will clarify this.
>>>
>>
>> Are you suggesting that instead of calling the hooks LSM_STATE and LSM_POLICY, we should keep it more generic so that it can be utilized by any subsystem to measure their "critical data"?
>
> Policy, state, history or whim, it should be up to the security module
> to determine what data it cares about, and how it should be measured.
> Smack does not keep its policy in a single blob of data, it uses lists
> which can be modified at will. Your definition of the behavior for
> LSM_POLICY wouldn't work for Smack. That doesn't mean that there isn't
> a viable way to measure the Smack policy, it just means that IMA isn't
> the place for it. If SELinux wants its data measured, SELinux should be
> providing the mechanism to do it.
>
> I guess that I'm agreeing with you in part. If you want a generic measurement
> of "critical data", you don't need to assign a type to it, you have the
> caller (a security module, a device driver or whatever) identify itself and
> how it is going to deal with the data. That's very different from what you've
> done to date.

Agree.

Like Stephen had stated earlier, the reason we kept separate hooks
(STATE and POLICY) is because the data for state is usually small and
therefore we measure the entire data. Whereas, policy data is usually
quite large (a few MB) and hence we measure a hash of the policy.

If change to a generic measurement of "critical data", at the least IMA
should provide a way to measure "data" and "hash(data)".

And, with the caller providing the identifying information, there would
be no need to call it "LSM_STATE" or "SELINUX_STATE" or such.

-lakshmi


2020-08-05 19:22:15

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/5/2020 10:25 AM, Lakshmi Ramasubramanian wrote:
> On 8/5/20 10:03 AM, Mimi Zohar wrote:
>> On Wed, 2020-08-05 at 10:45 -0500, Tyler Hicks wrote:
>>
>>> In addition to SELINUX_STATE and SELINUX_POLICY, we should also consider
>>> the proposed LSM_STATE and LSM_POLICY func values but require an "lsm"
>>> rule conditional.
>>>
>>> So the current proposed rules:
>>>
>>> ? measure func=LSM_STATE
>>> ? measure func=LSM_POLICY
>>>
>>> Would become:
>>>
>>> ? measure func=LSM_STATE lsm=selinux
>>> ? measure func=LSM_POLICY lsm=selinux
>>>
>>> The following rules would be rejected:
>>>
>>> ? measure func=LSM_STATE
>>> ? measure func=LSM_POLICY
>>> ? measure func=LSM_STATE lsm=apparmor
>>> ? measure func=LSM_POLICY lsm=smack
>>
>> Kees is cleaning up the firmware code which differentiated between how
>> firmware was loaded.?? There will be a single firmware enumeration.
>>
>> Similarly, the new IMA hook to measure critical state may be placed in
>> multiple places.? Is there really a need from a policy perspective for
>> differentiating the source of the critical state being measurind??? The
>> data being measured should include some identifying information.
>
> Yes Mimi - SELinux is including the identifying information in the "event name" field. Please see a sample measurement of STATE and POLICY for SELinux below:
>
> 10 e32e...5ac3 ima-buf sha256:86e8...4594 selinux-state-1595389364:287899386 696e697469616c697a65643d313b656e61626c65643d313b656e666f7263696e673d303b636865636b72657170726f743d313b6e6574776f726b5f706565725f636f6e74726f6c733d313b6f70656e5f7065726d733d313b657874656e6465645f736f636b65745f636c6173733d313b616c776179735f636865636b5f6e6574776f726b3d303b6367726f75705f7365636c6162656c3d313b6e6e705f6e6f737569645f7472616e736974696f6e3d313b67656e66735f7365636c6162656c5f73796d6c696e6b733d303
>
> 10 f4a7...9408 ima-ng sha256:8d1d...1834 selinux-policy-hash-1595389353:863934271
>
>>
>> I think moving away from the idea that measuring "critical" data should
>> be limited to LSMs, will clarify this.
>>
>
> Are you suggesting that instead of calling the hooks LSM_STATE and LSM_POLICY, we should keep it more generic so that it can be utilized by any subsystem to measure their "critical data"?

Policy, state, history or whim, it should be up to the security module
to determine what data it cares about, and how it should be measured.
Smack does not keep its policy in a single blob of data, it uses lists
which can be modified at will. Your definition of the behavior for
LSM_POLICY wouldn't work for Smack. That doesn't mean that there isn't
a viable way to measure the Smack policy, it just means that IMA isn't
the place for it. If SELinux wants its data measured, SELinux should be
providing the mechanism to do it.

I guess that I'm agreeing with you in part. If you want a generic measurement
of "critical data", you don't need to assign a type to it, you have the
caller (a security module, a device driver or whatever) identify itself and
how it is going to deal with the data. That's very different from what you've
done to date.

>
> I think that is a good idea.
>
> ?-lakshmi

2020-08-05 19:22:25

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/5/2020 9:32 AM, Tyler Hicks wrote:
> On 2020-08-05 09:21:24, Lakshmi Ramasubramanian wrote:
>> On 8/5/20 9:14 AM, Tyler Hicks wrote:
>>> On 2020-08-05 09:07:48, Lakshmi Ramasubramanian wrote:
>>>> On 8/5/20 8:45 AM, Tyler Hicks wrote:
>>>>> On 2020-08-05 08:36:40, Casey Schaufler wrote:
>>>>>> On 8/4/2020 6:14 PM, Lakshmi Ramasubramanian wrote:
>>>>>>> On 8/4/20 6:04 PM, Casey Schaufler wrote:
>>>>>>>> On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
>>>>>>>>> Critical data structures of security modules are currently not measured.
>>>>>>>>> Therefore an attestation service, for instance, would not be able to
>>>>>>>>> attest whether the security modules are always operating with the policies
>>>>>>>>> and configuration that the system administrator had setup. The policies
>>>>>>>>> and configuration for the security modules could be tampered with by
>>>>>>>>> malware by exploiting kernel vulnerabilities or modified through some
>>>>>>>>> inadvertent actions on the system. Measuring such critical data would
>>>>>>>>> enable an attestation service to better assess the state of the system.
>>>>>>>> I still wonder why you're calling this an LSM change/feature when
>>>>>>>> all the change is in IMA and SELinux. You're not putting anything
>>>>>>>> into the LSM infrastructure, not are you using the LSM infrastructure
>>>>>>>> to achieve your ends. Sure, you *could* support other security modules
>>>>>>>> using this scheme, but you have a configuration dependency on
>>>>>>>> SELinux, so that's at best going to be messy. If you want this to
>>>>>>>> be an LSM "feature" you need to use the LSM hooking mechanism.
>>>>>>>> I'm not objecting to the feature. It adds value. But as you've
>>>>>>>> implemented it it is either an IMA extension to SELinux, or an
>>>>>>>> SELiux extension to IMA. Could AppArmor add hooks for this without
>>>>>>>> changing the IMA code? It doesn't look like it to me.
>>>>>>> The check in IMA to allow the new IMA hook func LSM_STATE and LSM_POLICY when SELinux is enabled is just because SELinux is the only security module using these hooks now.
>>>>>>>
>>>>>>> To enable AppArmor, for instance, to use the new IMA hooks to measure state and policy would just require adding the check for CONFIG_SECURITY_APPARMOR. Other than that, there are no IMA changes needed to support AppArmor or other such security modules.
>>>>>> This is exactly what I'm objecting to. What if a system has both SELinux
>>>>>> and AppArmor compiled in? What if it has both enabled?
>>>>> The SELinux state and policy would be measured but the AppArmor
>>>>> state/policy would be silently ignored. This isn't ideal as the IMA
>>>>> policy author would need to read the kernel code to figure out which
>>>>> LSMs are going to be measured.
>>>> Tyler - I am not sure why AppArmor state\policy would be ignored when both
>>>> SELinux and AppArmor are enabled. Could you please clarify?
>>> I think Casey is talking about now (when AppArmor is not supported by
>>> this feature) and you're talking about the future (when AppArmor may be
>>> supported by this feature).
>> Got it - thanks for clarifying.
>>
>> But with the current code if SELinux is enabled on the system, but AppArmor
>> is not and the IMA policy contains "measure func=LSM_STATE" then the policy
>> will be rejected as "-EINVAL".
> The AppArmor policy load? Yes, the load will fail.
>
> What Casey is talking about is when SELinux and AppArmor are enabled in
> the kernel config but AppArmor is active. This scenario is true in
> distro kernels such as Ubuntu's kernel:
>
> $ grep -e CONFIG_SECURITY_SELINUX= -e CONFIG_SECURITY_APPARMOR= /boot/config-5.4.0-42-generic
> CONFIG_SECURITY_SELINUX=y
> CONFIG_SECURITY_APPARMOR=y
> $ cat /sys/kernel/security/lsm
> lockdown,capability,yama,apparmor

Yes. This is one reason that a compile time check is inappropriate.
You also have the case with SELinux where you can unload the module.
It's deprecated, but still possible.

If you boot with SELinux compiled in, but with security=none on
the boot line you also have a case where the compile time check is
inappropriate.

> Casey also likely has LSM stacking in mind here where SELinux and
> AppArmor could both be active at the same time but the LSM stacking
> series is not yet applied.

It isn't in Linus' kernel, but is available in Ubuntu.
The audit/IMA rule selection get hairy in the multiple
security module case, but you don't need to add that
for the proposed scheme to be flawed.

>
> Tyler
>
>> So the policy author would get a feedback even now.
>> Correct me if I am wrong.
>>
>> -lakshmi

2020-08-05 19:52:54

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On 8/5/20 11:07 AM, Tyler Hicks wrote:

> On 2020-08-05 10:27:43, Stephen Smalley wrote:
>> On Wed, Aug 5, 2020 at 9:20 AM Mimi Zohar <[email protected]> wrote:
>>> On Wed, 2020-08-05 at 09:03 -0400, Stephen Smalley wrote:
>>>> On Wed, Aug 5, 2020 at 8:57 AM Mimi Zohar <[email protected]> wrote:
>>>>> On Wed, 2020-08-05 at 08:46 -0400, Stephen Smalley wrote:
>>>>>> On 8/4/20 11:25 PM, Mimi Zohar wrote:
>>>>>>
>>>>>>> Hi Lakshmi,
>>>>>>>
>>>>>>> There's still a number of other patch sets needing to be reviewed
>>>>>>> before my getting to this one. The comment below is from a high level.
>>>>>>>
>>>>>>> On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
>>>>>>>> Critical data structures of security modules need to be measured to
>>>>>>>> enable an attestation service to verify if the configuration and
>>>>>>>> policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
>>>>>>>> measure the state and the policy provided by the security modules.
>>>>>>>> Update ima_match_rules() and ima_validate_rule() to check for
>>>>>>>> the new func and ima_parse_rule() to handle the new func.
>>>>>>> I can understand wanting to measure the in kernel LSM memory state to
>>>>>>> make sure it hasn't changed, but policies are stored as files. Buffer
>>>>>>> measurements should be limited to those things that are not files.
>>>>>>>
>>>>>>> Changing how data is passed to the kernel has been happening for a
>>>>>>> while. For example, instead of passing the kernel module or kernel
>>>>>>> image in a buffer, the new syscalls - finit_module, kexec_file_load -
>>>>>>> pass an open file descriptor. Similarly, instead of loading the IMA
>>>>>>> policy data, a pathname may be provided.
>>>>>>>
>>>>>>> Pre and post security hooks already exist for reading files. Instead
>>>>>>> of adding IMA support for measuring the policy file data, update the
>>>>>>> mechanism for loading the LSM policy. Then not only will you be able
>>>>>>> to measure the policy, you'll also be able to require the policy be
>>>>>>> signed.
>>>>>> To clarify, the policy being measured by this patch series is a
>>>>>> serialized representation of the in-memory policy data structures being
>>>>>> enforced by SELinux. Not the file that was loaded. Hence, this
>>>>>> measurement would detect tampering with the in-memory policy data
>>>>>> structures after the policy has been loaded. In the case of SELinux,
>>>>>> one can read this serialized representation via /sys/fs/selinux/policy.
>>>>>> The result is not byte-for-byte identical to the policy file that was
>>>>>> loaded but can be semantically compared via sediff and other tools to
>>>>>> determine whether it is equivalent.
>>>>> Thank you for the clarification. Could the policy hash be included
>>>>> with the other critical data? Does it really need to be measured
>>>>> independently?
>>>> They were split into two separate functions because we wanted to be
>>>> able to support using different templates for them (ima-buf for the
>>>> state variables so that the measurement includes the original buffer,
>>>> which is small and relatively fixed-size, and ima-ng for the policy
>>>> because it is large and we just want to capture the hash for later
>>>> comparison against known-good). Also, the state variables are
>>>> available for measurement always from early initialization, whereas
>>>> the policy is only available for measurement once we have loaded an
>>>> initial policy.
>>> Ok, measuring the policy separately from other critical data makes
>>> sense. Instead of measuring the policy, which is large, measure the
>>> policy hash.
>> I think that was the original approach. However, I had concerns with
>> adding code to SELinux to compute a hash over the policy versus
>> leaving that to IMA's existing policy and mechanism. If that's
>> preferred I guess we can do it that way but seems less flexible and
>> duplicative.
> In AppArmor, we store the sha1 of the raw policy as the policy is
> loaded. The hash is exposed to userspace in apparmorfs. See commit
> 5ac8c355ae00 ("apparmor: allow introspecting the loaded policy pre
> internal transform").
>
> It has proved useful as a mechanism for debugging as sometimes the
> on-disk policy doesn't match the loaded policy and this can be a good
> way to check that while providing support to users. John also mentions
> checkpoint/restore in the commit message and I could certainly see how
> the policy hashes would be useful in that scenario.
>
> When thinking through how Lakshmi's series could be extended for
> AppArmor support, I was thinking that the AppArmor policy measurement
> would be a measurement of these hashes that we already have in place.
>
> Perhaps there's some general usefulness in storing/exposing an SELinux
> policy hash rather than only seeing it as duplicative property required
> this measurement series?

That would be a hash of the policy file that was last loaded via the
selinuxfs interface for loading policy, not a hash of the in-memory
policy data structures at the time of measurement (which is what this
patch series is implementing).  The duplicative part is with respect to
selecting a hash algorithm and hashing the in-memory policy as part of
the SELinux code rather than just passing the policy buffer to IMA for
measurement like any other buffer.  Userspace can already hash the
in-memory policy data itself by running sha256sum or whatever on
/sys/fs/selinux/policy, so we don't need to save or expose that separately.


2020-08-05 19:56:29

by John Johansen

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On 8/5/20 8:43 AM, Stephen Smalley wrote:
> On 8/5/20 11:07 AM, Tyler Hicks wrote:
>
>> On 2020-08-05 10:27:43, Stephen Smalley wrote:
>>> On Wed, Aug 5, 2020 at 9:20 AM Mimi Zohar <[email protected]> wrote:
>>>> On Wed, 2020-08-05 at 09:03 -0400, Stephen Smalley wrote:
>>>>> On Wed, Aug 5, 2020 at 8:57 AM Mimi Zohar <[email protected]> wrote:
>>>>>> On Wed, 2020-08-05 at 08:46 -0400, Stephen Smalley wrote:
>>>>>>> On 8/4/20 11:25 PM, Mimi Zohar wrote:
>>>>>>>
>>>>>>>> Hi Lakshmi,
>>>>>>>>
>>>>>>>> There's still  a number of other patch sets needing to be reviewed
>>>>>>>> before my getting to this one.  The comment below is from a high level.
>>>>>>>>
>>>>>>>> On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
>>>>>>>>> Critical data structures of security modules need to be measured to
>>>>>>>>> enable an attestation service to verify if the configuration and
>>>>>>>>> policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
>>>>>>>>> measure the state and the policy provided by the security modules.
>>>>>>>>> Update ima_match_rules() and ima_validate_rule() to check for
>>>>>>>>> the new func and ima_parse_rule() to handle the new func.
>>>>>>>> I can understand wanting to measure the in kernel LSM memory state to
>>>>>>>> make sure it hasn't changed, but policies are stored as files.  Buffer
>>>>>>>> measurements should be limited  to those things that are not files.
>>>>>>>>
>>>>>>>> Changing how data is passed to the kernel has been happening for a
>>>>>>>> while.  For example, instead of passing the kernel module or kernel
>>>>>>>> image in a buffer, the new syscalls - finit_module, kexec_file_load -
>>>>>>>> pass an open file descriptor.  Similarly, instead of loading the IMA
>>>>>>>> policy data, a pathname may be provided.
>>>>>>>>
>>>>>>>> Pre and post security hooks already exist for reading files.   Instead
>>>>>>>> of adding IMA support for measuring the policy file data, update the
>>>>>>>> mechanism for loading the LSM policy.  Then not only will you be able
>>>>>>>> to measure the policy, you'll also be able to require the policy be
>>>>>>>> signed.
>>>>>>> To clarify, the policy being measured by this patch series is a
>>>>>>> serialized representation of the in-memory policy data structures being
>>>>>>> enforced by SELinux.  Not the file that was loaded.  Hence, this
>>>>>>> measurement would detect tampering with the in-memory policy data
>>>>>>> structures after the policy has been loaded.  In the case of SELinux,
>>>>>>> one can read this serialized representation via /sys/fs/selinux/policy.
>>>>>>> The result is not byte-for-byte identical to the policy file that was
>>>>>>> loaded but can be semantically compared via sediff and other tools to
>>>>>>> determine whether it is equivalent.
>>>>>> Thank you for the clarification.   Could the policy hash be included
>>>>>> with the other critical data?  Does it really need to be measured
>>>>>> independently?
>>>>> They were split into two separate functions because we wanted to be
>>>>> able to support using different templates for them (ima-buf for the
>>>>> state variables so that the measurement includes the original buffer,
>>>>> which is small and relatively fixed-size, and ima-ng for the policy
>>>>> because it is large and we just want to capture the hash for later
>>>>> comparison against known-good).  Also, the state variables are
>>>>> available for measurement always from early initialization, whereas
>>>>> the policy is only available for measurement once we have loaded an
>>>>> initial policy.
>>>> Ok, measuring the policy separately from other critical data makes
>>>> sense.  Instead of measuring the policy, which is large, measure the
>>>> policy hash.
>>> I think that was the original approach.  However, I had concerns with
>>> adding code to SELinux to compute a hash over the policy versus
>>> leaving that to IMA's existing policy and mechanism.  If that's
>>> preferred I guess we can do it that way but seems less flexible and
>>> duplicative.
>> In AppArmor, we store the sha1 of the raw policy as the policy is
>> loaded. The hash is exposed to userspace in apparmorfs. See commit
>> 5ac8c355ae00 ("apparmor: allow introspecting the loaded policy pre
>> internal transform").
>>
>> It has proved useful as a mechanism for debugging as sometimes the
>> on-disk policy doesn't match the loaded policy and this can be a good
>> way to check that while providing support to users. John also mentions
>> checkpoint/restore in the commit message and I could certainly see how
>> the policy hashes would be useful in that scenario.
>>
>> When thinking through how Lakshmi's series could be extended for
>> AppArmor support, I was thinking that the AppArmor policy measurement
>> would be a measurement of these hashes that we already have in place.
>>
>> Perhaps there's some general usefulness in storing/exposing an SELinux
>> policy hash rather than only seeing it as duplicative property required
>> this measurement series?
>
> That would be a hash of the policy file that was last loaded via the selinuxfs interface for loading policy, not a hash of the in-memory policy data structures at the time of measurement (which is what this patch series is implementing).  The duplicative part is with respect to selecting a hash algorithm and hashing the in-memory policy as part of the SELinux code rather than just passing the policy buffer to IMA for measurement like any other buffer.  Userspace can already hash the in-memory policy data itself by running sha256sum or whatever on /sys/fs/selinux/policy, so we don't need to save or expose that separately.
>
>

yeah apparmor exposes full loaded policy data that userspace could hash independently too, the hashing done by the kernel just reduces the amount of data that userspace has to suck down if they trust the kernel to do the hash. Those hashes are also used by apparmor internally for the first part of a dedup check so exposing them cost very little.

The hashing of the in-memory data structures and variables is something we are not currently doing. If we were to do it hashing in-memory apparmor policy would be quite involved and that would be something I would rather have LSMs export an interface for rather than having IMA poke directly at the data structures (ie. apparmor specific code in apparmor).

As for computing a measurement based on the hash instead of the in-memory policy, while quicker that would not detect memory corruption/attacks that manage to modify policy via writing kernel memory. Whether that type of measurement is sufficient depends on what you are trying to achieve.


2020-08-05 19:58:46

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On Wed, Aug 5, 2020 at 8:57 AM Mimi Zohar <[email protected]> wrote:
>
> On Wed, 2020-08-05 at 08:46 -0400, Stephen Smalley wrote:
> > On 8/4/20 11:25 PM, Mimi Zohar wrote:
> >
> > > Hi Lakshmi,
> > >
> > > There's still a number of other patch sets needing to be reviewed
> > > before my getting to this one. The comment below is from a high level.
> > >
> > > On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
> > > > Critical data structures of security modules need to be measured to
> > > > enable an attestation service to verify if the configuration and
> > > > policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
> > > > measure the state and the policy provided by the security modules.
> > > > Update ima_match_rules() and ima_validate_rule() to check for
> > > > the new func and ima_parse_rule() to handle the new func.
> > > I can understand wanting to measure the in kernel LSM memory state to
> > > make sure it hasn't changed, but policies are stored as files. Buffer
> > > measurements should be limited to those things that are not files.
> > >
> > > Changing how data is passed to the kernel has been happening for a
> > > while. For example, instead of passing the kernel module or kernel
> > > image in a buffer, the new syscalls - finit_module, kexec_file_load -
> > > pass an open file descriptor. Similarly, instead of loading the IMA
> > > policy data, a pathname may be provided.
> > >
> > > Pre and post security hooks already exist for reading files. Instead
> > > of adding IMA support for measuring the policy file data, update the
> > > mechanism for loading the LSM policy. Then not only will you be able
> > > to measure the policy, you'll also be able to require the policy be
> > > signed.
> >
> > To clarify, the policy being measured by this patch series is a
> > serialized representation of the in-memory policy data structures being
> > enforced by SELinux. Not the file that was loaded. Hence, this
> > measurement would detect tampering with the in-memory policy data
> > structures after the policy has been loaded. In the case of SELinux,
> > one can read this serialized representation via /sys/fs/selinux/policy.
> > The result is not byte-for-byte identical to the policy file that was
> > loaded but can be semantically compared via sediff and other tools to
> > determine whether it is equivalent.
>
> Thank you for the clarification. Could the policy hash be included
> with the other critical data? Does it really need to be measured
> independently?

They were split into two separate functions because we wanted to be
able to support using different templates for them (ima-buf for the
state variables so that the measurement includes the original buffer,
which is small and relatively fixed-size, and ima-ng for the policy
because it is large and we just want to capture the hash for later
comparison against known-good). Also, the state variables are
available for measurement always from early initialization, whereas
the policy is only available for measurement once we have loaded an
initial policy.

2020-08-05 19:59:19

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On 8/4/20 11:25 PM, Mimi Zohar wrote:

> Hi Lakshmi,
>
> There's still a number of other patch sets needing to be reviewed
> before my getting to this one. The comment below is from a high level.
>
> On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
>> Critical data structures of security modules need to be measured to
>> enable an attestation service to verify if the configuration and
>> policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
>> measure the state and the policy provided by the security modules.
>> Update ima_match_rules() and ima_validate_rule() to check for
>> the new func and ima_parse_rule() to handle the new func.
> I can understand wanting to measure the in kernel LSM memory state to
> make sure it hasn't changed, but policies are stored as files. Buffer
> measurements should be limited to those things that are not files.
>
> Changing how data is passed to the kernel has been happening for a
> while. For example, instead of passing the kernel module or kernel
> image in a buffer, the new syscalls - finit_module, kexec_file_load -
> pass an open file descriptor. Similarly, instead of loading the IMA
> policy data, a pathname may be provided.
>
> Pre and post security hooks already exist for reading files. Instead
> of adding IMA support for measuring the policy file data, update the
> mechanism for loading the LSM policy. Then not only will you be able
> to measure the policy, you'll also be able to require the policy be
> signed.

To clarify, the policy being measured by this patch series is a
serialized representation of the in-memory policy data structures being
enforced by SELinux.? Not the file that was loaded.? Hence, this
measurement would detect tampering with the in-memory policy data
structures after the policy has been loaded.? In the case of SELinux,
one can read this serialized representation via /sys/fs/selinux/policy.?
The result is not byte-for-byte identical to the policy file that was
loaded but can be semantically compared via sediff and other tools to
determine whether it is equivalent.


2020-08-05 20:01:07

by Tyler Hicks

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On 2020-08-05 10:27:43, Stephen Smalley wrote:
> On Wed, Aug 5, 2020 at 9:20 AM Mimi Zohar <[email protected]> wrote:
> >
> > On Wed, 2020-08-05 at 09:03 -0400, Stephen Smalley wrote:
> > > On Wed, Aug 5, 2020 at 8:57 AM Mimi Zohar <[email protected]> wrote:
> > > > On Wed, 2020-08-05 at 08:46 -0400, Stephen Smalley wrote:
> > > > > On 8/4/20 11:25 PM, Mimi Zohar wrote:
> > > > >
> > > > > > Hi Lakshmi,
> > > > > >
> > > > > > There's still a number of other patch sets needing to be reviewed
> > > > > > before my getting to this one. The comment below is from a high level.
> > > > > >
> > > > > > On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
> > > > > > > Critical data structures of security modules need to be measured to
> > > > > > > enable an attestation service to verify if the configuration and
> > > > > > > policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
> > > > > > > measure the state and the policy provided by the security modules.
> > > > > > > Update ima_match_rules() and ima_validate_rule() to check for
> > > > > > > the new func and ima_parse_rule() to handle the new func.
> > > > > > I can understand wanting to measure the in kernel LSM memory state to
> > > > > > make sure it hasn't changed, but policies are stored as files. Buffer
> > > > > > measurements should be limited to those things that are not files.
> > > > > >
> > > > > > Changing how data is passed to the kernel has been happening for a
> > > > > > while. For example, instead of passing the kernel module or kernel
> > > > > > image in a buffer, the new syscalls - finit_module, kexec_file_load -
> > > > > > pass an open file descriptor. Similarly, instead of loading the IMA
> > > > > > policy data, a pathname may be provided.
> > > > > >
> > > > > > Pre and post security hooks already exist for reading files. Instead
> > > > > > of adding IMA support for measuring the policy file data, update the
> > > > > > mechanism for loading the LSM policy. Then not only will you be able
> > > > > > to measure the policy, you'll also be able to require the policy be
> > > > > > signed.
> > > > >
> > > > > To clarify, the policy being measured by this patch series is a
> > > > > serialized representation of the in-memory policy data structures being
> > > > > enforced by SELinux. Not the file that was loaded. Hence, this
> > > > > measurement would detect tampering with the in-memory policy data
> > > > > structures after the policy has been loaded. In the case of SELinux,
> > > > > one can read this serialized representation via /sys/fs/selinux/policy.
> > > > > The result is not byte-for-byte identical to the policy file that was
> > > > > loaded but can be semantically compared via sediff and other tools to
> > > > > determine whether it is equivalent.
> > > >
> > > > Thank you for the clarification. Could the policy hash be included
> > > > with the other critical data? Does it really need to be measured
> > > > independently?
> > >
> > > They were split into two separate functions because we wanted to be
> > > able to support using different templates for them (ima-buf for the
> > > state variables so that the measurement includes the original buffer,
> > > which is small and relatively fixed-size, and ima-ng for the policy
> > > because it is large and we just want to capture the hash for later
> > > comparison against known-good). Also, the state variables are
> > > available for measurement always from early initialization, whereas
> > > the policy is only available for measurement once we have loaded an
> > > initial policy.
> >
> > Ok, measuring the policy separately from other critical data makes
> > sense. Instead of measuring the policy, which is large, measure the
> > policy hash.
>
> I think that was the original approach. However, I had concerns with
> adding code to SELinux to compute a hash over the policy versus
> leaving that to IMA's existing policy and mechanism. If that's
> preferred I guess we can do it that way but seems less flexible and
> duplicative.

In AppArmor, we store the sha1 of the raw policy as the policy is
loaded. The hash is exposed to userspace in apparmorfs. See commit
5ac8c355ae00 ("apparmor: allow introspecting the loaded policy pre
internal transform").

It has proved useful as a mechanism for debugging as sometimes the
on-disk policy doesn't match the loaded policy and this can be a good
way to check that while providing support to users. John also mentions
checkpoint/restore in the commit message and I could certainly see how
the policy hashes would be useful in that scenario.

When thinking through how Lakshmi's series could be extended for
AppArmor support, I was thinking that the AppArmor policy measurement
would be a measurement of these hashes that we already have in place.

Perhaps there's some general usefulness in storing/exposing an SELinux
policy hash rather than only seeing it as duplicative property required
this measurement series?

Tyler

2020-08-05 20:06:40

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On Wed, Aug 5, 2020 at 9:20 AM Mimi Zohar <[email protected]> wrote:
>
> On Wed, 2020-08-05 at 09:03 -0400, Stephen Smalley wrote:
> > On Wed, Aug 5, 2020 at 8:57 AM Mimi Zohar <[email protected]> wrote:
> > > On Wed, 2020-08-05 at 08:46 -0400, Stephen Smalley wrote:
> > > > On 8/4/20 11:25 PM, Mimi Zohar wrote:
> > > >
> > > > > Hi Lakshmi,
> > > > >
> > > > > There's still a number of other patch sets needing to be reviewed
> > > > > before my getting to this one. The comment below is from a high level.
> > > > >
> > > > > On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
> > > > > > Critical data structures of security modules need to be measured to
> > > > > > enable an attestation service to verify if the configuration and
> > > > > > policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
> > > > > > measure the state and the policy provided by the security modules.
> > > > > > Update ima_match_rules() and ima_validate_rule() to check for
> > > > > > the new func and ima_parse_rule() to handle the new func.
> > > > > I can understand wanting to measure the in kernel LSM memory state to
> > > > > make sure it hasn't changed, but policies are stored as files. Buffer
> > > > > measurements should be limited to those things that are not files.
> > > > >
> > > > > Changing how data is passed to the kernel has been happening for a
> > > > > while. For example, instead of passing the kernel module or kernel
> > > > > image in a buffer, the new syscalls - finit_module, kexec_file_load -
> > > > > pass an open file descriptor. Similarly, instead of loading the IMA
> > > > > policy data, a pathname may be provided.
> > > > >
> > > > > Pre and post security hooks already exist for reading files. Instead
> > > > > of adding IMA support for measuring the policy file data, update the
> > > > > mechanism for loading the LSM policy. Then not only will you be able
> > > > > to measure the policy, you'll also be able to require the policy be
> > > > > signed.
> > > >
> > > > To clarify, the policy being measured by this patch series is a
> > > > serialized representation of the in-memory policy data structures being
> > > > enforced by SELinux. Not the file that was loaded. Hence, this
> > > > measurement would detect tampering with the in-memory policy data
> > > > structures after the policy has been loaded. In the case of SELinux,
> > > > one can read this serialized representation via /sys/fs/selinux/policy.
> > > > The result is not byte-for-byte identical to the policy file that was
> > > > loaded but can be semantically compared via sediff and other tools to
> > > > determine whether it is equivalent.
> > >
> > > Thank you for the clarification. Could the policy hash be included
> > > with the other critical data? Does it really need to be measured
> > > independently?
> >
> > They were split into two separate functions because we wanted to be
> > able to support using different templates for them (ima-buf for the
> > state variables so that the measurement includes the original buffer,
> > which is small and relatively fixed-size, and ima-ng for the policy
> > because it is large and we just want to capture the hash for later
> > comparison against known-good). Also, the state variables are
> > available for measurement always from early initialization, whereas
> > the policy is only available for measurement once we have loaded an
> > initial policy.
>
> Ok, measuring the policy separately from other critical data makes
> sense. Instead of measuring the policy, which is large, measure the
> policy hash.

I think that was the original approach. However, I had concerns with
adding code to SELinux to compute a hash over the policy versus
leaving that to IMA's existing policy and mechanism. If that's
preferred I guess we can do it that way but seems less flexible and
duplicative.

2020-08-05 20:08:47

by Tyler Hicks

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 2020-08-05 09:21:24, Lakshmi Ramasubramanian wrote:
> On 8/5/20 9:14 AM, Tyler Hicks wrote:
> > On 2020-08-05 09:07:48, Lakshmi Ramasubramanian wrote:
> > > On 8/5/20 8:45 AM, Tyler Hicks wrote:
> > > > On 2020-08-05 08:36:40, Casey Schaufler wrote:
> > > > > On 8/4/2020 6:14 PM, Lakshmi Ramasubramanian wrote:
> > > > > > On 8/4/20 6:04 PM, Casey Schaufler wrote:
> > > > > > > On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
> > > > > > > > Critical data structures of security modules are currently not measured.
> > > > > > > > Therefore an attestation service, for instance, would not be able to
> > > > > > > > attest whether the security modules are always operating with the policies
> > > > > > > > and configuration that the system administrator had setup. The policies
> > > > > > > > and configuration for the security modules could be tampered with by
> > > > > > > > malware by exploiting kernel vulnerabilities or modified through some
> > > > > > > > inadvertent actions on the system. Measuring such critical data would
> > > > > > > > enable an attestation service to better assess the state of the system.
> > > > > > >
> > > > > > > I still wonder why you're calling this an LSM change/feature when
> > > > > > > all the change is in IMA and SELinux. You're not putting anything
> > > > > > > into the LSM infrastructure, not are you using the LSM infrastructure
> > > > > > > to achieve your ends. Sure, you *could* support other security modules
> > > > > > > using this scheme, but you have a configuration dependency on
> > > > > > > SELinux, so that's at best going to be messy. If you want this to
> > > > > > > be an LSM "feature" you need to use the LSM hooking mechanism.
> > > > > >
> > > > > > >
> > > > > > > I'm not objecting to the feature. It adds value. But as you've
> > > > > > > implemented it it is either an IMA extension to SELinux, or an
> > > > > > > SELiux extension to IMA. Could AppArmor add hooks for this without
> > > > > > > changing the IMA code? It doesn't look like it to me.
> > > > > >
> > > > > > The check in IMA to allow the new IMA hook func LSM_STATE and LSM_POLICY when SELinux is enabled is just because SELinux is the only security module using these hooks now.
> > > > > >
> > > > > > To enable AppArmor, for instance, to use the new IMA hooks to measure state and policy would just require adding the check for CONFIG_SECURITY_APPARMOR. Other than that, there are no IMA changes needed to support AppArmor or other such security modules.
> > > > >
> > > > > This is exactly what I'm objecting to. What if a system has both SELinux
> > > > > and AppArmor compiled in? What if it has both enabled?
> > > >
> > > > The SELinux state and policy would be measured but the AppArmor
> > > > state/policy would be silently ignored. This isn't ideal as the IMA
> > > > policy author would need to read the kernel code to figure out which
> > > > LSMs are going to be measured.
> > >
> > > Tyler - I am not sure why AppArmor state\policy would be ignored when both
> > > SELinux and AppArmor are enabled. Could you please clarify?
> >
> > I think Casey is talking about now (when AppArmor is not supported by
> > this feature) and you're talking about the future (when AppArmor may be
> > supported by this feature).
>
> Got it - thanks for clarifying.
>
> But with the current code if SELinux is enabled on the system, but AppArmor
> is not and the IMA policy contains "measure func=LSM_STATE" then the policy
> will be rejected as "-EINVAL".

The AppArmor policy load? Yes, the load will fail.

What Casey is talking about is when SELinux and AppArmor are enabled in
the kernel config but AppArmor is active. This scenario is true in
distro kernels such as Ubuntu's kernel:

$ grep -e CONFIG_SECURITY_SELINUX= -e CONFIG_SECURITY_APPARMOR= /boot/config-5.4.0-42-generic
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_APPARMOR=y
$ cat /sys/kernel/security/lsm
lockdown,capability,yama,apparmor

Casey also likely has LSM stacking in mind here where SELinux and
AppArmor could both be active at the same time but the LSM stacking
series is not yet applied.

Tyler

> So the policy author would get a feedback even now.
> Correct me if I am wrong.
>
> -lakshmi

2020-08-05 20:09:43

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v6 1/4] IMA: Add func to measure LSM state and policy

On Wed, 2020-08-05 at 09:03 -0400, Stephen Smalley wrote:
> On Wed, Aug 5, 2020 at 8:57 AM Mimi Zohar <[email protected]> wrote:
> > On Wed, 2020-08-05 at 08:46 -0400, Stephen Smalley wrote:
> > > On 8/4/20 11:25 PM, Mimi Zohar wrote:
> > >
> > > > Hi Lakshmi,
> > > >
> > > > There's still a number of other patch sets needing to be reviewed
> > > > before my getting to this one. The comment below is from a high level.
> > > >
> > > > On Tue, 2020-08-04 at 17:43 -0700, Lakshmi Ramasubramanian wrote:
> > > > > Critical data structures of security modules need to be measured to
> > > > > enable an attestation service to verify if the configuration and
> > > > > policies for the security modules 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 two new IMA policy func namely LSM_STATE and LSM_POLICY to
> > > > > measure the state and the policy provided by the security modules.
> > > > > Update ima_match_rules() and ima_validate_rule() to check for
> > > > > the new func and ima_parse_rule() to handle the new func.
> > > > I can understand wanting to measure the in kernel LSM memory state to
> > > > make sure it hasn't changed, but policies are stored as files. Buffer
> > > > measurements should be limited to those things that are not files.
> > > >
> > > > Changing how data is passed to the kernel has been happening for a
> > > > while. For example, instead of passing the kernel module or kernel
> > > > image in a buffer, the new syscalls - finit_module, kexec_file_load -
> > > > pass an open file descriptor. Similarly, instead of loading the IMA
> > > > policy data, a pathname may be provided.
> > > >
> > > > Pre and post security hooks already exist for reading files. Instead
> > > > of adding IMA support for measuring the policy file data, update the
> > > > mechanism for loading the LSM policy. Then not only will you be able
> > > > to measure the policy, you'll also be able to require the policy be
> > > > signed.
> > >
> > > To clarify, the policy being measured by this patch series is a
> > > serialized representation of the in-memory policy data structures being
> > > enforced by SELinux. Not the file that was loaded. Hence, this
> > > measurement would detect tampering with the in-memory policy data
> > > structures after the policy has been loaded. In the case of SELinux,
> > > one can read this serialized representation via /sys/fs/selinux/policy.
> > > The result is not byte-for-byte identical to the policy file that was
> > > loaded but can be semantically compared via sediff and other tools to
> > > determine whether it is equivalent.
> >
> > Thank you for the clarification. Could the policy hash be included
> > with the other critical data? Does it really need to be measured
> > independently?
>
> They were split into two separate functions because we wanted to be
> able to support using different templates for them (ima-buf for the
> state variables so that the measurement includes the original buffer,
> which is small and relatively fixed-size, and ima-ng for the policy
> because it is large and we just want to capture the hash for later
> comparison against known-good). Also, the state variables are
> available for measurement always from early initialization, whereas
> the policy is only available for measurement once we have loaded an
> initial policy.

Ok, measuring the policy separately from other critical data makes
sense. Instead of measuring the policy, which is large, measure the
policy hash.

Mimi

2020-08-05 20:10:02

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/5/20 9:14 AM, Tyler Hicks wrote:
> On 2020-08-05 09:07:48, Lakshmi Ramasubramanian wrote:
>> On 8/5/20 8:45 AM, Tyler Hicks wrote:
>>> On 2020-08-05 08:36:40, Casey Schaufler wrote:
>>>> On 8/4/2020 6:14 PM, Lakshmi Ramasubramanian wrote:
>>>>> On 8/4/20 6:04 PM, Casey Schaufler wrote:
>>>>>> On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
>>>>>>> Critical data structures of security modules are currently not measured.
>>>>>>> Therefore an attestation service, for instance, would not be able to
>>>>>>> attest whether the security modules are always operating with the policies
>>>>>>> and configuration that the system administrator had setup. The policies
>>>>>>> and configuration for the security modules could be tampered with by
>>>>>>> malware by exploiting kernel vulnerabilities or modified through some
>>>>>>> inadvertent actions on the system. Measuring such critical data would
>>>>>>> enable an attestation service to better assess the state of the system.
>>>>>>
>>>>>> I still wonder why you're calling this an LSM change/feature when
>>>>>> all the change is in IMA and SELinux. You're not putting anything
>>>>>> into the LSM infrastructure, not are you using the LSM infrastructure
>>>>>> to achieve your ends. Sure, you *could* support other security modules
>>>>>> using this scheme, but you have a configuration dependency on
>>>>>> SELinux, so that's at best going to be messy. If you want this to
>>>>>> be an LSM "feature" you need to use the LSM hooking mechanism.
>>>>>
>>>>>>
>>>>>> I'm not objecting to the feature. It adds value. But as you've
>>>>>> implemented it it is either an IMA extension to SELinux, or an
>>>>>> SELiux extension to IMA. Could AppArmor add hooks for this without
>>>>>> changing the IMA code? It doesn't look like it to me.
>>>>>
>>>>> The check in IMA to allow the new IMA hook func LSM_STATE and LSM_POLICY when SELinux is enabled is just because SELinux is the only security module using these hooks now.
>>>>>
>>>>> To enable AppArmor, for instance, to use the new IMA hooks to measure state and policy would just require adding the check for CONFIG_SECURITY_APPARMOR. Other than that, there are no IMA changes needed to support AppArmor or other such security modules.
>>>>
>>>> This is exactly what I'm objecting to. What if a system has both SELinux
>>>> and AppArmor compiled in? What if it has both enabled?
>>>
>>> The SELinux state and policy would be measured but the AppArmor
>>> state/policy would be silently ignored. This isn't ideal as the IMA
>>> policy author would need to read the kernel code to figure out which
>>> LSMs are going to be measured.
>>
>> Tyler - I am not sure why AppArmor state\policy would be ignored when both
>> SELinux and AppArmor are enabled. Could you please clarify?
>
> I think Casey is talking about now (when AppArmor is not supported by
> this feature) and you're talking about the future (when AppArmor may be
> supported by this feature).

Got it - thanks for clarifying.

But with the current code if SELinux is enabled on the system, but
AppArmor is not and the IMA policy contains "measure func=LSM_STATE"
then the policy will be rejected as "-EINVAL".
So the policy author would get a feedback even now.
Correct me if I am wrong.

-lakshmi

2020-08-05 20:11:24

by Tyler Hicks

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 2020-08-05 09:07:48, Lakshmi Ramasubramanian wrote:
> On 8/5/20 8:45 AM, Tyler Hicks wrote:
> > On 2020-08-05 08:36:40, Casey Schaufler wrote:
> > > On 8/4/2020 6:14 PM, Lakshmi Ramasubramanian wrote:
> > > > On 8/4/20 6:04 PM, Casey Schaufler wrote:
> > > > > On 8/4/2020 5:43 PM, Lakshmi Ramasubramanian wrote:
> > > > > > Critical data structures of security modules are currently not measured.
> > > > > > Therefore an attestation service, for instance, would not be able to
> > > > > > attest whether the security modules are always operating with the policies
> > > > > > and configuration that the system administrator had setup. The policies
> > > > > > and configuration for the security modules could be tampered with by
> > > > > > malware by exploiting kernel vulnerabilities or modified through some
> > > > > > inadvertent actions on the system. Measuring such critical data would
> > > > > > enable an attestation service to better assess the state of the system.
> > > > >
> > > > > I still wonder why you're calling this an LSM change/feature when
> > > > > all the change is in IMA and SELinux. You're not putting anything
> > > > > into the LSM infrastructure, not are you using the LSM infrastructure
> > > > > to achieve your ends. Sure, you *could* support other security modules
> > > > > using this scheme, but you have a configuration dependency on
> > > > > SELinux, so that's at best going to be messy. If you want this to
> > > > > be an LSM "feature" you need to use the LSM hooking mechanism.
> > > >
> > > > >
> > > > > I'm not objecting to the feature. It adds value. But as you've
> > > > > implemented it it is either an IMA extension to SELinux, or an
> > > > > SELiux extension to IMA. Could AppArmor add hooks for this without
> > > > > changing the IMA code? It doesn't look like it to me.
> > > >
> > > > The check in IMA to allow the new IMA hook func LSM_STATE and LSM_POLICY when SELinux is enabled is just because SELinux is the only security module using these hooks now.
> > > >
> > > > To enable AppArmor, for instance, to use the new IMA hooks to measure state and policy would just require adding the check for CONFIG_SECURITY_APPARMOR. Other than that, there are no IMA changes needed to support AppArmor or other such security modules.
> > >
> > > This is exactly what I'm objecting to. What if a system has both SELinux
> > > and AppArmor compiled in? What if it has both enabled?
> >
> > The SELinux state and policy would be measured but the AppArmor
> > state/policy would be silently ignored. This isn't ideal as the IMA
> > policy author would need to read the kernel code to figure out which
> > LSMs are going to be measured.
>
> Tyler - I am not sure why AppArmor state\policy would be ignored when both
> SELinux and AppArmor are enabled. Could you please clarify?

I think Casey is talking about now (when AppArmor is not supported by
this feature) and you're talking about the future (when AppArmor may be
supported by this feature).

Now, a "measure func=LSM_STATE" rule would be accepted by the IMA policy
parser but do nothing for the AppArmor LSM. The rule may do something in
the future but there's no difference in feedback to the IMA policy
author between now and the future.

Tyler

>
> When both the security modules are enabled, IMA policy validator would look
> like below:
>
> if (IS_ENABLED(CONFIG_SECURITY_SELINUX) ||
> IS_ENABLED(CONFIG_SECURITY_APPARMOR)) &&
> strcmp(args[0].from, "LSM_STATE") == 0)
> entry->func = LSM_STATE;
>
> Similar one for LSM_POLICY validation.
>
> Both SELinux and AppArmor can call ima_measure_lsm_state() and
> ima_measure_lsm_policy() to measure state and policy respectively.
>
> I don't think we should go the route of defining IMA hooks per security
> module (i.e., SELINUX_STATE, APPARMOR_STATE, SELINUX_POLICY, etc.) Instead
> keep the hook generic that any SM could use - which is what I have tried to
> address in this patch series.
>
> > >
> > > >
> > > > Please see Patch 1/4
> > > >
> > > > +??????????? else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
> > > > +???????????????? strcmp(args[0].from, "LSM_STATE") == 0)
> > > > +??????????????? entry->func = LSM_STATE;
> > > > +??????????? else if (IS_ENABLED(CONFIG_SECURITY_SELINUX) &&
> > > > +???????????????? strcmp(args[0].from, "LSM_POLICY") == 0)
> > > > +??????????????? entry->func = LSM_POLICY;
> > > >
> > > > And, if early boot measurement is needed for AppArmor the following change in IMA's Kconfig
> > > >
> > > > Patch 4/4
> > > >
> > > > +config IMA_QUEUE_EARLY_BOOT_DATA
> > > > ???? bool
> > > > +??? depends on SECURITY_SELINUX || (IMA_MEASURE_ASYMMETRIC_KEYS && SYSTEM_TRUSTED_KEYRING)
> > > > ???? default y
> > > >
> > > > If you think calling this an "LSM feature" is not appropriate, please suggest a better phrase.
> > >
> > > In the code above you are under CONFIG_SECURITY_SELINUX.
> > > I would suggest that it's an SELinux feature, so you should
> > > be using SELINUX_STATE and SELINUX_POLICY, as I suggested
> > > before. Just because SELinux has state and policy to measure
> > > doesn't mean that a different module might not have other data,
> > > such as history, that should be covered as well.
>
> Good point - if other SMs have data besides state and policy, we can define
> IMA hooks to measure that as well.
>
> But I still think it is not the right approach to call this SELINUX_STATE
> and SELINUX_POLICY - it will lead to unnecessary code duplication in IMA as
> more SMs are onboarded, in my opinion. Correct me if I am wrong.
>
> -lakshmi
>
> >
> > In addition to SELINUX_STATE and SELINUX_POLICY, we should also consider
> > the proposed LSM_STATE and LSM_POLICY func values but require an "lsm"
> > rule conditional.
> >
> > So the current proposed rules:
> >
> > measure func=LSM_STATE
> > measure func=LSM_POLICY
> >
> > Would become:
> >
> > measure func=LSM_STATE lsm=selinux
> > measure func=LSM_POLICY lsm=selinux
> >
> > The following rules would be rejected:
> >
> > measure func=LSM_STATE
> > measure func=LSM_POLICY
> > measure func=LSM_STATE lsm=apparmor
> > measure func=LSM_POLICY lsm=smack
> >
> > Of course, the apparmor and smack rules could/would be allowed when
> > proper support is in place.
> >
>
> >
> > >
> > > I realize that IMA already has compile time dependencies to
> > > determine which xattrs to measure. There's no reason that
> > > the xattr list couldn't be determined at boot time, with
> > > each security module providing the XATTR_NAME values it
> > > uses.
> > >
> > > >
> > > > But like I said above, with minimal change in IMA other security modules can be supported to measure STATE and POLICY data.
> > > >
> > > > ?-lakshmi
> > > >
> > > >

2020-08-12 20:41:20

by Lakshmi Ramasubramanian

[permalink] [raw]
Subject: Re: [PATCH v6 0/4] LSM: Measure security module data

On 8/5/20 11:25 AM, Casey Schaufler wrote:

>>>>>
>>>>> I think moving away from the idea that measuring "critical" data should
>>>>> be limited to LSMs, will clarify this.
>>>>>
>>>>
>>>> Are you suggesting that instead of calling the hooks LSM_STATE and LSM_POLICY, we should keep it more generic so that it can be utilized by any subsystem to measure their "critical data"?
>>>
>>> Policy, state, history or whim, it should be up to the security module
>>> to determine what data it cares about, and how it should be measured.
>>> Smack does not keep its policy in a single blob of data, it uses lists
>>> which can be modified at will. Your definition of the behavior for
>>> LSM_POLICY wouldn't work for Smack. That doesn't mean that there isn't
>>> a viable way to measure the Smack policy, it just means that IMA isn't
>>> the place for it. If SELinux wants its data measured, SELinux should be
>>> providing the mechanism to do it.
>>>
>>> I guess that I'm agreeing with you in part. If you want a generic measurement
>>> of "critical data", you don't need to assign a type to it, you have the
>>> caller (a security module, a device driver or whatever) identify itself and
>>> how it is going to deal with the data. That's very different from what you've
>>> done to date.
>>
>> Agree.
>>
>> Like Stephen had stated earlier, the reason we kept separate hooks (STATE and POLICY) is because the data for state is usually small and therefore we measure the entire data. Whereas, policy data is usually quite large (a few MB) and hence we measure a hash of the policy.
>
> SELinux should determine how it wants its data measured.
> SELinux, not IMA, should determine if some "critical data"
> be measured in total, by its hash or as a count of policy
> rules. It would be handy for IMA to supply functions to do
> data blobs and hashes, but it should be up to the caller to
> decide if they meet their needs.
>

Per feedback from you all, my colleague Tushar has posted a patch series
that defines a generic IMA hook to measure critical data from other
subsystems (such as SELinux, AppArmor, Device-Mapper targets, etc.)

Link to the patch series is given below:

https://patchwork.kernel.org/patch/11711249/

Shortly I will re-post the SELinux state and hash of policy measurement
patch that will be based on the above patch series.

thanks,
-lakshmi