lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1321885097-14166-1-git-send-email-roberto.sassu@polito.it>
Date:	Mon, 21 Nov 2011 15:18:10 +0100
From:	Roberto Sassu <roberto.sassu@...ito.it>
To:	linux-security-module@...r.kernel.org
Cc:	linux-kernel@...r.kernel.org, zohar@...ux.vnet.ibm.com,
	jmorris@...ei.org, srajiv@...ux.vnet.ibm.com,
	Roberto Sassu <roberto.sassu@...ito.it>
Subject: [RFC][PATCH] ima: add new kernel parameter ima_denycall_on_errors

The new kernel parameter tells IMA the action that must be done when an
error in the measurement process occurs. If 'ima_denycall_on_errors' is
equal to 1, the IMA hooks return an error, so that the system call will
not be executed. Otherwise, the default behavior is to execute the system
call and, eventually, to include in the measurements list those entries
for which the PCR extend operation was failed.

Signed-off-by: Roberto Sassu <roberto.sassu@...ito.it>
---
 Documentation/kernel-parameters.txt |    8 ++++
 security/integrity/ima/ima.h        |    5 ++-
 security/integrity/ima/ima_api.c    |   12 ++++--
 security/integrity/ima/ima_init.c   |   11 ++++--
 security/integrity/ima/ima_main.c   |   65 ++++++++++++++++++++++++-----------
 security/integrity/ima/ima_queue.c  |    9 +++--
 6 files changed, 78 insertions(+), 32 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a0c5c5f..6fe6634 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -995,6 +995,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			programs exec'd, files mmap'd for exec, and all files
 			opened for read by uid=0.
 
+	ima_denycall_on_errors=
+			[IMA]
+			Format: { "0" | "1" }
+			0 -- execute the system call even if the inode was not
+			     measured. (Default)
+			1 -- deny the system call execution if the inode
+			     measurement was failed.
+
 	init=		[KNL]
 			Format: <full_path>
 			Run specified binary instead of /sbin/init as init
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 3ccf7ac..79e259c 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -38,6 +38,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
 
 /* set during initialization */
 extern int ima_initialized;
+extern int ima_enforce;
 extern int ima_used_chip;
 extern char *ima_hash;
 
@@ -77,7 +78,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 int ima_calc_hash(struct file *file, char *digest);
 int ima_calc_template_hash(int template_len, void *template, char *digest);
 int ima_calc_boot_aggregate(char *digest);
-void ima_add_violation(struct inode *inode, const unsigned char *filename,
+int ima_add_violation(struct inode *inode, const unsigned char *filename,
 		       const char *op, const char *cause);
 
 /*
@@ -101,7 +102,7 @@ static inline unsigned long ima_hash_key(u8 *digest)
 int ima_must_measure(struct inode *inode, int mask, int function);
 int ima_collect_measurement(struct integrity_iint_cache *iint,
 			    struct file *file);
-void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
+int ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
 			   const unsigned char *filename);
 int ima_store_template(struct ima_template_entry *entry, int violation,
 		       struct inode *inode);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 88a2788..bae5b9e 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -67,7 +67,7 @@ int ima_store_template(struct ima_template_entry *entry,
  * By extending the PCR with 0xFF's instead of with zeroes, the PCR
  * value is invalidated.
  */
-void ima_add_violation(struct inode *inode, const unsigned char *filename,
+int ima_add_violation(struct inode *inode, const unsigned char *filename,
 		       const char *op, const char *cause)
 {
 	struct ima_template_entry *entry;
@@ -90,6 +90,7 @@ void ima_add_violation(struct inode *inode, const unsigned char *filename,
 err_out:
 	integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 			    op, cause, result, 0);
+	return result;
 }
 
 /**
@@ -157,7 +158,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
  *
  * Must be called with iint->mutex held.
  */
-void ima_store_measurement(struct integrity_iint_cache *iint,
+int ima_store_measurement(struct integrity_iint_cache *iint,
 			   struct file *file, const unsigned char *filename)
 {
 	const char *op = "add_template_measure";
@@ -171,15 +172,18 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
 	if (!entry) {
 		integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 				    op, audit_cause, result, 0);
-		return;
+		return result;
 	}
 	memset(&entry->template, 0, sizeof(entry->template));
 	memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE);
 	strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
 
 	result = ima_store_template(entry, violation, inode);
-	if (!result || result == -EEXIST)
+	if (!result || result == -EEXIST) {
 		iint->flags |= IMA_MEASURED;
+		result = 0;
+	}
 	if (result < 0)
 		kfree(entry);
+	return result;
 }
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 17f1f06..7e29d6f 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -39,7 +39,7 @@ int ima_used_chip;
  * a different value.) Violations add a zero entry to the measurement
  * list and extend the aggregate PCR value with ff...ff's.
  */
-static void __init ima_add_boot_aggregate(void)
+static int __init ima_add_boot_aggregate(void)
 {
 	struct ima_template_entry *entry;
 	const char *op = "add_boot_aggregate";
@@ -66,10 +66,12 @@ static void __init ima_add_boot_aggregate(void)
 	result = ima_store_template(entry, violation, NULL);
 	if (result < 0)
 		kfree(entry);
-	return;
+	goto out;
 err_out:
 	integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
 			    audit_cause, result, 0);
+out:
+	return result;
 }
 
 int __init ima_init(void)
@@ -85,7 +87,10 @@ int __init ima_init(void)
 	if (!ima_used_chip)
 		pr_info("IMA: No TPM chip found, activating TPM-bypass!\n");
 
