xref: /linux/security/integrity/ima/ima_policy.c (revision e7c568e0fd0cf6d9c8ab8ea537ba8f3a3ae7c3d8)
13323eec9SMimi Zohar /*
23323eec9SMimi Zohar  * Copyright (C) 2008 IBM Corporation
33323eec9SMimi Zohar  * Author: Mimi Zohar <zohar@us.ibm.com>
43323eec9SMimi Zohar  *
53323eec9SMimi Zohar  * This program is free software; you can redistribute it and/or modify
63323eec9SMimi Zohar  * it under the terms of the GNU General Public License as published by
73323eec9SMimi Zohar  * the Free Software Foundation, version 2 of the License.
83323eec9SMimi Zohar  *
93323eec9SMimi Zohar  * ima_policy.c
103323eec9SMimi Zohar  * 	- initialize default measure policy rules
113323eec9SMimi Zohar  *
123323eec9SMimi Zohar  */
133323eec9SMimi Zohar #include <linux/module.h>
143323eec9SMimi Zohar #include <linux/list.h>
153323eec9SMimi Zohar #include <linux/security.h>
163323eec9SMimi Zohar #include <linux/magic.h>
174af4662fSMimi Zohar #include <linux/parser.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
193323eec9SMimi Zohar 
203323eec9SMimi Zohar #include "ima.h"
213323eec9SMimi Zohar 
223323eec9SMimi Zohar /* flags definitions */
233323eec9SMimi Zohar #define IMA_FUNC 	0x0001
243323eec9SMimi Zohar #define IMA_MASK 	0x0002
253323eec9SMimi Zohar #define IMA_FSMAGIC	0x0004
263323eec9SMimi Zohar #define IMA_UID		0x0008
2707f6a794SMimi Zohar #define IMA_FOWNER	0x0010
283323eec9SMimi Zohar 
292fe5d6deSMimi Zohar #define UNKNOWN		0
3045e2472eSDmitry Kasatkin #define MEASURE		0x0001	/* same as IMA_MEASURE */
3145e2472eSDmitry Kasatkin #define DONT_MEASURE	0x0002
3245e2472eSDmitry Kasatkin #define APPRAISE	0x0004	/* same as IMA_APPRAISE */
3345e2472eSDmitry Kasatkin #define DONT_APPRAISE	0x0008
34*e7c568e0SPeter Moody #define AUDIT		0x0040
354af4662fSMimi Zohar 
364af4662fSMimi Zohar #define MAX_LSM_RULES 6
374af4662fSMimi Zohar enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
384af4662fSMimi Zohar 	LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
394af4662fSMimi Zohar };
403323eec9SMimi Zohar 
4107f6a794SMimi Zohar struct ima_rule_entry {
423323eec9SMimi Zohar 	struct list_head list;
432fe5d6deSMimi Zohar 	int action;
443323eec9SMimi Zohar 	unsigned int flags;
453323eec9SMimi Zohar 	enum ima_hooks func;
463323eec9SMimi Zohar 	int mask;
473323eec9SMimi Zohar 	unsigned long fsmagic;
483323eec9SMimi Zohar 	uid_t uid;
4907f6a794SMimi Zohar 	uid_t fowner;
504af4662fSMimi Zohar 	struct {
514af4662fSMimi Zohar 		void *rule;	/* LSM file metadata specific */
524af4662fSMimi Zohar 		int type;	/* audit type */
534af4662fSMimi Zohar 	} lsm[MAX_LSM_RULES];
543323eec9SMimi Zohar };
553323eec9SMimi Zohar 
565789ba3bSEric Paris /*
575789ba3bSEric Paris  * Without LSM specific knowledge, the default policy can only be
5807f6a794SMimi Zohar  * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
594af4662fSMimi Zohar  */
605789ba3bSEric Paris 
615789ba3bSEric Paris /*
625789ba3bSEric Paris  * The minimum rule set to allow for full TCB coverage.  Measures all files
635789ba3bSEric Paris  * opened or mmap for exec and everything read by root.  Dangerous because
645789ba3bSEric Paris  * normal users can easily run the machine out of memory simply building
655789ba3bSEric Paris  * and running executables.
665789ba3bSEric Paris  */
6707f6a794SMimi Zohar static struct ima_rule_entry default_rules[] = {
6875834fc3SEric Paris 	{.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC},
693323eec9SMimi Zohar 	{.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
703323eec9SMimi Zohar 	{.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
713323eec9SMimi Zohar 	{.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
724c2c3927SDmitry Kasatkin 	{.action = DONT_MEASURE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC},
738445d64dSDmitry Kasatkin 	{.action = DONT_MEASURE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC},
748445d64dSDmitry Kasatkin 	{.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC},
7575834fc3SEric Paris 	{.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
7675834fc3SEric Paris 	{.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
773323eec9SMimi Zohar 	{.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
783323eec9SMimi Zohar 	 .flags = IMA_FUNC | IMA_MASK},
793323eec9SMimi Zohar 	{.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
803323eec9SMimi Zohar 	 .flags = IMA_FUNC | IMA_MASK},
811e93d005SMimi Zohar 	{.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = 0,
825789ba3bSEric Paris 	 .flags = IMA_FUNC | IMA_MASK | IMA_UID},
833323eec9SMimi Zohar };
843323eec9SMimi Zohar 
8507f6a794SMimi Zohar static struct ima_rule_entry default_appraise_rules[] = {
8607f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC},
8707f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
8807f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
8907f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
9007f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC},
9107f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC},
9207f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC},
9307f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
9407f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
9507f6a794SMimi Zohar 	{.action = DONT_APPRAISE,.fsmagic = CGROUP_SUPER_MAGIC,.flags = IMA_FSMAGIC},
9607f6a794SMimi Zohar 	{.action = APPRAISE,.fowner = 0,.flags = IMA_FOWNER},
9707f6a794SMimi Zohar };
983323eec9SMimi Zohar 
9907f6a794SMimi Zohar static LIST_HEAD(ima_default_rules);
10007f6a794SMimi Zohar static LIST_HEAD(ima_policy_rules);
10107f6a794SMimi Zohar static struct list_head *ima_rules;
10207f6a794SMimi Zohar 
10307f6a794SMimi Zohar static DEFINE_MUTEX(ima_rules_mutex);
1044af4662fSMimi Zohar 
1055789ba3bSEric Paris static bool ima_use_tcb __initdata;
10607f6a794SMimi Zohar static int __init default_measure_policy_setup(char *str)
1075789ba3bSEric Paris {
1085789ba3bSEric Paris 	ima_use_tcb = 1;
1095789ba3bSEric Paris 	return 1;
1105789ba3bSEric Paris }
11107f6a794SMimi Zohar __setup("ima_tcb", default_measure_policy_setup);
11207f6a794SMimi Zohar 
11307f6a794SMimi Zohar static bool ima_use_appraise_tcb __initdata;
11407f6a794SMimi Zohar static int __init default_appraise_policy_setup(char *str)
11507f6a794SMimi Zohar {
11607f6a794SMimi Zohar 	ima_use_appraise_tcb = 1;
11707f6a794SMimi Zohar 	return 1;
11807f6a794SMimi Zohar }
11907f6a794SMimi Zohar __setup("ima_appraise_tcb", default_appraise_policy_setup);
1205789ba3bSEric Paris 
1213323eec9SMimi Zohar /**
1223323eec9SMimi Zohar  * ima_match_rules - determine whether an inode matches the measure rule.
1233323eec9SMimi Zohar  * @rule: a pointer to a rule
1243323eec9SMimi Zohar  * @inode: a pointer to an inode
1253323eec9SMimi Zohar  * @func: LIM hook identifier
1263323eec9SMimi Zohar  * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
1273323eec9SMimi Zohar  *
1283323eec9SMimi Zohar  * Returns true on rule match, false on failure.
1293323eec9SMimi Zohar  */
13007f6a794SMimi Zohar static bool ima_match_rules(struct ima_rule_entry *rule,
1313323eec9SMimi Zohar 			    struct inode *inode, enum ima_hooks func, int mask)
1323323eec9SMimi Zohar {
1333323eec9SMimi Zohar 	struct task_struct *tsk = current;
1343db59dd9SMimi Zohar 	const struct cred *cred = current_cred();
1354af4662fSMimi Zohar 	int i;
1363323eec9SMimi Zohar 
1373323eec9SMimi Zohar 	if ((rule->flags & IMA_FUNC) && rule->func != func)
1383323eec9SMimi Zohar 		return false;
1393323eec9SMimi Zohar 	if ((rule->flags & IMA_MASK) && rule->mask != mask)
1403323eec9SMimi Zohar 		return false;
1413323eec9SMimi Zohar 	if ((rule->flags & IMA_FSMAGIC)
1423323eec9SMimi Zohar 	    && rule->fsmagic != inode->i_sb->s_magic)
1433323eec9SMimi Zohar 		return false;
1443db59dd9SMimi Zohar 	if ((rule->flags & IMA_UID) && rule->uid != cred->uid)
1453323eec9SMimi Zohar 		return false;
14607f6a794SMimi Zohar 	if ((rule->flags & IMA_FOWNER) && rule->fowner != inode->i_uid)
14707f6a794SMimi Zohar 		return false;
1484af4662fSMimi Zohar 	for (i = 0; i < MAX_LSM_RULES; i++) {
14953fc0e22SMimi Zohar 		int rc = 0;
1504af4662fSMimi Zohar 		u32 osid, sid;
1514af4662fSMimi Zohar 
1524af4662fSMimi Zohar 		if (!rule->lsm[i].rule)
1534af4662fSMimi Zohar 			continue;
1544af4662fSMimi Zohar 
1554af4662fSMimi Zohar 		switch (i) {
1564af4662fSMimi Zohar 		case LSM_OBJ_USER:
1574af4662fSMimi Zohar 		case LSM_OBJ_ROLE:
1584af4662fSMimi Zohar 		case LSM_OBJ_TYPE:
1594af4662fSMimi Zohar 			security_inode_getsecid(inode, &osid);
1604af4662fSMimi Zohar 			rc = security_filter_rule_match(osid,
1614af4662fSMimi Zohar 							rule->lsm[i].type,
16253fc0e22SMimi Zohar 							Audit_equal,
1634af4662fSMimi Zohar 							rule->lsm[i].rule,
1644af4662fSMimi Zohar 							NULL);
1654af4662fSMimi Zohar 			break;
1664af4662fSMimi Zohar 		case LSM_SUBJ_USER:
1674af4662fSMimi Zohar 		case LSM_SUBJ_ROLE:
1684af4662fSMimi Zohar 		case LSM_SUBJ_TYPE:
1694af4662fSMimi Zohar 			security_task_getsecid(tsk, &sid);
1704af4662fSMimi Zohar 			rc = security_filter_rule_match(sid,
1714af4662fSMimi Zohar 							rule->lsm[i].type,
17253fc0e22SMimi Zohar 							Audit_equal,
1734af4662fSMimi Zohar 							rule->lsm[i].rule,
1744af4662fSMimi Zohar 							NULL);
1754af4662fSMimi Zohar 		default:
1764af4662fSMimi Zohar 			break;
1774af4662fSMimi Zohar 		}
1784af4662fSMimi Zohar 		if (!rc)
1794af4662fSMimi Zohar 			return false;
1804af4662fSMimi Zohar 	}
1813323eec9SMimi Zohar 	return true;
1823323eec9SMimi Zohar }
1833323eec9SMimi Zohar 
1843323eec9SMimi Zohar /**
1853323eec9SMimi Zohar  * ima_match_policy - decision based on LSM and other conditions
1863323eec9SMimi Zohar  * @inode: pointer to an inode for which the policy decision is being made
1873323eec9SMimi Zohar  * @func: IMA hook identifier
1883323eec9SMimi Zohar  * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
1893323eec9SMimi Zohar  *
1903323eec9SMimi Zohar  * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
1913323eec9SMimi Zohar  * conditions.
1923323eec9SMimi Zohar  *
1933323eec9SMimi Zohar  * (There is no need for locking when walking the policy list,
1943323eec9SMimi Zohar  * as elements in the list are never deleted, nor does the list
1953323eec9SMimi Zohar  * change.)
1963323eec9SMimi Zohar  */
1972fe5d6deSMimi Zohar int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
1982fe5d6deSMimi Zohar 		     int flags)
1993323eec9SMimi Zohar {
20007f6a794SMimi Zohar 	struct ima_rule_entry *entry;
2012fe5d6deSMimi Zohar 	int action = 0, actmask = flags | (flags << 1);
2023323eec9SMimi Zohar 
20307f6a794SMimi Zohar 	list_for_each_entry(entry, ima_rules, list) {
2043323eec9SMimi Zohar 
2052fe5d6deSMimi Zohar 		if (!(entry->action & actmask))
2062fe5d6deSMimi Zohar 			continue;
2072fe5d6deSMimi Zohar 
2082fe5d6deSMimi Zohar 		if (!ima_match_rules(entry, inode, func, mask))
2092fe5d6deSMimi Zohar 			continue;
2102fe5d6deSMimi Zohar 
21145e2472eSDmitry Kasatkin 		action |= entry->action & IMA_DO_MASK;
21245e2472eSDmitry Kasatkin 		if (entry->action & IMA_DO_MASK)
21345e2472eSDmitry Kasatkin 			actmask &= ~(entry->action | entry->action << 1);
21445e2472eSDmitry Kasatkin 		else
21545e2472eSDmitry Kasatkin 			actmask &= ~(entry->action | entry->action >> 1);
21645e2472eSDmitry Kasatkin 
2172fe5d6deSMimi Zohar 		if (!actmask)
2182fe5d6deSMimi Zohar 			break;
2193323eec9SMimi Zohar 	}
2202fe5d6deSMimi Zohar 
2212fe5d6deSMimi Zohar 	return action;
2223323eec9SMimi Zohar }
2233323eec9SMimi Zohar 
2243323eec9SMimi Zohar /**
2253323eec9SMimi Zohar  * ima_init_policy - initialize the default measure rules.
2263323eec9SMimi Zohar  *
22707f6a794SMimi Zohar  * ima_rules points to either the ima_default_rules or the
22807f6a794SMimi Zohar  * the new ima_policy_rules.
2293323eec9SMimi Zohar  */
230932995f0SEric Paris void __init ima_init_policy(void)
2313323eec9SMimi Zohar {
23207f6a794SMimi Zohar 	int i, measure_entries, appraise_entries;
2333323eec9SMimi Zohar 
2345789ba3bSEric Paris 	/* if !ima_use_tcb set entries = 0 so we load NO default rules */
23507f6a794SMimi Zohar 	measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0;
23607f6a794SMimi Zohar 	appraise_entries = ima_use_appraise_tcb ?
23707f6a794SMimi Zohar 			 ARRAY_SIZE(default_appraise_rules) : 0;
2385789ba3bSEric Paris 
23907f6a794SMimi Zohar 	for (i = 0; i < measure_entries + appraise_entries; i++) {
24007f6a794SMimi Zohar 		if (i < measure_entries)
24107f6a794SMimi Zohar 			list_add_tail(&default_rules[i].list,
24207f6a794SMimi Zohar 				      &ima_default_rules);
24307f6a794SMimi Zohar 		else {
24407f6a794SMimi Zohar 			int j = i - measure_entries;
24507f6a794SMimi Zohar 
24607f6a794SMimi Zohar 			list_add_tail(&default_appraise_rules[j].list,
24707f6a794SMimi Zohar 				      &ima_default_rules);
24807f6a794SMimi Zohar 		}
24907f6a794SMimi Zohar 	}
25007f6a794SMimi Zohar 
25107f6a794SMimi Zohar 	ima_rules = &ima_default_rules;
2523323eec9SMimi Zohar }
2534af4662fSMimi Zohar 
2544af4662fSMimi Zohar /**
2554af4662fSMimi Zohar  * ima_update_policy - update default_rules with new measure rules
2564af4662fSMimi Zohar  *
2574af4662fSMimi Zohar  * Called on file .release to update the default rules with a complete new
2584af4662fSMimi Zohar  * policy.  Once updated, the policy is locked, no additional rules can be
2594af4662fSMimi Zohar  * added to the policy.
2604af4662fSMimi Zohar  */
2614af4662fSMimi Zohar void ima_update_policy(void)
2624af4662fSMimi Zohar {
2634af4662fSMimi Zohar 	const char *op = "policy_update";
2644af4662fSMimi Zohar 	const char *cause = "already exists";
2654af4662fSMimi Zohar 	int result = 1;
2664af4662fSMimi Zohar 	int audit_info = 0;
2674af4662fSMimi Zohar 
26807f6a794SMimi Zohar 	if (ima_rules == &ima_default_rules) {
26907f6a794SMimi Zohar 		ima_rules = &ima_policy_rules;
2704af4662fSMimi Zohar 		cause = "complete";
2714af4662fSMimi Zohar 		result = 0;
2724af4662fSMimi Zohar 	}
2734af4662fSMimi Zohar 	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
2744af4662fSMimi Zohar 			    NULL, op, cause, result, audit_info);
2754af4662fSMimi Zohar }
2764af4662fSMimi Zohar 
2774af4662fSMimi Zohar enum {
2784af4662fSMimi Zohar 	Opt_err = -1,
2794af4662fSMimi Zohar 	Opt_measure = 1, Opt_dont_measure,
28007f6a794SMimi Zohar 	Opt_appraise, Opt_dont_appraise,
281*e7c568e0SPeter Moody 	Opt_audit,
2824af4662fSMimi Zohar 	Opt_obj_user, Opt_obj_role, Opt_obj_type,
2834af4662fSMimi Zohar 	Opt_subj_user, Opt_subj_role, Opt_subj_type,
28407f6a794SMimi Zohar 	Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner
2854af4662fSMimi Zohar };
2864af4662fSMimi Zohar 
2874af4662fSMimi Zohar static match_table_t policy_tokens = {
2884af4662fSMimi Zohar 	{Opt_measure, "measure"},
2894af4662fSMimi Zohar 	{Opt_dont_measure, "dont_measure"},
29007f6a794SMimi Zohar 	{Opt_appraise, "appraise"},
29107f6a794SMimi Zohar 	{Opt_dont_appraise, "dont_appraise"},
292*e7c568e0SPeter Moody 	{Opt_audit, "audit"},
2934af4662fSMimi Zohar 	{Opt_obj_user, "obj_user=%s"},
2944af4662fSMimi Zohar 	{Opt_obj_role, "obj_role=%s"},
2954af4662fSMimi Zohar 	{Opt_obj_type, "obj_type=%s"},
2964af4662fSMimi Zohar 	{Opt_subj_user, "subj_user=%s"},
2974af4662fSMimi Zohar 	{Opt_subj_role, "subj_role=%s"},
2984af4662fSMimi Zohar 	{Opt_subj_type, "subj_type=%s"},
2994af4662fSMimi Zohar 	{Opt_func, "func=%s"},
3004af4662fSMimi Zohar 	{Opt_mask, "mask=%s"},
3014af4662fSMimi Zohar 	{Opt_fsmagic, "fsmagic=%s"},
3024af4662fSMimi Zohar 	{Opt_uid, "uid=%s"},
30307f6a794SMimi Zohar 	{Opt_fowner, "fowner=%s"},
3044af4662fSMimi Zohar 	{Opt_err, NULL}
3054af4662fSMimi Zohar };
3064af4662fSMimi Zohar 
30707f6a794SMimi Zohar static int ima_lsm_rule_init(struct ima_rule_entry *entry,
3084af4662fSMimi Zohar 			     char *args, int lsm_rule, int audit_type)
3094af4662fSMimi Zohar {
3104af4662fSMimi Zohar 	int result;
3114af4662fSMimi Zohar 
3127b62e162SEric Paris 	if (entry->lsm[lsm_rule].rule)
3137b62e162SEric Paris 		return -EINVAL;
3147b62e162SEric Paris 
3154af4662fSMimi Zohar 	entry->lsm[lsm_rule].type = audit_type;
3164af4662fSMimi Zohar 	result = security_filter_rule_init(entry->lsm[lsm_rule].type,
31753fc0e22SMimi Zohar 					   Audit_equal, args,
3184af4662fSMimi Zohar 					   &entry->lsm[lsm_rule].rule);
319867c2026SMimi Zohar 	if (!entry->lsm[lsm_rule].rule)
320867c2026SMimi Zohar 		return -EINVAL;
3214af4662fSMimi Zohar 	return result;
3224af4662fSMimi Zohar }
3234af4662fSMimi Zohar 
3242f1506cdSEric Paris static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
3252f1506cdSEric Paris {
3262f1506cdSEric Paris 	audit_log_format(ab, "%s=", key);
3272f1506cdSEric Paris 	audit_log_untrustedstring(ab, value);
3282f1506cdSEric Paris 	audit_log_format(ab, " ");
3292f1506cdSEric Paris }
3302f1506cdSEric Paris 
33107f6a794SMimi Zohar static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
3324af4662fSMimi Zohar {
3334af4662fSMimi Zohar 	struct audit_buffer *ab;
3344af4662fSMimi Zohar 	char *p;
3354af4662fSMimi Zohar 	int result = 0;
3364af4662fSMimi Zohar 
337523979adSMimi Zohar 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
3384af4662fSMimi Zohar 
3397b62e162SEric Paris 	entry->uid = -1;
34007f6a794SMimi Zohar 	entry->fowner = -1;
341b9035b1fSEric Paris 	entry->action = UNKNOWN;
34228ef4002SEric Paris 	while ((p = strsep(&rule, " \t")) != NULL) {
3434af4662fSMimi Zohar 		substring_t args[MAX_OPT_ARGS];
3444af4662fSMimi Zohar 		int token;
3454af4662fSMimi Zohar 		unsigned long lnum;
3464af4662fSMimi Zohar 
3474af4662fSMimi Zohar 		if (result < 0)
3484af4662fSMimi Zohar 			break;
34928ef4002SEric Paris 		if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
35028ef4002SEric Paris 			continue;
3514af4662fSMimi Zohar 		token = match_token(p, policy_tokens, args);
3524af4662fSMimi Zohar 		switch (token) {
3534af4662fSMimi Zohar 		case Opt_measure:
3542f1506cdSEric Paris 			ima_log_string(ab, "action", "measure");
3557b62e162SEric Paris 
3567b62e162SEric Paris 			if (entry->action != UNKNOWN)
3577b62e162SEric Paris 				result = -EINVAL;
3587b62e162SEric Paris 
3594af4662fSMimi Zohar 			entry->action = MEASURE;
3604af4662fSMimi Zohar 			break;
3614af4662fSMimi Zohar 		case Opt_dont_measure:
3622f1506cdSEric Paris 			ima_log_string(ab, "action", "dont_measure");
3637b62e162SEric Paris 
3647b62e162SEric Paris 			if (entry->action != UNKNOWN)
3657b62e162SEric Paris 				result = -EINVAL;
3667b62e162SEric Paris 
3674af4662fSMimi Zohar 			entry->action = DONT_MEASURE;
3684af4662fSMimi Zohar 			break;
36907f6a794SMimi Zohar 		case Opt_appraise:
37007f6a794SMimi Zohar 			ima_log_string(ab, "action", "appraise");
37107f6a794SMimi Zohar 
37207f6a794SMimi Zohar 			if (entry->action != UNKNOWN)
37307f6a794SMimi Zohar 				result = -EINVAL;
37407f6a794SMimi Zohar 
37507f6a794SMimi Zohar 			entry->action = APPRAISE;
37607f6a794SMimi Zohar 			break;
37707f6a794SMimi Zohar 		case Opt_dont_appraise:
37807f6a794SMimi Zohar 			ima_log_string(ab, "action", "dont_appraise");
37907f6a794SMimi Zohar 
38007f6a794SMimi Zohar 			if (entry->action != UNKNOWN)
38107f6a794SMimi Zohar 				result = -EINVAL;
38207f6a794SMimi Zohar 
38307f6a794SMimi Zohar 			entry->action = DONT_APPRAISE;
38407f6a794SMimi Zohar 			break;
385*e7c568e0SPeter Moody 		case Opt_audit:
386*e7c568e0SPeter Moody 			ima_log_string(ab, "action", "audit");
387*e7c568e0SPeter Moody 
388*e7c568e0SPeter Moody 			if (entry->action != UNKNOWN)
389*e7c568e0SPeter Moody 				result = -EINVAL;
390*e7c568e0SPeter Moody 
391*e7c568e0SPeter Moody 			entry->action = AUDIT;
392*e7c568e0SPeter Moody 			break;
3934af4662fSMimi Zohar 		case Opt_func:
3942f1506cdSEric Paris 			ima_log_string(ab, "func", args[0].from);
3957b62e162SEric Paris 
3967b62e162SEric Paris 			if (entry->func)
3977b62e162SEric Paris 				result = -EINVAL;
3987b62e162SEric Paris 
3991e93d005SMimi Zohar 			if (strcmp(args[0].from, "FILE_CHECK") == 0)
4001e93d005SMimi Zohar 				entry->func = FILE_CHECK;
4011e93d005SMimi Zohar 			/* PATH_CHECK is for backwards compat */
4021e93d005SMimi Zohar 			else if (strcmp(args[0].from, "PATH_CHECK") == 0)
4031e93d005SMimi Zohar 				entry->func = FILE_CHECK;
4044af4662fSMimi Zohar 			else if (strcmp(args[0].from, "FILE_MMAP") == 0)
4054af4662fSMimi Zohar 				entry->func = FILE_MMAP;
4064af4662fSMimi Zohar 			else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
4074af4662fSMimi Zohar 				entry->func = BPRM_CHECK;
4084af4662fSMimi Zohar 			else
4094af4662fSMimi Zohar 				result = -EINVAL;
4104af4662fSMimi Zohar 			if (!result)
4114af4662fSMimi Zohar 				entry->flags |= IMA_FUNC;
4124af4662fSMimi Zohar 			break;
4134af4662fSMimi Zohar 		case Opt_mask:
4142f1506cdSEric Paris 			ima_log_string(ab, "mask", args[0].from);
4157b62e162SEric Paris 
4167b62e162SEric Paris 			if (entry->mask)
4177b62e162SEric Paris 				result = -EINVAL;
4187b62e162SEric Paris 
4194af4662fSMimi Zohar 			if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
4204af4662fSMimi Zohar 				entry->mask = MAY_EXEC;
4214af4662fSMimi Zohar 			else if (strcmp(args[0].from, "MAY_WRITE") == 0)
4224af4662fSMimi Zohar 				entry->mask = MAY_WRITE;
4234af4662fSMimi Zohar 			else if (strcmp(args[0].from, "MAY_READ") == 0)
4244af4662fSMimi Zohar 				entry->mask = MAY_READ;
4254af4662fSMimi Zohar 			else if (strcmp(args[0].from, "MAY_APPEND") == 0)
4264af4662fSMimi Zohar 				entry->mask = MAY_APPEND;
4274af4662fSMimi Zohar 			else
4284af4662fSMimi Zohar 				result = -EINVAL;
4294af4662fSMimi Zohar 			if (!result)
4304af4662fSMimi Zohar 				entry->flags |= IMA_MASK;
4314af4662fSMimi Zohar 			break;
4324af4662fSMimi Zohar 		case Opt_fsmagic:
4332f1506cdSEric Paris 			ima_log_string(ab, "fsmagic", args[0].from);
4347b62e162SEric Paris 
4357b62e162SEric Paris 			if (entry->fsmagic) {
4367b62e162SEric Paris 				result = -EINVAL;
4377b62e162SEric Paris 				break;
4387b62e162SEric Paris 			}
4397b62e162SEric Paris 
4404af4662fSMimi Zohar 			result = strict_strtoul(args[0].from, 16,
4414af4662fSMimi Zohar 						&entry->fsmagic);
4424af4662fSMimi Zohar 			if (!result)
4434af4662fSMimi Zohar 				entry->flags |= IMA_FSMAGIC;
4444af4662fSMimi Zohar 			break;
4454af4662fSMimi Zohar 		case Opt_uid:
4462f1506cdSEric Paris 			ima_log_string(ab, "uid", args[0].from);
4477b62e162SEric Paris 
4487b62e162SEric Paris 			if (entry->uid != -1) {
4497b62e162SEric Paris 				result = -EINVAL;
4507b62e162SEric Paris 				break;
4517b62e162SEric Paris 			}
4527b62e162SEric Paris 
4534af4662fSMimi Zohar 			result = strict_strtoul(args[0].from, 10, &lnum);
4544af4662fSMimi Zohar 			if (!result) {
4554af4662fSMimi Zohar 				entry->uid = (uid_t) lnum;
4564af4662fSMimi Zohar 				if (entry->uid != lnum)
4574af4662fSMimi Zohar 					result = -EINVAL;
4584af4662fSMimi Zohar 				else
4594af4662fSMimi Zohar 					entry->flags |= IMA_UID;
4604af4662fSMimi Zohar 			}
4614af4662fSMimi Zohar 			break;
46207f6a794SMimi Zohar 		case Opt_fowner:
46307f6a794SMimi Zohar 			ima_log_string(ab, "fowner", args[0].from);
46407f6a794SMimi Zohar 
46507f6a794SMimi Zohar 			if (entry->fowner != -1) {
46607f6a794SMimi Zohar 				result = -EINVAL;
46707f6a794SMimi Zohar 				break;
46807f6a794SMimi Zohar 			}
46907f6a794SMimi Zohar 
47007f6a794SMimi Zohar 			result = strict_strtoul(args[0].from, 10, &lnum);
47107f6a794SMimi Zohar 			if (!result) {
47207f6a794SMimi Zohar 				entry->fowner = (uid_t) lnum;
47307f6a794SMimi Zohar 				if (entry->fowner != lnum)
47407f6a794SMimi Zohar 					result = -EINVAL;
47507f6a794SMimi Zohar 				else
47607f6a794SMimi Zohar 					entry->flags |= IMA_FOWNER;
47707f6a794SMimi Zohar 			}
47807f6a794SMimi Zohar 			break;
4794af4662fSMimi Zohar 		case Opt_obj_user:
4802f1506cdSEric Paris 			ima_log_string(ab, "obj_user", args[0].from);
4814af4662fSMimi Zohar 			result = ima_lsm_rule_init(entry, args[0].from,
4824af4662fSMimi Zohar 						   LSM_OBJ_USER,
4834af4662fSMimi Zohar 						   AUDIT_OBJ_USER);
4844af4662fSMimi Zohar 			break;
4854af4662fSMimi Zohar 		case Opt_obj_role:
4862f1506cdSEric Paris 			ima_log_string(ab, "obj_role", args[0].from);
4874af4662fSMimi Zohar 			result = ima_lsm_rule_init(entry, args[0].from,
4884af4662fSMimi Zohar 						   LSM_OBJ_ROLE,
4894af4662fSMimi Zohar 						   AUDIT_OBJ_ROLE);
4904af4662fSMimi Zohar 			break;
4914af4662fSMimi Zohar 		case Opt_obj_type:
4922f1506cdSEric Paris 			ima_log_string(ab, "obj_type", args[0].from);
4934af4662fSMimi Zohar 			result = ima_lsm_rule_init(entry, args[0].from,
4944af4662fSMimi Zohar 						   LSM_OBJ_TYPE,
4954af4662fSMimi Zohar 						   AUDIT_OBJ_TYPE);
4964af4662fSMimi Zohar 			break;
4974af4662fSMimi Zohar 		case Opt_subj_user:
4982f1506cdSEric Paris 			ima_log_string(ab, "subj_user", args[0].from);
4994af4662fSMimi Zohar 			result = ima_lsm_rule_init(entry, args[0].from,
5004af4662fSMimi Zohar 						   LSM_SUBJ_USER,
5014af4662fSMimi Zohar 						   AUDIT_SUBJ_USER);
5024af4662fSMimi Zohar 			break;
5034af4662fSMimi Zohar 		case Opt_subj_role:
5042f1506cdSEric Paris 			ima_log_string(ab, "subj_role", args[0].from);
5054af4662fSMimi Zohar 			result = ima_lsm_rule_init(entry, args[0].from,
5064af4662fSMimi Zohar 						   LSM_SUBJ_ROLE,
5074af4662fSMimi Zohar 						   AUDIT_SUBJ_ROLE);
5084af4662fSMimi Zohar 			break;
5094af4662fSMimi Zohar 		case Opt_subj_type:
5102f1506cdSEric Paris 			ima_log_string(ab, "subj_type", args[0].from);
5114af4662fSMimi Zohar 			result = ima_lsm_rule_init(entry, args[0].from,
5124af4662fSMimi Zohar 						   LSM_SUBJ_TYPE,
5134af4662fSMimi Zohar 						   AUDIT_SUBJ_TYPE);
5144af4662fSMimi Zohar 			break;
5154af4662fSMimi Zohar 		case Opt_err:
5162f1506cdSEric Paris 			ima_log_string(ab, "UNKNOWN", p);
517e9d393bfSEric Paris 			result = -EINVAL;
5184af4662fSMimi Zohar 			break;
5194af4662fSMimi Zohar 		}
5204af4662fSMimi Zohar 	}
5217b62e162SEric Paris 	if (!result && (entry->action == UNKNOWN))
5224af4662fSMimi Zohar 		result = -EINVAL;
5234af4662fSMimi Zohar 
524b0d5de4dSEric Paris 	audit_log_format(ab, "res=%d", !result);
5254af4662fSMimi Zohar 	audit_log_end(ab);
5264af4662fSMimi Zohar 	return result;
5274af4662fSMimi Zohar }
5284af4662fSMimi Zohar 
5294af4662fSMimi Zohar /**
53007f6a794SMimi Zohar  * ima_parse_add_rule - add a rule to ima_policy_rules
5314af4662fSMimi Zohar  * @rule - ima measurement policy rule
5324af4662fSMimi Zohar  *
5334af4662fSMimi Zohar  * Uses a mutex to protect the policy list from multiple concurrent writers.
5346ccd0456SEric Paris  * Returns the length of the rule parsed, an error code on failure
5354af4662fSMimi Zohar  */
5366ccd0456SEric Paris ssize_t ima_parse_add_rule(char *rule)
5374af4662fSMimi Zohar {
538523979adSMimi Zohar 	const char *op = "update_policy";
5396ccd0456SEric Paris 	char *p;
54007f6a794SMimi Zohar 	struct ima_rule_entry *entry;
5416ccd0456SEric Paris 	ssize_t result, len;
5424af4662fSMimi Zohar 	int audit_info = 0;
5434af4662fSMimi Zohar 
5444af4662fSMimi Zohar 	/* Prevent installed policy from changing */
54507f6a794SMimi Zohar 	if (ima_rules != &ima_default_rules) {
5464af4662fSMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
5474af4662fSMimi Zohar 				    NULL, op, "already exists",
5484af4662fSMimi Zohar 				    -EACCES, audit_info);
5494af4662fSMimi Zohar 		return -EACCES;
5504af4662fSMimi Zohar 	}
5514af4662fSMimi Zohar 
5524af4662fSMimi Zohar 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
5534af4662fSMimi Zohar 	if (!entry) {
5544af4662fSMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
5554af4662fSMimi Zohar 				    NULL, op, "-ENOMEM", -ENOMEM, audit_info);
5564af4662fSMimi Zohar 		return -ENOMEM;
5574af4662fSMimi Zohar 	}
5584af4662fSMimi Zohar 
5594af4662fSMimi Zohar 	INIT_LIST_HEAD(&entry->list);
5604af4662fSMimi Zohar 
5616ccd0456SEric Paris 	p = strsep(&rule, "\n");
5626ccd0456SEric Paris 	len = strlen(p) + 1;
5637233e3eeSEric Paris 
5647233e3eeSEric Paris 	if (*p == '#') {
5657233e3eeSEric Paris 		kfree(entry);
5667233e3eeSEric Paris 		return len;
5677233e3eeSEric Paris 	}
5687233e3eeSEric Paris 
5696ccd0456SEric Paris 	result = ima_parse_rule(p, entry);
5707233e3eeSEric Paris 	if (result) {
5714af4662fSMimi Zohar 		kfree(entry);
572523979adSMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
573523979adSMimi Zohar 				    NULL, op, "invalid policy", result,
574523979adSMimi Zohar 				    audit_info);
5754af4662fSMimi Zohar 		return result;
5764af4662fSMimi Zohar 	}
5774af4662fSMimi Zohar 
57807f6a794SMimi Zohar 	mutex_lock(&ima_rules_mutex);
57907f6a794SMimi Zohar 	list_add_tail(&entry->list, &ima_policy_rules);
58007f6a794SMimi Zohar 	mutex_unlock(&ima_rules_mutex);
5817233e3eeSEric Paris 
5827233e3eeSEric Paris 	return len;
5837233e3eeSEric Paris }
5847233e3eeSEric Paris 
5854af4662fSMimi Zohar /* ima_delete_rules called to cleanup invalid policy */
58664c61d80SJames Morris void ima_delete_rules(void)
5874af4662fSMimi Zohar {
58807f6a794SMimi Zohar 	struct ima_rule_entry *entry, *tmp;
5894af4662fSMimi Zohar 
59007f6a794SMimi Zohar 	mutex_lock(&ima_rules_mutex);
59107f6a794SMimi Zohar 	list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
5924af4662fSMimi Zohar 		list_del(&entry->list);
5934af4662fSMimi Zohar 		kfree(entry);
5944af4662fSMimi Zohar 	}
59507f6a794SMimi Zohar 	mutex_unlock(&ima_rules_mutex);
5964af4662fSMimi Zohar }
597