summaryrefslogtreecommitdiffstats
path: root/security/integrity/ima
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima')
-rw-r--r--security/integrity/ima/Kconfig5
-rw-r--r--security/integrity/ima/ima.h2
-rw-r--r--security/integrity/ima/ima_audit.c2
-rw-r--r--security/integrity/ima/ima_crypto.c4
-rw-r--r--security/integrity/ima/ima_fs.c38
-rw-r--r--security/integrity/ima/ima_iint.c6
-rw-r--r--security/integrity/ima/ima_init.c2
-rw-r--r--security/integrity/ima/ima_main.c2
-rw-r--r--security/integrity/ima/ima_policy.c107
-rw-r--r--security/integrity/ima/ima_queue.c4
10 files changed, 112 insertions, 60 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 3d7846de8069..b6ecfd4d8d78 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -2,15 +2,14 @@
#
config IMA
bool "Integrity Measurement Architecture(IMA)"
- depends on ACPI
depends on SECURITY
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_MD5
select CRYPTO_SHA1
- select TCG_TPM
- select TCG_TIS
+ select TCG_TPM if !S390
+ select TCG_TIS if TCG_TPM
help
The Trusted Computing Group(TCG) runtime Integrity
Measurement Architecture(IMA) maintains a list of hash
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 47fb65d1fcbd..16d100d3fc38 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -135,7 +135,7 @@ enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK };
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask);
void ima_init_policy(void);
void ima_update_policy(void);
-int ima_parse_add_rule(char *);
+ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);
/* LSM based policy rules require audit */
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c
index 5af76340470c..c5c5a72c30be 100644
--- a/security/integrity/ima/ima_audit.c
+++ b/security/integrity/ima/ima_audit.c
@@ -41,7 +41,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
return;
ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
- audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u",
+ audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u",
current->pid, current_cred()->uid,
audit_get_loginuid(current),
audit_get_sessionid(current));
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 952e51373f58..9b3ade7468b2 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -27,7 +27,7 @@ static int init_desc(struct hash_desc *desc)
desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(desc->tfm)) {
- pr_info("failed to load %s transform: %ld\n",
+ pr_info("IMA: failed to load %s transform: %ld\n",
ima_hash, PTR_ERR(desc->tfm));
rc = PTR_ERR(desc->tfm);
return rc;
@@ -112,7 +112,7 @@ static void __init ima_pcrread(int idx, u8 *pcr)
return;
if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
- pr_err("Error Communicating to TPM chip\n");
+ pr_err("IMA: Error Communicating to TPM chip\n");
}
/*
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 07cb9c338cc4..8fe736aabe71 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -244,32 +244,34 @@ static const struct file_operations ima_ascii_measurements_ops = {
static ssize_t ima_write_policy(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
{
- char *data;
- int rc;
+ char *data = NULL;
+ ssize_t result;
if (datalen >= PAGE_SIZE)
- return -ENOMEM;
- if (*ppos != 0) {
- /* No partial writes. */
- return -EINVAL;
- }
+ datalen = PAGE_SIZE - 1;
+
+ /* No partial writes. */
+ result = -EINVAL;
+ if (*ppos != 0)
+ goto out;
+
+ result = -ENOMEM;
data = kmalloc(datalen + 1, GFP_KERNEL);
if (!data)
- return -ENOMEM;
+ goto out;
- if (copy_from_user(data, buf, datalen)) {
- kfree(data);
- return -EFAULT;
- }
*(data + datalen) = '\0';
- rc = ima_parse_add_rule(data);
- if (rc < 0) {
- datalen = -EINVAL;
- valid_policy = 0;
- }
+ result = -EFAULT;
+ if (copy_from_user(data, buf, datalen))
+ goto out;
+
+ result = ima_parse_add_rule(data);
+out:
+ if (result < 0)
+ valid_policy = 0;
kfree(data);
- return datalen;
+ return result;
}
static struct dentry *ima_dir;
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
index 2c744d488014..2dc2d6594145 100644
--- a/security/integrity/ima/ima_iint.c
+++ b/security/integrity/ima/ima_iint.c
@@ -80,17 +80,17 @@ void iint_free(struct kref *kref)
iint->version = 0;
iint->flags = 0UL;
if (iint->readcount != 0) {
- printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__,
+ printk(KERN_INFO "%s: readcount: %ld\n", __func__,
iint->readcount);
iint->readcount = 0;
}
if (iint->writecount != 0) {
- printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__,
+ printk(KERN_INFO "%s: writecount: %ld\n", __func__,
iint->writecount);
iint->writecount = 0;
}
if (iint->opencount != 0) {
- printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__,
+ printk(KERN_INFO "%s: opencount: %ld\n", __func__,
iint->opencount);
iint->opencount = 0;
}
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index b1bcb702a27c..17f1f060306f 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -83,7 +83,7 @@ int __init ima_init(void)
ima_used_chip = 1;
if (!ima_used_chip)
- pr_info("No TPM chip found, activating TPM-bypass!\n");
+ pr_info("IMA: No TPM chip found, activating TPM-bypass!\n");
ima_add_boot_aggregate(); /* boot aggregate must be first entry */
ima_init_policy();
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index b2c89d9de2a4..f93641382e9f 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -195,7 +195,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
(iint->writecount < 0)) &&
!ima_limit_imbalance(file)) {
printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n",
- __FUNCTION__, iint->readcount, iint->writecount,
+ __func__, iint->readcount, iint->writecount,
iint->opencount);
dump_stack();
}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 8643a93c5963..aef8c0a923ab 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -246,6 +246,9 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
{
int result;
+ if (entry->lsm[lsm_rule].rule)
+ return -EINVAL;
+
entry->lsm[lsm_rule].type = audit_type;
result = security_filter_rule_init(entry->lsm[lsm_rule].type,
Audit_equal, args,
@@ -253,6 +256,13 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
return result;
}
+static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
+{
+ audit_log_format(ab, "%s=", key);
+ audit_log_untrustedstring(ab, value);
+ audit_log_format(ab, " ");
+}
+
static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
{
struct audit_buffer *ab;
@@ -261,28 +271,41 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
- entry->action = -1;
- while ((p = strsep(&rule, " \n")) != NULL) {
+ entry->uid = -1;
+ entry->action = UNKNOWN;
+ while ((p = strsep(&rule, " \t")) != NULL) {
substring_t args[MAX_OPT_ARGS];
int token;
unsigned long lnum;
if (result < 0)
break;
- if (!*p)
+ if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
continue;
token = match_token(p, policy_tokens, args);
switch (token) {
case Opt_measure:
- audit_log_format(ab, "%s ", "measure");
+ ima_log_string(ab, "action", "measure");
+
+ if (entry->action != UNKNOWN)
+ result = -EINVAL;
+
entry->action = MEASURE;
break;
case Opt_dont_measure:
- audit_log_format(ab, "%s ", "dont_measure");
+ ima_log_string(ab, "action", "dont_measure");
+
+ if (entry->action != UNKNOWN)
+ result = -EINVAL;
+
entry->action = DONT_MEASURE;
break;
case Opt_func:
- audit_log_format(ab, "func=%s ", args[0].from);
+ ima_log_string(ab, "func", args[0].from);
+
+ if (entry->func)
+ result = -EINVAL;
+
if (strcmp(args[0].from, "FILE_CHECK") == 0)
entry->func = FILE_CHECK;
/* PATH_CHECK is for backwards compat */
@@ -298,7 +321,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
entry->flags |= IMA_FUNC;
break;
case Opt_mask:
- audit_log_format(ab, "mask=%s ", args[0].from);
+ ima_log_string(ab, "mask", args[0].from);
+
+ if (entry->mask)
+ result = -EINVAL;
+
if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
entry->mask = MAY_EXEC;
else if (strcmp(args[0].from, "MAY_WRITE") == 0)
@@ -313,14 +340,26 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
entry->flags |= IMA_MASK;
break;
case Opt_fsmagic:
- audit_log_format(ab, "fsmagic=%s ", args[0].from);
+ ima_log_string(ab, "fsmagic", args[0].from);
+
+ if (entry->fsmagic) {
+ result = -EINVAL;
+ break;
+ }
+
result = strict_strtoul(args[0].from, 16,
&entry->fsmagic);
if (!result)
entry->flags |= IMA_FSMAGIC;
break;
case Opt_uid:
- audit_log_format(ab, "uid=%s ", args[0].from);
+ ima_log_string(ab, "uid", args[0].from);
+
+ if (entry->uid != -1) {
+ result = -EINVAL;
+ break;
+ }
+
result = strict_strtoul(args[0].from, 10, &lnum);
if (!result) {
entry->uid = (uid_t) lnum;
@@ -331,50 +370,51 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
}
break;
case Opt_obj_user:
- audit_log_format(ab, "obj_user=%s ", args[0].from);
+ ima_log_string(ab, "obj_user", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from,
LSM_OBJ_USER,
AUDIT_OBJ_USER);
break;
case Opt_obj_role:
- audit_log_format(ab, "obj_role=%s ", args[0].from);
+ ima_log_string(ab, "obj_role", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from,
LSM_OBJ_ROLE,
AUDIT_OBJ_ROLE);
break;
case Opt_obj_type:
- audit_log_format(ab, "obj_type=%s ", args[0].from);
+ ima_log_string(ab, "obj_type", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from,
LSM_OBJ_TYPE,
AUDIT_OBJ_TYPE);
break;
case Opt_subj_user:
- audit_log_format(ab, "subj_user=%s ", args[0].from);
+ ima_log_string(ab, "subj_user", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from,
LSM_SUBJ_USER,
AUDIT_SUBJ_USER);
break;
case Opt_subj_role:
- audit_log_format(ab, "subj_role=%s ", args[0].from);
+ ima_log_string(ab, "subj_role", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from,
LSM_SUBJ_ROLE,
AUDIT_SUBJ_ROLE);
break;
case Opt_subj_type:
- audit_log_format(ab, "subj_type=%s ", args[0].from);
+ ima_log_string(ab, "subj_type", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from,
LSM_SUBJ_TYPE,
AUDIT_SUBJ_TYPE);
break;
case Opt_err:
- audit_log_format(ab, "UNKNOWN=%s ", p);
+ ima_log_string(ab, "UNKNOWN", p);
+ result = -EINVAL;
break;
}
}
- if (entry->action == UNKNOWN)
+ if (!result && (entry->action == UNKNOWN))
result = -EINVAL;
- audit_log_format(ab, "res=%d", !result ? 0 : 1);
+ audit_log_format(ab, "res=%d", !!result);
audit_log_end(ab);
return result;
}
@@ -384,13 +424,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
* @rule - ima measurement policy rule
*
* Uses a mutex to protect the policy list from multiple concurrent writers.
- * Returns 0 on success, an error code on failure.
+ * Returns the length of the rule parsed, an error code on failure
*/
-int ima_parse_add_rule(char *rule)
+ssize_t ima_parse_add_rule(char *rule)
{
const char *op = "update_policy";
+ char *p;
struct ima_measure_rule_entry *entry;
- int result = 0;
+ ssize_t result, len;
int audit_info = 0;
/* Prevent installed policy from changing */
@@ -410,18 +451,28 @@ int ima_parse_add_rule(char *rule)
INIT_LIST_HEAD(&entry->list);
- result = ima_parse_rule(rule, entry);
- if (!result) {
- mutex_lock(&ima_measure_mutex);
- list_add_tail(&entry->list, &measure_policy_rules);
- mutex_unlock(&ima_measure_mutex);
- } else {
+ p = strsep(&rule, "\n");
+ len = strlen(p) + 1;
+
+ if (*p == '#') {
+ kfree(entry);
+ return len;
+ }
+
+ result = ima_parse_rule(p, entry);
+ if (result) {
kfree(entry);
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
NULL, op, "invalid policy", result,
audit_info);
+ return result;
}
- return result;
+
+ mutex_lock(&ima_measure_mutex);
+ list_add_tail(&entry->list, &measure_policy_rules);
+ mutex_unlock(&ima_measure_mutex);
+
+ return len;
}
/* ima_delete_rules called to cleanup invalid policy */
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 46ba62b1adf5..8e28f04a5e2e 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -71,7 +71,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry)
qe = kmalloc(sizeof(*qe), GFP_KERNEL);
if (qe == NULL) {
- pr_err("OUT OF MEMORY ERROR creating queue entry.\n");
+ pr_err("IMA: OUT OF MEMORY ERROR creating queue entry.\n");
return -ENOMEM;
}
qe->entry = entry;
@@ -94,7 +94,7 @@ static int ima_pcr_extend(const u8 *hash)
result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
if (result != 0)
- pr_err("Error Communicating to TPM chip\n");
+ pr_err("IMA: Error Communicating to TPM chip\n");
return result;
}
OpenPOWER on IntegriCloud