summaryrefslogtreecommitdiff
path: root/security/integrity/ima/ima_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima/ima_main.c')
-rw-r--r--security/integrity/ima/ima_main.c83
1 files changed, 74 insertions, 9 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index b028c501949c..cdd225f65a62 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -27,6 +27,7 @@
#include <linux/fs.h>
#include <linux/iversion.h>
#include <linux/evm.h>
+#include <linux/crash_dump.h>
#include "ima.h"
@@ -38,11 +39,30 @@ int ima_appraise;
int __ro_after_init ima_hash_algo = HASH_ALGO_SHA1;
static int hash_setup_done;
+static int ima_disabled __ro_after_init;
static struct notifier_block ima_lsm_policy_notifier = {
.notifier_call = ima_lsm_policy_change,
};
+static int __init ima_setup(char *str)
+{
+ if (!is_kdump_kernel()) {
+ pr_info("Warning: ima setup option only permitted in kdump");
+ return 1;
+ }
+
+ if (strncmp(str, "off", 3) == 0)
+ ima_disabled = 1;
+ else if (strncmp(str, "on", 2) == 0)
+ ima_disabled = 0;
+ else
+ pr_err("Invalid ima setup option: \"%s\" , please specify ima=on|off.", str);
+
+ return 1;
+}
+__setup("ima=", ima_setup);
+
static int __init hash_setup(char *str)
{
struct ima_template_desc *template_desc = ima_template_desc_current();
@@ -129,16 +149,22 @@ static void ima_rdwr_violation_check(struct file *file,
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
if (!iint)
iint = ima_iint_find(inode);
+
/* IMA_MEASURE is set from reader side */
- if (iint && test_bit(IMA_MUST_MEASURE,
- &iint->atomic_flags))
+ if (iint && test_and_clear_bit(IMA_MAY_EMIT_TOMTOU,
+ &iint->atomic_flags))
send_tomtou = true;
}
} else {
if (must_measure)
- set_bit(IMA_MUST_MEASURE, &iint->atomic_flags);
- if (inode_is_open_for_write(inode) && must_measure)
- send_writers = true;
+ set_bit(IMA_MAY_EMIT_TOMTOU, &iint->atomic_flags);
+
+ /* Limit number of open_writers violations */
+ if (inode_is_open_for_write(inode) && must_measure) {
+ if (!test_and_set_bit(IMA_EMITTED_OPENWRITERS,
+ &iint->atomic_flags))
+ send_writers = true;
+ }
}
if (!send_tomtou && !send_writers)
@@ -167,6 +193,8 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
if (atomic_read(&inode->i_writecount) == 1) {
struct kstat stat;
+ clear_bit(IMA_EMITTED_OPENWRITERS, &iint->atomic_flags);
+
update = test_and_clear_bit(IMA_UPDATE_XATTR,
&iint->atomic_flags);
if ((iint->flags & IMA_NEW_FILE) ||
@@ -237,7 +265,9 @@ static int process_measurement(struct file *file, const struct cred *cred,
&allowed_algos);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK ||
func == MMAP_CHECK_REQPROT) &&
- (ima_policy_flag & IMA_MEASURE));
+ (ima_policy_flag & IMA_MEASURE) &&
+ ((action & IMA_MEASURE) ||
+ (file->f_mode & FMODE_WRITE)));
if (!action && !violation_check)
return 0;
@@ -558,6 +588,34 @@ static int ima_bprm_check(struct linux_binprm *bprm)
}
/**
+ * ima_bprm_creds_for_exec - collect/store/appraise measurement.
+ * @bprm: contains the linux_binprm structure
+ *
+ * Based on the IMA policy and the execveat(2) AT_EXECVE_CHECK flag, measure
+ * and appraise the integrity of a file to be executed by script interpreters.
+ * Unlike any of the other LSM hooks where the kernel enforces file integrity,
+ * enforcing file integrity is left up to the discretion of the script
+ * interpreter (userspace).
+ *
+ * On success return 0. On integrity appraisal error, assuming the file
+ * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
+ */
+static int ima_bprm_creds_for_exec(struct linux_binprm *bprm)
+{
+ /*
+ * As security_bprm_check() is called multiple times, both
+ * the script and the shebang interpreter are measured, appraised,
+ * and audited. Limit usage of this LSM hook to just measuring,
+ * appraising, and auditing the indirect script execution
+ * (e.g. ./sh example.sh).
+ */
+ if (!bprm->is_check)
+ return 0;
+
+ return ima_bprm_check(bprm);
+}
+
+/**
* ima_file_check - based on policy, collect/store measurement.
* @file: pointer to the file to be measured
* @mask: contains MAY_READ, MAY_WRITE, MAY_EXEC or MAY_APPEND
@@ -986,9 +1044,9 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
}
/*
- * Both LSM hooks and auxilary based buffer measurements are
- * based on policy. To avoid code duplication, differentiate
- * between the LSM hooks and auxilary buffer measurements,
+ * Both LSM hooks and auxiliary based buffer measurements are
+ * based on policy. To avoid code duplication, differentiate
+ * between the LSM hooks and auxiliary buffer measurements,
* retrieving the policy rule information only for the LSM hook
* buffer measurements.
*/
@@ -1148,6 +1206,12 @@ static int __init init_ima(void)
{
int error;
+ /*Note that turning IMA off is intentionally limited to kdump kernel.*/
+ if (ima_disabled && is_kdump_kernel()) {
+ pr_info("IMA functionality is disabled");
+ return 0;
+ }
+
ima_appraise_parse_cmdline();
ima_init_template_list();
hash_setup(CONFIG_IMA_DEFAULT_HASH);
@@ -1177,6 +1241,7 @@ static int __init init_ima(void)
static struct security_hook_list ima_hooks[] __ro_after_init = {
LSM_HOOK_INIT(bprm_check_security, ima_bprm_check),
+ LSM_HOOK_INIT(bprm_creds_for_exec, ima_bprm_creds_for_exec),
LSM_HOOK_INIT(file_post_open, ima_file_check),
LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile),
LSM_HOOK_INIT(file_release, ima_file_free),