-	ima_add_boot_aggregate();	/* boot aggregate must be first entry */
+	rc = ima_add_boot_aggregate();	/* boot aggregate must be first entry */
+	if (rc != 0)
+		return -EACCES;
+
 	ima_init_policy();
 
 	return ima_fs_init();
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 1eff5cb..9f2edf5 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -27,6 +27,20 @@
 #include "ima.h"
 
 int ima_initialized;
+int ima_enforce;
+
+/* ima_denycall_setup - deny syscall execution when inode measurement fails */
+int ima_denycall_on_errors;
+static int __init ima_denycall_setup(char *str)
+{
+	unsigned long deny;
+
+	ima_denycall_on_errors = 0;
+	if (!kstrtoul(str, 0, &deny))
+		ima_denycall_on_errors = deny ? 1 : 0;
+	return 1;
+}
+__setup("ima_denycall_on_errors=", ima_denycall_setup);
 
 char *ima_hash = "sha1";
 static int __init hash_setup(char *str)
@@ -47,16 +61,16 @@ __setup("ima_hash=", hash_setup);
  * 	  could result in a file measurement error.
  *
  */
-static void ima_rdwr_violation_check(struct file *file)
+static int ima_rdwr_violation_check(struct file *file)
 {
 	struct dentry *dentry = file->f_path.dentry;
 	struct inode *inode = dentry->d_inode;
 	fmode_t mode = file->f_mode;
-	int rc;
+	int rc = 0;
 	bool send_tomtou = false, send_writers = false;
 
 	if (!S_ISREG(inode->i_mode) || !ima_initialized)
-		return;
+		return 0;
 
 	mutex_lock(&inode->i_mutex);	/* file metadata: permissions, xattr */
 
@@ -67,8 +81,10 @@ static void ima_rdwr_violation_check(struct file *file)
 	}
 
 	rc = ima_must_measure(inode, MAY_READ, FILE_CHECK);
-	if (rc < 0)
+	if (rc < 0) {
+		rc = 0;
 		goto out;
+	}
 
 	if (atomic_read(&inode->i_writecount) > 0)
 		send_writers = true;
@@ -76,11 +92,12 @@ out:
 	mutex_unlock(&inode->i_mutex);
 
 	if (send_tomtou)
-		ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
-				  "ToMToU");
+		rc = ima_add_violation(inode, dentry->d_name.name,
+				       "invalid_pcr", "ToMToU");
 	if (send_writers)
-		ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
-				  "open_writers");
+		rc = ima_add_violation(inode, dentry->d_name.name,
+				       "invalid_pcr", "open_writers");
+	return (!rc) ? 0 : -EACCES;
 }
 
 static void ima_check_last_writer(struct integrity_iint_cache *iint,
@@ -130,28 +147,31 @@ static int process_measurement(struct file *file, const unsigned char *filename,
 
 	rc = ima_must_measure(inode, mask, function);
 	if (rc != 0)
-		return rc;
+		return 0;
 retry:
 	iint = integrity_iint_find(inode);
 	if (!iint) {
 		rc = integrity_inode_alloc(inode);
-		if (!rc || rc == -EEXIST)
+		if (!rc || rc == -EEXIST) {
+			rc = 0;
 			goto retry;
+		}
 		return rc;
 	}
 
 	mutex_lock(&iint->mutex);
 
-	rc = iint->flags & IMA_MEASURED ? 1 : 0;
-	if (rc != 0)
+	if (iint->flags & IMA_MEASURED)
 		goto out;
 
 	rc = ima_collect_measurement(iint, file);
-	if (!rc)
-		ima_store_measurement(iint, file, filename);
+	if (rc != 0)
+		goto out;
+
+	rc = ima_store_measurement(iint, file, filename);
 out:
 	mutex_unlock(&iint->mutex);
-	return rc;
+	return (!rc) ? 0 : -EACCES;
 }
 
 /**
@@ -167,14 +187,14 @@ out:
  */
 int ima_file_mmap(struct file *file, unsigned long prot)
 {
-	int rc;
+	int rc = 0;
 
 	if (!file)
 		return 0;
 	if (prot & PROT_EXEC)
 		rc = process_measurement(file, file->f_dentry->d_name.name,
 					 MAY_EXEC, FILE_MMAP);
-	return 0;
+	return (ima_enforce) ? rc : 0;
 }
 
 /**
@@ -196,7 +216,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
 
 	rc = process_measurement(bprm->file, bprm->filename,
 				 MAY_EXEC, BPRM_CHECK);
-	return 0;
+	return (ima_enforce) ? rc : 0;
 }
 
 /**
@@ -213,11 +233,15 @@ int ima_file_check(struct file *file, int mask)
 {
 	int rc;
 
-	ima_rdwr_violation_check(file);
+	rc = ima_rdwr_violation_check(file);
+	if (rc != 0 && ima_enforce)
+		goto out;
+
 	rc = process_measurement(file, file->f_dentry->d_name.name,
 				 mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
 				 FILE_CHECK);
-	return 0;
+out:
+	return (ima_enforce) ? rc : 0;
 }
 EXPORT_SYMBOL_GPL(ima_file_check);
 
@@ -226,6 +250,7 @@ static int __init init_ima(void)
 	int error;
 
 	error = ima_init();
+	ima_enforce |= ima_denycall_on_errors;
 	ima_initialized = 1;
 	return error;
 }
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 7ae1e9a..cc1989f 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -147,9 +147,12 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 	if (result != 0) {
 		audit_cause = "TPM error";
 		audit_info = 0;
-		result = -ECOMM;
-		kfree(qe);
-		goto out;
+		result = 1;
+		if (ima_enforce) {
+			result = -ECOMM;
+			kfree(qe);
+			goto out;
+		}
 	}
 
 	ima_add_digest_entry(qe);
-- 
1.7.6.4


Download attachment "smime.p7s" of type "application/x-pkcs7-signature" (2061 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